source: src/mlx/config.py@ 531:f8ffb59d8112

xplane
Last change on this file since 531:f8ffb59d8112 was 503:7a2894109717, checked in by István Váradi <ivaradi@…>, 12 years ago

The default simulator type is now remembered

File size: 34.9 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"
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._pirepDirectory = None
236 self._pirepAutoSave = False
237
238 self._defaultMSFS = os.name=="nt"
239
240 self._enableSounds = not secondaryInstallation
241
242 self._pilotControlsSounds = True
243 self._pilotHotkey = Hotkey(ctrl = True, shift = False, key = "0")
244
245 self._enableApproachCallouts = False
246 self._speedbrakeAtTD = True
247
248 self._enableChecklists = False
249 self._checklistHotkey = Hotkey(ctrl = True, shift = True, key = "0")
250
251 self._autoUpdate = True
252 self._updateURL = Config.DEFAULT_UPDATE_URL
253 if secondaryInstallation:
254 self._updateURL += "/exp"
255
256 self._messageTypeLevels = {}
257
258 self._checklists = {}
259 self._approachCallouts = {}
260 for aircraftType in const.aircraftTypes:
261 self._checklists[aircraftType] = Checklist()
262 self._approachCallouts[aircraftType] = ApproachCallouts()
263
264 self._modified = False
265
266 @property
267 def pilotID(self):
268 """Get the pilot ID."""
269 return self._pilotID
270
271 @pilotID.setter
272 def pilotID(self, pilotID):
273 """Set the pilot ID."""
274 if pilotID!=self._pilotID:
275 self._pilotID = pilotID
276 self._modified = True
277
278 @property
279 def password(self):
280 """Get the password."""
281 return self._password
282
283 @password.setter
284 def password(self, password):
285 """Set the password."""
286 if password!=self._password:
287 self._password = password
288 self._modified = True
289
290 @property
291 def rememberPassword(self):
292 """Get if we should remember the password."""
293 return self._rememberPassword
294
295 @rememberPassword.setter
296 def rememberPassword(self, rememberPassword):
297 """Set if we should remember the password."""
298 if rememberPassword!=self._rememberPassword:
299 self._rememberPassword = rememberPassword
300 self._modified = True
301
302 @property
303 def language(self):
304 """Get the language to use."""
305 return self._language
306
307 @language.setter
308 def language(self, language):
309 """Set the language to use."""
310 if language!=self._language:
311 self._language = language
312 self._modified = True
313
314 @property
315 def hideMinimizedWindow(self):
316 """Get whether a minimized window should be hidden."""
317 return self._hideMinimizedWindow
318
319 @hideMinimizedWindow.setter
320 def hideMinimizedWindow(self, hideMinimizedWindow):
321 """Set whether a minimized window should be hidden."""
322 if hideMinimizedWindow!=self._hideMinimizedWindow:
323 self._hideMinimizedWindow = hideMinimizedWindow
324 self._modified = True
325
326 @property
327 def quitOnClose(self):
328 """Get whether the application should quit when the close button is
329 clicked."""
330 return self._quitOnClose
331
332 @quitOnClose.setter
333 def quitOnClose(self, quitOnClose):
334 """Set whether the application should quit when the close button is
335 clicked."""
336 if quitOnClose!=self._quitOnClose:
337 self._quitOnClose = quitOnClose
338 self._modified = True
339
340 @property
341 def onlineGateSystem(self):
342 """Get whether the online gate system should be used."""
343 return self._onlineGateSystem
344
345 @onlineGateSystem.setter
346 def onlineGateSystem(self, onlineGateSystem):
347 """Set whether the online gate system should be used."""
348 if onlineGateSystem!=self._onlineGateSystem:
349 self._onlineGateSystem = onlineGateSystem
350 self._modified = True
351
352 @property
353 def onlineACARS(self):
354 """Get whether the online ACARS system should be used."""
355 return self._onlineACARS
356
357 @onlineACARS.setter
358 def onlineACARS(self, onlineACARS):
359 """Set whether the online ACARS system should be used."""
360 if onlineACARS!=self._onlineACARS:
361 self._onlineACARS = onlineACARS
362 self._modified = True
363
364 @property
365 def flareTimeFromFS(self):
366 """Get whether the flare time should be calculated from the time values
367 returned by the simulator."""
368 return self._flareTimeFromFS
369
370 @flareTimeFromFS.setter
371 def flareTimeFromFS(self, flareTimeFromFS):
372 """Set whether the flare time should be calculated from the time values
373 returned by the simulator."""
374 if flareTimeFromFS!=self._flareTimeFromFS:
375 self._flareTimeFromFS = flareTimeFromFS
376 self._modified = True
377
378 @property
379 def syncFSTime(self):
380 """Get whether the simulator's time should be synchronized with the
381 machine's clock."""
382 return self._syncFSTime
383
384 @syncFSTime.setter
385 def syncFSTime(self, syncFSTime):
386 """Set whether the simulator's time should be synchronized with the
387 machine's clock."""
388 if syncFSTime!=self._syncFSTime:
389 self._syncFSTime = syncFSTime
390 self._modified = True
391
392 @property
393 def usingFS2Crew(self):
394 """Get whether the FS2Crew addon is being used."""
395 return self._usingFS2Crew
396
397 @usingFS2Crew.setter
398 def usingFS2Crew(self, usingFS2Crew):
399 """Set whether the FS2Crew addon is being used."""
400 if usingFS2Crew!=self._usingFS2Crew:
401 self._usingFS2Crew = usingFS2Crew
402 self._modified = True
403
404 @property
405 def iasSmoothingLength(self):
406 """Get the number of samples over which the IAS is averaged for the
407 smoothed IAS calculation. It may be negative, in which case smoothing
408 is disabled, but we nevertheless store the number of seconds in case it
409 may become useful later."""
410 return self._iasSmoothingLength
411
412 @property
413 def realIASSmoothingLength(self):
414 """Get the real smoothing length of IAS."""
415 return max(self._iasSmoothingLength, 1)
416
417 @iasSmoothingLength.setter
418 def iasSmoothingLength(self, iasSmoothingLength):
419 """Set the number of samples over which the IAS is averaged for the
420 smoothed IAS calculation."""
421 if iasSmoothingLength!=self._iasSmoothingLength:
422 self._iasSmoothingLength = iasSmoothingLength
423 self._modified = True
424
425 @property
426 def vsSmoothingLength(self):
427 """Get the number of samples over which the VS is averaged for the
428 smoothed VS calculation. It may be negative, in which case smoothing
429 is disabled, but we nevertheless store the number of seconds in case it
430 may become useful later."""
431 return self._vsSmoothingLength
432
433 @property
434 def realVSSmoothingLength(self):
435 """Get the real smoothing length of VS."""
436 return max(self._vsSmoothingLength, 1)
437
438 @vsSmoothingLength.setter
439 def vsSmoothingLength(self, vsSmoothingLength):
440 """Set the number of samples over which the VS is averaged for the
441 smoothed VS calculation."""
442 if vsSmoothingLength!=self._vsSmoothingLength:
443 self._vsSmoothingLength = vsSmoothingLength
444 self._modified = True
445
446 @property
447 def pirepDirectory(self):
448 """Get the directory offered by default when saving a PIREP."""
449 return self._pirepDirectory
450
451 @pirepDirectory.setter
452 def pirepDirectory(self, pirepDirectory):
453 """Get the directory offered by default when saving a PIREP."""
454 if pirepDirectory!=self._pirepDirectory and \
455 (pirepDirectory!="" or self._pirepDirectory is not None):
456 self._pirepDirectory = None if pirepDirectory=="" \
457 else pirepDirectory
458 if self._pirepDirectory is None:
459 self._pirepAutoSave = False
460 self._modified = True
461
462 @property
463 def pirepAutoSave(self):
464 """Get whether the PIREP should be saved automatically when it becomes
465 saveable."""
466 return self._pirepAutoSave
467
468 @pirepAutoSave.setter
469 def pirepAutoSave(self, pirepAutoSave):
470 """Set whether the PIREP should be saved automatically when it becomes
471 saveable."""
472 pirepAutoSave = pirepAutoSave and self._pirepDirectory is not None
473 if pirepAutoSave!=self._pirepAutoSave:
474 self._pirepAutoSave = pirepAutoSave
475 self._modified = True
476
477 @property
478 def defaultMSFS(self):
479 """Get if the default simulator type is MS FS."""
480 return self._defaultMSFS
481
482 @defaultMSFS.setter
483 def defaultMSFS(self, defaultMSFS):
484 """Set if the default simulator type is MS FS."""
485 if defaultMSFS!=self._defaultMSFS:
486 self._defaultMSFS = defaultMSFS
487 self._modified = True
488
489 def getMessageTypeLevel(self, messageType):
490 """Get the level for the given message type."""
491 return self._messageTypeLevels[messageType] \
492 if messageType in self._messageTypeLevels \
493 else const.MESSAGELEVEL_NONE
494
495 def isMessageTypeFS(self, messageType):
496 """Determine if the given message type is displayed in the
497 simulator."""
498 level = self.getMessageTypeLevel(messageType)
499 return level==const.MESSAGELEVEL_FS or \
500 level==const.MESSAGELEVEL_BOTH
501
502 def setMessageTypeLevel(self, messageType, level):
503 """Set the level of the given message type."""
504 if messageType not in self._messageTypeLevels or \
505 self._messageTypeLevels[messageType]!=level:
506 self._messageTypeLevels[messageType] = level
507 self._modified = True
508
509 @property
510 def enableSounds(self):
511 """Get whether background sounds are enabled."""
512 return self._enableSounds
513
514 @enableSounds.setter
515 def enableSounds(self, enableSounds):
516 """Set whether background sounds are enabled."""
517 if enableSounds!=self._enableSounds:
518 self._enableSounds = enableSounds
519 self._modified = True
520
521 @property
522 def pilotControlsSounds(self):
523 """Get whether the pilot controls the background sounds."""
524 return self._pilotControlsSounds
525
526 @pilotControlsSounds.setter
527 def pilotControlsSounds(self, pilotControlsSounds):
528 """Set whether the pilot controls the background sounds."""
529 if pilotControlsSounds!=self._pilotControlsSounds:
530 self._pilotControlsSounds = pilotControlsSounds
531 self._modified = True
532
533 @property
534 def pilotHotkey(self):
535 """Get the pilot's hotkey."""
536 return self._pilotHotkey
537
538 @pilotHotkey.setter
539 def pilotHotkey(self, pilotHotkey):
540 """Set the pilot's hotkey."""
541 if pilotHotkey!=self._pilotHotkey:
542 self._pilotHotkey = pilotHotkey
543 self._modified = True
544
545 @property
546 def enableApproachCallouts(self):
547 """Get whether the approach callouts should be played."""
548 return self._enableApproachCallouts
549
550 @enableApproachCallouts.setter
551 def enableApproachCallouts(self, enableApproachCallouts):
552 """Set whether the approach callouts should be played."""
553 if enableApproachCallouts!=self._enableApproachCallouts:
554 self._enableApproachCallouts = enableApproachCallouts
555 self._modified = True
556
557 @property
558 def speedbrakeAtTD(self):
559 """Get whether the speedbrake sounds should be played at touchdown."""
560 return self._speedbrakeAtTD
561
562 @speedbrakeAtTD.setter
563 def speedbrakeAtTD(self, speedbrakeAtTD):
564 """Set whether the speedbrake sounds should be played at touchdown."""
565 if speedbrakeAtTD!=self._speedbrakeAtTD:
566 self._speedbrakeAtTD = speedbrakeAtTD
567 self._modified = True
568
569 @property
570 def enableChecklists(self):
571 """Get whether aircraft-specific checklists should be played."""
572 return self._enableChecklists
573
574 @enableChecklists.setter
575 def enableChecklists(self, enableChecklists):
576 """Get whether aircraft-specific checklists should be played."""
577 if enableChecklists!=self._enableChecklists:
578 self._enableChecklists = enableChecklists
579 self._modified = True
580
581 @property
582 def checklistHotkey(self):
583 """Get the checklist hotkey."""
584 return self._checklistHotkey
585
586 @checklistHotkey.setter
587 def checklistHotkey(self, checklistHotkey):
588 """Set the checklist hotkey."""
589 if checklistHotkey!=self._checklistHotkey:
590 self._checklistHotkey = checklistHotkey
591 self._modified = True
592
593 @property
594 def autoUpdate(self):
595 """Get if an automatic update is needed."""
596 return self._autoUpdate
597
598 @autoUpdate.setter
599 def autoUpdate(self, autoUpdate):
600 """Set if an automatic update is needed."""
601 if autoUpdate!=self._autoUpdate:
602 self._autoUpdate = autoUpdate
603 self._modified = True
604
605 @property
606 def updateURL(self):
607 """Get the update URL."""
608 return self._updateURL
609
610 @updateURL.setter
611 def updateURL(self, updateURL):
612 """Set the update URL."""
613 if updateURL!=self._updateURL:
614 self._updateURL = updateURL
615 self._modified = True
616
617 def getChecklist(self, aircraftType):
618 """Get the checklist for the given aircraft type."""
619 return self._checklists[aircraftType]
620
621 def setChecklist(self, aircraftType, checklist):
622 """Set the checklist for the given aircraft type."""
623 if checklist!=self._checklists[aircraftType]:
624 self._checklists[aircraftType] = checklist.clone()
625 self._modified = True
626
627 def getApproachCallouts(self, aircraftType):
628 """Get the approach callouts for the given aircraft type."""
629 return self._approachCallouts[aircraftType]
630
631 def setApproachCallouts(self, aircraftType, approachCallouts):
632 """Set the approach callouts for the given aircraft type."""
633 if not approachCallouts==self._approachCallouts[aircraftType]:
634 self._approachCallouts[aircraftType] = approachCallouts.clone()
635 self._modified = True
636
637 def load(self):
638 """Load the configuration from its default location."""
639 try:
640 config = ConfigParser.RawConfigParser()
641 config.read(configPath)
642 except:
643 traceback.print_exc()
644 return
645
646 self._pilotID = self._get(config, "login", "id", "")
647 self._password = self._get(config, "login", "password", "")
648 self._rememberPassword = self._getBoolean(config, "login",
649 "rememberPassword", False)
650
651 self._language = self._get(config, "general", "language", "")
652
653 self._hideMinimizedWindow = self._getBoolean(config, "general",
654 "hideMinimizedWindow",
655 True)
656 self._quitOnClose = self._getBoolean(config, "general",
657 "quitOnClose", False)
658
659 self._onlineGateSystem = self._getBoolean(config, "general",
660 "onlineGateSystem",
661 not secondaryInstallation)
662 self._onlineACARS = self._getBoolean(config, "general",
663 "onlineACARS",
664 not secondaryInstallation)
665 self._flareTimeFromFS = self._getBoolean(config, "general",
666 "flareTimeFromFS",
667 False)
668 self._syncFSTime = self._getBoolean(config, "general",
669 "syncFSTime",
670 False)
671 self._usingFS2Crew = self._getBoolean(config, "general",
672 "usingFS2Crew",
673 False)
674 self._iasSmoothingLength = int(self._get(config, "general",
675 "iasSmoothingLength",
676 -2))
677 self._vsSmoothingLength = int(self._get(config, "general",
678 "vsSmoothingLength",
679 -2))
680 self._pirepDirectory = self._get(config, "general",
681 "pirepDirectory", None)
682
683 self._pirepAutoSave = self._getBoolean(config, "general",
684 "pirepAutoSave", False)
685 if self._pirepDirectory is None:
686 self._pirepAutoSave = False
687
688 self._messageTypeLevels = {}
689 for messageType in const.messageTypes:
690 self._messageTypeLevels[messageType] = \
691 self._getMessageTypeLevel(config, messageType)
692
693 self._enableSounds = self._getBoolean(config, "sounds", "enable",
694 not secondaryInstallation)
695 self._pilotControlsSounds = self._getBoolean(config, "sounds",
696 "pilotControls", True)
697 self._pilotHotkey.set(self._get(config, "sounds",
698 "pilotHotkey", "C0"))
699 self._enableApproachCallouts = \
700 self._getBoolean(config, "sounds", "enableApproachCallouts", False)
701 self._speedbrakeAtTD = self._getBoolean(config, "sounds",
702 "speedbrakeAtTD", True)
703
704 self._enableChecklists = self._getBoolean(config, "sounds",
705 "enableChecklists", False)
706 self._checklistHotkey.set(self._get(config, "sounds",
707 "checklistHotkey", "CS0"))
708
709 self._autoUpdate = self._getBoolean(config, "update", "auto", True)
710 self._updateURL = self._get(config, "update", "url",
711 Config.DEFAULT_UPDATE_URL +
712 ("/exp" if secondaryInstallation else ""))
713
714 for aircraftType in const.aircraftTypes:
715 self._checklists[aircraftType] = \
716 Checklist.fromConfig(config, aircraftType)
717 self._approachCallouts[aircraftType] = \
718 ApproachCallouts.fromConfig(config, aircraftType)
719
720 self._defaultMSFS = self._getBoolean(config, "general",
721 "defaultMSFS", os.name=="nt")
722
723 self._modified = False
724
725 def save(self):
726 """Save the configuration file if it has been modified."""
727 if not self._modified:
728 return
729
730 config = ConfigParser.RawConfigParser()
731
732 config.add_section("login")
733 config.set("login", "id", self._pilotID)
734 config.set("login", "password", self._password)
735 config.set("login", "rememberPassword",
736 "yes" if self._rememberPassword else "no")
737
738 config.add_section("general")
739 if self._language:
740 config.set("general", "language", self._language)
741 config.set("general", "hideMinimizedWindow",
742 "yes" if self._hideMinimizedWindow else "no")
743 config.set("general", "quitOnClose",
744 "yes" if self._quitOnClose else "no")
745 config.set("general", "onlineGateSystem",
746 "yes" if self._onlineGateSystem else "no")
747 config.set("general", "onlineACARS",
748 "yes" if self._onlineACARS else "no")
749 config.set("general", "flareTimeFromFS",
750 "yes" if self._flareTimeFromFS else "no")
751 config.set("general", "syncFSTime",
752 "yes" if self._syncFSTime else "no")
753 config.set("general", "usingFS2Crew",
754 "yes" if self._usingFS2Crew else "no")
755 config.set("general", "iasSmoothingLength",
756 str(self._iasSmoothingLength))
757 config.set("general", "vsSmoothingLength",
758 str(self._vsSmoothingLength))
759
760 if self._pirepDirectory is not None:
761 config.set("general", "pirepDirectory", self._pirepDirectory)
762 config.set("general", "pirepAutoSave",
763 "yes" if self._pirepAutoSave else "no")
764
765 config.set("general", "defaultMSFS",
766 "yes" if self._defaultMSFS else "no")
767
768 config.add_section(Config._messageTypesSection)
769 for messageType in const.messageTypes:
770 if messageType in self._messageTypeLevels:
771 option = self._getMessageTypeLevelOptionName(messageType)
772 level = self._messageTypeLevels[messageType]
773 config.set(Config._messageTypesSection, option,
774 const.messageLevel2string(level))
775
776 config.add_section("sounds")
777 config.set("sounds", "enable",
778 "yes" if self._enableSounds else "no")
779 config.set("sounds", "pilotControls",
780 "yes" if self._pilotControlsSounds else "no")
781 config.set("sounds", "pilotHotkey", str(self._pilotHotkey))
782 config.set("sounds", "enableApproachCallouts",
783 "yes" if self._enableApproachCallouts else "no")
784 config.set("sounds", "speedbrakeAtTD",
785 "yes" if self._speedbrakeAtTD else "no")
786
787 config.set("sounds", "enableChecklists",
788 "yes" if self._enableChecklists else "no")
789 config.set("sounds", "checklistHotkey",
790 str(self._checklistHotkey))
791
792 config.add_section("update")
793 config.set("update", "auto",
794 "yes" if self._autoUpdate else "no")
795 config.set("update", "url", self._updateURL)
796
797 config.add_section(Checklist.SECTION)
798 config.add_section(ApproachCallouts.SECTION)
799 for aircraftType in const.aircraftTypes:
800 self._checklists[aircraftType].toConfig(config, aircraftType)
801 self._approachCallouts[aircraftType].toConfig(config, aircraftType)
802
803 try:
804 fd = os.open(configPath, os.O_CREAT|os.O_TRUNC|os.O_WRONLY,
805 0600)
806 with os.fdopen(fd, "wt") as f:
807 config.write(f)
808 self._modified = False
809
810 print "Configuration saved:"
811 self.log()
812
813 except Exception, e:
814 print >> sys.stderr, "Failed to update config: " + \
815 utf2unicode(str(e))
816
817 def _getBoolean(self, config, section, option, default):
818 """Get the given option as a boolean, if found in the given config,
819 otherwise the default."""
820 return config.getboolean(section, option) \
821 if config.has_option(section, option) \
822 else default
823
824 def _get(self, config, section, option, default):
825 """Get the given option as a string, if found in the given config,
826 otherwise the default."""
827 return config.get(section, option) \
828 if config.has_option(section, option) \
829 else default
830
831 def _getMessageTypeLevel(self, config, messageType):
832 """Get the message type level for the given message type."""
833 option = self._getMessageTypeLevelOptionName(messageType)
834 if config.has_option(Config._messageTypesSection, option):
835 value = config.get(Config._messageTypesSection, option)
836 return const.string2messageLevel(value)
837 elif secondaryInstallation:
838 return const.MESSAGELEVEL_NONE
839 elif messageType in [const.MESSAGETYPE_LOGGER_ERROR,
840 const.MESSAGETYPE_FAULT,
841 const.MESSAGETYPE_NOGO,
842 const.MESSAGETYPE_GATE_SYSTEM,
843 const.MESSAGETYPE_HELP]:
844 return const.MESSAGELEVEL_BOTH
845 else:
846 return const.MESSAGELEVEL_FS
847
848 def _getMessageTypeLevelOptionName(self, messageType):
849 """Get the option name for the given message type level."""
850 return const.messageType2string(messageType)
851
852 def setupLocale(self):
853 """Setup the locale based on the language set.
854
855 Return True if a specific language was set, False otherwise."""
856 import locale
857 if self._language:
858 print "Setting up locale for", self._language
859 os.environ["LANGUAGE"] = self._language
860 langAndEncoding = self._language + "." + locale.getpreferredencoding()
861 os.environ["LANG"] = langAndEncoding
862 os.environ["LC_MESSAGES"] = langAndEncoding
863 os.environ["LC_COLLATE"] = langAndEncoding
864 os.environ["LC_CTYPE"] = langAndEncoding
865 os.environ["LC_MONETARY"] = langAndEncoding
866 os.environ["LC_NUMERIC"] = langAndEncoding
867 os.environ["LC_TIME"] = langAndEncoding
868 return True
869 else:
870 return False
871
872 def getLanguage(self):
873 """Get the language to be used."""
874 import locale
875 if self._language:
876 if os.name=="nt":
877 if self._language in _languageMap:
878 locale.setlocale(locale.LC_ALL, _languageMap[self._language])
879 else:
880 locale.setlocale(locale.LC_ALL, "")
881 else:
882 locale.setlocale(locale.LC_ALL, (self._language,
883 locale.getpreferredencoding()))
884 return self._language
885 else:
886 locale.setlocale(locale.LC_ALL, "")
887 return locale.getdefaultlocale()[0]
888
889 def log(self):
890 """Log the configuration by printing the values"""
891 print " pilot ID:", self._pilotID
892 print " rememberPassword:", self._rememberPassword
893
894 print " language:", self._language
895
896 print " hideMinimizedWindow:", self._hideMinimizedWindow
897 print " quitOnClose:", self._quitOnClose
898
899 print " onlineGateSystem:", self._onlineGateSystem
900 print " onlineACARS:", self._onlineACARS
901
902 print " flareTimeFromFS:", self._flareTimeFromFS
903 print " syncFSTime:", self._syncFSTime
904 print " usingFS2Crew:", self._usingFS2Crew
905
906 print " iasSmoothingLength:", self._iasSmoothingLength
907 print " vsSmoothingLength:", self._vsSmoothingLength
908
909 print " pirepDirectory:", self._pirepDirectory
910 print " pirepAutoSave:", self._pirepAutoSave
911
912 print " defaultMSFS:", self._defaultMSFS
913
914 print " enableSounds:", self._enableSounds
915
916 print " pilotControlsSounds:", self._pilotControlsSounds
917 print " pilotHotkey:", str(self._pilotHotkey)
918
919 print " enableApproachCallouts:", self._enableApproachCallouts
920 print " speedbrakeAtTD:", self._speedbrakeAtTD
921
922 print " enableChecklists:", self._enableChecklists
923 print " checklistHotkey:", str(self._checklistHotkey)
924
925 print " autoUpdate:", self._autoUpdate
926 print " updateURL:", self._updateURL
927
928 print " messageTypeLevels:"
929 for (type, level) in self._messageTypeLevels.iteritems():
930 print " %s: %s" % (const.messageType2string(type),
931 const.messageLevel2string(level))
932
933 print " checklists:"
934 for (type, checklist) in self._checklists.iteritems():
935 print " %s:" % (const.icaoCodes[type],)
936 for path in checklist:
937 print " " + path
938
939 print " approachCallouts:"
940 for (type, approachCallouts) in self._approachCallouts.iteritems():
941 print " %s:" % (const.icaoCodes[type],)
942 for (altitude, path) in approachCallouts:
943 print " %d: %s" % (altitude, path)
944
945#-------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.