source: src/mlx/config.py@ 168:71af690e0c26

Last change on this file since 168:71af690e0c26 was 166:e4ba22b7a13b, checked in by István Váradi <ivaradi@…>, 13 years ago

The configuration loading/saving and the basic GUI for the sound preferences work

File size: 19.8 KB
Line 
1# Configuration and related stuff
2# -*- encoding: utf-8 -*-
3
4#-------------------------------------------------------------------------------
5
6import const
7
8import os
9import sys
10import ConfigParser
11
12#-------------------------------------------------------------------------------
13
14configPath = os.path.join(os.path.expanduser("~"),
15 "mlx.config" if os.name=="nt" else ".mlxrc")
16
17#-------------------------------------------------------------------------------
18
19if os.name=="nt":
20 _languageMap = { "en_GB" : "eng",
21 "hu_HU" : "hun" }
22
23#-------------------------------------------------------------------------------
24
25class Hotkey(object):
26 """A hotkey."""
27 def __init__(self, ctrl = False, shift = False, key = "0"):
28 """Construct the hotkey."""
29 self.ctrl = ctrl
30 self.shift = shift
31 self.key = key
32
33 def set(self, s):
34 """Set the hotkey from the given string."""
35 self.ctrl = "C" in s[:-1]
36 self.shift = "S" in s[:-1]
37 self.key = s[-1]
38
39 def __eq__(self, other):
40 """Check if the given hotkey is equal to the other one."""
41 return self.ctrl == other.ctrl and self.shift == other.shift and \
42 self.key == other.key
43
44 def __str__(self):
45 """Construct the hotkey to a string."""
46 s = ""
47 if self.ctrl: s += "C"
48 if self.shift: s += "S"
49 s += self.key
50 return s
51
52#-------------------------------------------------------------------------------
53
54class Config(object):
55 """Our configuration."""
56 DEFAULT_UPDATE_URL = "http://mlx.varadiistvan.hu/update"
57
58 _messageTypesSection = "messageTypes"
59
60 def __init__(self):
61 """Construct the configuration with default values."""
62
63 self._pilotID = ""
64 self._password = ""
65 self._rememberPassword = False
66
67 self._language = ""
68 self._hideMinimizedWindow = True
69 self._onlineGateSystem = True
70 self._onlineACARS = True
71 self._flareTimeFromFS = False
72 self._syncFSTime = False
73
74 self._pirepDirectory = None
75
76 self._enableSounds = True
77
78 self._pilotControlsSounds = True
79 self._pilotHotkey = Hotkey(ctrl = True, shift = False, key = "0")
80
81 #self._approachCallOuts = False
82 self._speedbrakeAtTD = True
83
84 self._enableChecklists = False
85 self._checklistHotkey = Hotkey(ctrl = True, shift = True, key = "0")
86
87 self._autoUpdate = True
88 self._updateURL = Config.DEFAULT_UPDATE_URL
89
90 self._messageTypeLevels = {}
91
92 self._modified = False
93
94 @property
95 def pilotID(self):
96 """Get the pilot ID."""
97 return self._pilotID
98
99 @pilotID.setter
100 def pilotID(self, pilotID):
101 """Set the pilot ID."""
102 if pilotID!=self._pilotID:
103 self._pilotID = pilotID
104 self._modified = True
105
106 @property
107 def password(self):
108 """Get the password."""
109 return self._password
110
111 @password.setter
112 def password(self, password):
113 """Set the password."""
114 if password!=self._password:
115 self._password = password
116 self._modified = True
117
118 @property
119 def rememberPassword(self):
120 """Get if we should remember the password."""
121 return self._rememberPassword
122
123 @rememberPassword.setter
124 def rememberPassword(self, rememberPassword):
125 """Set if we should remember the password."""
126 if rememberPassword!=self._rememberPassword:
127 self._rememberPassword = rememberPassword
128 self._modified = True
129
130 @property
131 def language(self):
132 """Get the language to use."""
133 return self._language
134
135 @language.setter
136 def language(self, language):
137 """Set the language to use."""
138 if language!=self._language:
139 self._language = language
140 self._modified = True
141
142 @property
143 def hideMinimizedWindow(self):
144 """Get whether a minimized window should be hidden."""
145 return self._hideMinimizedWindow
146
147 @hideMinimizedWindow.setter
148 def hideMinimizedWindow(self, hideMinimizedWindow):
149 """Set whether a minimized window should be hidden."""
150 if hideMinimizedWindow!=self._hideMinimizedWindow:
151 self._hideMinimizedWindow = hideMinimizedWindow
152 self._modified = True
153
154 @property
155 def onlineGateSystem(self):
156 """Get whether the online gate system should be used."""
157 return self._onlineGateSystem
158
159 @onlineGateSystem.setter
160 def onlineGateSystem(self, onlineGateSystem):
161 """Set whether the online gate system should be used."""
162 if onlineGateSystem!=self._onlineGateSystem:
163 self._onlineGateSystem = onlineGateSystem
164 self._modified = True
165
166 @property
167 def onlineACARS(self):
168 """Get whether the online ACARS system should be used."""
169 return self._onlineACARS
170
171 @onlineACARS.setter
172 def onlineACARS(self, onlineACARS):
173 """Set whether the online ACARS system should be used."""
174 if onlineACARS!=self._onlineACARS:
175 self._onlineACARS = onlineACARS
176 self._modified = True
177
178 @property
179 def flareTimeFromFS(self):
180 """Get whether the flare time should be calculated from the time values
181 returned by the simulator."""
182 return self._flareTimeFromFS
183
184 @flareTimeFromFS.setter
185 def flareTimeFromFS(self, flareTimeFromFS):
186 """Set whether the flare time should be calculated from the time values
187 returned by the simulator."""
188 if flareTimeFromFS!=self._flareTimeFromFS:
189 self._flareTimeFromFS = flareTimeFromFS
190 self._modified = True
191
192 @property
193 def syncFSTime(self):
194 """Get whether the simulator's time should be synchronized with the
195 machine's clock."""
196 return self._syncFSTime
197
198 @syncFSTime.setter
199 def syncFSTime(self, syncFSTime):
200 """Set whether the simulator's time should be synchronized with the
201 machine's clock."""
202 if syncFSTime!=self._syncFSTime:
203 self._syncFSTime = syncFSTime
204 self._modified = True
205
206 @property
207 def pirepDirectory(self):
208 """Get the directory offered by default when saving a PIREP."""
209 return self._pirepDirectory
210
211 @pirepDirectory.setter
212 def pirepDirectory(self, pirepDirectory):
213 """Get the directory offered by default when saving a PIREP."""
214 if pirepDirectory!=self._pirepDirectory and \
215 (pirepDirectory!="" or self._pirepDirectory is not None):
216 self._pirepDirectory = None if pirepDirectory=="" \
217 else pirepDirectory
218 self._modified = True
219
220 def getMessageTypeLevel(self, messageType):
221 """Get the level for the given message type."""
222 return self._messageTypeLevels[messageType] \
223 if messageType in self._messageTypeLevels \
224 else const.MESSAGELEVEL_NONE
225
226 def isMessageTypeFS(self, messageType):
227 """Determine if the given message type is displayed in the
228 simulator."""
229 level = self.getMessageTypeLevel(messageType)
230 return level==const.MESSAGELEVEL_FS or \
231 level==const.MESSAGELEVEL_BOTH
232
233 def setMessageTypeLevel(self, messageType, level):
234 """Set the level of the given message type."""
235 if messageType not in self._messageTypeLevels or \
236 self._messageTypeLevels[messageType]!=level:
237 self._messageTypeLevels[messageType] = level
238 self._modified = True
239
240 @property
241 def enableSounds(self):
242 """Get whether background sounds are enabled."""
243 return self._enableSounds
244
245 @enableSounds.setter
246 def enableSounds(self, enableSounds):
247 """Set whether background sounds are enabled."""
248 if enableSounds!=self._enableSounds:
249 self._enableSounds = enableSounds
250 self._modified = True
251
252 @property
253 def pilotControlsSounds(self):
254 """Get whether the pilot controls the background sounds."""
255 return self._pilotControlsSounds
256
257 @pilotControlsSounds.setter
258 def pilotControlsSounds(self, pilotControlsSounds):
259 """Set whether the pilot controls the background sounds."""
260 if pilotControlsSounds!=self._pilotControlsSounds:
261 self._pilotControlsSounds = pilotControlsSounds
262 self._modified = True
263
264 @property
265 def pilotHotkey(self):
266 """Get the pilot's hotkey."""
267 return self._pilotHotkey
268
269 @pilotHotkey.setter
270 def pilotHotkey(self, pilotHotkey):
271 """Set the pilot's hotkey."""
272 if pilotHotkey!=self._pilotHotkey:
273 self._pilotHotkey = pilotHotkey
274 self._modified = True
275
276 # @property
277 # def approachCallOuts(self):
278 # """Get whether the approach callouts should be played."""
279 # return self._approachCallOuts
280
281 # @approachCallOuts.setter
282 # def approachCallOuts(self, approachCallOuts):
283 # """Set whether the approach callouts should be played."""
284 # if approachCallOuts!=self._approachCallOuts:
285 # self._approachCallOuts = approachCallOuts
286 # self._modified = True
287
288 @property
289 def speedbrakeAtTD(self):
290 """Get whether the speedbrake sounds should be played at touchdown."""
291 return self._speedbrakeAtTD
292
293 @speedbrakeAtTD.setter
294 def speedbrakeAtTD(self, speedbrakeAtTD):
295 """Set whether the speedbrake sounds should be played at touchdown."""
296 if speedbrakeAtTD!=self._speedbrakeAtTD:
297 self._speedbrakeAtTD = speedbrakeAtTD
298 self._modified = True
299
300 @property
301 def enableChecklists(self):
302 """Get whether aircraft-specific checklists should be played."""
303 return self._enableChecklists
304
305 @enableChecklists.setter
306 def enableChecklists(self, enableChecklists):
307 """Get whether aircraft-specific checklists should be played."""
308 if enableChecklists!=self._enableChecklists:
309 self._enableChecklists = enableChecklists
310 self._modified = True
311
312 @property
313 def checklistHotkey(self):
314 """Get the checklist hotkey."""
315 return self._checklistHotkey
316
317 @checklistHotkey.setter
318 def checklistHotkey(self, checklistHotkey):
319 """Set the checklist hotkey."""
320 if checklistHotkey!=self._checklistHotkey:
321 self._checklistHotkey = checklistHotkey
322 self._modified = True
323
324 @property
325 def autoUpdate(self):
326 """Get if an automatic update is needed."""
327 return self._autoUpdate
328
329 @autoUpdate.setter
330 def autoUpdate(self, autoUpdate):
331 """Set if an automatic update is needed."""
332 if autoUpdate!=self._autoUpdate:
333 self._autoUpdate = autoUpdate
334 self._modified = True
335
336 @property
337 def updateURL(self):
338 """Get the update URL."""
339 return self._updateURL
340
341 @updateURL.setter
342 def updateURL(self, updateURL):
343 """Set the update URL."""
344 if updateURL!=self._updateURL:
345 self._updateURL = updateURL
346 self._modified = True
347
348 def load(self):
349 """Load the configuration from its default location."""
350 config = ConfigParser.RawConfigParser()
351 config.read(configPath)
352
353 self._pilotID = self._get(config, "login", "id", "")
354 self._password = self._get(config, "login", "password", "")
355 self._rememberPassword = self._getBoolean(config, "login",
356 "rememberPassword", False)
357
358 self._language = self._get(config, "general", "language", "")
359 self._hideMinimizedWindow = self._getBoolean(config, "general",
360 "hideMinimizedWindow",
361 True)
362 self._onlineGateSystem = self._getBoolean(config, "general",
363 "onlineGateSystem",
364 True)
365 self._onlineACARS = self._getBoolean(config, "general",
366 "onlineACARS", True)
367 self._flareTimeFromFS = self._getBoolean(config, "general",
368 "flareTimeFromFS",
369 False)
370 self._syncFSTime = self._getBoolean(config, "general",
371 "syncFSTime",
372 False)
373 self._pirepDirectory = self._get(config, "general",
374 "pirepDirectory", None)
375
376 self._messageTypeLevels = {}
377 for messageType in const.messageTypes:
378 self._messageTypeLevels[messageType] = \
379 self._getMessageTypeLevel(config, messageType)
380
381 self._enableSounds = self._getBoolean(config, "sounds",
382 "enable", True)
383 self._pilotControlsSounds = self._getBoolean(config, "sounds",
384 "pilotControls", True)
385 self._pilotHotkey.set(self._get(config, "sounds",
386 "pilotHotkey", "C0"))
387 #self._approachCallOuts = self._getBoolean(config, "sounds",
388 # "approachCallOuts", False)
389 self._speedbrakeAtTD = self._getBoolean(config, "sounds",
390 "speedbrakeAtTD", True)
391
392 self._enableChecklists = self._getBoolean(config, "sounds",
393 "enableChecklists", False)
394 self._checklistHotkey.set(self._get(config, "sounds",
395 "checklistHotkey", "CS0"))
396
397 self._autoUpdate = self._getBoolean(config, "update", "auto", True)
398 self._updateURL = self._get(config, "update", "url",
399 Config.DEFAULT_UPDATE_URL)
400
401 self._modified = False
402
403 def save(self):
404 """Save the configuration file if it has been modified."""
405 if not self._modified:
406 return
407
408 config = ConfigParser.RawConfigParser()
409
410 config.add_section("login")
411 config.set("login", "id", self._pilotID)
412 config.set("login", "password", self._password)
413 config.set("login", "rememberPassword",
414 "yes" if self._rememberPassword else "no")
415
416 config.add_section("general")
417 if self._language:
418 config.set("general", "language", self._language)
419 config.set("general", "hideMinimizedWindow",
420 "yes" if self._hideMinimizedWindow else "no")
421 config.set("general", "onlineGateSystem",
422 "yes" if self._onlineGateSystem else "no")
423 config.set("general", "onlineACARS",
424 "yes" if self._onlineACARS else "no")
425 config.set("general", "flareTimeFromFS",
426 "yes" if self._flareTimeFromFS else "no")
427 config.set("general", "syncFSTime",
428 "yes" if self._syncFSTime else "no")
429
430 if self._pirepDirectory is not None:
431 config.set("general", "pirepDirectory", self._pirepDirectory)
432
433 config.add_section(Config._messageTypesSection)
434 for messageType in const.messageTypes:
435 if messageType in self._messageTypeLevels:
436 option = self._getMessageTypeLevelOptionName(messageType)
437 level = self._messageTypeLevels[messageType]
438 config.set(Config._messageTypesSection, option,
439 const.messageLevel2string(level))
440
441 config.add_section("sounds")
442 config.set("sounds", "enable",
443 "yes" if self._enableSounds else "no")
444 config.set("sounds", "pilotControls",
445 "yes" if self._pilotControlsSounds else "no")
446 config.set("sounds", "pilotHotkey", str(self._pilotHotkey))
447 #config.set("sounds", "approachCallOuts",
448 # "yes" if self._approachCallOuts else "no")
449 config.set("sounds", "speedbrakeAtTD",
450 "yes" if self._speedbrakeAtTD else "no")
451
452 config.set("sounds", "enableChecklists",
453 "yes" if self._enableChecklists else "no")
454 config.set("sounds", "checklistHotkey",
455 str(self._checklistHotkey))
456
457 config.add_section("update")
458 config.set("update", "auto",
459 "yes" if self._autoUpdate else "no")
460 config.set("update", "url", self._updateURL)
461
462 try:
463 fd = os.open(configPath, os.O_CREAT|os.O_TRUNC|os.O_WRONLY,
464 0600)
465 with os.fdopen(fd, "wt") as f:
466 config.write(f)
467 self._modified = False
468 except Exception, e:
469 print >> sys.stderr, "Failed to update config: " + str(e)
470
471 def _getBoolean(self, config, section, option, default):
472 """Get the given option as a boolean, if found in the given config,
473 otherwise the default."""
474 return config.getboolean(section, option) \
475 if config.has_option(section, option) \
476 else default
477
478 def _get(self, config, section, option, default):
479 """Get the given option as a string, if found in the given config,
480 otherwise the default."""
481 return config.get(section, option) \
482 if config.has_option(section, option) \
483 else default
484
485 def _getMessageTypeLevel(self, config, messageType):
486 """Get the message type level for the given message type."""
487 option = self._getMessageTypeLevelOptionName(messageType)
488 if config.has_option(Config._messageTypesSection, option):
489 value = config.get(Config._messageTypesSection, option)
490 return const.string2messageLevel(value)
491 elif messageType in [const.MESSAGETYPE_LOGGER_ERROR,
492 const.MESSAGETYPE_FAULT,
493 const.MESSAGETYPE_NOGO,
494 const.MESSAGETYPE_GATE_SYSTEM,
495 const.MESSAGETYPE_HELP]:
496 return const.MESSAGELEVEL_BOTH
497 else:
498 return const.MESSAGELEVEL_FS
499
500 def _getMessageTypeLevelOptionName(self, messageType):
501 """Get the option name for the given message type level."""
502 return const.messageType2string(messageType)
503
504 def setupLocale(self):
505 """Setup the locale based on the language set.
506
507 Return True if a specific language was set, False otherwise."""
508 import locale
509 if self._language:
510 print "Setting up locale for", self._language
511 os.environ["LANGUAGE"] = self._language
512 langAndEncoding = self._language + "." + locale.getpreferredencoding()
513 os.environ["LANG"] = langAndEncoding
514 os.environ["LC_MESSAGES"] = langAndEncoding
515 os.environ["LC_COLLATE"] = langAndEncoding
516 os.environ["LC_CTYPE"] = langAndEncoding
517 os.environ["LC_MONETARY"] = langAndEncoding
518 os.environ["LC_NUMERIC"] = langAndEncoding
519 os.environ["LC_TIME"] = langAndEncoding
520 return True
521 else:
522 return False
523
524 def getLanguage(self):
525 """Get the language to be used."""
526 import locale
527 if self._language:
528 if os.name=="nt":
529 if self._language in _languageMap:
530 locale.setlocale(locale.LC_ALL, _languageMap[self._language])
531 else:
532 locale.setlocale(locale.LC_ALL, "")
533 else:
534 locale.setlocale(locale.LC_ALL, (self._language,
535 locale.getpreferredencoding()))
536 return self._language
537 else:
538 locale.setlocale(locale.LC_ALL, "")
539 return locale.getdefaultlocale()[0]
540
541#-------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.