source: src/mlx/gui/common.py@ 846:d11ea8564da8

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

The values are checked and the OK button is updated accordingly (re #307)

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