source: src/mlx/gui/common.py@ 925:7b6e501f28a1

python3
Last change on this file since 925:7b6e501f28a1 was 925:7b6e501f28a1, checked in by István Váradi <ivaradi@…>, 4 years ago

GI modules are required properly (re #347).

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