source: src/mlx/config.py@ 684:64c3835e1ef4

cef
Last change on this file since 684:64c3835e1ef4 was 684:64c3835e1ef4, checked in by István Váradi <ivaradi@…>, 7 years ago

The usage of SimBrief can be enabled/disabled from the configuration (re #279).

File size: 35.6 KB
Line 
1# -*- encoding: utf-8 -*-
2
3import const
4from util import secondaryInstallation, utf2unicode
5
6import os
7import sys
8import traceback
9import ConfigParser
10
11## @package mlx.config
12#
13# The handling of the configuration.
14#
15# The \ref Config class contains the main configuration and is capable of
16# loading and saving the configuration. It contains getters and setters for the
17# configuration options.
18#
19# Some parts of the configuration are not simple data items, like strings or
20# booleans, but more complicated data. These have their own class, like \ref
21# ApproachCallouts or \ref Checklist.
22
23#-------------------------------------------------------------------------------
24
25configPath = os.path.join(os.path.expanduser("~"),
26 "mlx.config" if os.name=="nt" else ".mlxrc") + \
27 ("-secondary" if secondaryInstallation else "")
28
29#-------------------------------------------------------------------------------
30
31if os.name=="nt":
32 _languageMap = { "en_GB" : "eng",
33 "hu_HU" : "hun" }
34
35#-------------------------------------------------------------------------------
36
37class Hotkey(object):
38 """A hotkey."""
39 def __init__(self, ctrl = False, shift = False, key = "0"):
40 """Construct the hotkey."""
41 self.ctrl = ctrl
42 self.shift = shift
43 self.key = key
44
45 def set(self, s):
46 """Set the hotkey from the given string."""
47 self.ctrl = "C" in s[:-1]
48 self.shift = "S" in s[:-1]
49 self.key = s[-1]
50
51 def __eq__(self, other):
52 """Check if the given hotkey is equal to the other one."""
53 return self.ctrl == other.ctrl and self.shift == other.shift and \
54 self.key == other.key
55
56 def __ne__(self, other):
57 """Check if the given hotkey is not equal to the other one."""
58 return not self==other
59
60 def __str__(self):
61 """Construct the hotkey to a string."""
62 s = ""
63 if self.ctrl: s += "C"
64 if self.shift: s += "S"
65 s += self.key
66 return s
67
68#-------------------------------------------------------------------------------
69
70class Checklist(object):
71 """A checklist for a certain aircraft type."""
72 # The name of the section of the checklists
73 SECTION="checklists"
74
75 @staticmethod
76 def fromConfig(config, aircraftType):
77 """Create a checklist for the given aircraft type from the given
78 config."""
79 baseName = "checklist." + const.icaoCodes[aircraftType] + "."
80 fileList = []
81 while True:
82 option = baseName + str(len(fileList))
83 if config.has_option(Checklist.SECTION, option):
84 fileList.append(config.get(Checklist.SECTION, option))
85 else:
86 break
87
88 return Checklist(fileList)
89
90 def __init__(self, fileList = None):
91 """Construct the check list with the given file list."""
92 self._fileList = [] if fileList is None else fileList[:]
93
94 def clone(self):
95 """Clone the checklist."""
96 return Checklist(self._fileList)
97
98 def toConfig(self, config, aircraftType):
99 """Add this checklist to the given config."""
100 baseName = "checklist." + const.icaoCodes[aircraftType] + "."
101 for index in range(0, len(self._fileList)):
102 option = baseName + str(index)
103 config.set(Checklist.SECTION, option,
104 self._fileList[index])
105
106 def __eq__(self, other):
107 """Determine if the checklist is equal to the given other one."""
108 return self._fileList == other._fileList
109
110 def __ne__(self, other):
111 """Determine if the checklist is not equal to the given other one."""
112 return not self==other
113
114 def __len__(self):
115 """Get the length of the file list."""
116 return len(self._fileList)
117
118 def __getitem__(self, index):
119 """Get the file with the given index."""
120 return self._fileList[index]
121
122 def __iter__(self):
123 """Iterate over the files."""
124 return iter(self._fileList)
125
126#-------------------------------------------------------------------------------
127
128class ApproachCallouts(object):
129 """The approach callouts for a certain aircraft type."""
130 # The name of the section of the approach callouts
131 SECTION="callouts"
132
133 @staticmethod
134 def fromConfig(config, aircraftType):
135 """Create a checklist for the given aircraft type from the given
136 config."""
137 baseName = "callouts." + const.icaoCodes[aircraftType] + "."
138 mapping = {}
139 while True:
140 option = baseName + str(len(mapping))
141 if config.has_option(ApproachCallouts.SECTION, option):
142 value = config.get(ApproachCallouts.SECTION, option)
143 (altitude, path) = value.split(",")
144 altitude = int(altitude.strip())
145 path = path.strip()
146 mapping[altitude] = path
147 else:
148 break
149
150 return ApproachCallouts(mapping)
151
152 def __init__(self, mapping = None):
153 """Construct the check list with the given mapping of altitudes to
154 files."""
155 self._mapping = {} if mapping is None else mapping.copy()
156
157 def clone(self):
158 """Clone the callout information."""
159 return ApproachCallouts(self._mapping)
160
161 def toConfig(self, config, aircraftType):
162 """Add this checklist to the given config."""
163 baseName = "callouts." + const.icaoCodes[aircraftType] + "."
164 index = 0
165 for (altitude, path) in self._mapping.iteritems():
166 option = baseName + str(index)
167 config.set(ApproachCallouts.SECTION, option,
168 "%d, %s" % (altitude, path))
169 index += 1
170
171 def getAltitudes(self, descending = True):
172 """Get the altitudes in decreasing order by default."""
173 altitudes = self._mapping.keys()
174 altitudes.sort(reverse = descending)
175 return altitudes
176
177 def __nonzero__(self):
178 """Return if there is anything in the mapping."""
179 return not not self._mapping
180
181 def __eq__(self, other):
182 """Determine if the approach callout mapping is equal to the given
183 other one."""
184 return self._mapping == other._mapping
185
186 def __ne__(self, other):
187 """Determine if the approach callout mapping is not equal to the given
188 other one."""
189 return not self==other
190
191 def __len__(self):
192 """Get the number of elements in the mapping."""
193 return len(self._mapping)
194
195 def __getitem__(self, altitude):
196 """Get the file that is associated with the given altitude.
197
198 If no such file found, return None."""
199 return self._mapping[altitude] if altitude in self._mapping else None
200
201 def __iter__(self):
202 """Iterate over the pairs of altitudes and paths in decreasing order of
203 the altitude."""
204 altitudes = self.getAltitudes()
205
206 for altitude in altitudes:
207 yield (altitude, self._mapping[altitude])
208
209#-------------------------------------------------------------------------------
210
211class Config(object):
212 """Our configuration."""
213 DEFAULT_UPDATE_URL = "http://mlx.varadiistvan.hu/update/cef"
214
215 _messageTypesSection = "messageTypes"
216
217 def __init__(self):
218 """Construct the configuration with default values."""
219
220 self._pilotID = ""
221 self._password = ""
222 self._rememberPassword = False
223
224 self._language = ""
225 self._hideMinimizedWindow = True
226 self._quitOnClose = False
227 self._onlineGateSystem = not secondaryInstallation
228 self._onlineACARS = not secondaryInstallation
229 self._flareTimeFromFS = False
230 self._syncFSTime = False
231 self._usingFS2Crew = False
232 self._iasSmoothingLength = -2
233 self._vsSmoothingLength = -2
234
235 self._useSimBrief = False
236
237 self._pirepDirectory = None
238 self._pirepAutoSave = False
239
240 self._defaultMSFS = os.name=="nt"
241
242 self._enableSounds = not secondaryInstallation
243
244 self._pilotControlsSounds = True
245 self._pilotHotkey = Hotkey(ctrl = True, shift = False, key = "0")
246
247 self._enableApproachCallouts = False
248 self._speedbrakeAtTD = True
249
250 self._enableChecklists = False
251 self._checklistHotkey = Hotkey(ctrl = True, shift = True, key = "0")
252
253 self._autoUpdate = True
254 self._updateURL = Config.DEFAULT_UPDATE_URL
255 if secondaryInstallation:
256 self._updateURL += "/exp"
257
258 self._messageTypeLevels = {}
259
260 self._checklists = {}
261 self._approachCallouts = {}
262 for aircraftType in const.aircraftTypes:
263 self._checklists[aircraftType] = Checklist()
264 self._approachCallouts[aircraftType] = ApproachCallouts()
265
266 self._modified = False
267
268 @property
269 def pilotID(self):
270 """Get the pilot ID."""
271 return self._pilotID
272
273 @pilotID.setter
274 def pilotID(self, pilotID):
275 """Set the pilot ID."""
276 if pilotID!=self._pilotID:
277 self._pilotID = pilotID
278 self._modified = True
279
280 @property
281 def password(self):
282 """Get the password."""
283 return self._password
284
285 @password.setter
286 def password(self, password):
287 """Set the password."""
288 if password!=self._password:
289 self._password = password
290 self._modified = True
291
292 @property
293 def rememberPassword(self):
294 """Get if we should remember the password."""
295 return self._rememberPassword
296
297 @rememberPassword.setter
298 def rememberPassword(self, rememberPassword):
299 """Set if we should remember the password."""
300 if rememberPassword!=self._rememberPassword:
301 self._rememberPassword = rememberPassword
302 self._modified = True
303
304 @property
305 def language(self):
306 """Get the language to use."""
307 return self._language
308
309 @language.setter
310 def language(self, language):
311 """Set the language to use."""
312 if language!=self._language:
313 self._language = language
314 self._modified = True
315
316 @property
317 def hideMinimizedWindow(self):
318 """Get whether a minimized window should be hidden."""
319 return self._hideMinimizedWindow
320
321 @hideMinimizedWindow.setter
322 def hideMinimizedWindow(self, hideMinimizedWindow):
323 """Set whether a minimized window should be hidden."""
324 if hideMinimizedWindow!=self._hideMinimizedWindow:
325 self._hideMinimizedWindow = hideMinimizedWindow
326 self._modified = True
327
328 @property
329 def quitOnClose(self):
330 """Get whether the application should quit when the close button is
331 clicked."""
332 return self._quitOnClose
333
334 @quitOnClose.setter
335 def quitOnClose(self, quitOnClose):
336 """Set whether the application should quit when the close button is
337 clicked."""
338 if quitOnClose!=self._quitOnClose:
339 self._quitOnClose = quitOnClose
340 self._modified = True
341
342 @property
343 def onlineGateSystem(self):
344 """Get whether the online gate system should be used."""
345 return self._onlineGateSystem
346
347 @onlineGateSystem.setter
348 def onlineGateSystem(self, onlineGateSystem):
349 """Set whether the online gate system should be used."""
350 if onlineGateSystem!=self._onlineGateSystem:
351 self._onlineGateSystem = onlineGateSystem
352 self._modified = True
353
354 @property
355 def onlineACARS(self):
356 """Get whether the online ACARS system should be used."""
357 return self._onlineACARS
358
359 @onlineACARS.setter
360 def onlineACARS(self, onlineACARS):
361 """Set whether the online ACARS system should be used."""
362 if onlineACARS!=self._onlineACARS:
363 self._onlineACARS = onlineACARS
364 self._modified = True
365
366 @property
367 def flareTimeFromFS(self):
368 """Get whether the flare time should be calculated from the time values
369 returned by the simulator."""
370 return self._flareTimeFromFS
371
372 @flareTimeFromFS.setter
373 def flareTimeFromFS(self, flareTimeFromFS):
374 """Set whether the flare time should be calculated from the time values
375 returned by the simulator."""
376 if flareTimeFromFS!=self._flareTimeFromFS:
377 self._flareTimeFromFS = flareTimeFromFS
378 self._modified = True
379
380 @property
381 def syncFSTime(self):
382 """Get whether the simulator's time should be synchronized with the
383 machine's clock."""
384 return self._syncFSTime
385
386 @syncFSTime.setter
387 def syncFSTime(self, syncFSTime):
388 """Set whether the simulator's time should be synchronized with the
389 machine's clock."""
390 if syncFSTime!=self._syncFSTime:
391 self._syncFSTime = syncFSTime
392 self._modified = True
393
394 @property
395 def usingFS2Crew(self):
396 """Get whether the FS2Crew addon is being used."""
397 return self._usingFS2Crew
398
399 @usingFS2Crew.setter
400 def usingFS2Crew(self, usingFS2Crew):
401 """Set whether the FS2Crew addon is being used."""
402 if usingFS2Crew!=self._usingFS2Crew:
403 self._usingFS2Crew = usingFS2Crew
404 self._modified = True
405
406 @property
407 def iasSmoothingLength(self):
408 """Get the number of samples over which the IAS is averaged for the
409 smoothed IAS calculation. It may be negative, in which case smoothing
410 is disabled, but we nevertheless store the number of seconds in case it
411 may become useful later."""
412 return self._iasSmoothingLength
413
414 @property
415 def realIASSmoothingLength(self):
416 """Get the real smoothing length of IAS."""
417 return max(self._iasSmoothingLength, 1)
418
419 @iasSmoothingLength.setter
420 def iasSmoothingLength(self, iasSmoothingLength):
421 """Set the number of samples over which the IAS is averaged for the
422 smoothed IAS calculation."""
423 if iasSmoothingLength!=self._iasSmoothingLength:
424 self._iasSmoothingLength = iasSmoothingLength
425 self._modified = True
426
427 @property
428 def vsSmoothingLength(self):
429 """Get the number of samples over which the VS is averaged for the
430 smoothed VS calculation. It may be negative, in which case smoothing
431 is disabled, but we nevertheless store the number of seconds in case it
432 may become useful later."""
433 return self._vsSmoothingLength
434
435 @property
436 def realVSSmoothingLength(self):
437 """Get the real smoothing length of VS."""
438 return max(self._vsSmoothingLength, 1)
439
440 @vsSmoothingLength.setter
441 def vsSmoothingLength(self, vsSmoothingLength):
442 """Set the number of samples over which the VS is averaged for the
443 smoothed VS calculation."""
444 if vsSmoothingLength!=self._vsSmoothingLength:
445 self._vsSmoothingLength = vsSmoothingLength
446 self._modified = True
447
448 @property
449 def useSimBrief(self):
450 """Check if SimBrief should be used."""
451 return self._useSimBrief
452
453 @useSimBrief.setter
454 def useSimBrief(self, useSimBrief):
455 """Check if SimBrief should be used."""
456 if self._useSimBrief != useSimBrief:
457 self._useSimBrief = useSimBrief
458 self._modified = True
459
460 @property
461 def pirepDirectory(self):
462 """Get the directory offered by default when saving a PIREP."""
463 return self._pirepDirectory
464
465 @pirepDirectory.setter
466 def pirepDirectory(self, pirepDirectory):
467 """Get the directory offered by default when saving a PIREP."""
468 if pirepDirectory!=self._pirepDirectory and \
469 (pirepDirectory!="" or self._pirepDirectory is not None):
470 self._pirepDirectory = None if pirepDirectory=="" \
471 else pirepDirectory
472 if self._pirepDirectory is None:
473 self._pirepAutoSave = False
474 self._modified = True
475
476 @property
477 def pirepAutoSave(self):
478 """Get whether the PIREP should be saved automatically when it becomes
479 saveable."""
480 return self._pirepAutoSave
481
482 @pirepAutoSave.setter
483 def pirepAutoSave(self, pirepAutoSave):
484 """Set whether the PIREP should be saved automatically when it becomes
485 saveable."""
486 pirepAutoSave = pirepAutoSave and self._pirepDirectory is not None
487 if pirepAutoSave!=self._pirepAutoSave:
488 self._pirepAutoSave = pirepAutoSave
489 self._modified = True
490
491 @property
492 def defaultMSFS(self):
493 """Get if the default simulator type is MS FS."""
494 return self._defaultMSFS
495
496 @defaultMSFS.setter
497 def defaultMSFS(self, defaultMSFS):
498 """Set if the default simulator type is MS FS."""
499 if defaultMSFS!=self._defaultMSFS:
500 self._defaultMSFS = defaultMSFS
501 self._modified = True
502
503 def getMessageTypeLevel(self, messageType):
504 """Get the level for the given message type."""
505 return self._messageTypeLevels[messageType] \
506 if messageType in self._messageTypeLevels \
507 else const.MESSAGELEVEL_NONE
508
509 def isMessageTypeFS(self, messageType):
510 """Determine if the given message type is displayed in the
511 simulator."""
512 level = self.getMessageTypeLevel(messageType)
513 return level==const.MESSAGELEVEL_FS or \
514 level==const.MESSAGELEVEL_BOTH
515
516 def setMessageTypeLevel(self, messageType, level):
517 """Set the level of the given message type."""
518 if messageType not in self._messageTypeLevels or \
519 self._messageTypeLevels[messageType]!=level:
520 self._messageTypeLevels[messageType] = level
521 self._modified = True
522
523 @property
524 def enableSounds(self):
525 """Get whether background sounds are enabled."""
526 return self._enableSounds
527
528 @enableSounds.setter
529 def enableSounds(self, enableSounds):
530 """Set whether background sounds are enabled."""
531 if enableSounds!=self._enableSounds:
532 self._enableSounds = enableSounds
533 self._modified = True
534
535 @property
536 def pilotControlsSounds(self):
537 """Get whether the pilot controls the background sounds."""
538 return self._pilotControlsSounds
539
540 @pilotControlsSounds.setter
541 def pilotControlsSounds(self, pilotControlsSounds):
542 """Set whether the pilot controls the background sounds."""
543 if pilotControlsSounds!=self._pilotControlsSounds:
544 self._pilotControlsSounds = pilotControlsSounds
545 self._modified = True
546
547 @property
548 def pilotHotkey(self):
549 """Get the pilot's hotkey."""
550 return self._pilotHotkey
551
552 @pilotHotkey.setter
553 def pilotHotkey(self, pilotHotkey):
554 """Set the pilot's hotkey."""
555 if pilotHotkey!=self._pilotHotkey:
556 self._pilotHotkey = pilotHotkey
557 self._modified = True
558
559 @property
560 def enableApproachCallouts(self):
561 """Get whether the approach callouts should be played."""
562 return self._enableApproachCallouts
563
564 @enableApproachCallouts.setter
565 def enableApproachCallouts(self, enableApproachCallouts):
566 """Set whether the approach callouts should be played."""
567 if enableApproachCallouts!=self._enableApproachCallouts:
568 self._enableApproachCallouts = enableApproachCallouts
569 self._modified = True
570
571 @property
572 def speedbrakeAtTD(self):
573 """Get whether the speedbrake sounds should be played at touchdown."""
574 return self._speedbrakeAtTD
575
576 @speedbrakeAtTD.setter
577 def speedbrakeAtTD(self, speedbrakeAtTD):
578 """Set whether the speedbrake sounds should be played at touchdown."""
579 if speedbrakeAtTD!=self._speedbrakeAtTD:
580 self._speedbrakeAtTD = speedbrakeAtTD
581 self._modified = True
582
583 @property
584 def enableChecklists(self):
585 """Get whether aircraft-specific checklists should be played."""
586 return self._enableChecklists
587
588 @enableChecklists.setter
589 def enableChecklists(self, enableChecklists):
590 """Get whether aircraft-specific checklists should be played."""
591 if enableChecklists!=self._enableChecklists:
592 self._enableChecklists = enableChecklists
593 self._modified = True
594
595 @property
596 def checklistHotkey(self):
597 """Get the checklist hotkey."""
598 return self._checklistHotkey
599
600 @checklistHotkey.setter
601 def checklistHotkey(self, checklistHotkey):
602 """Set the checklist hotkey."""
603 if checklistHotkey!=self._checklistHotkey:
604 self._checklistHotkey = checklistHotkey
605 self._modified = True
606
607 @property
608 def autoUpdate(self):
609 """Get if an automatic update is needed."""
610 return self._autoUpdate
611
612 @autoUpdate.setter
613 def autoUpdate(self, autoUpdate):
614 """Set if an automatic update is needed."""
615 if autoUpdate!=self._autoUpdate:
616 self._autoUpdate = autoUpdate
617 self._modified = True
618
619 @property
620 def updateURL(self):
621 """Get the update URL."""
622 return self._updateURL
623
624 @updateURL.setter
625 def updateURL(self, updateURL):
626 """Set the update URL."""
627 if updateURL!=self._updateURL:
628 self._updateURL = updateURL
629 self._modified = True
630
631 def getChecklist(self, aircraftType):
632 """Get the checklist for the given aircraft type."""
633 return self._checklists[aircraftType]
634
635 def setChecklist(self, aircraftType, checklist):
636 """Set the checklist for the given aircraft type."""
637 if checklist!=self._checklists[aircraftType]:
638 self._checklists[aircraftType] = checklist.clone()
639 self._modified = True
640
641 def getApproachCallouts(self, aircraftType):
642 """Get the approach callouts for the given aircraft type."""
643 return self._approachCallouts[aircraftType]
644
645 def setApproachCallouts(self, aircraftType, approachCallouts):
646 """Set the approach callouts for the given aircraft type."""
647 if not approachCallouts==self._approachCallouts[aircraftType]:
648 self._approachCallouts[aircraftType] = approachCallouts.clone()
649 self._modified = True
650
651 def load(self):
652 """Load the configuration from its default location."""
653 try:
654 config = ConfigParser.RawConfigParser()
655 config.read(configPath)
656 except:
657 traceback.print_exc()
658 return
659
660 self._pilotID = self._get(config, "login", "id", "")
661 self._password = self._get(config, "login", "password", "")
662 self._rememberPassword = self._getBoolean(config, "login",
663 "rememberPassword", False)
664
665 self._language = self._get(config, "general", "language", "")
666
667 self._hideMinimizedWindow = self._getBoolean(config, "general",
668 "hideMinimizedWindow",
669 True)
670 self._quitOnClose = self._getBoolean(config, "general",
671 "quitOnClose", False)
672
673 self._onlineGateSystem = self._getBoolean(config, "general",
674 "onlineGateSystem",
675 not secondaryInstallation)
676 self._onlineACARS = self._getBoolean(config, "general",
677 "onlineACARS",
678 not secondaryInstallation)
679 self._flareTimeFromFS = self._getBoolean(config, "general",
680 "flareTimeFromFS",
681 False)
682 self._syncFSTime = self._getBoolean(config, "general",
683 "syncFSTime",
684 False)
685 self._usingFS2Crew = self._getBoolean(config, "general",
686 "usingFS2Crew",
687 False)
688 self._iasSmoothingLength = int(self._get(config, "general",
689 "iasSmoothingLength",
690 -2))
691 self._vsSmoothingLength = int(self._get(config, "general",
692 "vsSmoothingLength",
693 -2))
694
695 self._useSimBrief = self._getBoolean(config, "general",
696 "useSimBrief", False)
697
698 self._pirepDirectory = self._get(config, "general",
699 "pirepDirectory", None)
700
701 self._pirepAutoSave = self._getBoolean(config, "general",
702 "pirepAutoSave", False)
703 if self._pirepDirectory is None:
704 self._pirepAutoSave = False
705
706 self._messageTypeLevels = {}
707 for messageType in const.messageTypes:
708 self._messageTypeLevels[messageType] = \
709 self._getMessageTypeLevel(config, messageType)
710
711 self._enableSounds = self._getBoolean(config, "sounds", "enable",
712 not secondaryInstallation)
713 self._pilotControlsSounds = self._getBoolean(config, "sounds",
714 "pilotControls", True)
715 self._pilotHotkey.set(self._get(config, "sounds",
716 "pilotHotkey", "C0"))
717 self._enableApproachCallouts = \
718 self._getBoolean(config, "sounds", "enableApproachCallouts", False)
719 self._speedbrakeAtTD = self._getBoolean(config, "sounds",
720 "speedbrakeAtTD", True)
721
722 self._enableChecklists = self._getBoolean(config, "sounds",
723 "enableChecklists", False)
724 self._checklistHotkey.set(self._get(config, "sounds",
725 "checklistHotkey", "CS0"))
726
727 self._autoUpdate = self._getBoolean(config, "update", "auto", True)
728 self._updateURL = self._get(config, "update", "url",
729 Config.DEFAULT_UPDATE_URL +
730 ("/exp" if secondaryInstallation else ""))
731
732 for aircraftType in const.aircraftTypes:
733 self._checklists[aircraftType] = \
734 Checklist.fromConfig(config, aircraftType)
735 self._approachCallouts[aircraftType] = \
736 ApproachCallouts.fromConfig(config, aircraftType)
737
738 self._defaultMSFS = self._getBoolean(config, "general",
739 "defaultMSFS", os.name=="nt")
740
741 self._modified = False
742
743 def save(self):
744 """Save the configuration file if it has been modified."""
745 if not self._modified:
746 return
747
748 config = ConfigParser.RawConfigParser()
749
750 config.add_section("login")
751 config.set("login", "id", self._pilotID)
752 config.set("login", "password", self._password)
753 config.set("login", "rememberPassword",
754 "yes" if self._rememberPassword else "no")
755
756 config.add_section("general")
757 if self._language:
758 config.set("general", "language", self._language)
759 config.set("general", "hideMinimizedWindow",
760 "yes" if self._hideMinimizedWindow else "no")
761 config.set("general", "quitOnClose",
762 "yes" if self._quitOnClose else "no")
763 config.set("general", "onlineGateSystem",
764 "yes" if self._onlineGateSystem else "no")
765 config.set("general", "onlineACARS",
766 "yes" if self._onlineACARS else "no")
767 config.set("general", "flareTimeFromFS",
768 "yes" if self._flareTimeFromFS else "no")
769 config.set("general", "syncFSTime",
770 "yes" if self._syncFSTime else "no")
771 config.set("general", "usingFS2Crew",
772 "yes" if self._usingFS2Crew else "no")
773 config.set("general", "iasSmoothingLength",
774 str(self._iasSmoothingLength))
775 config.set("general", "vsSmoothingLength",
776 str(self._vsSmoothingLength))
777
778 config.set("general", "useSimBrief",
779 "yes" if self._useSimBrief else "no")
780
781 if self._pirepDirectory is not None:
782 config.set("general", "pirepDirectory", self._pirepDirectory)
783 config.set("general", "pirepAutoSave",
784 "yes" if self._pirepAutoSave else "no")
785
786 config.set("general", "defaultMSFS",
787 "yes" if self._defaultMSFS else "no")
788
789 config.add_section(Config._messageTypesSection)
790 for messageType in const.messageTypes:
791 if messageType in self._messageTypeLevels:
792 option = self._getMessageTypeLevelOptionName(messageType)
793 level = self._messageTypeLevels[messageType]
794 config.set(Config._messageTypesSection, option,
795 const.messageLevel2string(level))
796
797 config.add_section("sounds")
798 config.set("sounds", "enable",
799 "yes" if self._enableSounds else "no")
800 config.set("sounds", "pilotControls",
801 "yes" if self._pilotControlsSounds else "no")
802 config.set("sounds", "pilotHotkey", str(self._pilotHotkey))
803 config.set("sounds", "enableApproachCallouts",
804 "yes" if self._enableApproachCallouts else "no")
805 config.set("sounds", "speedbrakeAtTD",
806 "yes" if self._speedbrakeAtTD else "no")
807
808 config.set("sounds", "enableChecklists",
809 "yes" if self._enableChecklists else "no")
810 config.set("sounds", "checklistHotkey",
811 str(self._checklistHotkey))
812
813 config.add_section("update")
814 config.set("update", "auto",
815 "yes" if self._autoUpdate else "no")
816 config.set("update", "url", self._updateURL)
817
818 config.add_section(Checklist.SECTION)
819 config.add_section(ApproachCallouts.SECTION)
820 for aircraftType in const.aircraftTypes:
821 self._checklists[aircraftType].toConfig(config, aircraftType)
822 self._approachCallouts[aircraftType].toConfig(config, aircraftType)
823
824 try:
825 fd = os.open(configPath, os.O_CREAT|os.O_TRUNC|os.O_WRONLY,
826 0600)
827 with os.fdopen(fd, "wt") as f:
828 config.write(f)
829 self._modified = False
830
831 print "Configuration saved:"
832 self.log()
833
834 except Exception, e:
835 print >> sys.stderr, "Failed to update config: " + \
836 utf2unicode(str(e))
837
838 def _getBoolean(self, config, section, option, default):
839 """Get the given option as a boolean, if found in the given config,
840 otherwise the default."""
841 return config.getboolean(section, option) \
842 if config.has_option(section, option) \
843 else default
844
845 def _get(self, config, section, option, default):
846 """Get the given option as a string, if found in the given config,
847 otherwise the default."""
848 return config.get(section, option) \
849 if config.has_option(section, option) \
850 else default
851
852 def _getMessageTypeLevel(self, config, messageType):
853 """Get the message type level for the given message type."""
854 option = self._getMessageTypeLevelOptionName(messageType)
855 if config.has_option(Config._messageTypesSection, option):
856 value = config.get(Config._messageTypesSection, option)
857 return const.string2messageLevel(value)
858 elif secondaryInstallation:
859 return const.MESSAGELEVEL_NONE
860 elif messageType in [const.MESSAGETYPE_LOGGER_ERROR,
861 const.MESSAGETYPE_FAULT,
862 const.MESSAGETYPE_NOGO,
863 const.MESSAGETYPE_GATE_SYSTEM,
864 const.MESSAGETYPE_HELP]:
865 return const.MESSAGELEVEL_BOTH
866 else:
867 return const.MESSAGELEVEL_FS
868
869 def _getMessageTypeLevelOptionName(self, messageType):
870 """Get the option name for the given message type level."""
871 return const.messageType2string(messageType)
872
873 def setupLocale(self):
874 """Setup the locale based on the language set.
875
876 Return True if a specific language was set, False otherwise."""
877 import locale
878 if self._language:
879 print "Setting up locale for", self._language
880 os.environ["LANGUAGE"] = self._language
881 langAndEncoding = self._language + "." + locale.getpreferredencoding()
882 os.environ["LANG"] = langAndEncoding
883 os.environ["LC_MESSAGES"] = langAndEncoding
884 os.environ["LC_COLLATE"] = langAndEncoding
885 os.environ["LC_CTYPE"] = langAndEncoding
886 os.environ["LC_MONETARY"] = langAndEncoding
887 os.environ["LC_NUMERIC"] = langAndEncoding
888 os.environ["LC_TIME"] = langAndEncoding
889 return True
890 else:
891 return False
892
893 def getLanguage(self):
894 """Get the language to be used."""
895 import locale
896 if self._language:
897 if os.name=="nt":
898 if self._language in _languageMap:
899 locale.setlocale(locale.LC_ALL, _languageMap[self._language])
900 else:
901 locale.setlocale(locale.LC_ALL, "")
902 else:
903 locale.setlocale(locale.LC_ALL, (self._language,
904 locale.getpreferredencoding()))
905 return self._language
906 else:
907 locale.setlocale(locale.LC_ALL, "")
908 return locale.getdefaultlocale()[0]
909
910 def log(self):
911 """Log the configuration by printing the values"""
912 print " pilot ID:", self._pilotID
913 print " rememberPassword:", self._rememberPassword
914
915 print " language:", self._language
916
917 print " hideMinimizedWindow:", self._hideMinimizedWindow
918 print " quitOnClose:", self._quitOnClose
919
920 print " onlineGateSystem:", self._onlineGateSystem
921 print " onlineACARS:", self._onlineACARS
922
923 print " flareTimeFromFS:", self._flareTimeFromFS
924 print " syncFSTime:", self._syncFSTime
925 print " usingFS2Crew:", self._usingFS2Crew
926
927 print " iasSmoothingLength:", self._iasSmoothingLength
928 print " vsSmoothingLength:", self._vsSmoothingLength
929
930 print " useSimBrief:", self._useSimBrief
931
932 print " pirepDirectory:", self._pirepDirectory
933 print " pirepAutoSave:", self._pirepAutoSave
934
935 print " defaultMSFS:", self._defaultMSFS
936
937 print " enableSounds:", self._enableSounds
938
939 print " pilotControlsSounds:", self._pilotControlsSounds
940 print " pilotHotkey:", str(self._pilotHotkey)
941
942 print " enableApproachCallouts:", self._enableApproachCallouts
943 print " speedbrakeAtTD:", self._speedbrakeAtTD
944
945 print " enableChecklists:", self._enableChecklists
946 print " checklistHotkey:", str(self._checklistHotkey)
947
948 print " autoUpdate:", self._autoUpdate
949 print " updateURL:", self._updateURL
950
951 print " messageTypeLevels:"
952 for (type, level) in self._messageTypeLevels.iteritems():
953 print " %s: %s" % (const.messageType2string(type),
954 const.messageLevel2string(level))
955
956 print " checklists:"
957 for (type, checklist) in self._checklists.iteritems():
958 print " %s:" % (const.icaoCodes[type],)
959 for path in checklist:
960 print " " + path
961
962 print " approachCallouts:"
963 for (type, approachCallouts) in self._approachCallouts.iteritems():
964 print " %s:" % (const.icaoCodes[type],)
965 for (altitude, path) in approachCallouts:
966 print " %d: %s" % (altitude, path)
967
968#-------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.