source: src/mlx/gui/common.py@ 863:4c7bfec09347

Last change on this file since 863:4c7bfec09347 was 863:4c7bfec09347, checked in by István Váradi <ivaradi@…>, 6 years ago

The briefing can be printed from the program (re #307)

File size: 23.0 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
10import time
11import calendar
12
13#-----------------------------------------------------------------------------
14
15## @package mlx.gui.common
16#
17# Common definitions and utilities for the GUI
18#
19# The main purpose of this module is to provide common definitions for things
20# that are named differently in Gtk+ 2 and 3. This way the other parts of the
21# GUI have to check the version in use very rarely. The variable \c pygobject
22# tells which version is being used. If it is \c True, Gtk+ 3 is used via the
23# PyGObject interface. Otherwise Gtk+ 2 is used, which is the default on
24# Windows or when the \c FORCE_PYGTK environment variable is set.
25#
26# Besides this there are some common utility classes and functions.
27
28#-----------------------------------------------------------------------------
29
30appIndicator = False
31
32if not pygobject:
33 print "Using PyGTK"
34 pygobject = False
35 import pygtk
36 pygtk.require("2.0")
37 import gtk.gdk as gdk
38 import gtk
39 import pango
40
41 try:
42 import appindicator
43 appIndicator = True
44 except Exception, e:
45 pass
46
47 MESSAGETYPE_ERROR = gtk.MESSAGE_ERROR
48 MESSAGETYPE_QUESTION = gtk.MESSAGE_QUESTION
49 MESSAGETYPE_INFO = gtk.MESSAGE_INFO
50
51 RESPONSETYPE_NONE = gtk.RESPONSE_NONE
52 RESPONSETYPE_OK = gtk.RESPONSE_OK
53 RESPONSETYPE_YES = gtk.RESPONSE_YES
54 RESPONSETYPE_NO = gtk.RESPONSE_NO
55 RESPONSETYPE_ACCEPT = gtk.RESPONSE_ACCEPT
56 RESPONSETYPE_REJECT = gtk.RESPONSE_REJECT
57 RESPONSETYPE_CANCEL = gtk.RESPONSE_CANCEL
58
59 ACCEL_VISIBLE = gtk.ACCEL_VISIBLE
60 CONTROL_MASK = gdk.CONTROL_MASK
61 DIALOG_MODAL = gtk.DIALOG_MODAL
62 WRAP_WORD = gtk.WRAP_WORD
63
64 JUSTIFY_CENTER = gtk.JUSTIFY_CENTER
65 JUSTIFY_LEFT = gtk.JUSTIFY_LEFT
66
67 CONTROL_MASK = gdk.CONTROL_MASK
68 SHIFT_MASK = gdk.SHIFT_MASK
69 BUTTON1_MASK = gdk.BUTTON1_MASK
70
71 SCROLL_UP = gdk.SCROLL_UP
72 SCROLL_DOWN = gdk.SCROLL_DOWN
73
74 SPIN_USER_DEFINED = gtk.SPIN_USER_DEFINED
75
76 FILE_CHOOSER_ACTION_SELECT_FOLDER = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER
77 FILE_CHOOSER_ACTION_OPEN = gtk.FILE_CHOOSER_ACTION_OPEN
78 FILE_CHOOSER_ACTION_SAVE = gtk.FILE_CHOOSER_ACTION_SAVE
79
80 SELECTION_MULTIPLE = gtk.SELECTION_MULTIPLE
81
82 SHADOW_IN = gtk.SHADOW_IN
83 SHADOW_NONE = gtk.SHADOW_NONE
84
85 POLICY_AUTOMATIC = gtk.POLICY_AUTOMATIC
86 POLICY_NEVER = gtk.POLICY_NEVER
87 POLICY_ALWAYS = gtk.POLICY_ALWAYS
88
89 WEIGHT_NORMAL = pango.WEIGHT_NORMAL
90 WEIGHT_BOLD = pango.WEIGHT_BOLD
91
92 WINDOW_STATE_ICONIFIED = gdk.WINDOW_STATE_ICONIFIED
93 WINDOW_STATE_WITHDRAWN = gdk.WINDOW_STATE_WITHDRAWN
94
95 SORT_ASCENDING = gtk.SORT_ASCENDING
96 SORT_DESCENDING = gtk.SORT_DESCENDING
97
98 EVENT_BUTTON_PRESS = gdk.BUTTON_PRESS
99
100 TREE_VIEW_COLUMN_FIXED = gtk.TREE_VIEW_COLUMN_FIXED
101
102 FILL = gtk.FILL
103 EXPAND = gtk.EXPAND
104
105 UPDATE_IF_VALID = gtk.UPDATE_IF_VALID
106
107 SELECTION_MULTIPLE = gtk.SELECTION_MULTIPLE
108
109 WINDOW_POPUP = gtk.WINDOW_POPUP
110
111 pixbuf_new_from_file = gdk.pixbuf_new_from_file
112
113 def text2unicode(text):
114 """Convert the given text, returned by a Gtk widget, to Unicode."""
115 return unicode(text)
116
117 def text2str(text):
118 """Convert the given text, returned by xstr to a string."""
119 return str(text)
120
121else: # pygobject
122 from gi.repository import Gdk as gdk
123 from gi.repository import GdkPixbuf as gdkPixbuf
124 from gi.repository import Gtk as gtk
125 from gi.repository import AppIndicator3 as appindicator
126 from gi.repository import Pango as pango
127
128 appIndicator = True
129
130
131 MESSAGETYPE_ERROR = gtk.MessageType.ERROR
132 MESSAGETYPE_QUESTION = gtk.MessageType.QUESTION
133 MESSAGETYPE_INFO = gtk.MessageType.INFO
134 RESPONSETYPE_NONE = gtk.ResponseType.NONE
135 RESPONSETYPE_OK = gtk.ResponseType.OK
136 RESPONSETYPE_YES = gtk.ResponseType.YES
137 RESPONSETYPE_NO = gtk.ResponseType.NO
138 RESPONSETYPE_ACCEPT = gtk.ResponseType.ACCEPT
139 RESPONSETYPE_REJECT = gtk.ResponseType.REJECT
140 RESPONSETYPE_CANCEL = gtk.ResponseType.CANCEL
141 ACCEL_VISIBLE = gtk.AccelFlags.VISIBLE
142 CONTROL_MASK = gdk.ModifierType.CONTROL_MASK
143 DIALOG_MODAL = gtk.DialogFlags.MODAL
144 WRAP_WORD = gtk.WrapMode.WORD
145 JUSTIFY_CENTER = gtk.Justification.CENTER
146 JUSTIFY_LEFT = gtk.Justification.LEFT
147
148 CONTROL_MASK = gdk.ModifierType.CONTROL_MASK
149 SHIFT_MASK = gdk.ModifierType.SHIFT_MASK
150 BUTTON1_MASK = gdk.ModifierType.BUTTON1_MASK
151
152 SCROLL_UP = gdk.ScrollDirection.UP
153 SCROLL_DOWN = gdk.ScrollDirection.DOWN
154
155 SPIN_USER_DEFINED = gtk.SpinType.USER_DEFINED
156
157 FILE_CHOOSER_ACTION_SELECT_FOLDER = gtk.FileChooserAction.SELECT_FOLDER
158 FILE_CHOOSER_ACTION_OPEN = gtk.FileChooserAction.OPEN
159 FILE_CHOOSER_ACTION_SAVE = gtk.FileChooserAction.SAVE
160
161 SELECTION_MULTIPLE = gtk.SelectionMode.MULTIPLE
162
163 SHADOW_IN = gtk.ShadowType.IN
164 SHADOW_NONE = gtk.ShadowType.NONE
165
166 POLICY_AUTOMATIC = gtk.PolicyType.AUTOMATIC
167 POLICY_NEVER = gtk.PolicyType.NEVER
168 POLICY_ALWAYS = gtk.PolicyType.ALWAYS
169
170 WEIGHT_NORMAL = pango.Weight.NORMAL
171 WEIGHT_BOLD = pango.Weight.BOLD
172
173 WINDOW_STATE_ICONIFIED = gdk.WindowState.ICONIFIED
174 WINDOW_STATE_WITHDRAWN = gdk.WindowState.WITHDRAWN
175
176 SORT_ASCENDING = gtk.SortType.ASCENDING
177 SORT_DESCENDING = gtk.SortType.DESCENDING
178
179 EVENT_BUTTON_PRESS = gdk.EventType.BUTTON_PRESS
180
181 TREE_VIEW_COLUMN_FIXED = gtk.TreeViewColumnSizing.FIXED
182
183 FILL = gtk.AttachOptions.FILL
184 EXPAND = gtk.AttachOptions.EXPAND
185
186 UPDATE_IF_VALID = gtk.SpinButtonUpdatePolicy.IF_VALID
187
188 SELECTION_MULTIPLE = gtk.SelectionMode.MULTIPLE
189
190 pixbuf_new_from_file = gdkPixbuf.Pixbuf.new_from_file
191
192 import codecs
193 _utf8Decoder = codecs.getdecoder("utf-8")
194
195 def text2unicode(str):
196 """Convert the given text, returned by a Gtk widget, to Unicode."""
197 return _utf8Decoder(str)[0]
198
199 def text2str(text):
200 """Convert the given text, returned by xstr to a string."""
201 return _utf8Decoder(text)[0]
202
203import cairo
204
205#------------------------------------------------------------------------------
206
207class FlightStatusHandler(object):
208 """Base class for objects that handle the flight status in some way."""
209 def __init__(self):
210 self._stage = None
211 self._rating = 100
212 self._noGoReason = None
213
214 def resetFlightStatus(self):
215 """Reset the flight status."""
216 self._stage = None
217 self._rating = 100
218 self._noGoReason = None
219 self._updateFlightStatus()
220
221 def setStage(self, stage):
222 """Set the stage of the flight."""
223 if stage!=self._stage:
224 self._stage = stage
225 self._updateFlightStatus()
226
227 def setRating(self, rating):
228 """Set the rating to the given value."""
229 if rating!=self._rating:
230 self._rating = rating
231 if self._noGoReason is None:
232 self._updateFlightStatus()
233
234 def setNoGo(self, reason):
235 """Set a No-Go condition with the given reason."""
236 if self._noGoReason is None:
237 self._noGoReason = reason
238 self._updateFlightStatus()
239
240#------------------------------------------------------------------------------
241
242class IntegerEntry(gtk.Entry):
243 """An entry that allows only either an empty value, or an integer."""
244 def __init__(self, defaultValue = None):
245 """Construct the entry."""
246 gtk.Entry.__init__(self)
247
248 self.set_alignment(1.0)
249
250 self._defaultValue = defaultValue
251 self._currentInteger = defaultValue
252 self._selfSetting = False
253 self._set_text()
254
255 self.connect("changed", self._handle_changed)
256
257 def get_int(self):
258 """Get the integer."""
259 return self._currentInteger
260
261 def reset(self):
262 """Reset the integer."""
263 self.set_int(None)
264
265 def set_int(self, value):
266 """Set the integer."""
267 if value!=self._currentInteger:
268 self._currentInteger = value
269 self.emit("integer-changed", self._currentInteger)
270 self._set_text()
271
272 def _handle_changed(self, widget):
273 """Handle the changed signal."""
274 if self._selfSetting:
275 return
276 text = self.get_text()
277 if text=="":
278 self.set_int(self._defaultValue)
279 else:
280 try:
281 self.set_int(int(text))
282 except:
283 self._set_text()
284
285 def _set_text(self):
286 """Set the text value from the current integer."""
287 self._selfSetting = True
288 self.set_text("" if self._currentInteger is None
289 else str(self._currentInteger))
290 self._selfSetting = False
291
292#------------------------------------------------------------------------------
293
294class TimeEntry(gtk.Entry):
295 """Widget to display and edit a time value in HH:MM format."""
296 def __init__(self):
297 """Construct the entry"""
298 super(TimeEntry, self).__init__(max = 5)
299
300 self.connect("insert-text", self._insertText)
301 self.connect("delete-text", self._deleteText)
302 self.connect("focus-out-event", self._focusOutEvent)
303
304 @property
305 def hour(self):
306 """Get the hour from the current text"""
307 text = self.get_text()
308 if not text or text==":":
309 return 0
310
311 words = text.split(":")
312 if len(words)==1:
313 return 0
314 elif len(words)>=2:
315 return 0 if len(words[0])==0 else int(words[0])
316 else:
317 return 0
318
319 @property
320 def minute(self):
321 """Get the hour from the current text"""
322 text = self.get_text()
323 if not text or text==":":
324 return 0
325
326 words = text.split(":")
327 if len(words)==1:
328 return 0 if len(words[0])==0 else int(words[0])
329 elif len(words)>=2:
330 return 0 if len(words[1])==0 else int(words[1])
331 else:
332 return 0
333
334 @property
335 def minutes(self):
336 """Get the time in minutes, i.e. hour*60+minute."""
337 return self.hour * 60 + self.minute
338
339 def setTimestamp(self, timestamp):
340 """Set the hour and minute from the given timestamp in UTC."""
341 tm = time.gmtime(timestamp)
342 self.set_text("%02d:%02d" % (tm.tm_hour, tm.tm_min))
343
344 def getTimestampFrom(self, timestamp):
345 """Get the timestamp by replacing the hour and minute from the given
346 timestamp with what is set in this widget."""
347 tm = time.gmtime(timestamp)
348 ts = calendar.timegm((tm.tm_year, tm.tm_mon, tm.tm_mday,
349 self.hour, self.minute, 0,
350 tm.tm_wday, tm.tm_yday, tm.tm_isdst))
351
352 if ts > (timestamp + (16*60*60)):
353 ts -= 24*60*60
354 elif (ts + 16*60*60) < timestamp:
355 ts += 24*60*60
356
357 return ts
358
359 def _focusOutEvent(self, widget, event):
360 """Reformat the text to match pattern HH:MM"""
361 text = "%02d:%02d" % (self.hour, self.minute)
362 if text!=self.get_text():
363 self.set_text(text)
364
365 def _insertText(self, entry, text, length, position):
366 """Called when some text is inserted into the entry."""
367 text=text[:length]
368 currentText = self.get_text()
369 position = self.get_position()
370 newText = currentText[:position] + text + currentText[position:]
371 self._checkText(newText, "insert-text")
372
373 def _deleteText(self, entry, start, end):
374 """Called when some text is erased from the entry."""
375 currentText = self.get_text()
376 newText = currentText[:start] + currentText[end:]
377 self._checkText(newText, "delete-text")
378
379 def _checkText(self, newText, signal):
380 """Check the given text.
381
382 If it is not suitable, stop the emission of the signal to prevent the
383 change from appearing."""
384 if not newText or newText==":":
385 return
386
387 words = newText.split(":")
388 if (len(words)==1 and
389 len(words[0])<=2 and (len(words[0])==0 or
390 (words[0].isdigit() and int(words[0])<60))) or \
391 (len(words)==2 and
392 len(words[0])<=2 and (len(words[0])==0 or
393 (words[0].isdigit() and int(words[0])<24)) and
394 len(words[1])<=2 and (len(words[1])==0 or
395 (words[1].isdigit() and int(words[1])<60))):
396 pass
397 else:
398 gtk.gdk.display_get_default().beep()
399 self.stop_emission(signal)
400
401#------------------------------------------------------------------------------
402
403class CredentialsDialog(gtk.Dialog):
404 """A dialog window to ask for a user name and a password."""
405 def __init__(self, gui, userName, password,
406 titleLabel, cancelButtonLabel, okButtonLabel,
407 userNameLabel, userNameTooltip,
408 passwordLabel, passwordTooltip,
409 infoText = None,
410 rememberPassword = None,
411 rememberLabel = None, rememberTooltip = None):
412 """Construct the dialog."""
413 super(CredentialsDialog, self).__init__(WINDOW_TITLE_BASE + " - " +
414 titleLabel,
415 gui.mainWindow,
416 DIALOG_MODAL)
417 self.add_button(cancelButtonLabel, RESPONSETYPE_CANCEL)
418 self.add_button(okButtonLabel, RESPONSETYPE_OK)
419
420 contentArea = self.get_content_area()
421
422 contentAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
423 xscale = 0.0, yscale = 0.0)
424 contentAlignment.set_padding(padding_top = 4, padding_bottom = 16,
425 padding_left = 8, padding_right = 8)
426
427 contentArea.pack_start(contentAlignment, False, False, 0)
428
429 contentVBox = gtk.VBox()
430 contentAlignment.add(contentVBox)
431
432 if infoText is not None:
433 label = gtk.Label(infoText)
434 label.set_alignment(0.0, 0.0)
435
436 contentVBox.pack_start(label, False, False, 0)
437
438 tableAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
439 xscale = 0.0, yscale = 0.0)
440 tableAlignment.set_padding(padding_top = 24, padding_bottom = 0,
441 padding_left = 0, padding_right = 0)
442
443 table = gtk.Table(3, 2)
444 table.set_row_spacings(4)
445 table.set_col_spacings(16)
446 table.set_homogeneous(False)
447
448 tableAlignment.add(table)
449 contentVBox.pack_start(tableAlignment, True, True, 0)
450
451 label = gtk.Label(userNameLabel)
452 label.set_use_underline(True)
453 label.set_alignment(0.0, 0.5)
454 table.attach(label, 0, 1, 0, 1)
455
456 self._userName = gtk.Entry()
457 self._userName.set_width_chars(16)
458 # FIXME: enabled the OK button only when there is something in thr
459 # user name and password fields
460 #self._userName.connect("changed",
461 # lambda button: self._updateForwardButton())
462 self._userName.set_tooltip_text(userNameTooltip)
463 self._userName.set_text(userName)
464 table.attach(self._userName, 1, 2, 0, 1)
465 label.set_mnemonic_widget(self._userName)
466
467 label = gtk.Label(passwordLabel)
468 label.set_use_underline(True)
469 label.set_alignment(0.0, 0.5)
470 table.attach(label, 0, 1, 1, 2)
471
472 self._password = gtk.Entry()
473 self._password.set_visibility(False)
474 #self._password.connect("changed",
475 # lambda button: self._updateForwardButton())
476 self._password.set_tooltip_text(passwordTooltip)
477 self._password.set_text(password)
478 table.attach(self._password, 1, 2, 1, 2)
479 label.set_mnemonic_widget(self._password)
480
481 if rememberPassword is not None:
482 self._rememberButton = gtk.CheckButton(rememberLabel)
483 self._rememberButton.set_use_underline(True)
484 self._rememberButton.set_tooltip_text(rememberTooltip)
485 self._rememberButton.set_active(rememberPassword)
486 table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
487 else:
488 self._rememberButton = None
489
490 @property
491 def userName(self):
492 """Get the user name entered."""
493 return self._userName.get_text()
494
495 @property
496 def password(self):
497 """Get the password entered."""
498 return self._password.get_text()
499
500 @property
501 def rememberPassword(self):
502 """Get whether the password is to be remembered."""
503 return None if self._rememberButton is None \
504 else self._rememberButton.get_active()
505
506 def run(self):
507 """Run the dialog."""
508 self.show_all()
509
510 response = super(CredentialsDialog, self).run()
511
512 self.hide()
513
514 return response
515
516#------------------------------------------------------------------------------
517
518gobject.signal_new("integer-changed", IntegerEntry, gobject.SIGNAL_RUN_FIRST,
519 None, (object,))
520
521#------------------------------------------------------------------------------
522
523PROGRAM_NAME = "MAVA Logger X"
524
525WINDOW_TITLE_BASE = PROGRAM_NAME + " " + _const.VERSION
526if secondaryInstallation:
527 WINDOW_TITLE_BASE += " (" + xstr("secondary") + ")"
528
529#------------------------------------------------------------------------------
530
531# A mapping of aircraft types to their screen names
532aircraftNames = { _const.AIRCRAFT_B736 : xstr("aircraft_b736"),
533 _const.AIRCRAFT_B737 : xstr("aircraft_b737"),
534 _const.AIRCRAFT_B738 : xstr("aircraft_b738"),
535 _const.AIRCRAFT_B738C : xstr("aircraft_b738c"),
536 _const.AIRCRAFT_B732 : xstr("aircraft_b732"),
537 _const.AIRCRAFT_B733 : xstr("aircraft_b733"),
538 _const.AIRCRAFT_B734 : xstr("aircraft_b734"),
539 _const.AIRCRAFT_B735 : xstr("aircraft_b735"),
540 _const.AIRCRAFT_DH8D : xstr("aircraft_dh8d"),
541 _const.AIRCRAFT_B762 : xstr("aircraft_b762"),
542 _const.AIRCRAFT_B763 : xstr("aircraft_b763"),
543 _const.AIRCRAFT_CRJ2 : xstr("aircraft_crj2"),
544 _const.AIRCRAFT_F70 : xstr("aircraft_f70"),
545 _const.AIRCRAFT_DC3 : xstr("aircraft_dc3"),
546 _const.AIRCRAFT_T134 : xstr("aircraft_t134"),
547 _const.AIRCRAFT_T154 : xstr("aircraft_t154"),
548 _const.AIRCRAFT_YK40 : xstr("aircraft_yk40"),
549 _const.AIRCRAFT_B462 : xstr("aircraft_b462") }
550
551#------------------------------------------------------------------------------
552
553aircraftFamilyNames = {
554 _const.AIRCRAFT_FAMILY_B737NG: xstr("aircraft_family_b737ng"),
555
556 _const.AIRCRAFT_FAMILY_B737CL: xstr("aircraft_family_b737cl"),
557
558 _const.AIRCRAFT_FAMILY_DH8D: xstr("aircraft_family_dh8d"),
559
560 _const.AIRCRAFT_FAMILY_B767: xstr("aircraft_family_b767"),
561
562 _const.AIRCRAFT_FAMILY_CRJ2: xstr("aircraft_family_crj2"),
563
564 _const.AIRCRAFT_FAMILY_F70: xstr("aircraft_family_f70"),
565
566 _const.AIRCRAFT_FAMILY_DC3: xstr("aircraft_family_dc3"),
567
568 _const.AIRCRAFT_FAMILY_T134: xstr("aircraft_family_t134"),
569
570 _const.AIRCRAFT_FAMILY_T154: xstr("aircraft_family_t154"),
571
572 _const.AIRCRAFT_FAMILY_YK40: xstr("aircraft_family_yk40"),
573
574 _const.AIRCRAFT_FAMILY_B462: xstr("aircraft_family_b462")
575}
576
577#------------------------------------------------------------------------------
578
579def formatFlightLogLine(timeStr, line):
580 """Format the given flight log line."""
581 """Format the given line for flight logging."""
582 if timeStr is not None:
583 line = timeStr + ": " + line
584 return line + "\n"
585
586#------------------------------------------------------------------------------
587
588def addFaultTag(buffer):
589 """Add a tag named 'fault' to the given buffer."""
590 buffer.create_tag("fault", foreground="red", weight=WEIGHT_BOLD)
591
592#------------------------------------------------------------------------------
593
594def appendTextBuffer(buffer, text, isFault = False):
595 """Append the given line at the end of the given text buffer.
596
597 If isFault is set, use the tag named 'fault'."""
598 insertTextBuffer(buffer, buffer.get_end_iter(), text, isFault)
599
600#------------------------------------------------------------------------------
601
602def insertTextBuffer(buffer, iter, text, isFault = False):
603 """Insert the given line into the given text buffer at the given iterator.
604
605 If isFault is set, use the tag named 'fault' else use the tag named
606 'normal'."""
607 line = iter.get_line()
608
609 buffer.insert(iter, text)
610
611 iter0 = buffer.get_iter_at_line(line)
612 iter1 = buffer.get_iter_at_line(line+1)
613 if isFault:
614 buffer.apply_tag_by_name("fault", iter0, iter1)
615 else:
616 buffer.remove_all_tags(iter0, iter1)
617
618#------------------------------------------------------------------------------
619
620def askYesNo(question, parent = None, title = WINDOW_TITLE_BASE):
621 """Ask a Yes/No question.
622
623 Return a boolean indicating the answer."""
624 dialog = gtk.MessageDialog(parent = parent,
625 type = MESSAGETYPE_QUESTION,
626 message_format = question)
627
628 dialog.add_button(xstr("button_no"), RESPONSETYPE_NO)
629 dialog.add_button(xstr("button_yes"), RESPONSETYPE_YES)
630
631 dialog.set_title(title)
632 result = dialog.run()
633 dialog.hide()
634
635 return result==RESPONSETYPE_YES
636
637#------------------------------------------------------------------------------
638
639def errorDialog(message, parent = None, secondary = None,
640 title = WINDOW_TITLE_BASE):
641 """Display an error dialog box with the given message."""
642 dialog = gtk.MessageDialog(parent = parent,
643 type = MESSAGETYPE_ERROR,
644 message_format = message)
645 dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
646 dialog.set_title(title)
647 if secondary is not None:
648 dialog.format_secondary_markup(secondary)
649
650 dialog.run()
651 dialog.hide()
652
653#------------------------------------------------------------------------------
654
655def communicationErrorDialog(parent = None, title = WINDOW_TITLE_BASE):
656 """Display a communication error dialog."""
657 errorDialog(xstr("error_communication"), parent = parent,
658 secondary = xstr("error_communication_secondary"),
659 title = title)
660
661#------------------------------------------------------------------------------
662
663def createFlightTypeComboBox():
664 flightTypeModel = gtk.ListStore(str, int)
665 for type in _const.flightTypes:
666 name = "flighttype_" + _const.flightType2string(type)
667 flightTypeModel.append([xstr(name), type])
668
669 flightType = gtk.ComboBox(model = flightTypeModel)
670 renderer = gtk.CellRendererText()
671 flightType.pack_start(renderer, True)
672 flightType.add_attribute(renderer, "text", 0)
673
674 return flightType
675
676#------------------------------------------------------------------------------
677
678def getTextViewText(textView):
679 """Get the text from the given text view."""
680 buffer = textView.get_buffer()
681 return buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), True)
682
683#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.