class UserPrefs(EventDispatcher): ''' A class to manage user preferences for the RaceCapture app ''' DEFAULT_DASHBOARD_SCREENS = ['5x_gauge_view', 'laptime_view', 'tach_view', 'rawchannel_view'] DEFAULT_PREFS_DICT = {'range_alerts': {}, 'gauge_settings':{}, 'screens':DEFAULT_DASHBOARD_SCREENS, 'alerts': {}} DEFAULT_ANALYSIS_CHANNELS = ['Speed'] prefs_file_name = 'prefs.json' def __init__(self, data_dir, user_files_dir, save_timeout=0.2, **kwargs): self._prefs_dict = UserPrefs.DEFAULT_PREFS_DICT self.config = ConfigParser() self.data_dir = data_dir self.user_files_dir = user_files_dir self.prefs_file = path.join(self.data_dir, self.prefs_file_name) self.register_event_type("on_pref_change") self.load() def on_pref_change(self, section, option, value): pass def set_range_alert(self, key, range_alert): ''' Sets a range alert with the specified key :param key the key for the range alert :type string :param range_alert the range alert :type object ''' self._prefs_dict["range_alerts"][key] = range_alert self.save() def get_range_alert(self, key, default=None): ''' Retrives a range alert for the specified key :param key the key for the range alert :type key string :param default the default value, optional :type default user specified :return the range alert, or the default value ''' return self._prefs_dict["range_alerts"].get(key, default) def get_alertrules(self, channel): ''' Retrieve the alert_rules for the specified channel. If the alertrules do not exist for the specified channel, return an empty default AlertRuleCollection :return AlertRuleCollection ''' alertrules = self._prefs_dict['alerts'].get(channel) if alertrules is None: alertrules = AlertRuleCollection(channel, []) self._prefs_dict['alerts'][channel] = alertrules return alertrules def set_alertrules(self, channel, alertrules): self._prefs_dict['alerts'][channel] = alertrules self.save() def set_gauge_config(self, gauge_id, config_value): ''' Stores a gauge configuration for the specified gauge_id :param gauge_id the key for the gauge :type gauge_id string :param config_value the configuration value to set :type config_value string ''' self._prefs_dict["gauge_settings"][gauge_id] = config_value self.save() def get_gauge_config(self, gauge_id): ''' Get the gauge configuration for the specified gauge_id :param gauge_id the key for the gauge :type string :return the gauge configuration ''' return self._prefs_dict["gauge_settings"].get(gauge_id, False) def get_dashboard_screens(self): return copy(self._prefs_dict['screens']) def set_dashboard_screens(self, screens): self._prefs_dict['screens'] = copy(screens) self.save() # Regular preferences below here def get_last_selected_track_id(self): return self.get_pref('track_detection', 'last_selected_track_id') def get_last_selected_track_timestamp(self): return self.get_pref_int('track_detection', 'last_selected_track_timestamp') def get_user_cancelled_location(self): return self.get_pref('track_detection', 'user_cancelled_location') def set_last_selected_track(self, track_id, timestamp, user_cancelled_location='0,0'): self.set_pref('track_detection', 'last_selected_track_id', track_id) self.set_pref('track_detection', 'last_selected_track_timestamp', timestamp) self.set_pref('track_detection', 'user_cancelled_location', user_cancelled_location) self.save() @property def datastore_location(self): return os.path.join(self.data_dir, 'datastore.sq3') def save(self, *largs): ''' Saves the current configuration ''' Logger.info('UserPrefs: Saving preferences') with open(self.prefs_file, 'w+') as prefs_file: data = self.to_json() prefs_file.write(data) def set_config_defaults(self): ''' Set defaults for preferences ''' # Base system preferences self.config.adddefaultsection('help') self.config.adddefaultsection('preferences') self.config.setdefault('preferences', 'distance_units', 'miles') self.config.setdefault('preferences', 'temperature_units', 'Fahrenheit') self.config.setdefault('preferences', 'show_laptimes', 1) self.config.setdefault('preferences', 'startup_screen', 'Home Page') default_user_files_dir = self.user_files_dir self.config.setdefault('preferences', 'config_file_dir', default_user_files_dir) self.config.setdefault('preferences', 'export_file_dir', default_user_files_dir) self.config.setdefault('preferences', 'firmware_dir', default_user_files_dir) self.config.setdefault('preferences', 'import_datalog_dir', default_user_files_dir) self.config.setdefault('preferences', 'send_telemetry', '0') self.config.setdefault('preferences', 'record_session', '1') self.config.setdefault('preferences', 'global_help', True) # Connection type for mobile if is_mobile_platform(): if is_android(): self.config.setdefault('preferences', 'conn_type', 'Bluetooth') elif is_ios(): self.config.setdefault('preferences', 'conn_type', 'WiFi') else: self.config.setdefault('preferences', 'conn_type', 'Serial') # Dashboard preferences self.config.adddefaultsection('dashboard_preferences') self.config.setdefault('dashboard_preferences', 'last_dash_screen', '5x_gauge_view') self.config.setdefault('dashboard_preferences', 'pitstoptimer_enabled', 1) self.config.setdefault('dashboard_preferences', 'pitstoptimer_trigger_speed', 5) self.config.setdefault('dashboard_preferences', 'pitstoptimer_alert_speed', 25) self.config.setdefault('dashboard_preferences', 'pitstoptimer_exit_speed', 55) # Track detection pref self.config.adddefaultsection('track_detection') self.config.setdefault('track_detection', 'last_selected_track_id', 0) self.config.setdefault('track_detection', 'last_selected_track_timestamp', 0) self.config.setdefault('track_detection', 'user_cancelled_location', '0,0') self.config.adddefaultsection('analysis_preferences') self.config.setdefault('analysis_preferences', 'selected_sessions_laps', '{"sessions":{}}') self.config.setdefault('analysis_preferences', 'selected_analysis_channels', ','.join(UserPrefs.DEFAULT_ANALYSIS_CHANNELS)) self.config.adddefaultsection('setup') self.config.setdefault('setup', 'setup_enabled', 1) def load(self): Logger.info('UserPrefs: Data Dir is: {}'.format(self.data_dir)) self.config.read(os.path.join(self.data_dir, 'preferences.ini')) self.set_config_defaults() try: with open(self.prefs_file, 'r') as data: content = data.read() content_dict = json.loads(content) if content_dict.has_key("gauge_settings"): for id, channel in content_dict["gauge_settings"].iteritems(): self._prefs_dict["gauge_settings"][id] = channel if content_dict.has_key('screens'): self._prefs_dict['screens'] = content_dict['screens'] if content_dict.has_key('alerts'): for channel, alertrules in content_dict['alerts'].iteritems(): self._prefs_dict['alerts'][channel] = AlertRuleCollection.from_dict(alertrules) except Exception as e: Logger.error('Error loading preferences, using defaults. {}'.format(e)) def init_pref_section(self, section): ''' Initializes a preferences section with the specified name. if the section already exists, there is no effect. :param section the name of the preference section :type string ''' self.config.adddefaultsection(section) def get_pref_bool(self, section, option, default=None): ''' Retrieve a preferences value as a bool. return default value if preference does not exist :param section the configuration section for the preference :type section string :param option the option for the section :type option string :param default :type default bool :return bool preference value ''' try: return self.config.getboolean(section, option) except (NoOptionError, ValueError): return default def get_pref_float(self, section, option, default=None): ''' Retrieve a preferences value as a float. return default value if preference does not exist :param section the configuration section for the preference :type section string :param option the option for the section :type option string :param default :type default float :return float preference value ''' try: return self.config.getfloat(section, option) except (NoOptionError, ValueError): return default def get_pref_int(self, section, option, default=None): ''' Retrieve a preferences value as an int. return default value if preference does not exist :param section the configuration section for the preference :type section string :param option the option for the section :type option string :param default :type default user specified :return int preference value ''' try: return self.config.getint(section, option) except (NoOptionError, ValueError): return default def get_pref(self, section, option, default=None): ''' Retrieve a preferences value as a string. return default value if preference does not exist :param section the configuration section for the preference :type section string :param option the option for the section :type option string :param default :type default user specified :return string preference value ''' try: return self.config.get(section, option) except (NoOptionError, ValueError): return default def get_pref_list(self, section, option, default=[]): """ Retrieve a preferences value as a list. return default value if preference does not exist :param section the configuration section for the preference :type section string :param option the option for the section :type option string :param default :type default user specified :return list of string values """ try: return self.config.get(section, option).split(',') except (NoOptionError, ValueError): return default def set_pref(self, section, option, value): ''' Set a preference value :param section the configuration section for the preference :type string :param option the option for the section :type string :param value the preference value to set :type value user specified ''' current_value = None try: current_value = self.config.get(section, option) except NoOptionError: pass self.config.set(section, option, value) self.config.write() if value != current_value: self.dispatch('on_pref_change', section, option, value) def set_pref_list(self, section, option, value): """ Set a preference value by list :param section the configuration section for the preference :type string :param option the option for the section :type string :param value the preference value to set :type value list (list of strings) """ try: self.set_pref(section, option, ','.join(value)) except TypeError: Logger.error('UserPrefs: failed to set preference list for {}:{} - {}'.format(section, option, value)) def to_json(self): ''' Serialize preferences to json ''' data = {'range_alerts': {}, 'gauge_settings':{}, 'screens': [], 'alerts': {}} for name, range_alert in self._prefs_dict["range_alerts"].iteritems(): data["range_alerts"][name] = range_alert.to_dict() for id, channel in self._prefs_dict["gauge_settings"].iteritems(): data["gauge_settings"][id] = channel for name, alertrules in self._prefs_dict['alerts'].iteritems(): data['alerts'][name] = alertrules.to_dict() data['screens'] = self._prefs_dict['screens'] return json.dumps(data, sort_keys=True, indent=2, separators=(',', ': '))
def update_program(self): """Проверяет наличие обновлений на сервере github,com. Проверяестя версия программы, версии плагинов, наличие измененных программых файлов.""" if platform != "android": print("Проверка обновлений:") print("------------------------------------") temp_path = "{}/Data/temp".format(core.prog_path) if not os.path.exists(temp_path): os.mkdir(temp_path) update_file = urllib.urlopen( "https://github.com/HeaTTheatR/HeaTDV4A/raw/master/" "Data/uploadinfo.ini").read() open("{}/uploadinfo.ini".format(temp_path), "w").write( update_file) config_update = ConfigParser() config_update.read("{}/uploadinfo.ini".format(temp_path)) info_list_update = [] new_version_program = \ config_update.getfloat("info_update", "new_version_program") updated_files_program = \ eval(config_update.get("info_update", "updated_files_program")) dict_official_plugins_program = \ config_update.items("plugin_update") official_plugins_program = dict(dict_official_plugins_program) install_user_plugins = self.started_plugins current_version_program = __version__ if platform != "android": print("Проверка версии программы ...") print("Проверка актуальности плагинов ...") for plugin in install_user_plugins.keys(): try: info_official_plugin = eval(official_plugins_program[plugin]) if info_official_plugin[plugin]['plugin-version'] > \ install_user_plugins[plugin]['plugin-version']: info_list_update.append(info_official_plugin) if platform != "android": print("Плагин '{}' обновился до версии '{}'!".format( plugin, info_official_plugin[plugin][ 'plugin-version'])) except KeyError: continue if platform != "android": print("Проверка обновлений завершена ...") print("------------------------------------") print() if len(info_list_update) or new_version_program > \ current_version_program: self.update = True if platform != "android": print("Доступны обновления!") print("------------------------------------") print() else: if platform != "android": print("Обновлений нет!") print("------------------------------------") print()
class UserPrefs(EventDispatcher): ''' A class to manage user preferences for the RaceCapture app ''' _schedule_save = None _prefs_dict = {'range_alerts': {}, 'gauge_settings':{}} store = None prefs_file_name = 'prefs.json' prefs_file = None config = None data_dir = '.' user_files_dir = '.' def __init__(self, data_dir, user_files_dir, save_timeout=2, **kwargs): self.data_dir = data_dir self.user_files_dir = user_files_dir self.prefs_file = path.join(self.data_dir, self.prefs_file_name) self.load() self._schedule_save = Clock.create_trigger(self.save, save_timeout) def set_range_alert(self, key, range_alert): ''' Sets a range alert with the specified key :param key the key for the range alert :type string :param range_alert the range alert :type object ''' self._prefs_dict["range_alerts"][key] = range_alert self._schedule_save() def get_range_alert(self, key, default=None): ''' Retrives a range alert for the specified key :param key the key for the range alert :type key string :param default the default value, optional :type default user specified :return the range alert, or the default value ''' return self._prefs_dict["range_alerts"].get(key, default) def set_gauge_config(self, gauge_id, channel): ''' Stores a gauge configuration for the specified gauge_id :param gauge_id the key for the gauge :type gauge_id string :param channel the configuration for the channel :type channel object ''' self._prefs_dict["gauge_settings"][gauge_id] = channel self._schedule_save() def get_gauge_config(self, gauge_id): ''' Get the gauge configuration for the specified gauge_id :param gauge_id the key for the gauge :type string :return the gauge configuration ''' return self._prefs_dict["gauge_settings"].get(gauge_id, False) def get_last_selected_track_id(self): return self.get_pref('track_detection', 'last_selected_track_id') def get_last_selected_track_timestamp(self): return self.get_pref_int('track_detection', 'last_selected_track_timestamp') def set_last_selected_track(self, track_id, timestamp): self.set_pref('track_detection', 'last_selected_track_id', track_id) self.set_pref('track_detection', 'last_selected_track_timestamp', timestamp) @property def datastore_location(self): return os.path.join(self.data_dir, 'datastore.sq3') def save(self, *largs): ''' Saves the current configuration ''' with open(self.prefs_file, 'w+') as prefs_file: data = self.to_json() prefs_file.write(data) def set_config_defaults(self): ''' Set defaults for preferences ''' # Base system preferences self.config.adddefaultsection('help') self.config.adddefaultsection('preferences') self.config.setdefault('preferences', 'distance_units', 'miles') self.config.setdefault('preferences', 'temperature_units', 'Fahrenheit') self.config.setdefault('preferences', 'show_laptimes', 1) self.config.setdefault('preferences', 'startup_screen', 'Home Page') default_user_files_dir = self.user_files_dir self.config.setdefault('preferences', 'config_file_dir', default_user_files_dir) self.config.setdefault('preferences', 'firmware_dir', default_user_files_dir) self.config.setdefault('preferences', 'import_datalog_dir', default_user_files_dir) self.config.setdefault('preferences', 'first_time_setup', '1') self.config.setdefault('preferences', 'send_telemetry', '0') self.config.setdefault('preferences', 'record_session', '1') self.config.setdefault('preferences', 'last_dash_screen', 'gaugeView') self.config.setdefault('preferences', 'global_help', True) if platform == 'android': self.config.setdefault('preferences', 'conn_type', 'Bluetooth') # Dashboard preferences self.config.adddefaultsection('dashboard_preferences') self.config.setdefault('dashboard_preferences', 'pitstoptimer_enabled', 1) self.config.setdefault('dashboard_preferences', 'pitstoptimer_trigger_speed', 5) self.config.setdefault('dashboard_preferences', 'pitstoptimer_alert_speed', 25) self.config.setdefault('dashboard_preferences', 'pitstoptimer_exit_speed', 55) # Track detection pref self.config.adddefaultsection('track_detection') self.config.setdefault('track_detection', 'last_selected_track_id', 0) self.config.setdefault('track_detection', 'last_selected_track_timestamp', 0) self.config.adddefaultsection('analysis_preferences') self.config.setdefault('analysis_preferences', 'selected_sessions_laps', '{"sessions":{}}') def load(self): Logger.info('UserPrefs: Data Dir is: {}'.format(self.data_dir)) self.config = ConfigParser() self.config.read(os.path.join(self.data_dir, 'preferences.ini')) self.set_config_defaults() self._prefs_dict = {'range_alerts': {}, 'gauge_settings':{}} try: with open(self.prefs_file, 'r') as data: content = data.read() content_dict = json.loads(content) if content_dict.has_key("range_alerts"): for name, settings in content_dict["range_alerts"].iteritems(): self._prefs_dict["range_alerts"][name] = Range.from_dict(settings) if content_dict.has_key("gauge_settings"): for id, channel in content_dict["gauge_settings"].iteritems(): self._prefs_dict["gauge_settings"][id] = channel except Exception: pass def get_pref_bool(self, section, option, default=None): ''' Retrieve a preferences value as a bool. return default value if preference does not exist :param section the configuration section for the preference :type section string :param option the option for the section :type option string :param default :type default bool :return bool preference value ''' try: return self.config.getboolean(section, option) except (NoOptionError, ValueError): return default def get_pref_float(self, section, option, default=None): ''' Retrieve a preferences value as a float. return default value if preference does not exist :param section the configuration section for the preference :type section string :param option the option for the section :type option string :param default :type default float :return float preference value ''' try: return self.config.getfloat(section, option) except (NoOptionError, ValueError): return default def get_pref_int(self, section, option, default=None): ''' Retrieve a preferences value as an int. return default value if preference does not exist :param section the configuration section for the preference :type section string :param option the option for the section :type option string :param default :type default user specified :return int preference value ''' try: return self.config.getint(section, option) except (NoOptionError, ValueError): return default def get_pref(self, section, option, default=None): ''' Retrieve a preferences value as a string. return default value if preference does not exist :param section the configuration section for the preference :type section string :param option the option for the section :type option string :param default :type default user specified :return string preference value ''' try: return self.config.get(section, option) except (NoOptionError, ValueError): return default def set_pref(self, section, option, value): ''' Set a preference value :param section the configuration section for the preference :type string :param option the option for the section :type string :param value the preference value to set :type value user specified ''' self.config.set(section, option, value) self.config.write() def to_json(self): ''' Serialize preferences to json ''' data = {'range_alerts': {}, 'gauge_settings':{}} for name, range_alert in self._prefs_dict["range_alerts"].iteritems(): data["range_alerts"][name] = range_alert.to_dict() for id, channel in self._prefs_dict["gauge_settings"].iteritems(): data["gauge_settings"][id] = channel return json.dumps(data)