Beispiel #1
0
 def run(self):
     try:
         webdriver = selenium_webdriver.Firefox()
         with self.lock:
             print "Starting", self.name
         while True:
             try:
                 suite_name, suite = self.q.get_nowait()
                 log = lambda message: self.log(suite_name, message)
                 for ui_map, actions in suite:
                     # log the UI map name if in debug mode
                     if self.store['debug']:
                         log(ui_map)
                     # create the page and test it
                     page = Page(
                         suite_name,
                         actions,
                         webdriver,
                         self.store,
                         self.log
                     )
                     page.test()
                 # suite is complete: success!
                 log("Suite Passed")
             except Queue.Empty:
                 # nothing left to consume
                 break
             except WebDriverException, e:
                 # Houston, we have a problem
                 try:
                     log("X Page Failed: %s" % ui_map)
                     log("X %s" % e)
                     log("X Suite Failed: %s" % suite_name)
                 except:
                     # these variables (log, ui_map, suite_name)
                     # may not be assigned yet on CTL-C
                     pass
     # the following exceptions occur on CTL-C
     except KeyboardInterrupt:
         pass
     except URLError:
         pass
     except BadStatusLine:
         pass
     except Exception, e:
         print "Exception:", e
         print e.__class__
         print_exc()
class ICanReadActivity(activity.Activity):
    ''' ICanRead Reading guide '''
    def __init__(self, handle):
        ''' Initialize the toolbars and the reading board '''
        super(ICanReadActivity, self).__init__(handle)
        self.reading = False
        self.testing = False
        self.recording = False
        self.grecord = None
        self.datapath = get_path(activity, 'instance')

        if 'LANG' in os.environ:
            language = os.environ['LANG'][0:2]
        elif 'LANGUAGE' in os.environ:
            language = os.environ['LANGUAGE'][0:2]
        else:
            language = 'es'  # default to Spanish

        # FIXME: find some reasonable default situation
        language = 'es'

        if os.path.exists(os.path.join('~', 'Activities',
                                       'ICanRead.activity')):
            self._lessons_path = os.path.join('~', 'Activities',
                                              'ICanRead.activity', 'lessons',
                                              language)
        else:
            self._lessons_path = os.path.join('.', 'lessons', language)

        self._images_path = self._lessons_path.replace('lessons', 'images')
        self._sounds_path = self._lessons_path.replace('lessons', 'sounds')
        self._setup_toolbars()

        # Create a canvas
        self.scrolled_window = gtk.ScrolledWindow()
        self.set_canvas(self.scrolled_window)
        self.scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        self.scrolled_window.show()
        canvas = gtk.DrawingArea()
        width = gtk.gdk.screen_width()
        height = int(gtk.gdk.screen_height() * 2.75)
        canvas.set_size_request(width, height)
        self.scrolled_window.add_with_viewport(canvas)
        canvas.show()

        self._level = self._levels_combo.get_active()
        self._page = Page(canvas,
                          self._lessons_path,
                          self._images_path,
                          self._sounds_path,
                          self._levels[self._level],
                          parent=self)

        # Restore state from Journal or start new session
        if 'page' in self.metadata:
            self._restore()
        else:
            self._page.new_page()

        # Set up sound combo box
        self._reload_sound_combo()
        self._selected_sound = self.sounds_combo.get_active()

    def _setup_toolbars(self):
        ''' Setup the toolbars.. '''

        # no sharing
        self.max_participants = 1

        if _HAVE_TOOLBOX:
            toolbox = ToolbarBox()

            # Activity toolbar
            activity_button = ActivityToolbarButton(self)

            toolbox.toolbar.insert(activity_button, 0)
            activity_button.show()

            lesson_toolbar = gtk.Toolbar()
            lesson_toolbar_button = ToolbarButton(label=_('Select a lesson'),
                                                  page=lesson_toolbar,
                                                  icon_name='text-x-generic')
            record_toolbar = gtk.Toolbar()
            record_toolbar_button = ToolbarButton(label=_('Record a sound'),
                                                  page=record_toolbar,
                                                  icon_name='media-audio')

            self.set_toolbar_box(toolbox)
            toolbox.show()
            lesson_toolbar_button.show()
            toolbox.toolbar.insert(lesson_toolbar_button, -1)
            record_toolbar_button.show()
            toolbox.toolbar.insert(record_toolbar_button, -1)
            primary_toolbar = toolbox.toolbar

        else:
            # Use pre-0.86 toolbar design
            primary_toolbar = gtk.Toolbar()
            lesson_toolbar = gtk.Toolbar()
            record_toolbar = gtk.Toolbar()
            toolbox = activity.ActivityToolbox(self)
            self.set_toolbox(toolbox)
            toolbox.add_toolbar(_('Page'), primary_toolbar)
            toolbox.show()
            toolbox.add_toolbar(_('Lesson'), lesson_toolbar)
            toolbox.show()
            toolbox.add_toolbar(_('Record'), record_toolbar)
            toolbox.show()
            toolbox.set_current_toolbar(1)

            # no sharing
            if hasattr(toolbox, 'share'):
                toolbox.share.hide()
            elif hasattr(toolbox, 'props'):
                toolbox.props.visible = False

        _label_factory(_('Select a lesson') + ':', lesson_toolbar)
        self._levels = self._get_levels(self._lessons_path)
        self._levels_combo = _combo_factory(self._levels, _('Select a lesson'),
                                            lesson_toolbar, self._levels_cb)

        _separator_factory(lesson_toolbar)

        self._lesson_button = _button_factory(
            'load-from-journal', _('Load a new lesson from the Journal'),
            self._lesson_cb, lesson_toolbar)

        _separator_factory(lesson_toolbar)

        self._create_lesson_button = _button_factory('view-source-insensitive',
                                                     _('Create a new lesson'),
                                                     self._create_lesson_cb,
                                                     lesson_toolbar)

        self._save_lesson_button = _button_factory(
            'save-to-journal-insensitive', _('Nothing to save'),
            self._save_lesson_cb, lesson_toolbar)

        self._sounds = self._get_sounds()
        self.sounds_combo = _combo_factory(self._sounds, _('Record a sound'),
                                           record_toolbar, self._sounds_cb)

        _separator_factory(record_toolbar)

        _label_factory(_('Record a sound') + ':', record_toolbar)
        self._record_lesson_button = _button_factory('media-record',
                                                     _('Start recording'),
                                                     self._record_lesson_cb,
                                                     record_toolbar)

        _separator_factory(record_toolbar)

        self._playback_button = _button_factory(
            'media-playback-start-insensitive', _('Nothing to play'),
            self._playback_recording_cb, record_toolbar)

        self._save_recording_button = _button_factory('sound-save-insensitive',
                                                      _('Nothing to save'),
                                                      self._save_recording_cb,
                                                      record_toolbar)

        _separator_factory(primary_toolbar)

        self._list_button = _button_factory('letter-list', _('Letter list'),
                                            self._list_cb, primary_toolbar)

        self._prev_page_button = _button_factory('previous-letter-insensitive',
                                                 _('Previous letter'),
                                                 self._prev_page_cb,
                                                 primary_toolbar)

        self._next_page_button = _button_factory('next-letter',
                                                 _('Next letter'),
                                                 self._next_page_cb,
                                                 primary_toolbar)

        _separator_factory(primary_toolbar)

        self._read_button = _button_factory('read',
                                            _('Read the sounds one at a time'),
                                            self._read_cb, primary_toolbar)

        _separator_factory(primary_toolbar)

        self._test_button = _button_factory('go-right', _('Self test'),
                                            self._test_cb, primary_toolbar)

        self.status = _label_factory('', primary_toolbar)

        if _HAVE_TOOLBOX:
            _separator_factory(toolbox.toolbar, False, True)

            stop_button = StopButton(self)
            stop_button.props.accelerator = '<Ctrl>q'
            toolbox.toolbar.insert(stop_button, -1)
            stop_button.show()
        lesson_toolbar.show()
        record_toolbar.show()

    def _levels_cb(self, combobox=None):
        ''' The combo box has changed. '''
        if hasattr(self, '_levels_combo'):
            i = self._levels_combo.get_active()
            if i != -1 and i != self._level:
                self._level = i
                # TODO: levels stored in Journal have a different path
                try:
                    self._page.load_level(
                        os.path.join(self._lessons_path,
                                     self._levels[self._level] + '.csv'))
                except IndexError:
                    print "couldn't restore level %s" % (
                        self.metadata['level'])
                    self._levels_combo.set_active(0)
            self._page.page = 0
            self._page.new_page()
            print 'reloading sound combo box with level sounds'
            self._reload_sound_combo()
            self._selected_sound = self.sounds_combo.get_active()
        return

    def _lesson_cb(self, button=None):
        ''' Chose a lesson file from the Sugar Journal. '''
        chooser(self, '', self._load_lesson)
        return

    def _create_lesson_cb(self, button=None):
        ''' Chose a lesson file from the Sugar Journal. '''
        # Do something here:
        #    We need a place to add and edit text
        #    We need a place to select phonemes and assign colors
        return

    def _save_lesson_cb(self, button=None):
        ''' Save a lesson file to the Sugar Journal. '''
        if self._nothing_to_save:
            return
        # Do something here
        return

    def _sounds_cb(self, combobox=None):
        ''' The combo box has changed. '''
        if hasattr(self, 'sounds_combo'):
            self._selected_sound = self.sounds_combo.get_active()

    def _list_cb(self, button=None):
        ''' Letter list '''
        self._page.page_list()
        self.reading = False

    def _prev_page_cb(self, button=None):
        ''' Start a new letter. '''
        if self._page.page > 0:
            self._page.page -= 1
        if self._page.page == 0:
            self._prev_page_button.set_icon('previous-letter-insensitive')
        self._page.new_page()
        self.reading = False
        self.testing = False
        self._read_button.set_icon('read')
        self._read_button.set_tooltip(_('Show letter'))
        self._test_button.set_icon('go-right')
        self._test_button.set_tooltip(_('Self test'))

    def _next_page_cb(self, button=None):
        ''' Start a new letter. '''
        self._page.page += 1
        self._page.new_page()
        self.reading = False
        self.testing = False
        self._read_button.set_icon('read')
        self._read_button.set_tooltip(_('Show letter'))
        self._prev_page_button.set_icon('previous-letter')
        self._test_button.set_icon('go-right')
        self._test_button.set_tooltip(_('Self test'))

    def _read_cb(self, button=None):
        ''' Start a new page. '''
        if not self.reading:
            self.reading = True
            self.testing = False
            self._page.read()
            self._read_button.set_icon('listen')
            self._read_button.set_tooltip(_('Show letter'))
            self._test_button.set_icon('go-right')
            self._test_button.set_tooltip(_('Self test'))
        else:
            self.reading = False
            self.testing = False
            self._page.reload()
            self._read_button.set_icon('read')
            self._read_button.set_tooltip(_('Read the sounds one at a time'))
            self._test_button.set_icon('go-right')
            self._test_button.set_tooltip(_('Self test'))

    def _test_cb(self, button=None):
        ''' Start a test. '''
        if not self.testing:
            self.testing = True
            self._page.test()
            self._test_button.set_icon('go-left')
            self._test_button.set_tooltip(_('Return to reading'))
        else:
            self.testing = False
            self._page.reload()
            self._test_button.set_icon('go-right')
            self._test_button.set_tooltip(_('Self test'))

    def write_file(self, file_path):
        ''' Write status to the Journal '''
        if not hasattr(self, '_page'):
            return
        self.metadata['page'] = str(self._page.page)
        self.metadata['level'] = str(self._level)

    def _restore(self):
        ''' Load up cards until we get to the page we stopped on. '''
        if 'level' in self.metadata:
            level = int(self.metadata['level'])
            self._level = level
            self._levels_combo.set_active(level)
            try:
                self._page.load_level(
                    os.path.join(self._lessons_path,
                                 self._levels[self._level] + '.csv'))
            except IndexError:
                print "couldn't restore level %s" % (self.metadata['level'])
                self._levels_combo.set_active(0)
            self._page.page = 0
            self._page.new_page()
        if 'page' in self.metadata:
            page = int(self.metadata['page'])
            for _i in range(page):
                self._next_page_cb()

    def _get_levels(self, path):
        ''' Look for level files in lessons directory. '''
        level_files = []
        if path is not None:
            candidates = os.listdir(path)
            for filename in candidates:
                if not self._skip_this_file(filename):
                    level_files.append(filename.split('.')[0])
        level_files.reverse()
        return level_files

    def _get_sounds(self):
        ''' Look for sounds list. '''
        if hasattr(self, '_page'):
            sound_list = self._page.get_phrase_list()
            for i in range(len(sound_list)):
                sound_list[i] = sound_list[i].replace('(', '')
                sound_list[i] = sound_list[i].replace(')', '')
            return sound_list
        else:
            return ([])

    def _reload_sound_combo(self):
        ''' Rebuild sounds combobox. '''
        self.sounds_combo.remove_all()  # Remove old list.
        self._sounds = self._get_sounds()
        for i, sound in enumerate(self._sounds):
            self.sounds_combo.append_item(i, sound.lower(), None)
        self.sounds_combo.set_active(self._page.page)

    def _record_lesson_cb(self, button=None):
        if self.grecord is None:
            self.grecord = Grecord(self)
        if self.recording:
            self.grecord.stop_recording_audio()
            self.recording = False
            self._record_lesson_button.set_icon('media-record')
            self._record_lesson_button.set_tooltip(_('Start recording'))
            self._playback_button.set_icon('media-playback-start')
            self._playback_button.set_tooltip(_('Play recording'))
            self._save_recording_button.set_icon('sound-save')
            self._save_recording_button.set_tooltip(_('Save recording'))
        else:
            self.grecord.record_audio()
            self.recording = True
            self._record_lesson_button.set_icon('media-recording')
            self._record_lesson_button.set_tooltip(_('Stop recording'))

    def _playback_recording_cb(self, button=None):
        play_audio_from_file(self._page,
                             os.path.join(self.datapath, 'output.ogg'))
        return

    def _save_recording_cb(self, button=None):
        savename = self._sounds[self._selected_sound].lower() + '.ogg'
        if os.path.exists(os.path.join(self.datapath, 'output.ogg')):
            dsobject = datastore.create()
            dsobject.metadata['title'] = savename
            dsobject.metadata['icon-color'] = \
                profile.get_color().to_string()
            dsobject.metadata['mime_type'] = 'audio/ogg'
            dsobject.set_file_path(os.path.join(self.datapath, 'output.ogg'))
            datastore.write(dsobject)
            dsobject.destroy()
        return

    def _skip_this_file(self, filename):
        ''' Ignore tmp files '''
        if filename[0] in '#.' or filename[-1] == '~':
            return True
        return False

    def _load_lesson(self, dsobject):
        # TODO: load level and set combo to proper entry
        # save levels for latter restoring
        print dsobject.metadata['title']
        self._levels_combo.append_item(0, dsobject.metadata['title'], None)
        self._levels_combo.set_active(0)
        self._page.load_level(dsobject.file_path)
        self._page.page = 0
        self._page.new_page()