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@…>, 5 years ago

GI modules are required properly (re #347).

File size: 23.0 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:
[919]33 print("Using PyGTK")
[28]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
[919]44 except Exception as e:
[28]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
[858]109 WINDOW_POPUP = gtk.WINDOW_POPUP
110
[227]111 pixbuf_new_from_file = gdk.pixbuf_new_from_file
112
[97]113 def text2unicode(text):
114 """Convert the given text, returned by a Gtk widget, to Unicode."""
[919]115 return str(text)
[276]116
117 def text2str(text):
118 """Convert the given text, returned by xstr to a string."""
119 return str(text)
[401]120
[575]121else: # pygobject
[925]122 import gi
123 gi.require_version("Gdk", "3.0")
[29]124 from gi.repository import Gdk as gdk
[227]125 from gi.repository import GdkPixbuf as gdkPixbuf
[925]126 gi.require_version("Gtk", "3.0")
[28]127 from gi.repository import Gtk as gtk
128 from gi.repository import AppIndicator3 as appindicator
[44]129 from gi.repository import Pango as pango
[575]130
[28]131 appIndicator = True
[401]132
[575]133
[42]134 MESSAGETYPE_ERROR = gtk.MessageType.ERROR
[76]135 MESSAGETYPE_QUESTION = gtk.MessageType.QUESTION
[97]136 MESSAGETYPE_INFO = gtk.MessageType.INFO
[850]137 RESPONSETYPE_NONE = gtk.ResponseType.NONE
[124]138 RESPONSETYPE_OK = gtk.ResponseType.OK
[76]139 RESPONSETYPE_YES = gtk.ResponseType.YES
[124]140 RESPONSETYPE_NO = gtk.ResponseType.NO
[123]141 RESPONSETYPE_ACCEPT = gtk.ResponseType.ACCEPT
142 RESPONSETYPE_REJECT = gtk.ResponseType.REJECT
[149]143 RESPONSETYPE_CANCEL = gtk.ResponseType.CANCEL
[93]144 ACCEL_VISIBLE = gtk.AccelFlags.VISIBLE
145 CONTROL_MASK = gdk.ModifierType.CONTROL_MASK
[123]146 DIALOG_MODAL = gtk.DialogFlags.MODAL
[127]147 WRAP_WORD = gtk.WrapMode.WORD
[132]148 JUSTIFY_CENTER = gtk.Justification.CENTER
[604]149 JUSTIFY_LEFT = gtk.Justification.LEFT
[42]150
[144]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
[149]160 FILE_CHOOSER_ACTION_SELECT_FOLDER = gtk.FileChooserAction.SELECT_FOLDER
[151]161 FILE_CHOOSER_ACTION_OPEN = gtk.FileChooserAction.OPEN
162 FILE_CHOOSER_ACTION_SAVE = gtk.FileChooserAction.SAVE
[149]163
[175]164 SELECTION_MULTIPLE = gtk.SelectionMode.MULTIPLE
165
[220]166 SHADOW_IN = gtk.ShadowType.IN
[433]167 SHADOW_NONE = gtk.ShadowType.NONE
[220]168
169 POLICY_AUTOMATIC = gtk.PolicyType.AUTOMATIC
[604]170 POLICY_NEVER = gtk.PolicyType.NEVER
171 POLICY_ALWAYS = gtk.PolicyType.ALWAYS
[220]172
[362]173 WEIGHT_NORMAL = pango.Weight.NORMAL
[226]174 WEIGHT_BOLD = pango.Weight.BOLD
175
[246]176 WINDOW_STATE_ICONIFIED = gdk.WindowState.ICONIFIED
177 WINDOW_STATE_WITHDRAWN = gdk.WindowState.WITHDRAWN
178
[264]179 SORT_ASCENDING = gtk.SortType.ASCENDING
180 SORT_DESCENDING = gtk.SortType.DESCENDING
181
[277]182 EVENT_BUTTON_PRESS = gdk.EventType.BUTTON_PRESS
183
[433]184 TREE_VIEW_COLUMN_FIXED = gtk.TreeViewColumnSizing.FIXED
185
[438]186 FILL = gtk.AttachOptions.FILL
187 EXPAND = gtk.AttachOptions.EXPAND
188
[554]189 UPDATE_IF_VALID = gtk.SpinButtonUpdatePolicy.IF_VALID
190
[823]191 SELECTION_MULTIPLE = gtk.SelectionMode.MULTIPLE
192
[227]193 pixbuf_new_from_file = gdkPixbuf.Pixbuf.new_from_file
194
[97]195 import codecs
196 _utf8Decoder = codecs.getdecoder("utf-8")
[401]197
[97]198 def text2unicode(str):
199 """Convert the given text, returned by a Gtk widget, to Unicode."""
200 return _utf8Decoder(str)[0]
201
[276]202 def text2str(text):
203 """Convert the given text, returned by xstr to a string."""
204 return _utf8Decoder(text)[0]
205
[28]206import cairo
207
[32]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()
[401]223
[32]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#------------------------------------------------------------------------------
[84]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
[86]251 self.set_alignment(1.0)
252
[84]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
[241]264 def reset(self):
265 """Reset the integer."""
266 self.set_int(None)
267
[84]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()
[401]274
[84]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
[401]294
[84]295#------------------------------------------------------------------------------
296
[837]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
[846]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
[837]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
[851]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
[837]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
[741]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
[84]521gobject.signal_new("integer-changed", IntegerEntry, gobject.SIGNAL_RUN_FIRST,
522 None, (object,))
523
524#------------------------------------------------------------------------------
[105]525
[227]526PROGRAM_NAME = "MAVA Logger X"
527
[732]528WINDOW_TITLE_BASE = PROGRAM_NAME + " " + _const.VERSION
[373]529if secondaryInstallation:
530 WINDOW_TITLE_BASE += " (" + xstr("secondary") + ")"
[105]531
532#------------------------------------------------------------------------------
[175]533
534# A mapping of aircraft types to their screen names
[191]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"),
[790]539 _const.AIRCRAFT_B732 : xstr("aircraft_b732"),
[191]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"),
[443]551 _const.AIRCRAFT_YK40 : xstr("aircraft_yk40"),
552 _const.AIRCRAFT_B462 : xstr("aircraft_b462") }
[175]553
554#------------------------------------------------------------------------------
[221]555
[858]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
[226]582def formatFlightLogLine(timeStr, line):
[221]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#------------------------------------------------------------------------------
[226]590
591def addFaultTag(buffer):
592 """Add a tag named 'fault' to the given buffer."""
[362]593 buffer.create_tag("fault", foreground="red", weight=WEIGHT_BOLD)
[226]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'."""
[345]601 insertTextBuffer(buffer, buffer.get_end_iter(), text, isFault)
[226]602
603#------------------------------------------------------------------------------
[345]604
605def insertTextBuffer(buffer, iter, text, isFault = False):
606 """Insert the given line into the given text buffer at the given iterator.
607
[362]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)
[345]616 if isFault:
[362]617 buffer.apply_tag_by_name("fault", iter0, iter1)
[345]618 else:
[362]619 buffer.remove_all_tags(iter0, iter1)
[345]620
621#------------------------------------------------------------------------------
[826]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#------------------------------------------------------------------------------
[828]641
[863]642def errorDialog(message, parent = None, secondary = None,
[828]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."""
[863]660 errorDialog(xstr("error_communication"), parent = parent,
[828]661 secondary = xstr("error_communication_secondary"),
662 title = title)
663
664#------------------------------------------------------------------------------
[836]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#------------------------------------------------------------------------------
[852]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.