Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: client/bin/factory_ui

Issue 3226005: Refactory UI to grab shortcut keys, and tests to not look for triggers. (Closed) Base URL: http://git.chromium.org/git/autotest.git
Patch Set: Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « client/bin/factory.py ('k') | client/bin/factory_ui_lib.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # 2 #
3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 7
8 # DESCRIPTION : 8 # DESCRIPTION :
9 # 9 #
10 # This UI is intended to be used by the factory autotest suite to 10 # This UI is intended to be used by the factory autotest suite to
(...skipping 10 matching lines...) Expand all
21 # associated keyboard shortcuts. As tests are run, their status is 21 # associated keyboard shortcuts. As tests are run, their status is
22 # color-indicated to the operator -- greyed out means untested, yellow 22 # color-indicated to the operator -- greyed out means untested, yellow
23 # means active, green passed and red failed. 23 # means active, green passed and red failed.
24 24
25 25
26 import gobject 26 import gobject
27 import gtk 27 import gtk
28 import imp 28 import imp
29 import os 29 import os
30 import pango 30 import pango
31 import signal
31 import subprocess 32 import subprocess
32 import sys 33 import sys
33 import time 34 import time
34 35
35 import common 36 import common
36 import factory 37 import factory
37 import factory_ui_lib as ful 38 import factory_ui_lib as ful
38 39
40 from gtk import gdk
41 from Xlib import X
42 from Xlib.display import Display as X_Display
43
39 44
40 # These definitions are expose these classes directly into this 45 # These definitions are expose these classes directly into this
41 # namespace, so that the test_list that is sent from the control file 46 # namespace, so that the test_list that is sent from the control file
42 # can have cleaner syntax. These are done in this fashion, as opposed 47 # can have cleaner syntax. These are done in this fashion, as opposed
43 # to "from factory import <class>" to work-around Python namespace 48 # to "from factory import <class>" to work-around Python namespace
44 # wackiness -- the from syntax does not work, creating new classes. 49 # wackiness -- the from syntax does not work, creating new classes.
45 OperatorTest = factory.OperatorTest 50 OperatorTest = factory.OperatorTest
46 InformationScreen = factory.InformationScreen 51 InformationScreen = factory.InformationScreen
47 AutomatedSequence = factory.AutomatedSequence 52 AutomatedSequence = factory.AutomatedSequence
48 AutomatedSubTest = factory.AutomatedSubTest 53 AutomatedSubTest = factory.AutomatedSubTest
49 AutomatedRebootSubTest = factory.AutomatedRebootSubTest 54 AutomatedRebootSubTest = factory.AutomatedRebootSubTest
50 55
51 56
52 _SEP_COLOR = gtk.gdk.color_parse('grey50')
53
54 _LABEL_EN_SIZE = (170, 35) 57 _LABEL_EN_SIZE = (170, 35)
55 _LABEL_ZW_SIZE = (70, 35) 58 _LABEL_ZW_SIZE = (70, 35)
56 _LABEL_EN_FONT = pango.FontDescription('courier new extra-condensed 16') 59 _LABEL_EN_FONT = pango.FontDescription('courier new extra-condensed 16')
57 _LABEL_ZW_FONT = pango.FontDescription('normal 12') 60 _LABEL_ZW_FONT = pango.FontDescription('normal 12')
58 _LABEL_T_SIZE = (30, 35) 61 _LABEL_T_SIZE = (30, 35)
59 _LABEL_T_FONT = pango.FontDescription('courier new italic ultra-condensed 10') 62 _LABEL_T_FONT = pango.FontDescription('courier new italic ultra-condensed 10')
60 _LABEL_UNTESTED_FG = gtk.gdk.color_parse('grey40') 63 _LABEL_UNTESTED_FG = gtk.gdk.color_parse('grey40')
61 _LABEL_TROUGH_COLOR = gtk.gdk.color_parse('grey20') 64 _LABEL_TROUGH_COLOR = gtk.gdk.color_parse('grey20')
62 _LABEL_STATUS_SIZE = (140, 30) 65 _LABEL_STATUS_SIZE = (140, 30)
63 _LABEL_STATUS_FONT = pango.FontDescription( 66 _LABEL_STATUS_FONT = pango.FontDescription(
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 def update(self, status): 156 def update(self, status):
154 if status == ful.UNTESTED: 157 if status == ful.UNTESTED:
155 return 158 return
156 self.label_status.set_text(status) 159 self.label_status.set_text(status)
157 self.label_status.modify_fg(gtk.STATE_NORMAL, ful.LABEL_COLORS[status]) 160 self.label_status.modify_fg(gtk.STATE_NORMAL, ful.LABEL_COLORS[status])
158 self.queue_draw() 161 self.queue_draw()
159 162
160 163
161 class UiState(): 164 class UiState():
162 165
163 def __init__(self, window, status_map, test_widget_box): 166 def __init__(self, status_map, test_widget_box):
164 167
165 def make_empty_test_label_widget(): 168 def make_empty_test_label_widget():
166 label_box = gtk.EventBox() 169 label_box = gtk.EventBox()
167 label_box.modify_bg(gtk.STATE_NORMAL, ful.BLACK) 170 label_box.modify_bg(gtk.STATE_NORMAL, ful.BLACK)
168 label = ful.make_label('no active test', font=_OTHER_LABEL_FONT, 171 label = ful.make_label('no active test', font=_OTHER_LABEL_FONT,
169 alignment=(0.5, 0.5)) 172 alignment=(0.5, 0.5))
170 label_box.add(label) 173 label_box.add(label)
171 return label_box 174 return label_box
172 175
173 def make_automated_seq_label_widget(subtest_list): 176 def make_automated_seq_label_widget(subtest_list):
174 vbox = gtk.VBox() 177 vbox = gtk.VBox()
175 vbox.set_spacing(0) 178 vbox.set_spacing(0)
176 for subtest in subtest_list: 179 for subtest in subtest_list:
177 label_box = SubTestLabelBox(subtest) 180 label_box = SubTestLabelBox(subtest)
178 status_map.set_label_box(subtest, label_box) 181 status_map.set_label_box(subtest, label_box)
179 vbox.pack_start(status_map.lookup_label_box(subtest), 182 vbox.pack_start(status_map.lookup_label_box(subtest),
180 False, False) 183 False, False)
181 return vbox 184 return vbox
182 185
183 self._window = window
184 self._status_map = status_map 186 self._status_map = status_map
185 self._test_widget_box = test_widget_box 187 self._test_widget_box = test_widget_box
186 self._empty_test_widget = make_empty_test_label_widget() 188 self._empty_test_widget = make_empty_test_label_widget()
187 self._active_test_widget = self._empty_test_widget 189 self._active_test_widget = self._empty_test_widget
188 self.active_test = None 190 self.active_test = None
189 191
190 self._test_widget_box.add(self._empty_test_widget) 192 self._test_widget_box.add(self._empty_test_widget)
191 193
192 self._automated_seq_widget_map = dict( 194 self._automated_seq_widget_map = dict(
193 (t, make_automated_seq_label_widget(t.subtest_list)) 195 (t, make_automated_seq_label_widget(t.subtest_list))
(...skipping 11 matching lines...) Expand all
205 return 207 return
206 factory.log('UI active test -> %s' % 208 factory.log('UI active test -> %s' %
207 self._status_map.test_db.get_unique_details(test)) 209 self._status_map.test_db.get_unique_details(test))
208 self.active_test = test 210 self.active_test = test
209 self._test_widget_box.remove(self._active_test_widget) 211 self._test_widget_box.remove(self._active_test_widget)
210 active_widget = (test in self._status_map.test_db.seq_test_set 212 active_widget = (test in self._status_map.test_db.seq_test_set
211 and self._automated_seq_widget_map[test] 213 and self._automated_seq_widget_map[test]
212 or self._empty_test_widget) 214 or self._empty_test_widget)
213 self._test_widget_box.add(active_widget) 215 self._test_widget_box.add(active_widget)
214 self._active_test_widget = active_widget 216 self._active_test_widget = active_widget
215 self._window.show_all() 217 self._test_widget_box.show_all()
216
217
218 def make_hsep(width=1):
219 frame = gtk.EventBox()
220 frame.set_size_request(-1, width)
221 frame.modify_bg(gtk.STATE_NORMAL, _SEP_COLOR)
222 return frame
223
224
225 def make_vsep(width=1):
226 frame = gtk.EventBox()
227 frame.set_size_request(width, -1)
228 frame.modify_bg(gtk.STATE_NORMAL, _SEP_COLOR)
229 return frame
230 218
231 219
232 def refresh_status(status_map, ui_state): 220 def refresh_status(status_map, ui_state):
233 status_map.read_new_data() 221 status_map.read_new_data()
234 active_test = status_map.get_active_top_level_test() 222 active_test = status_map.get_active_top_level_test()
235 ui_state.set_active_test(active_test) 223 ui_state.set_active_test(active_test)
236 return True 224 return True
237 225
238 226
239 def main(): 227 def grab_shortcut_keys(kbd_shortcut_set, control_pid):
228 disp = X_Display()
229 root = disp.screen().root
230
231 # We want to receive KeyPress events
232 root.change_attributes(event_mask = X.KeyPressMask)
233
234 keycode_map = {}
235 for shortcut in kbd_shortcut_set:
236 keysym = gdk.keyval_from_name(shortcut)
237 keycode = disp.keysym_to_keycode(keysym)
238 keycode_map[keycode] = shortcut
239 root.grab_key(keycode, X.ControlMask, 1,
240 X.GrabModeAsync, X.GrabModeAsync)
241
242 # This flushes the XGrabKey calls to the server.
243 for x in range(0, root.display.pending_events()):
244 root.display.next_event()
245
246 def handle_xevent(src, cond, xhandle=root.display,
247 keycode_map=keycode_map,
248 control_pid=control_pid):
249 for i in range(0, xhandle.pending_events()):
250 xevent = xhandle.next_event()
251 if xevent.type == X.KeyPress:
252 keycode = xevent.detail
253 factory.log_shared_data('activated_kbd_shortcut',
254 keycode_map[keycode])
255 os.kill(control_pid, signal.SIGUSR1)
256 return True
257
258 gobject.io_add_watch(root.display, gobject.IO_IN, handle_xevent)
259
260
261 def main(test_list, status_file_path, control_pid):
240 '''This process is launched by the autotest suite_Factory control 262 '''This process is launched by the autotest suite_Factory control
241 process. Communication with this process is an exchange of well 263 process, which should be identified by the <control pid> cmdline
242 formed python expressions over stdin and stdout. Basically 264 argument. When operators press keyboard shortcuts, the shortcut
243 sending wraps arguments in a call to repr() and recv calls eval() 265 value is logged with log_shared_data() and a SIGUSR1 is sent to
244 to re-generate the python data.''' 266 the control program.'''
245
246 def control_recv():
247 return eval(sys.stdin.readline().rstrip())
248
249 def control_send(x):
250 print repr(x)
251 sys.stdout.flush()
252
253 # On startup, get the list of tests to run (in order) and the
254 # autotest status file path.
255 factory.log('pulling control info')
256 test_list = control_recv()
257 status_file_path = control_recv()
258 267
259 status_map = factory.StatusMap(test_list, status_file_path) 268 status_map = factory.StatusMap(test_list, status_file_path)
260 269
261 window = gtk.Window(gtk.WINDOW_TOPLEVEL) 270 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
262 window.connect('destroy', lambda _: gtk.main_quit()) 271 window.connect('destroy', lambda _: gtk.main_quit())
263 window.modify_bg(gtk.STATE_NORMAL, ful.BLACK) 272 window.modify_bg(gtk.STATE_NORMAL, ful.BLACK)
264 273
265 screen = window.get_screen() 274 screen = window.get_screen()
275 if (screen is None):
276 log('ERROR: communication with the X server is not working, ' +
277 'could not find a working screen. UI exiting.')
278 sys.exit(1)
279
266 screen_size = (screen.get_width(), screen.get_height()) 280 screen_size = (screen.get_width(), screen.get_height())
267 window.set_size_request(*screen_size) 281 window.set_size_request(*screen_size)
268 282
269 label_trough = gtk.VBox() 283 label_trough = gtk.VBox()
270 label_trough.set_spacing(0) 284 label_trough.set_spacing(0)
271 285
272 rhs_box = gtk.EventBox() 286 rhs_box = gtk.EventBox()
273 rhs_box.modify_bg(gtk.STATE_NORMAL, _LABEL_TROUGH_COLOR) 287 rhs_box.modify_bg(gtk.STATE_NORMAL, _LABEL_TROUGH_COLOR)
274 rhs_box.add(label_trough) 288 rhs_box.add(label_trough)
275 289
276 console_box = gtk.EventBox() 290 console_box = gtk.EventBox()
277 console_box.set_size_request(-1, 180) 291 console_box.set_size_request(-1, 180)
278 console_box.modify_bg(gtk.STATE_NORMAL, ful.BLACK) 292 console_box.modify_bg(gtk.STATE_NORMAL, ful.BLACK)
279 293
280 test_widget_box = gtk.Alignment(xalign=0.5, yalign=0.5) 294 test_widget_box = gtk.Alignment(xalign=0.5, yalign=0.5)
281 test_widget_box.set_size_request(-1, -1) 295 test_widget_box.set_size_request(-1, -1)
282 296
283 ui_state = UiState(window, status_map, test_widget_box) 297 ui_state = UiState(status_map, test_widget_box)
284 298
285 lhs_box = gtk.VBox() 299 lhs_box = gtk.VBox()
286 lhs_box.pack_end(console_box, False, False) 300 lhs_box.pack_end(console_box, False, False)
287 lhs_box.pack_start(test_widget_box) 301 lhs_box.pack_start(test_widget_box)
288 lhs_box.pack_start(make_hsep(3), False, False) 302 lhs_box.pack_start(ful.make_hsep(3), False, False)
289 303
290 base_box = gtk.HBox() 304 base_box = gtk.HBox()
291 base_box.pack_end(rhs_box, False, False) 305 base_box.pack_end(rhs_box, False, False)
292 base_box.pack_end(make_vsep(3), False, False) 306 base_box.pack_end(ful.make_vsep(3), False, False)
293 base_box.pack_start(lhs_box) 307 base_box.pack_start(lhs_box)
294 308
295 window.connect('key-release-event', handle_key_release_event) 309 window.connect('key-release-event', handle_key_release_event)
296 window.add_events(gtk.gdk.KEY_RELEASE_MASK) 310 window.add_events(gtk.gdk.KEY_RELEASE_MASK)
297 311
298 gobject.timeout_add(_STATUS_REFRESH_MS, refresh_status, 312 gobject.timeout_add(_STATUS_REFRESH_MS, refresh_status,
299 status_map, ui_state) 313 status_map, ui_state)
300 314
301 for test in test_list: 315 for test in test_list:
302 label_box = TestLabelBox(test) 316 label_box = TestLabelBox(test)
303 status_map.set_label_box(test, label_box) 317 status_map.set_label_box(test, label_box)
304 label_trough.pack_start(label_box, False, False) 318 label_trough.pack_start(label_box, False, False)
305 label_trough.pack_start(make_hsep(), False, False) 319 label_trough.pack_start(ful.make_hsep(), False, False)
306 320
307 window.add(base_box) 321 window.add(base_box)
308 window.show_all() 322 window.show_all()
309 323
324 grab_shortcut_keys(status_map.test_db.kbd_shortcut_set, control_pid)
325
310 ful.hide_cursor(window.window) 326 ful.hide_cursor(window.window)
311 327
312 test_widget_allocation = test_widget_box.get_allocation() 328 test_widget_allocation = test_widget_box.get_allocation()
313 test_widget_size = (test_widget_allocation.width, 329 test_widget_size = (test_widget_allocation.width,
314 test_widget_allocation.height) 330 test_widget_allocation.height)
315 factory.log('test_widget_size = %s' % repr(test_widget_size)) 331 factory.log_shared_data('test_widget_size', test_widget_size)
316 control_send(test_widget_size)
317 332
318 console = Console(console_box.get_allocation()) 333 console = Console(console_box.get_allocation())
319 334
320 factory.log('factory_ui setup done, starting gtk.main()...') 335 factory.log('factory_ui setup done, starting gtk.main()...')
321 336
322 gtk.main() 337 gtk.main()
323 338
324 factory.log('factory_ui gtk.main() finished, exiting.') 339 factory.log('factory_ui gtk.main() finished, exiting.')
325 340
326 if __name__ == '__main__': 341 if __name__ == '__main__':
327 main() 342
343 if len(sys.argv) != 4:
344 print ('usage: %s <test list path> <status file path> <control pid>' %
345 sys.argv[0])
346 test_list_path, status_file_path, control_pid_str = sys.argv[1:]
347 control_pid = int(control_pid_str)
348
349 execfile(test_list_path)
350
351 main(TEST_LIST, status_file_path, control_pid)
OLDNEW
« no previous file with comments | « client/bin/factory.py ('k') | client/bin/factory_ui_lib.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698