source: src/mlx/gui/common.py@ 855:c1d387ee73d6

Last change on this file since 855:c1d387ee73d6 was 852:fff6327db8e6, checked in by István Váradi <ivaradi@…>, 7 years ago

Utility function to get all the text in a text view.

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