497 lines
16 KiB
Python
497 lines
16 KiB
Python
# #### BEGIN GPL LICENSE BLOCK #####
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# 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 General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
# ##### END GPL LICENSE BLOCK #####
|
|
|
|
from typing import Dict
|
|
import os
|
|
|
|
try:
|
|
import ConfigParser
|
|
except Exception:
|
|
import configparser as ConfigParser
|
|
|
|
from . import reporting
|
|
from .modules.poliigon_core.api_remote_control_params import (
|
|
CATEGORY_ALL,
|
|
KEY_TAB_IMPORTED,
|
|
KEY_TAB_MY_ASSETS,
|
|
KEY_TAB_RECENT_DOWNLOADS,
|
|
KEY_TAB_ONLINE,
|
|
KEY_TAB_LOCAL)
|
|
from .modules.poliigon_core.plan_manager import PoliigonSubscription
|
|
from .modules.poliigon_core.user import PoliigonUser
|
|
|
|
from .dialogs.utils_dlg import check_dpi
|
|
from .notifications import build_writing_settings_failed_notification
|
|
from .utils import (
|
|
f_Ex,
|
|
f_MDir)
|
|
|
|
|
|
# Use _get_default_settings() to get the default settings.
|
|
DEFAULT_SETTINGS = {
|
|
"area": KEY_TAB_ONLINE,
|
|
"auto_download": 1,
|
|
"category": {
|
|
KEY_TAB_IMPORTED: [CATEGORY_ALL],
|
|
KEY_TAB_MY_ASSETS: [CATEGORY_ALL],
|
|
KEY_TAB_RECENT_DOWNLOADS: [CATEGORY_ALL],
|
|
KEY_TAB_ONLINE: [CATEGORY_ALL],
|
|
KEY_TAB_LOCAL: [CATEGORY_ALL]
|
|
},
|
|
"conform": 0,
|
|
"default_lod": "LOD1",
|
|
"del_zip": 1,
|
|
"disabled_dirs": [],
|
|
"download_lods": 1,
|
|
"download_prefer_blend": 1,
|
|
"download_link_blend": 0,
|
|
"hdri_use_jpg_bg": False,
|
|
"hide_labels": 1,
|
|
"hide_scene": 0,
|
|
"hide_suggest": 0,
|
|
"location": "Properties",
|
|
"mapping_type": "UV + UberMapping",
|
|
"mat_props": [],
|
|
"mix_props": [],
|
|
"new_release": "",
|
|
"last_update": "",
|
|
"new_top": 1,
|
|
"notify": 5,
|
|
"one_click_purchase": 1,
|
|
"page": 6,
|
|
"popup_welcome": 0,
|
|
"popup_download": 0,
|
|
"popup_preview": 0,
|
|
"preview_size": 7, # 7 currently constant/hard coded
|
|
"previews": 1,
|
|
# Note on reporting rates:
|
|
# These will only be changed upon successful update-requests
|
|
# and only ever store custom rates from updater. Any default
|
|
# values and/or forced sampling values will and must not be stored
|
|
# here!
|
|
"reporting_error_rate": -1, # no valid value
|
|
"reporting_transaction_rate": -1, # no valid value
|
|
"set_library": "",
|
|
"show_active": 1,
|
|
"show_add_dir": 1,
|
|
"show_asset_info": 1,
|
|
"show_credits": 1,
|
|
"show_default_prefs": 1,
|
|
"show_display_prefs": 1,
|
|
"show_import_prefs": 1,
|
|
"show_asset_browser_prefs": True,
|
|
"show_mat_ops": 0,
|
|
"show_mat_props": 0,
|
|
"show_mat_texs": 0,
|
|
"show_mix_props": 1,
|
|
"show_pass": 0,
|
|
"show_plan": 1,
|
|
"show_feedback": 0,
|
|
"show_settings": 0,
|
|
"show_user": 0,
|
|
"sorting": "Latest",
|
|
"thumbsize": "Medium",
|
|
"unzip": 1,
|
|
"update_sel": 1,
|
|
"use_16": 1,
|
|
"use_ao": 1,
|
|
"use_bump": 1,
|
|
"use_disp": 1,
|
|
"use_subdiv": 1,
|
|
"version": None, # initialized in _get_default_settings()
|
|
"win_scale": 1,
|
|
"first_enabled_time": "",
|
|
|
|
"res": "2K",
|
|
"lod": "NONE",
|
|
"mres": "2K",
|
|
"hdri": "1K",
|
|
"hdrib": "8K",
|
|
"hdrif": "EXR", # TODO(Andreas): constant and used in commented code, only
|
|
"brush": "2K",
|
|
|
|
# TODO(Andreas): Why did we store a list of map types in settings???
|
|
# "maps": cTB.vMaps,
|
|
}
|
|
|
|
|
|
def _get_default_settings(cTB) -> Dict[str, any]:
|
|
"""Returns default settings from above dictionary, augmented with runtime
|
|
infos like e.g. version.
|
|
"""
|
|
|
|
settings = DEFAULT_SETTINGS
|
|
settings["version"] = cTB.version
|
|
return settings
|
|
|
|
|
|
def _read_config(cTB):
|
|
"""Safely reads the config or returns an empty one if corrupted."""
|
|
|
|
config = ConfigParser.ConfigParser()
|
|
config.optionxform = str
|
|
with cTB.lock_settings_file:
|
|
try:
|
|
config.read(cTB.path_settings)
|
|
except ConfigParser.Error:
|
|
# Corrupted file, return empty config.
|
|
cTB.logger.exception(
|
|
"Config parsing error, using fresh empty config instead.")
|
|
config = ConfigParser.ConfigParser()
|
|
config.optionxform = str
|
|
return config
|
|
|
|
|
|
def _get_settings_section_user(cTB, config: ConfigParser) -> bool:
|
|
"""Returns False, if section 'user' is not found."""
|
|
|
|
if not config.has_section("user"):
|
|
return False
|
|
|
|
if cTB.user is None:
|
|
# Note: Marking non existing user by setting user ID None
|
|
cTB.user = PoliigonUser(
|
|
user_name="", user_id=None, plan=PoliigonSubscription())
|
|
|
|
user = cTB.user
|
|
for _key in config.options("user"):
|
|
if _key in cTB.skip_legacy_settings:
|
|
continue
|
|
if _key in ["credits", "credits_od"]:
|
|
try:
|
|
setattr(user, _key, int(config.get("user", _key)))
|
|
except ValueError:
|
|
setattr(user, _key, 0)
|
|
elif _key == "token":
|
|
token = config.get("user", "token")
|
|
if token and token != "None":
|
|
cTB._api.token = config.get("user", "token")
|
|
elif _key == "user_name":
|
|
setattr(user, _key, config.get("user", _key))
|
|
elif _key == "id":
|
|
try:
|
|
user_id_config = config.get("user", _key)
|
|
user.user_id = int(user_id_config)
|
|
except ValueError:
|
|
if user_id_config not in [None, "None"]: # Typical logged out case
|
|
cTB.logger.exception(f"Couldn't set user '{user_id_config}':")
|
|
user.user_id = None # mark user not existent
|
|
elif _key == "user_id":
|
|
pass # ignore, likely a remnant from a bug during development
|
|
# elif _key == "plan_name":
|
|
# user.plan.plan_name = config.get("user", _key)
|
|
elif _key == "plan_credit":
|
|
try:
|
|
setattr(user.plan, _key, int(config.get("user", _key)))
|
|
except ValueError:
|
|
setattr(user.plan, _key, None)
|
|
elif _key in ["plan_name", "plan_paused_at", "plan_paused_until"]:
|
|
setattr(user.plan, _key, config.get("user", _key))
|
|
elif _key == "plan_next_renew":
|
|
user.plan.next_subscription_renewal_date = config.get("user", _key)
|
|
elif _key == "plan_next_credits":
|
|
user.plan.next_credit_renewal_date = config.get("user", _key)
|
|
elif _key == "plan_paused":
|
|
pass # we do get this info from addon-core, now
|
|
elif _key == "is_free_user":
|
|
pass # we do get this info from addon-core, now
|
|
else:
|
|
# TODO(Andreas): Remove, when working. Or add logging/reporting
|
|
cTB.logger.debug("UNSET USER PARAM", _key)
|
|
|
|
if user.user_id is None:
|
|
cTB.user = None
|
|
else:
|
|
reporting.assign_user(cTB.user.user_id)
|
|
|
|
return True
|
|
|
|
|
|
def _get_settings_section_settings(cTB, config: ConfigParser) -> None:
|
|
if not config.has_section("settings"):
|
|
return
|
|
|
|
for _key in config.options("settings"):
|
|
if _key.startswith("category"):
|
|
try:
|
|
cTB.settings["category"] = config.get(
|
|
"settings", _key
|
|
).split("/")
|
|
if "" in cTB.settings[_key]:
|
|
cTB.settings["category"].remove("")
|
|
except Exception:
|
|
pass
|
|
else:
|
|
cTB.settings[_key] = config.get("settings", _key)
|
|
|
|
if _key in [
|
|
"add_dirs",
|
|
"disabled_dirs",
|
|
"mat_props",
|
|
"mix_props",
|
|
]:
|
|
cTB.settings[_key] = cTB.settings[_key].split(";")
|
|
if "" in cTB.settings[_key]:
|
|
cTB.settings[_key].remove("")
|
|
elif cTB.settings[_key] == "True":
|
|
cTB.settings[_key] = 1
|
|
elif cTB.settings[_key] == "False":
|
|
cTB.settings[_key] = 0
|
|
else:
|
|
try:
|
|
cTB.settings[_key] = int(cTB.settings[_key])
|
|
except Exception:
|
|
try:
|
|
cTB.settings[_key] = float(cTB.settings[_key])
|
|
except Exception:
|
|
pass
|
|
# Fallback, if lod was set to SOURCE
|
|
if _key == "lod" and cTB.settings[_key] == "SOURCE":
|
|
# TODO(Andreas): Fallback to LOD0 correct?
|
|
cTB.settings[_key] = "LOD0"
|
|
|
|
|
|
def _get_settings_section_presets(cTB, config: ConfigParser) -> None:
|
|
if not config.has_section("presets"):
|
|
return
|
|
|
|
for _key in config.options("presets"):
|
|
try:
|
|
cTB.vPresets[_key] = [
|
|
float(_value)
|
|
for _value in config.get("presets", _key).split(";")
|
|
]
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def _get_settings_section_mixpresets(cTB, config: ConfigParser) -> None:
|
|
if not config.has_section("mixpresets"):
|
|
return
|
|
|
|
for _key in config.options("mixpresets"):
|
|
try:
|
|
cTB.vMixPresets[_key] = [
|
|
float(_value)
|
|
for _value in config.get("mixpresets", _key).split(";")
|
|
]
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def _get_settings_section_download(cTB, config: ConfigParser) -> None:
|
|
if not config.has_section("download"):
|
|
return
|
|
|
|
for _key in config.options("download"):
|
|
if _key == "res":
|
|
cTB.settings["res"] = config.get("download", _key)
|
|
elif _key == "maps":
|
|
value = config.get("download", _key)
|
|
cTB.settings["maps"] = value.split(";")
|
|
|
|
|
|
def get_settings_section_map_prefs(cTB) -> None:
|
|
config = _read_config(cTB)
|
|
if not config.has_section("map_preferences"):
|
|
return
|
|
|
|
user_prefs = cTB.user.map_preferences
|
|
if user_prefs is None:
|
|
return
|
|
|
|
for _map_format in user_prefs.texture_maps:
|
|
map_name = _map_format.map_type.name
|
|
local_ext_pref = config.get(
|
|
"map_preferences", str(map_name), fallback="")
|
|
local_ext_available = _map_format.extensions.get(
|
|
local_ext_pref.lower(), True)
|
|
|
|
if local_ext_pref in [None, ""] or not local_ext_available:
|
|
continue
|
|
elif local_ext_pref == "NONE":
|
|
_map_format.selected = None
|
|
_map_format.enabled = False
|
|
else:
|
|
_map_format.selected = local_ext_pref.lower()
|
|
_map_format.enabled = True
|
|
|
|
|
|
def get_settings(cTB) -> None:
|
|
cTB.logger.debug("get_settings")
|
|
|
|
cTB.skip_legacy_settings = ["name", "email"]
|
|
|
|
cTB.settings = _get_default_settings(cTB)
|
|
|
|
check_dpi(cTB)
|
|
|
|
cTB.vPresets = {}
|
|
cTB.vMixPresets = {}
|
|
|
|
cTB.vReleases = {}
|
|
|
|
if f_Ex(cTB.path_settings): # check done outside of lock should still be ok
|
|
config = _read_config(cTB)
|
|
|
|
if not _get_settings_section_user(cTB, config):
|
|
with cTB.lock_settings_file:
|
|
os.remove(cTB.path_settings)
|
|
config = ConfigParser.ConfigParser()
|
|
|
|
_get_settings_section_settings(cTB, config)
|
|
_get_settings_section_presets(cTB, config)
|
|
_get_settings_section_mixpresets(cTB, config)
|
|
_get_settings_section_download(cTB, config)
|
|
# Loading of map prefs works differently, as it happens upon
|
|
# receiving map prefs from server.
|
|
|
|
if cTB.settings.get("library", "") == "":
|
|
cTB.settings["set_library"] = cTB.dir_settings.replace(
|
|
"Blender", "Library")
|
|
|
|
cTB.settings["show_user"] = 0
|
|
cTB.settings["mat_props_edit"] = 0
|
|
|
|
cTB.settings["area"] = KEY_TAB_ONLINE
|
|
cTB.settings["category"] = [CATEGORY_ALL]
|
|
|
|
save_settings(cTB)
|
|
|
|
|
|
def _save_settings_section_user(cTB, config: ConfigParser) -> None:
|
|
if not config.has_section("user"):
|
|
config.add_section("user")
|
|
|
|
# for vK in cTB.vUser.keys():
|
|
# if vK in cTB.skip_legacy_settings:
|
|
# config.remove_option("user", vK)
|
|
# continue
|
|
# config.set("user", vK, str(cTB.vUser[vK]))
|
|
if cTB.user is not None:
|
|
config.set("user", "id", str(cTB.user.user_id))
|
|
config.set("user", "user_name", str(cTB.user.user_name))
|
|
|
|
# Save token as if cTB field, on load will be parsed to _api.token
|
|
config.set("user", "token", str(cTB._api.token))
|
|
|
|
|
|
def _save_settings_section_settings(cTB, config: ConfigParser) -> None:
|
|
if not config.has_section("settings"):
|
|
config.add_section("settings")
|
|
|
|
for _key in cTB.settings.keys():
|
|
if _key == "category":
|
|
config.set("settings", _key, "/".join(cTB.settings[_key]))
|
|
elif _key in ["add_dirs", "disabled_dirs", "mat_props", "mix_props"]:
|
|
config.set("settings", _key, ";".join(cTB.settings[_key]))
|
|
else:
|
|
config.set("settings", _key, str(cTB.settings[_key]))
|
|
|
|
|
|
def _save_settings_section_presets(cTB, config: ConfigParser) -> None:
|
|
if not config.has_section("presets"):
|
|
config.add_section("presets")
|
|
|
|
for _key in cTB.vPresets.keys():
|
|
config.set(
|
|
"presets", _key,
|
|
";".join([str(_value) for _value in cTB.vPresets[_key]])
|
|
)
|
|
|
|
|
|
def _save_settings_section_mixpresets(cTB, config: ConfigParser) -> None:
|
|
if not config.has_section("mixpresets"):
|
|
config.add_section("mixpresets")
|
|
|
|
for _key in cTB.vMixPresets.keys():
|
|
config.set(
|
|
"mixpresets",
|
|
_key, ";".join([str(_value) for _value in cTB.vMixPresets[_key]])
|
|
)
|
|
|
|
|
|
def _save_settings_section_download(cTB, config: ConfigParser) -> None:
|
|
if config.has_section("download"):
|
|
config.remove_section("download")
|
|
|
|
config.add_section("download")
|
|
|
|
for _key in cTB.settings:
|
|
if _key == "res":
|
|
config.set("download", _key, cTB.settings[_key])
|
|
elif _key == "maps":
|
|
config.set("download", _key, ";".join(cTB.settings[_key]))
|
|
|
|
|
|
def _remove_replaced_legacy_settings(cTB, config: ConfigParser) -> None:
|
|
try:
|
|
config.remove_option("settings", "library")
|
|
except ConfigParser.NoSectionError:
|
|
pass # it's fine if not existing
|
|
try:
|
|
config.remove_option("settings", "add_dirs")
|
|
except ConfigParser.NoSectionError:
|
|
pass # it's fine if not existing
|
|
|
|
|
|
def _save_settings_section_map_prefs(cTB, config: ConfigParser) -> None:
|
|
if not config.has_section("map_preferences"):
|
|
config.add_section("map_preferences")
|
|
|
|
if cTB.user is None:
|
|
return
|
|
user_prefs = cTB.user.map_preferences
|
|
if user_prefs is None:
|
|
return
|
|
|
|
for _map_format in user_prefs.texture_maps:
|
|
map_name = _map_format.map_type.name
|
|
selected = _map_format.selected
|
|
extension = selected if selected is not None else "NONE"
|
|
|
|
config.set("map_preferences", str(map_name), str(extension))
|
|
|
|
|
|
def save_settings(cTB) -> None:
|
|
cTB.logger.debug("save_settings")
|
|
|
|
config = _read_config(cTB)
|
|
|
|
_remove_replaced_legacy_settings(cTB, config)
|
|
|
|
_save_settings_section_user(cTB, config)
|
|
_save_settings_section_settings(cTB, config)
|
|
_save_settings_section_presets(cTB, config)
|
|
_save_settings_section_mixpresets(cTB, config)
|
|
_save_settings_section_download(cTB, config)
|
|
_save_settings_section_map_prefs(cTB, config)
|
|
|
|
f_MDir(cTB.dir_settings)
|
|
|
|
with cTB.lock_settings_file:
|
|
try:
|
|
with open(cTB.path_settings, "w+") as file:
|
|
config.write(file)
|
|
except OSError as e:
|
|
if e.errno != 28:
|
|
# Below notice assumes the OSError is for disk space only,
|
|
# so let's report if this ever isn't the case
|
|
reporting.capture_exception(e)
|
|
build_writing_settings_failed_notification(cTB, e.strerror)
|