1 # Types of model changes for view updates
2 (MODEL_PROFILE_CHANGE, MODEL_VALUE_CHANGE) = range(2)
4 class ConfigModel(object):
5 """A simple settings dictionary with support for saving and loading profiles.
7 The following four methods need to be implemented by sub-classes:
8 - read_settings: read current system configuration
9 - write_settings: write self.settings to system
10 - profile_to_string: convert a dictionary into a single-line string for storage.
11 - string_to_profile: the inverse of the above.
13 The class implements a basic model-view pattern. The user-interface can attach
14 to this to receive updates whenever the values are modified.
17 - MODEL_PROFILE_CHANGE:
18 Issued when the sets of defined profiles has been modified.
19 This is relevant for widgets which handle profile creation/deletion.
21 Issued whenever a new profile is loaded. This is useful for all widgets
22 which actually display and edit a configuration.
24 def __init__(self, profiles_file, *views, **kwargs):
25 """Creates a new configuration settings model.
27 This currently provides support for a model/view pattern and
28 unmodifiable default profiles.
30 @profiles_file: name of the file to which to save/store all profiles.
31 @views: all positional arguments are views.
32 @kwargs: all keyword arguments should be default profiles.
34 self.views = list(views)
37 # these cannot be edited
38 self.default_profiles = kwargs
40 self.profiles_file = profiles_file
45 def notify(self, reason, *args):
46 """Dispatches all views."""
48 v.update_view(reason, *args)
50 def set_profile(self, name, dictionary):
51 """Inserts a new profile into the profile dictionary.
53 Issues a MODEL_PROFILE_CHANGE event and passes the name of
54 the profile to the views along with all new profiles.
56 notify = name not in self.profiles
57 self.profiles.setdefault(name, {}).update(dictionary)
59 self.notify(MODEL_PROFILE_CHANGE, name, self.profiles)
61 def delete_profile(self, name):
62 """Removes profile <name>, if it exists.
64 If, and only if, the profile name existed a MODEL_PROFILE_CHANGE
65 event is issued to all views. No new selected profile will be passed.
66 If name was the active profile, then the views can select a new one.
68 notify = name in self.profiles
69 del self.profiles[name]
71 self.notify(MODEL_PROFILE_CHANGE, '', self.profiles)
73 def load_profile(self, settings):
74 """Directly loads the profile specified by settings.
76 Dispatches the views with a MODEL_VALUE_CHANGE event.
78 self.settings.update(settings)
79 self.notify(MODEL_VALUE_CHANGE, self.settings)
81 def load_named_profile(self, name):
82 """If <name> is a valid profile, make it active.
84 Inspects the default profiles before the custom profiles and dispatches
85 the views with a MODEL_VALUE_CHANGE event.
88 if name in self.default_profiles:
89 self.settings.update(self.default_profiles[name])
90 elif name in self.profiles:
91 self.settings.update(self.profiles[name])
95 self.notify(MODEL_VALUE_CHANGE, self.settings)
97 def fetch_profiles(self):
98 """Load non-default profiles from disk."""
99 with open(self.profiles_file, 'r') as f:
105 self.profiles[name] = self.string_to_profile(line.rstrip())
108 def store_profiles(self):
109 """Write all non-default profiles to disk."""
110 with open(self.profiles_file, 'w') as f:
111 for name in sorted(self.profiles.keys()):
112 f.write('%s\n%s\n' % (name, self.profile_to_string(self.profiles[name])))
114 def read_settings(self):
115 """Read current configuration from the system.
117 Needs to be implemented by sub-classes.
121 def write_settings(self):
122 """Write current configuration to system.
124 Needs to be implemented by sub-classes.
128 def profile_to_string(self, dct):
129 """Convert a configuration profile to a single-line string.
131 Sub-classes should override this with a more optimal implementation.
135 def string_to_profile(self, s):
136 """Convert a profile string to a configuration profile.
138 This is intended to be overridden by sub-classes.
139 It should be the inverse operation of profile_to_string.