source: src/mlx/gui/prefs.py@ 547:df60c0ef6637

Last change on this file since 547:df60c0ef6637 was 392:ddb312cb8a3d, checked in by István Váradi <ivaradi@…>, 12 years ago

Implemented the configuration of automatic PIREP saving (re #163)

File size: 35.0 KB
Line 
1
2from common import *
3
4from mlx.i18n import xstr
5import mlx.const as const
6import mlx.config as config
7
8import urlparse
9
10#------------------------------------------------------------------------------
11
12## @package mlx.gui.prefs
13#
14# The preferences dialog.
15#
16# This module implements the preferences dialog, allowing the editing of the
17# configuration of the program. The preferences are grouped into tabs, each
18# containing the necessary controls to set the various options.
19
20#------------------------------------------------------------------------------
21
22class Hotkey(gtk.HBox):
23 """A widget to handle a hotkey."""
24
25 # Constant to denote that the status of the Ctrl modifier is changed
26 CHANGED_CTRL = 1
27
28 # Constant to denote that the status of the Shift modifier is changed
29 CHANGED_SHIFT = 2
30
31 # Constant to denote that the value of the key is changed
32 CHANGED_KEY = 3
33
34 def __init__(self, labelText, tooltips):
35 """Construct the hotkey widget.
36
37 labelText is the text for the label before the hotkey.
38
39 The tooltips parameter is an array of the tooltips for:
40 - the hotkey combo box,
41 - the control check box, and
42 - the shift check box."""
43 super(Hotkey, self).__init__()
44
45 label = gtk.Label(labelText)
46 label.set_use_underline(True)
47 labelAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
48 xscale = 0.0, yscale = 0.0)
49 labelAlignment.set_padding(padding_top = 0, padding_bottom = 0,
50 padding_left = 0, padding_right = 4)
51 labelAlignment.add(label)
52 self.pack_start(labelAlignment, False, False, 0)
53
54 self._ctrl = gtk.CheckButton("Ctrl")
55 self._ctrl.set_tooltip_text(tooltips[1])
56 self._ctrl.connect("toggled", self._ctrlToggled)
57 self.pack_start(self._ctrl, False, False, 4)
58
59 self._shift = gtk.CheckButton("Shift")
60 self._shift.set_tooltip_text(tooltips[2])
61 self._shift.connect("toggled", self._shiftToggled)
62 self.pack_start(self._shift, False, False, 4)
63
64 self._hotkeyModel = gtk.ListStore(str)
65 for keyCode in range(ord("0"), ord("9")+1) + range(ord("A"), ord("Z")+1):
66 self._hotkeyModel.append([chr(keyCode)])
67
68 self._hotkey = gtk.ComboBox(model = self._hotkeyModel)
69 cell = gtk.CellRendererText()
70 self._hotkey.pack_start(cell, True)
71 self._hotkey.add_attribute(cell, 'text', 0)
72 self._hotkey.set_tooltip_text(tooltips[0])
73 self._hotkey.connect("changed", self._keyChanged)
74 self.pack_start(self._hotkey, False, False, 4)
75
76 label.set_mnemonic_widget(self._hotkey)
77
78 self._setting = False
79
80 @property
81 def ctrl(self):
82 """Get whether the Ctrl modifier is selected."""
83 return self._ctrl.get_active()
84
85 @ctrl.setter
86 def ctrl(self, ctrl):
87 """Get whether the Ctrl modifier is selected."""
88 self._setting = True
89 self._ctrl.set_active(ctrl)
90 self._setting = False
91
92 @property
93 def shift(self):
94 """Get whether the Shift modifier is selected."""
95 return self._shift.get_active()
96
97 @shift.setter
98 def shift(self, shift):
99 """Get whether the Shift modifier is selected."""
100 self._setting = True
101 self._shift.set_active(shift)
102 self._setting = False
103
104 @property
105 def key(self):
106 """Get the value of the key."""
107 return self._hotkeyModel.get_value(self._hotkey.get_active_iter(), 0)
108
109 @key.setter
110 def key(self, key):
111 """Set the value of the key."""
112 self._setting = True
113
114 hotkeyModel = self._hotkeyModel
115 iter = hotkeyModel.get_iter_first()
116 while iter is not None and \
117 hotkeyModel.get_value(iter, 0)!=key:
118 iter = hotkeyModel.iter_next(iter)
119
120 if iter is None:
121 iter = hotkeyModel.get_iter_first()
122
123 self._hotkey.set_active_iter(iter)
124
125 self._setting = False
126
127 def set(self, hotkey):
128 """Set the hotkey widget from the given hotkey."""
129 self.ctrl = hotkey.ctrl
130 self.shift = hotkey.shift
131 self.key = hotkey.key
132
133 def get(self):
134 """Get a hotkey corresponding to the settings in the widghet."""
135
136 key = self._hotkeyModel.get_value(self._hotkey.get_active_iter(), 0)
137
138 return config.Hotkey(ctrl = self.ctrl, shift = self.shift,
139 key = self.key)
140
141 def _ctrlToggled(self, checkButton):
142 """Called when the status of the Ctrl modifier has changed."""
143 if not self._setting:
144 self.emit("hotkey-changed", Hotkey.CHANGED_CTRL)
145
146 def _shiftToggled(self, checkButton):
147 """Called when the status of the Shift modifier has changed."""
148 if not self._setting:
149 self.emit("hotkey-changed", Hotkey.CHANGED_SHIFT)
150
151 def _keyChanged(self, comboBox):
152 """Called when the value of the key has changed."""
153 if not self._setting:
154 self.emit("hotkey-changed", Hotkey.CHANGED_KEY)
155
156 def __eq__(self, other):
157 """Determine if the two hotkeys are equal."""
158 return self.ctrl==other.ctrl and self.shift==other.shift and \
159 self.key==other.key
160
161#------------------------------------------------------------------------------
162
163gobject.signal_new("hotkey-changed", Hotkey, gobject.SIGNAL_RUN_FIRST,
164 None, (int,))
165
166#------------------------------------------------------------------------------
167
168class Preferences(gtk.Dialog):
169 """The preferences dialog."""
170 def __init__(self, gui):
171 """Construct the dialog."""
172 super(Preferences, self).__init__(WINDOW_TITLE_BASE + " " +
173 xstr("prefs_title"),
174 gui.mainWindow,
175 DIALOG_MODAL)
176
177 self.add_button(xstr("button_cancel"), RESPONSETYPE_REJECT)
178 self.add_button(xstr("button_ok"), RESPONSETYPE_ACCEPT)
179 self.set_resizable(False)
180
181 self._gui = gui
182 self._settingFromConfig = False
183
184 contentArea = self.get_content_area()
185
186 notebook = gtk.Notebook()
187 contentArea.pack_start(notebook, True, True, 4)
188
189 general = self._buildGeneral()
190 label = gtk.Label(xstr("prefs_tab_general"))
191 label.set_use_underline(True)
192 label.set_tooltip_text(xstr("prefs_tab_general_tooltip"))
193 notebook.append_page(general, label)
194
195 messages = self._buildMessages()
196 label = gtk.Label(xstr("prefs_tab_messages"))
197 label.set_use_underline(True)
198 label.set_tooltip_text(xstr("prefs_tab_message_tooltip"))
199 notebook.append_page(messages, label)
200
201 sounds = self._buildSounds()
202 label = gtk.Label(xstr("prefs_tab_sounds"))
203 label.set_use_underline(True)
204 label.set_tooltip_text(xstr("prefs_tab_sounds_tooltip"))
205 notebook.append_page(sounds, label)
206
207 advanced = self._buildAdvanced()
208 label = gtk.Label(xstr("prefs_tab_advanced"))
209 label.set_use_underline(True)
210 label.set_tooltip_text(xstr("prefs_tab_advanced_tooltip"))
211 notebook.append_page(advanced, label)
212
213 def run(self, config):
214 """Run the preferences dialog.
215
216 The dialog will be set up from data in the given configuration. If the
217 changes are accepted by the user, the configuration is updated and saved."""
218 self._fromConfig(config)
219
220 self.show_all()
221 response = super(Preferences, self).run()
222 self.hide()
223
224 if response==RESPONSETYPE_ACCEPT:
225 self._toConfig(config)
226 config.save()
227
228 def _fromConfig(self, config):
229 """Setup the dialog from the given configuration."""
230 self._settingFromConfig = True
231
232 self._setLanguage(config.language)
233 self._hideMinimizedWindow.set_active(config.hideMinimizedWindow)
234 self._quitOnClose.set_active(config.quitOnClose)
235 self._onlineGateSystem.set_active(config.onlineGateSystem)
236 self._onlineACARS.set_active(config.onlineACARS)
237 self._flareTimeFromFS.set_active(config.flareTimeFromFS)
238 self._syncFSTime.set_active(config.syncFSTime)
239 self._usingFS2Crew.set_active(config.usingFS2Crew)
240
241 self._setSmoothing(self._iasSmoothingEnabled, self._iasSmoothingLength,
242 config.iasSmoothingLength)
243 self._setSmoothing(self._vsSmoothingEnabled, self._vsSmoothingLength,
244 config.vsSmoothingLength)
245
246 pirepDirectory = config.pirepDirectory
247 self._pirepDirectory.set_text("" if pirepDirectory is None
248 else pirepDirectory)
249 self._pirepAutoSave.set_active(config.pirepAutoSave)
250 if not pirepDirectory:
251 self._pirepAutoSave.set_sensitive(False)
252
253 for messageType in const.messageTypes:
254 level = config.getMessageTypeLevel(messageType)
255 button = self._msgFSCheckButtons[messageType]
256 button.set_active(level == const.MESSAGELEVEL_FS or
257 level == const.MESSAGELEVEL_BOTH)
258 button = self._msgSoundCheckButtons[messageType]
259 button.set_active(level == const.MESSAGELEVEL_SOUND or
260 level == const.MESSAGELEVEL_BOTH)
261
262 self._enableSounds.set_active(config.enableSounds)
263 self._pilotControlsSounds.set_active(config.pilotControlsSounds)
264 self._pilotHotkey.set(config.pilotHotkey)
265 self._enableApproachCallouts.set_active(config.enableApproachCallouts)
266 self._speedbrakeAtTD.set_active(config.speedbrakeAtTD)
267
268 self._enableChecklists.set_active(config.enableChecklists)
269 self._checklistHotkey.set(config.checklistHotkey)
270
271 self._autoUpdate.set_active(config.autoUpdate)
272 if not config.autoUpdate:
273 self._warnedAutoUpdate = True
274
275 self._updateURL.set_text(config.updateURL)
276
277 self._settingFromConfig = False
278
279 def _toConfig(self, config):
280 """Setup the given config from the settings in the dialog."""
281 config.language = self._getLanguage()
282 config.hideMinimizedWindow = self._hideMinimizedWindow.get_active()
283 config.quitOnClose = self._quitOnClose.get_active()
284 config.onlineGateSystem = self._onlineGateSystem.get_active()
285 config.onlineACARS = self._onlineACARS.get_active()
286 config.flareTimeFromFS = self._flareTimeFromFS.get_active()
287 config.syncFSTime = self._syncFSTime.get_active()
288 config.usingFS2Crew = self._usingFS2Crew.get_active()
289 config.iasSmoothingLength = self._getSmoothing(self._iasSmoothingEnabled,
290 self._iasSmoothingLength)
291 config.vsSmoothingLength = self._getSmoothing(self._vsSmoothingEnabled,
292 self._vsSmoothingLength)
293 config.pirepDirectory = text2unicode(self._pirepDirectory.get_text())
294 config.pirepAutoSave = self._pirepAutoSave.get_active()
295
296 for messageType in const.messageTypes:
297 fsButtonActive = self._msgFSCheckButtons[messageType].get_active()
298 soundButtonActive = self._msgSoundCheckButtons[messageType].get_active()
299 if fsButtonActive:
300 level = const.MESSAGELEVEL_BOTH if soundButtonActive \
301 else const.MESSAGELEVEL_FS
302 elif soundButtonActive:
303 level = const.MESSAGELEVEL_SOUND
304 else:
305 level = const.MESSAGELEVEL_NONE
306 config.setMessageTypeLevel(messageType, level)
307
308 config.enableSounds = self._enableSounds.get_active()
309 config.pilotControlsSounds = self._pilotControlsSounds.get_active()
310 config.pilotHotkey = self._pilotHotkey.get()
311 config.enableApproachCallouts = self._enableApproachCallouts.get_active()
312 config.speedbrakeAtTD = self._speedbrakeAtTD.get_active()
313
314 config.enableChecklists = self._enableChecklists.get_active()
315 config.checklistHotkey = self._checklistHotkey.get()
316
317 config.autoUpdate = self._autoUpdate.get_active()
318 config.updateURL = self._updateURL.get_text()
319
320 def _buildGeneral(self):
321 """Build the page for the general settings."""
322 mainAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
323 xscale = 1.0, yscale = 0.0)
324 mainAlignment.set_padding(padding_top = 0, padding_bottom = 8,
325 padding_left = 4, padding_right = 4)
326 mainBox = gtk.VBox()
327 mainAlignment.add(mainBox)
328
329 guiBox = self._createFrame(mainBox, xstr("prefs_frame_gui"))
330
331 languageBox = gtk.HBox()
332 guiBox.pack_start(languageBox, False, False, 4)
333
334 label = gtk.Label(xstr("prefs_language"))
335 label.set_use_underline(True)
336
337 languageBox.pack_start(label, False, False, 4)
338
339 self._languageList = gtk.ListStore(str, str)
340 for language in const.languages:
341 self._languageList.append([xstr("prefs_lang_" + language),
342 language])
343
344 self._languageComboBox = languageComboBox = \
345 gtk.ComboBox(model = self._languageList)
346 cell = gtk.CellRendererText()
347 languageComboBox.pack_start(cell, True)
348 languageComboBox.add_attribute(cell, 'text', 0)
349 languageComboBox.set_tooltip_text(xstr("prefs_language_tooltip"))
350 languageComboBox.connect("changed", self._languageChanged)
351 languageBox.pack_start(languageComboBox, False, False, 4)
352
353 label.set_mnemonic_widget(languageComboBox)
354
355 self._changingLanguage = False
356 self._warnedRestartNeeded = False
357
358 self._hideMinimizedWindow = gtk.CheckButton(xstr("prefs_hideMinimizedWindow"))
359 self._hideMinimizedWindow.set_use_underline(True)
360 self._hideMinimizedWindow.set_tooltip_text(xstr("prefs_hideMinimizedWindow_tooltip"))
361 guiBox.pack_start(self._hideMinimizedWindow, False, False, 4)
362
363 self._quitOnClose = gtk.CheckButton(xstr("prefs_quitOnClose"))
364 self._quitOnClose.set_use_underline(True)
365 self._quitOnClose.set_tooltip_text(xstr("prefs_quitOnClose_tooltip"))
366 guiBox.pack_start(self._quitOnClose, False, False, 4)
367
368 onlineBox = self._createFrame(mainBox, xstr("prefs_frame_online"))
369
370 self._onlineGateSystem = gtk.CheckButton(xstr("prefs_onlineGateSystem"))
371 self._onlineGateSystem.set_use_underline(True)
372 self._onlineGateSystem.set_tooltip_text(xstr("prefs_onlineGateSystem_tooltip"))
373 onlineBox.pack_start(self._onlineGateSystem, False, False, 4)
374
375 self._onlineACARS = gtk.CheckButton(xstr("prefs_onlineACARS"))
376 self._onlineACARS.set_use_underline(True)
377 self._onlineACARS.set_tooltip_text(xstr("prefs_onlineACARS_tooltip"))
378 onlineBox.pack_start(self._onlineACARS, False, False, 4)
379
380 simulatorBox = self._createFrame(mainBox, xstr("prefs_frame_simulator"))
381
382 self._flareTimeFromFS = gtk.CheckButton(xstr("prefs_flaretimeFromFS"))
383 self._flareTimeFromFS.set_use_underline(True)
384 self._flareTimeFromFS.set_tooltip_text(xstr("prefs_flaretimeFromFS_tooltip"))
385 simulatorBox.pack_start(self._flareTimeFromFS, False, False, 4)
386
387 self._syncFSTime = gtk.CheckButton(xstr("prefs_syncFSTime"))
388 self._syncFSTime.set_use_underline(True)
389 self._syncFSTime.set_tooltip_text(xstr("prefs_syncFSTime_tooltip"))
390 simulatorBox.pack_start(self._syncFSTime, False, False, 4)
391
392 self._usingFS2Crew = gtk.CheckButton(xstr("prefs_usingFS2Crew"))
393 self._usingFS2Crew.set_use_underline(True)
394 self._usingFS2Crew.set_tooltip_text(xstr("prefs_usingFS2Crew_tooltip"))
395 simulatorBox.pack_start(self._usingFS2Crew, False, False, 4)
396
397 (iasSmoothingBox, self._iasSmoothingEnabled,
398 self._iasSmoothingLength) = \
399 self._createSmoothingBox(xstr("prefs_iasSmoothingEnabled"),
400 xstr("prefs_iasSmoothingEnabledTooltip"))
401 simulatorBox.pack_start(iasSmoothingBox, False, False, 4)
402
403 (vsSmoothingBox, self._vsSmoothingEnabled,
404 self._vsSmoothingLength) = \
405 self._createSmoothingBox(xstr("prefs_vsSmoothingEnabled"),
406 xstr("prefs_vsSmoothingEnabledTooltip"))
407 simulatorBox.pack_start(vsSmoothingBox, False, False, 4)
408
409 pirepBox = gtk.HBox()
410 mainBox.pack_start(pirepBox, False, False, 8)
411
412 label = gtk.Label(xstr("prefs_pirepDirectory"))
413 label.set_use_underline(True)
414 pirepBox.pack_start(label, False, False, 4)
415
416 self._pirepDirectory = gtk.Entry()
417 self._pirepDirectory.set_tooltip_text(xstr("prefs_pirepDirectory_tooltip"))
418 self._pirepDirectory.connect("changed", self._pirepDirectoryChanged)
419 label.set_mnemonic_widget(self._pirepDirectory)
420 pirepBox.pack_start(self._pirepDirectory, True, True, 4)
421
422 self._pirepDirectoryButton = gtk.Button(xstr("button_browse"))
423 self._pirepDirectoryButton.connect("clicked",
424 self._pirepDirectoryButtonClicked)
425 pirepBox.pack_start(self._pirepDirectoryButton, False, False, 4)
426
427 self._pirepAutoSave = gtk.CheckButton(xstr("prefs_pirepAutoSave"))
428 self._pirepAutoSave.set_use_underline(True)
429 self._pirepAutoSave.set_tooltip_text(xstr("prefs_pirepAutoSave_tooltip"))
430 mainBox.pack_start(self._pirepAutoSave, False, False, 0)
431
432 return mainAlignment
433
434 def _createFrame(self, mainBox, label):
435 """Create a frame with an inner alignment and VBox.
436
437 Return the vbox."""
438 frame = gtk.Frame(label = label)
439 mainBox.pack_start(frame, False, False, 4)
440 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
441 xscale = 1.0, yscale = 0.0)
442 alignment.set_padding(padding_top = 4, padding_bottom = 0,
443 padding_left = 0, padding_right = 0)
444 frame.add(alignment)
445 vbox = gtk.VBox()
446 alignment.add(vbox)
447
448 return vbox
449
450 def _createSmoothingBox(self, checkBoxLabel, checkBoxTooltip,
451 maxSeconds = 10):
452 """Create a HBox that contains entry fields for smoothing some value."""
453 smoothingBox = gtk.HBox()
454
455 smoothingEnabled = gtk.CheckButton(checkBoxLabel)
456 smoothingEnabled.set_use_underline(True)
457 smoothingEnabled.set_tooltip_text(checkBoxTooltip)
458
459 smoothingBox.pack_start(smoothingEnabled, False, False, 0)
460
461 smoothingLength = gtk.SpinButton()
462 smoothingLength.set_numeric(True)
463 smoothingLength.set_range(2, maxSeconds)
464 smoothingLength.set_increments(1, 1)
465 smoothingLength.set_alignment(1.0)
466 smoothingLength.set_width_chars(2)
467
468 smoothingBox.pack_start(smoothingLength, False, False, 0)
469
470 smoothingBox.pack_start(gtk.Label(xstr("prefs_smoothing_seconds")),
471 False, False, 4)
472
473 smoothingEnabled.connect("toggled", self._smoothingToggled,
474 smoothingLength)
475 smoothingLength.set_sensitive(False)
476
477 return (smoothingBox, smoothingEnabled, smoothingLength)
478
479 def _setLanguage(self, language):
480 """Set the language to the given one."""
481 iter = self._languageList.get_iter_first()
482 while iter is not None:
483 (lang,) = self._languageList.get(iter, 1)
484 if (not language and lang=="$system") or \
485 lang==language:
486 self._changingLanguage = True
487 self._languageComboBox.set_active_iter(iter)
488 self._changingLanguage = False
489 break
490 else:
491 iter = self._languageList.iter_next(iter)
492
493 def _getLanguage(self):
494 """Get the language selected by the user."""
495 iter = self._languageComboBox.get_active_iter()
496 (lang,) = self._languageList.get(iter, 1)
497 return "" if lang=="$system" else lang
498
499 def _languageChanged(self, comboBox):
500 """Called when the language has changed."""
501 if not self._changingLanguage and not self._warnedRestartNeeded:
502 dialog = gtk.MessageDialog(parent = self,
503 type = MESSAGETYPE_INFO,
504 message_format = xstr("prefs_restart"))
505 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
506 dialog.set_title(self.get_title())
507 dialog.format_secondary_markup(xstr("prefs_language_restart_sec"))
508 dialog.run()
509 dialog.hide()
510 self._warnedRestartNeeded = True
511
512 def _smoothingToggled(self, smoothingEnabled, smoothingLength):
513 """Called when a smoothing enabled check box is toggled."""
514 sensitive = smoothingEnabled.get_active()
515 smoothingLength.set_sensitive(sensitive)
516 if sensitive:
517 smoothingLength.grab_focus()
518
519 def _setSmoothing(self, smoothingEnabled, smoothingLength, smoothing):
520 """Set the smoothing controls from the given value.
521
522 If the value is less than 2, smoothing is disabled. The smoothing
523 length is the absolute value of the value."""
524 smoothingEnabled.set_active(smoothing>=2)
525 smoothingLength.set_value(abs(smoothing))
526
527 def _getSmoothing(self, smoothingEnabled, smoothingLength):
528 """Get the smoothing value from the given controls.
529
530 The returned value is the value of smoothingLength multiplied by -1, if
531 smoothing is disabled."""
532 value = smoothingLength.get_value_as_int()
533 if not smoothingEnabled.get_active():
534 value *= -1
535 return value
536
537 def _pirepDirectoryButtonClicked(self, button):
538 """Called when the PIREP directory button is clicked."""
539 dialog = gtk.FileChooserDialog(title = WINDOW_TITLE_BASE + " - " +
540 xstr("prefs_pirepDirectory_browser_title"),
541 action = FILE_CHOOSER_ACTION_SELECT_FOLDER,
542 buttons = (gtk.STOCK_CANCEL, RESPONSETYPE_CANCEL,
543 gtk.STOCK_OK, RESPONSETYPE_OK),
544 parent = self)
545 dialog.set_modal(True)
546 dialog.set_transient_for(self)
547
548 directory = self._pirepDirectory.get_text()
549 if directory:
550 dialog.select_filename(directory)
551
552 result = dialog.run()
553 dialog.hide()
554
555 if result==RESPONSETYPE_OK:
556 self._pirepDirectory.set_text(text2unicode(dialog.get_filename()))
557
558 def _pirepDirectoryChanged(self, entry):
559 """Called when the PIREP directory is changed."""
560 if self._pirepDirectory.get_text():
561 self._pirepAutoSave.set_sensitive(True)
562 else:
563 self._pirepAutoSave.set_active(False)
564 self._pirepAutoSave.set_sensitive(False)
565
566 def _buildMessages(self):
567 """Build the page for the message settings."""
568
569 mainAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
570 xscale = 0.0, yscale = 0.0)
571 mainAlignment.set_padding(padding_top = 16, padding_bottom = 8,
572 padding_left = 4, padding_right = 4)
573 mainBox = gtk.VBox()
574 mainAlignment.add(mainBox)
575
576 table = gtk.Table(len(const.messageTypes) + 1, 3)
577 table.set_row_spacings(8)
578 table.set_col_spacings(32)
579 table.set_homogeneous(False)
580 mainBox.pack_start(table, False, False, 4)
581
582 label = gtk.Label(xstr("prefs_msgs_fs"))
583 label.set_justify(JUSTIFY_CENTER)
584 label.set_alignment(0.5, 1.0)
585 table.attach(label, 1, 2, 0, 1)
586
587 label = gtk.Label(xstr("prefs_msgs_sound"))
588 label.set_justify(JUSTIFY_CENTER)
589 label.set_alignment(0.5, 1.0)
590 table.attach(label, 2, 3, 0, 1)
591
592 self._msgFSCheckButtons = {}
593 self._msgSoundCheckButtons = {}
594 row = 1
595 for messageType in const.messageTypes:
596 messageTypeStr = const.messageType2string(messageType)
597 label = gtk.Label(xstr("prefs_msgs_type_" + messageTypeStr))
598 label.set_justify(JUSTIFY_CENTER)
599 label.set_use_underline(True)
600 label.set_alignment(0.5, 0.5)
601 table.attach(label, 0, 1, row, row+1)
602
603 fsCheckButton = gtk.CheckButton()
604 alignment = gtk.Alignment(xscale = 0.0, yscale = 0.0,
605 xalign = 0.5, yalign = 0.5)
606 alignment.add(fsCheckButton)
607 table.attach(alignment, 1, 2, row, row+1)
608 self._msgFSCheckButtons[messageType] = fsCheckButton
609
610 soundCheckButton = gtk.CheckButton()
611 alignment = gtk.Alignment(xscale = 0.0, yscale = 0.0,
612 xalign = 0.5, yalign = 0.5)
613 alignment.add(soundCheckButton)
614 table.attach(alignment, 2, 3, row, row+1)
615 self._msgSoundCheckButtons[messageType] = soundCheckButton
616
617 mnemonicWidget = gtk.Label("")
618 table.attach(mnemonicWidget, 3, 4, row, row+1)
619 label.set_mnemonic_widget(mnemonicWidget)
620 mnemonicWidget.connect("mnemonic-activate",
621 self._msgLabelActivated,
622 messageType)
623
624 row += 1
625
626 return mainAlignment
627
628 def _msgLabelActivated(self, button, cycle_group, messageType):
629 """Called when the mnemonic of a label is activated.
630
631 It cycles the corresponding options."""
632 fsCheckButton = self._msgFSCheckButtons[messageType]
633 soundCheckButton = self._msgSoundCheckButtons[messageType]
634
635 num = 1 if fsCheckButton.get_active() else 0
636 num += 2 if soundCheckButton.get_active() else 0
637 num += 1
638
639 fsCheckButton.set_active((num&0x01)==0x01)
640 soundCheckButton.set_active((num&0x02)==0x02)
641
642 return True
643
644 def _buildSounds(self):
645 """Build the page for the sounds."""
646 mainAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
647 xscale = 1.0, yscale = 1.0)
648 mainAlignment.set_padding(padding_top = 8, padding_bottom = 8,
649 padding_left = 4, padding_right = 4)
650
651 mainBox = gtk.VBox()
652 mainAlignment.add(mainBox)
653
654 backgroundFrame = gtk.Frame(label = xstr("prefs_sounds_frame_bg"))
655 mainBox.pack_start(backgroundFrame, False, False, 4)
656
657 backgroundAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
658 xscale = 1.0, yscale = 0.0)
659 backgroundAlignment.set_padding(padding_top = 4, padding_bottom = 4,
660 padding_left = 4, padding_right = 4)
661 backgroundFrame.add(backgroundAlignment)
662
663 backgroundBox = gtk.VBox()
664 backgroundAlignment.add(backgroundBox)
665
666 self._enableSounds = gtk.CheckButton(xstr("prefs_sounds_enable"))
667 self._enableSounds.set_use_underline(True)
668 self._enableSounds.set_tooltip_text(xstr("prefs_sounds_enable_tooltip"))
669 self._enableSounds.connect("toggled", self._enableSoundsToggled)
670 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
671 xscale = 1.0, yscale = 0.0)
672 alignment.add(self._enableSounds)
673 backgroundBox.pack_start(alignment, False, False, 4)
674
675 self._pilotControlsSounds = gtk.CheckButton(xstr("prefs_sounds_pilotControls"))
676 self._pilotControlsSounds.set_use_underline(True)
677 self._pilotControlsSounds.set_tooltip_text(xstr("prefs_sounds_pilotControls_tooltip"))
678 self._pilotControlsSounds.connect("toggled", self._pilotControlsSoundsToggled)
679 backgroundBox.pack_start(self._pilotControlsSounds, False, False, 4)
680
681 self._pilotHotkey = Hotkey(xstr("prefs_sounds_pilotHotkey"),
682 [xstr("prefs_sounds_pilotHotkey_tooltip"),
683 xstr("prefs_sounds_pilotHotkeyCtrl_tooltip"),
684 xstr("prefs_sounds_pilotHotkeyShift_tooltip")])
685
686 backgroundBox.pack_start(self._pilotHotkey, False, False, 4)
687
688 self._enableApproachCallouts = gtk.CheckButton(xstr("prefs_sounds_approachCallouts"))
689 self._enableApproachCallouts.set_use_underline(True)
690 self._enableApproachCallouts.set_tooltip_text(xstr("prefs_sounds_approachCallouts_tooltip"))
691 backgroundBox.pack_start(self._enableApproachCallouts, False, False, 4)
692
693 self._speedbrakeAtTD = gtk.CheckButton(xstr("prefs_sounds_speedbrakeAtTD"))
694 self._speedbrakeAtTD.set_use_underline(True)
695 self._speedbrakeAtTD.set_tooltip_text(xstr("prefs_sounds_speedbrakeAtTD_tooltip"))
696 backgroundBox.pack_start(self._speedbrakeAtTD, False, False, 4)
697
698 checklistFrame = gtk.Frame(label = xstr("prefs_sounds_frame_checklists"))
699 mainBox.pack_start(checklistFrame, False, False, 4)
700
701 checklistAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
702 xscale = 1.0, yscale = 0.0)
703 checklistAlignment.set_padding(padding_top = 4, padding_bottom = 4,
704 padding_left = 4, padding_right = 4)
705 checklistFrame.add(checklistAlignment)
706
707 checklistBox = gtk.VBox()
708 checklistAlignment.add(checklistBox)
709
710 self._enableChecklists = gtk.CheckButton(xstr("prefs_sounds_enableChecklists"))
711 self._enableChecklists.set_use_underline(True)
712 self._enableChecklists.set_tooltip_text(xstr("prefs_sounds_enableChecklists_tooltip"))
713 self._enableChecklists.connect("toggled", self._enableChecklistsToggled)
714 checklistBox.pack_start(self._enableChecklists, False, False, 4)
715
716 self._checklistHotkey = Hotkey(xstr("prefs_sounds_checklistHotkey"),
717 [xstr("prefs_sounds_checklistHotkey_tooltip"),
718 xstr("prefs_sounds_checklistHotkeyCtrl_tooltip"),
719 xstr("prefs_sounds_checklistHotkeyShift_tooltip")])
720
721 checklistBox.pack_start(self._checklistHotkey, False, False, 4)
722
723 self._enableSoundsToggled(self._enableSounds)
724 self._enableChecklistsToggled(self._enableChecklists)
725
726 self._pilotHotkey.connect("hotkey-changed", self._reconcileHotkeys,
727 self._checklistHotkey)
728 self._checklistHotkey.connect("hotkey-changed", self._reconcileHotkeys,
729 self._pilotHotkey)
730
731 return mainAlignment
732
733 def _enableSoundsToggled(self, button):
734 """Called when the enable sounds button is toggled."""
735 active = button.get_active()
736 self._pilotControlsSounds.set_sensitive(active)
737 self._pilotControlsSoundsToggled(self._pilotControlsSounds)
738 self._enableApproachCallouts.set_sensitive(active)
739 self._speedbrakeAtTD.set_sensitive(active)
740
741 def _pilotControlsSoundsToggled(self, button):
742 """Called when the enable sounds button is toggled."""
743 active = button.get_active() and self._enableSounds.get_active()
744 self._pilotHotkey.set_sensitive(active)
745 if active and self._checklistHotkey.get_sensitive():
746 self._reconcileHotkeys(self._checklistHotkey, Hotkey.CHANGED_SHIFT,
747 self._pilotHotkey)
748
749 def _enableChecklistsToggled(self, button):
750 """Called when the enable checklists button is toggled."""
751 active = button.get_active()
752 self._checklistHotkey.set_sensitive(active)
753 if active and self._pilotHotkey.get_sensitive():
754 self._reconcileHotkeys(self._pilotHotkey, Hotkey.CHANGED_SHIFT,
755 self._checklistHotkey)
756
757 def _reconcileHotkeys(self, changedHotkey, what, otherHotkey):
758 """Reconcile the given hotkeys so that they are different.
759
760 changedHotkey is the hotkey that has changed. what is one of the
761 Hotkey.CHANGED_XXX constants denoting what has changed. otherHotkey is
762 the other hotkey that must be reconciled.
763
764 If the other hotkey is not sensitive or is not equal to the changed
765 one, nothing happens.
766
767 Otherwise, if the status of the Ctrl modifier has changed, the status
768 of the Ctrl modifier on the other hotkey will be negated. Similarly, if
769 the Shift modifier has changed. If the key has changed, the Shift
770 modifier is negated in the other hotkey."""
771 if otherHotkey.get_sensitive() and changedHotkey==otherHotkey:
772 if what==Hotkey.CHANGED_CTRL:
773 otherHotkey.ctrl = not changedHotkey.ctrl
774 elif what==Hotkey.CHANGED_SHIFT or what==Hotkey.CHANGED_KEY:
775 otherHotkey.shift = not changedHotkey.shift
776
777 def _buildAdvanced(self):
778 """Build the page for the advanced settings."""
779
780 mainAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
781 xscale = 1.0, yscale = 0.0)
782 mainAlignment.set_padding(padding_top = 16, padding_bottom = 8,
783 padding_left = 4, padding_right = 4)
784 mainBox = gtk.VBox()
785 mainAlignment.add(mainBox)
786
787 self._autoUpdate = gtk.CheckButton(xstr("prefs_update_auto"))
788 mainBox.pack_start(self._autoUpdate, False, False, 4)
789
790 self._autoUpdate.set_use_underline(True)
791 self._autoUpdate.connect("toggled", self._autoUpdateToggled)
792 self._autoUpdate.set_tooltip_text(xstr("prefs_update_auto_tooltip"))
793 self._warnedAutoUpdate = False
794
795 updateURLBox = gtk.HBox()
796 mainBox.pack_start(updateURLBox, False, False, 4)
797 label = gtk.Label(xstr("prefs_update_url"))
798 label.set_use_underline(True)
799 updateURLBox.pack_start(label, False, False, 4)
800
801 self._updateURL = gtk.Entry()
802 label.set_mnemonic_widget(self._updateURL)
803 self._updateURL.set_width_chars(40)
804 self._updateURL.set_tooltip_text(xstr("prefs_update_url_tooltip"))
805 self._updateURL.connect("changed", self._updateURLChanged)
806 updateURLBox.pack_start(self._updateURL, True, True, 4)
807
808 return mainAlignment
809
810 def _setOKButtonSensitivity(self):
811 """Set the sensitive state of the OK button."""
812 sensitive = False
813 try:
814 result = urlparse.urlparse(self._updateURL.get_text())
815 sensitive = result.scheme!="" and (result.netloc + result.path)!=""
816 except:
817 pass
818
819 okButton = self.get_widget_for_response(RESPONSETYPE_ACCEPT)
820 okButton.set_sensitive(sensitive)
821
822 def _autoUpdateToggled(self, button):
823 """Called when the auto update check button is toggled."""
824 if not self._settingFromConfig and not self._warnedAutoUpdate and \
825 not self._autoUpdate.get_active():
826 dialog = gtk.MessageDialog(parent = self,
827 type = MESSAGETYPE_INFO,
828 message_format = xstr("prefs_update_auto_warning"))
829 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
830 dialog.set_title(self.get_title())
831 dialog.run()
832 dialog.hide()
833 self._warnedAutoUpdate = True
834
835 def _updateURLChanged(self, entry):
836 """Called when the update URL is changed."""
837 self._setOKButtonSensitivity()
838
Note: See TracBrowser for help on using the repository browser.