source: src/mlx/gui/common.py@ 812:b912f62025a6

Last change on this file since 812:b912f62025a6 was 790:e69a08004f40, checked in by István Váradi <ivaradi@…>, 8 years ago

Added support for the Boeing 737-200 aircraft type (weight data is still missing, re #302)

File size: 15.8 KB
Line 
1
2from mlx.common import *
3
4import mlx.const as _const
5from mlx.i18n import xstr
6
7from mlx.util import secondaryInstallation
8
9import os
10
11#-----------------------------------------------------------------------------
12
13## @package mlx.gui.common
14#
15# Common definitions and utilities for the GUI
16#
17# The main purpose of this module is to provide common definitions for things
18# that are named differently in Gtk+ 2 and 3. This way the other parts of the
19# GUI have to check the version in use very rarely. The variable \c pygobject
20# tells which version is being used. If it is \c True, Gtk+ 3 is used via the
21# PyGObject interface. Otherwise Gtk+ 2 is used, which is the default on
22# Windows or when the \c FORCE_PYGTK environment variable is set.
23#
24# Besides this there are some common utility classes and functions.
25
26#-----------------------------------------------------------------------------
27
28appIndicator = False
29
30if not pygobject:
31 print "Using PyGTK"
32 pygobject = False
33 import pygtk
34 pygtk.require("2.0")
35 import gtk.gdk as gdk
36 import gtk
37 import pango
38
39 try:
40 import appindicator
41 appIndicator = True
42 except Exception, e:
43 pass
44
45 MESSAGETYPE_ERROR = gtk.MESSAGE_ERROR
46 MESSAGETYPE_QUESTION = gtk.MESSAGE_QUESTION
47 MESSAGETYPE_INFO = gtk.MESSAGE_INFO
48
49 RESPONSETYPE_OK = gtk.RESPONSE_OK
50 RESPONSETYPE_YES = gtk.RESPONSE_YES
51 RESPONSETYPE_NO = gtk.RESPONSE_NO
52 RESPONSETYPE_ACCEPT = gtk.RESPONSE_ACCEPT
53 RESPONSETYPE_REJECT = gtk.RESPONSE_REJECT
54 RESPONSETYPE_CANCEL = gtk.RESPONSE_CANCEL
55
56 ACCEL_VISIBLE = gtk.ACCEL_VISIBLE
57 CONTROL_MASK = gdk.CONTROL_MASK
58 DIALOG_MODAL = gtk.DIALOG_MODAL
59 WRAP_WORD = gtk.WRAP_WORD
60
61 JUSTIFY_CENTER = gtk.JUSTIFY_CENTER
62 JUSTIFY_LEFT = gtk.JUSTIFY_LEFT
63
64 CONTROL_MASK = gdk.CONTROL_MASK
65 SHIFT_MASK = gdk.SHIFT_MASK
66 BUTTON1_MASK = gdk.BUTTON1_MASK
67
68 SCROLL_UP = gdk.SCROLL_UP
69 SCROLL_DOWN = gdk.SCROLL_DOWN
70
71 SPIN_USER_DEFINED = gtk.SPIN_USER_DEFINED
72
73 FILE_CHOOSER_ACTION_SELECT_FOLDER = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER
74 FILE_CHOOSER_ACTION_OPEN = gtk.FILE_CHOOSER_ACTION_OPEN
75 FILE_CHOOSER_ACTION_SAVE = gtk.FILE_CHOOSER_ACTION_SAVE
76
77 SELECTION_MULTIPLE = gtk.SELECTION_MULTIPLE
78
79 SHADOW_IN = gtk.SHADOW_IN
80 SHADOW_NONE = gtk.SHADOW_NONE
81
82 POLICY_AUTOMATIC = gtk.POLICY_AUTOMATIC
83 POLICY_NEVER = gtk.POLICY_NEVER
84 POLICY_ALWAYS = gtk.POLICY_ALWAYS
85
86 WEIGHT_NORMAL = pango.WEIGHT_NORMAL
87 WEIGHT_BOLD = pango.WEIGHT_BOLD
88
89 WINDOW_STATE_ICONIFIED = gdk.WINDOW_STATE_ICONIFIED
90 WINDOW_STATE_WITHDRAWN = gdk.WINDOW_STATE_WITHDRAWN
91
92 SORT_ASCENDING = gtk.SORT_ASCENDING
93 SORT_DESCENDING = gtk.SORT_DESCENDING
94
95 EVENT_BUTTON_PRESS = gdk.BUTTON_PRESS
96
97 TREE_VIEW_COLUMN_FIXED = gtk.TREE_VIEW_COLUMN_FIXED
98
99 FILL = gtk.FILL
100 EXPAND = gtk.EXPAND
101
102 UPDATE_IF_VALID = gtk.UPDATE_IF_VALID
103
104 pixbuf_new_from_file = gdk.pixbuf_new_from_file
105
106 def text2unicode(text):
107 """Convert the given text, returned by a Gtk widget, to Unicode."""
108 return unicode(text)
109
110 def text2str(text):
111 """Convert the given text, returned by xstr to a string."""
112 return str(text)
113
114else: # pygobject
115 from gi.repository import Gdk as gdk
116 from gi.repository import GdkPixbuf as gdkPixbuf
117 from gi.repository import Gtk as gtk
118 from gi.repository import AppIndicator3 as appindicator
119 from gi.repository import Pango as pango
120
121 appIndicator = True
122
123
124 MESSAGETYPE_ERROR = gtk.MessageType.ERROR
125 MESSAGETYPE_QUESTION = gtk.MessageType.QUESTION
126 MESSAGETYPE_INFO = gtk.MessageType.INFO
127 RESPONSETYPE_OK = gtk.ResponseType.OK
128 RESPONSETYPE_YES = gtk.ResponseType.YES
129 RESPONSETYPE_NO = gtk.ResponseType.NO
130 RESPONSETYPE_ACCEPT = gtk.ResponseType.ACCEPT
131 RESPONSETYPE_REJECT = gtk.ResponseType.REJECT
132 RESPONSETYPE_CANCEL = gtk.ResponseType.CANCEL
133 ACCEL_VISIBLE = gtk.AccelFlags.VISIBLE
134 CONTROL_MASK = gdk.ModifierType.CONTROL_MASK
135 DIALOG_MODAL = gtk.DialogFlags.MODAL
136 WRAP_WORD = gtk.WrapMode.WORD
137 JUSTIFY_CENTER = gtk.Justification.CENTER
138 JUSTIFY_LEFT = gtk.Justification.LEFT
139
140 CONTROL_MASK = gdk.ModifierType.CONTROL_MASK
141 SHIFT_MASK = gdk.ModifierType.SHIFT_MASK
142 BUTTON1_MASK = gdk.ModifierType.BUTTON1_MASK
143
144 SCROLL_UP = gdk.ScrollDirection.UP
145 SCROLL_DOWN = gdk.ScrollDirection.DOWN
146
147 SPIN_USER_DEFINED = gtk.SpinType.USER_DEFINED
148
149 FILE_CHOOSER_ACTION_SELECT_FOLDER = gtk.FileChooserAction.SELECT_FOLDER
150 FILE_CHOOSER_ACTION_OPEN = gtk.FileChooserAction.OPEN
151 FILE_CHOOSER_ACTION_SAVE = gtk.FileChooserAction.SAVE
152
153 SELECTION_MULTIPLE = gtk.SelectionMode.MULTIPLE
154
155 SHADOW_IN = gtk.ShadowType.IN
156 SHADOW_NONE = gtk.ShadowType.NONE
157
158 POLICY_AUTOMATIC = gtk.PolicyType.AUTOMATIC
159 POLICY_NEVER = gtk.PolicyType.NEVER
160 POLICY_ALWAYS = gtk.PolicyType.ALWAYS
161
162 WEIGHT_NORMAL = pango.Weight.NORMAL
163 WEIGHT_BOLD = pango.Weight.BOLD
164
165 WINDOW_STATE_ICONIFIED = gdk.WindowState.ICONIFIED
166 WINDOW_STATE_WITHDRAWN = gdk.WindowState.WITHDRAWN
167
168 SORT_ASCENDING = gtk.SortType.ASCENDING
169 SORT_DESCENDING = gtk.SortType.DESCENDING
170
171 EVENT_BUTTON_PRESS = gdk.EventType.BUTTON_PRESS
172
173 TREE_VIEW_COLUMN_FIXED = gtk.TreeViewColumnSizing.FIXED
174
175 FILL = gtk.AttachOptions.FILL
176 EXPAND = gtk.AttachOptions.EXPAND
177
178 UPDATE_IF_VALID = gtk.SpinButtonUpdatePolicy.IF_VALID
179
180 pixbuf_new_from_file = gdkPixbuf.Pixbuf.new_from_file
181
182 import codecs
183 _utf8Decoder = codecs.getdecoder("utf-8")
184
185 def text2unicode(str):
186 """Convert the given text, returned by a Gtk widget, to Unicode."""
187 return _utf8Decoder(str)[0]
188
189 def text2str(text):
190 """Convert the given text, returned by xstr to a string."""
191 return _utf8Decoder(text)[0]
192
193import cairo
194
195#------------------------------------------------------------------------------
196
197class FlightStatusHandler(object):
198 """Base class for objects that handle the flight status in some way."""
199 def __init__(self):
200 self._stage = None
201 self._rating = 100
202 self._noGoReason = None
203
204 def resetFlightStatus(self):
205 """Reset the flight status."""
206 self._stage = None
207 self._rating = 100
208 self._noGoReason = None
209 self._updateFlightStatus()
210
211 def setStage(self, stage):
212 """Set the stage of the flight."""
213 if stage!=self._stage:
214 self._stage = stage
215 self._updateFlightStatus()
216
217 def setRating(self, rating):
218 """Set the rating to the given value."""
219 if rating!=self._rating:
220 self._rating = rating
221 if self._noGoReason is None:
222 self._updateFlightStatus()
223
224 def setNoGo(self, reason):
225 """Set a No-Go condition with the given reason."""
226 if self._noGoReason is None:
227 self._noGoReason = reason
228 self._updateFlightStatus()
229
230#------------------------------------------------------------------------------
231
232class IntegerEntry(gtk.Entry):
233 """An entry that allows only either an empty value, or an integer."""
234 def __init__(self, defaultValue = None):
235 """Construct the entry."""
236 gtk.Entry.__init__(self)
237
238 self.set_alignment(1.0)
239
240 self._defaultValue = defaultValue
241 self._currentInteger = defaultValue
242 self._selfSetting = False
243 self._set_text()
244
245 self.connect("changed", self._handle_changed)
246
247 def get_int(self):
248 """Get the integer."""
249 return self._currentInteger
250
251 def reset(self):
252 """Reset the integer."""
253 self.set_int(None)
254
255 def set_int(self, value):
256 """Set the integer."""
257 if value!=self._currentInteger:
258 self._currentInteger = value
259 self.emit("integer-changed", self._currentInteger)
260 self._set_text()
261
262 def _handle_changed(self, widget):
263 """Handle the changed signal."""
264 if self._selfSetting:
265 return
266 text = self.get_text()
267 if text=="":
268 self.set_int(self._defaultValue)
269 else:
270 try:
271 self.set_int(int(text))
272 except:
273 self._set_text()
274
275 def _set_text(self):
276 """Set the text value from the current integer."""
277 self._selfSetting = True
278 self.set_text("" if self._currentInteger is None
279 else str(self._currentInteger))
280 self._selfSetting = False
281
282#------------------------------------------------------------------------------
283
284class CredentialsDialog(gtk.Dialog):
285 """A dialog window to ask for a user name and a password."""
286 def __init__(self, gui, userName, password,
287 titleLabel, cancelButtonLabel, okButtonLabel,
288 userNameLabel, userNameTooltip,
289 passwordLabel, passwordTooltip,
290 infoText = None,
291 rememberPassword = None,
292 rememberLabel = None, rememberTooltip = None):
293 """Construct the dialog."""
294 super(CredentialsDialog, self).__init__(WINDOW_TITLE_BASE + " - " +
295 titleLabel,
296 gui.mainWindow,
297 DIALOG_MODAL)
298 self.add_button(cancelButtonLabel, RESPONSETYPE_CANCEL)
299 self.add_button(okButtonLabel, RESPONSETYPE_OK)
300
301 contentArea = self.get_content_area()
302
303 contentAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
304 xscale = 0.0, yscale = 0.0)
305 contentAlignment.set_padding(padding_top = 4, padding_bottom = 16,
306 padding_left = 8, padding_right = 8)
307
308 contentArea.pack_start(contentAlignment, False, False, 0)
309
310 contentVBox = gtk.VBox()
311 contentAlignment.add(contentVBox)
312
313 if infoText is not None:
314 label = gtk.Label(infoText)
315 label.set_alignment(0.0, 0.0)
316
317 contentVBox.pack_start(label, False, False, 0)
318
319 tableAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
320 xscale = 0.0, yscale = 0.0)
321 tableAlignment.set_padding(padding_top = 24, padding_bottom = 0,
322 padding_left = 0, padding_right = 0)
323
324 table = gtk.Table(3, 2)
325 table.set_row_spacings(4)
326 table.set_col_spacings(16)
327 table.set_homogeneous(False)
328
329 tableAlignment.add(table)
330 contentVBox.pack_start(tableAlignment, True, True, 0)
331
332 label = gtk.Label(userNameLabel)
333 label.set_use_underline(True)
334 label.set_alignment(0.0, 0.5)
335 table.attach(label, 0, 1, 0, 1)
336
337 self._userName = gtk.Entry()
338 self._userName.set_width_chars(16)
339 # FIXME: enabled the OK button only when there is something in thr
340 # user name and password fields
341 #self._userName.connect("changed",
342 # lambda button: self._updateForwardButton())
343 self._userName.set_tooltip_text(userNameTooltip)
344 self._userName.set_text(userName)
345 table.attach(self._userName, 1, 2, 0, 1)
346 label.set_mnemonic_widget(self._userName)
347
348 label = gtk.Label(passwordLabel)
349 label.set_use_underline(True)
350 label.set_alignment(0.0, 0.5)
351 table.attach(label, 0, 1, 1, 2)
352
353 self._password = gtk.Entry()
354 self._password.set_visibility(False)
355 #self._password.connect("changed",
356 # lambda button: self._updateForwardButton())
357 self._password.set_tooltip_text(passwordTooltip)
358 self._password.set_text(password)
359 table.attach(self._password, 1, 2, 1, 2)
360 label.set_mnemonic_widget(self._password)
361
362 if rememberPassword is not None:
363 self._rememberButton = gtk.CheckButton(rememberLabel)
364 self._rememberButton.set_use_underline(True)
365 self._rememberButton.set_tooltip_text(rememberTooltip)
366 self._rememberButton.set_active(rememberPassword)
367 table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
368 else:
369 self._rememberButton = None
370
371 @property
372 def userName(self):
373 """Get the user name entered."""
374 return self._userName.get_text()
375
376 @property
377 def password(self):
378 """Get the password entered."""
379 return self._password.get_text()
380
381 @property
382 def rememberPassword(self):
383 """Get whether the password is to be remembered."""
384 return None if self._rememberButton is None \
385 else self._rememberButton.get_active()
386
387 def run(self):
388 """Run the dialog."""
389 self.show_all()
390
391 response = super(CredentialsDialog, self).run()
392
393 self.hide()
394
395 return response
396
397#------------------------------------------------------------------------------
398
399gobject.signal_new("integer-changed", IntegerEntry, gobject.SIGNAL_RUN_FIRST,
400 None, (object,))
401
402#------------------------------------------------------------------------------
403
404PROGRAM_NAME = "MAVA Logger X"
405
406WINDOW_TITLE_BASE = PROGRAM_NAME + " " + _const.VERSION
407if secondaryInstallation:
408 WINDOW_TITLE_BASE += " (" + xstr("secondary") + ")"
409
410#------------------------------------------------------------------------------
411
412# A mapping of aircraft types to their screen names
413aircraftNames = { _const.AIRCRAFT_B736 : xstr("aircraft_b736"),
414 _const.AIRCRAFT_B737 : xstr("aircraft_b737"),
415 _const.AIRCRAFT_B738 : xstr("aircraft_b738"),
416 _const.AIRCRAFT_B738C : xstr("aircraft_b738c"),
417 _const.AIRCRAFT_B732 : xstr("aircraft_b732"),
418 _const.AIRCRAFT_B733 : xstr("aircraft_b733"),
419 _const.AIRCRAFT_B734 : xstr("aircraft_b734"),
420 _const.AIRCRAFT_B735 : xstr("aircraft_b735"),
421 _const.AIRCRAFT_DH8D : xstr("aircraft_dh8d"),
422 _const.AIRCRAFT_B762 : xstr("aircraft_b762"),
423 _const.AIRCRAFT_B763 : xstr("aircraft_b763"),
424 _const.AIRCRAFT_CRJ2 : xstr("aircraft_crj2"),
425 _const.AIRCRAFT_F70 : xstr("aircraft_f70"),
426 _const.AIRCRAFT_DC3 : xstr("aircraft_dc3"),
427 _const.AIRCRAFT_T134 : xstr("aircraft_t134"),
428 _const.AIRCRAFT_T154 : xstr("aircraft_t154"),
429 _const.AIRCRAFT_YK40 : xstr("aircraft_yk40"),
430 _const.AIRCRAFT_B462 : xstr("aircraft_b462") }
431
432#------------------------------------------------------------------------------
433
434def formatFlightLogLine(timeStr, line):
435 """Format the given flight log line."""
436 """Format the given line for flight logging."""
437 if timeStr is not None:
438 line = timeStr + ": " + line
439 return line + "\n"
440
441#------------------------------------------------------------------------------
442
443def addFaultTag(buffer):
444 """Add a tag named 'fault' to the given buffer."""
445 buffer.create_tag("fault", foreground="red", weight=WEIGHT_BOLD)
446
447#------------------------------------------------------------------------------
448
449def appendTextBuffer(buffer, text, isFault = False):
450 """Append the given line at the end of the given text buffer.
451
452 If isFault is set, use the tag named 'fault'."""
453 insertTextBuffer(buffer, buffer.get_end_iter(), text, isFault)
454
455#------------------------------------------------------------------------------
456
457def insertTextBuffer(buffer, iter, text, isFault = False):
458 """Insert the given line into the given text buffer at the given iterator.
459
460 If isFault is set, use the tag named 'fault' else use the tag named
461 'normal'."""
462 line = iter.get_line()
463
464 buffer.insert(iter, text)
465
466 iter0 = buffer.get_iter_at_line(line)
467 iter1 = buffer.get_iter_at_line(line+1)
468 if isFault:
469 buffer.apply_tag_by_name("fault", iter0, iter1)
470 else:
471 buffer.remove_all_tags(iter0, iter1)
472
473#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.