source: src/mlx/config.py@ 721:54d88df2580d

cef
Last change on this file since 721:54d88df2580d was 689:7aa9d7136b41, checked in by István Váradi <ivaradi@…>, 9 years ago

Added configuration items for the SimBrief credentials (re #279)

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