source: src/mlx/gui/flight.py@ 50:19d4098081e8

Last change on this file since 50:19d4098081e8 was 50:19d4098081e8, checked in by István Váradi <ivaradi@…>, 12 years ago

Added environment variable to display the more natural size of the window

File size: 13.3 KB
Line 
1# The flight handling "wizard"
2
3from mlx.gui.common import *
4
5#-----------------------------------------------------------------------------
6
7class Page(gtk.Alignment):
8 """A page in the flight wizard."""
9 def __init__(self, wizard, title, help):
10 """Construct the page."""
11 super(Page, self).__init__(xalign = 0.0, yalign = 0.0,
12 xscale = 1.0, yscale = 1.0)
13 self.set_padding(padding_top = 4, padding_bottom = 4,
14 padding_left = 12, padding_right = 12)
15
16 frame = gtk.Frame()
17 self.add(frame)
18
19 style = self.get_style() if pygobject else self.rc_get_style()
20
21 self._vbox = gtk.VBox()
22 self._vbox.set_homogeneous(False)
23 frame.add(self._vbox)
24
25 eventBox = gtk.EventBox()
26 eventBox.modify_bg(0, style.bg[3])
27
28 alignment = gtk.Alignment(xalign = 0.0, xscale = 0.0)
29
30 label = gtk.Label(title)
31 label.modify_fg(0, style.fg[3])
32 label.modify_font(pango.FontDescription("bold 24"))
33 alignment.set_padding(padding_top = 4, padding_bottom = 4,
34 padding_left = 6, padding_right = 0)
35
36 alignment.add(label)
37 eventBox.add(alignment)
38
39 self._vbox.pack_start(eventBox, False, False, 0)
40
41 table = gtk.Table(3, 1)
42 table.set_homogeneous(True)
43
44 alignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
45 xscale = 1.0, yscale = 1.0)
46 alignment.set_padding(padding_top = 16, padding_bottom = 16,
47 padding_left = 16, padding_right = 16)
48 alignment.add(table)
49 self._vbox.pack_start(alignment, True, True, 0)
50
51 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
52 xscale = 0, yscale = 0.0)
53 alignment.set_padding(padding_top = 0, padding_bottom = 16,
54 padding_left = 0, padding_right = 0)
55
56 label = gtk.Label(help)
57 label.set_justify(gtk.Justification.CENTER if pygobject
58 else gtk.JUSTIFY_CENTER)
59 alignment.add(label)
60 table.attach(alignment, 0, 1, 0, 1)
61
62 self._mainAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
63 xscale = 1.0, yscale = 1.0)
64 table.attach(self._mainAlignment, 0, 1, 1, 3)
65
66 buttonAlignment = gtk.Alignment(xalign = 1.0, xscale=0.0, yscale = 0.0)
67 buttonAlignment.set_padding(padding_top = 4, padding_bottom = 10,
68 padding_left = 16, padding_right = 16)
69
70 self._buttonBox = gtk.HButtonBox()
71 self._defaultButton = None
72 buttonAlignment.add(self._buttonBox)
73
74 self._vbox.pack_start(buttonAlignment, False, False, 0)
75
76 self._wizard = wizard
77
78 def setMainWidget(self, widget):
79 """Set the given widget as the main one."""
80 self._mainAlignment.add(widget)
81
82 def addButton(self, label, default = False):
83 """Add a button with the given label.
84
85 Return the button object created."""
86 button = gtk.Button(label)
87 self._buttonBox.add(button)
88 button.set_use_underline(True)
89 if default:
90 button.set_can_default(True)
91 self._defaultButton = button
92 return button
93
94 def activate(self):
95 """Called when this page becomes active.
96
97 This default implementation does nothing."""
98 pass
99
100 def grabDefault(self):
101 """If the page has a default button, make it the default one."""
102 if self._defaultButton is not None:
103 self._defaultButton.grab_default()
104
105#-----------------------------------------------------------------------------
106
107class LoginPage(Page):
108 """The login page."""
109 def __init__(self, wizard):
110 """Construct the login page."""
111 help = "Enter your MAVA pilot's ID and password to\n" \
112 "log in to the MAVA website and download\n" \
113 "your booked flights."
114 super(LoginPage, self).__init__(wizard, "Login", help)
115
116 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
117 xscale = 0.0, yscale = 0.0)
118
119 table = gtk.Table(2, 3)
120 table.set_row_spacings(4)
121 table.set_col_spacings(32)
122 alignment.add(table)
123 self.setMainWidget(alignment)
124
125 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
126 label = gtk.Label("Pilot _ID:")
127 label.set_use_underline(True)
128 labelAlignment.add(label)
129 table.attach(labelAlignment, 0, 1, 0, 1)
130
131 self._pilotID = gtk.Entry()
132 self._pilotID.connect("changed", self._setLoginButton)
133 self._pilotID.set_tooltip_text("Enter your MAVA pilot's ID. This "
134 "usually starts with a "
135 "'P' followed by 3 digits.")
136 table.attach(self._pilotID, 1, 2, 0, 1)
137 label.set_mnemonic_widget(self._pilotID)
138
139 labelAlignment = gtk.Alignment(xalign=1.0, xscale=0.0)
140 label = gtk.Label("_Password:")
141 label.set_use_underline(True)
142 labelAlignment.add(label)
143 table.attach(labelAlignment, 0, 1, 1, 2)
144
145 self._password = gtk.Entry()
146 self._password.set_visibility(False)
147 self._password.connect("changed", self._setLoginButton)
148 self._password.set_tooltip_text("Enter the password for your pilot's ID")
149 table.attach(self._password, 1, 2, 1, 2)
150 label.set_mnemonic_widget(self._password)
151
152 self._rememberButton = gtk.CheckButton("_Remember password")
153 self._rememberButton.set_use_underline(True)
154 self._rememberButton.set_tooltip_text("If checked, your password will "
155 "be stored, so that you should "
156 "not have to enter it every time. "
157 "Note, however, that the password "
158 "is stored as text, and anybody "
159 "who can access your files will "
160 "be able to read it.")
161 table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
162
163 self._loginButton = self.addButton("_Login", default = True)
164 self._loginButton.set_sensitive(False)
165 self._loginButton.connect("clicked", self._loginClicked)
166 self._loginButton.set_tooltip_text("Click to log in.")
167
168 config = self._wizard.gui.config
169 self._pilotID.set_text(config.pilotID)
170 self._password.set_text(config.password)
171 self._rememberButton.set_active(config.rememberPassword)
172
173 def _setLoginButton(self, entry):
174 """Set the login button's sensitivity.
175
176 The button is sensitive only if both the pilot ID and the password
177 fields contain values."""
178 self._loginButton.set_sensitive(self._pilotID.get_text()!="" and
179 self._password.get_text()!="")
180
181 def _loginClicked(self, button):
182 """Called when the login button was clicked."""
183 self._wizard.gui.beginBusy("Logging in...")
184 self._wizard.gui.webHandler.login(self._pilotID.get_text(),
185 self._password.get_text(),
186 self._loginResultCallback)
187
188 def _loginResultCallback(self, returned, result):
189 """The login result callback, called in the web handler's thread."""
190 gobject.idle_add(self._handleLoginResult, returned, result)
191
192 def _handleLoginResult(self, returned, result):
193 """Handle the login result."""
194 self._wizard.gui.endBusy()
195 if returned:
196 if result.loggedIn:
197 config = self._wizard.gui.config
198
199 config.pilotID = self._pilotID.get_text()
200
201 rememberPassword = self._rememberButton.get_active()
202 config.password = self._password.get_text() if rememberPassword \
203 else ""
204
205 config.rememberPassword = rememberPassword
206
207 config.save()
208 self._wizard._loginResult = result
209 self._wizard.nextPage()
210 else:
211 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
212 buttons = BUTTONSTYPE_OK,
213 message_format =
214 "Invalid pilot's ID or password.")
215 dialog.format_secondary_markup("Check the ID and try to reenter"
216 " the password.")
217 dialog.run()
218 dialog.hide()
219 else:
220 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
221 buttons = BUTTONSTYPE_OK,
222 message_format =
223 "Failed to connect to the MAVA website.")
224 dialog.format_secondary_markup("Try again in a few minutes.")
225 dialog.run()
226 dialog.hide()
227
228#-----------------------------------------------------------------------------
229
230class FlightSelectionPage(Page):
231 """The page to select the flight."""
232 def __init__(self, wizard):
233 """Construct the flight selection page."""
234 super(FlightSelectionPage, self).__init__(wizard, "Flight selection",
235 "Select the flight you want "
236 "to perform.")
237
238
239 self._listStore = gtk.ListStore(str, str, str, str)
240 self._flightList = gtk.TreeView(self._listStore)
241 column = gtk.TreeViewColumn("Flight no.", gtk.CellRendererText(),
242 text = 1)
243 column.set_expand(True)
244 self._flightList.append_column(column)
245 column = gtk.TreeViewColumn("Departure time [UTC]", gtk.CellRendererText(),
246 text = 0)
247 column.set_expand(True)
248 self._flightList.append_column(column)
249 column = gtk.TreeViewColumn("From", gtk.CellRendererText(),
250 text = 2)
251 column.set_expand(True)
252 self._flightList.append_column(column)
253 column = gtk.TreeViewColumn("To", gtk.CellRendererText(),
254 text = 3)
255 column.set_expand(True)
256 self._flightList.append_column(column)
257
258 flightSelection = self._flightList.get_selection()
259 flightSelection.connect("changed", self._selectionChanged)
260
261 scrolledWindow = gtk.ScrolledWindow()
262 scrolledWindow.add(self._flightList)
263 scrolledWindow.set_size_request(400, -1)
264 scrolledWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
265 else gtk.POLICY_AUTOMATIC,
266 gtk.PolicyType.ALWAYS if pygobject
267 else gtk.POLICY_ALWAYS)
268
269 alignment = gtk.Alignment(xalign = 0.5, yalign = 0.0, xscale = 0.0, yscale = 1.0)
270 alignment.add(scrolledWindow)
271
272 self.setMainWidget(alignment)
273
274 self._button = self.addButton(gtk.STOCK_GO_FORWARD, default = True)
275 self._button.set_use_stock(True)
276 self._button.set_sensitive(False)
277
278 self._activated = False
279
280 def activate(self):
281 """Fill the flight list."""
282 if not self._activated:
283 for flight in self._wizard.loginResult.flights:
284 self._listStore.append([str(flight.departureTime),
285 flight.callsign,
286 flight.departureICAO,
287 flight.arrivalICAO])
288 self._activated = True
289
290 def _selectionChanged(self, selection):
291 """Called when the selection is changed."""
292 self._button.set_sensitive(selection.count_selected_rows()==1)
293
294#-----------------------------------------------------------------------------
295
296class Wizard(gtk.VBox):
297 """The flight wizard."""
298 def __init__(self, gui):
299 """Construct the wizard."""
300 super(Wizard, self).__init__()
301
302 self.gui = gui
303
304 self._pages = []
305 self._currentPage = None
306
307 self._pages.append(LoginPage(self))
308 self._pages.append(FlightSelectionPage(self))
309
310 self._loginResult = None
311
312 self.setCurrentPage(0)
313
314 @property
315 def loginResult(self):
316 """Get the login result."""
317 return self._loginResult
318
319 def setCurrentPage(self, index):
320 """Set the current page to the one with the given index."""
321 assert index < len(self._pages)
322
323 if self._currentPage is not None:
324 self.remove(self._pages[self._currentPage])
325
326 self._currentPage = index
327 self.add(self._pages[index])
328 self._pages[index].activate()
329 self.show_all()
330
331 def nextPage(self):
332 """Go to the next page."""
333 self.setCurrentPage(self._currentPage + 1)
334 self.grabDefault()
335
336 def grabDefault(self):
337 """Make the default button of the current page the default."""
338 self._pages[self._currentPage].grabDefault()
339
340#-----------------------------------------------------------------------------
341
Note: See TracBrowser for help on using the repository browser.