# python import import logging, os, threading, time from functools import partial from gettext import gettext as _ # gtk import import gtk, glib # ... gtk.gdk.threads_init() # sugar import from sugar.activity import activity # atoidejouer import from atoidejouer.db import story from atoidejouer.ui import screen, toolbar from atoidejouer.tools import config, storage # get application logger logger = logging.getLogger('atoidejouer') logger.setLevel(logging.DEBUG) class ThreadAnim(threading.Thread): def __init__(self, activity_): # init parent threading.Thread.__init__(self) # main flag self._die = False self._pause = True # main vars self._activity = activity_ self._time = 0 # start right now self.start() def pause(self, stop=False): self._pause = True # reset time on stop if stop is True: self._time = 0 else: self.set_time() def play(self): self._pause = False def kill(self): self._die = True def set_time(self, time_=None, rate=0, pause=None, key=None): # ensure time time_ = self._time if time_ is None else time_ # update time self._time = time_ + rate # get current screen _current_screen = self._activity.get_current_screen() # update scene if hasattr(_current_screen, 'refresh'): _current_screen.refresh(key=key) # update slider if self._activity._toolbar: self._activity._toolbar.refresh(self._time) # pause if pause and not self._pause: self._activity._toolbar.pause() # set pause self._pause = self._pause if pause is None else pause def run(self): while self._die is False: # get current rate _rate = config.Config().get_rate_value() time.sleep(_rate) # do pause if self._time >= self._activity.max_time\ and self._pause is False: self._time = self._activity.max_time self.set_time(pause=True) continue # .. do nothing elif self._pause is True: continue # .. do something else: self.set_time(rate=_rate) def _toolbar_changed(toolbox, page, activity_): """Catch toolbox activity tab focus to display settings screen. """ # is the activity tab? if page == 0\ and activity_._updating is False: # show the activity screen activity_.change_screen('activity') else: pass # propagate it return True class AToiDeJouerActivity(activity.Activity): def __init__(self, handle): # init parent activity.Activity.__init__(self, handle) # init activity working folder storage.init_activity_files() # db init story.DB(create=True) # .. self.max_participants = 1 # get toolbox self._toolbox = activity.ActivityToolbox(self) # add tool bars self.set_toolbox(self._toolbox) # keep thread & screen self._thread = None self._screens = dict() self._current = None self._previous = None self._splash = None self._handler_id = None self.max_time = 0 # show self._toolbox.show() self._toolbar = None # set toolbox cb self._updating = False self._toolbox.connect('current-toolbar-changed', _toolbar_changed, self) # do anim self._thread = ThreadAnim(self) # get bundle path _path = os.path.join(storage.BUND, 'static', 'ext', 'db') # file by file has_included_stories = False for _f in os.listdir(_path): if _f == 'blank': continue has_included_story = True break # show the activity screen if has_included_stories: self.change_screen('activity') # show edit screen if nothing to work on else: self.change_screen('edit') def update_max_time(self): self.max_time = story.DB().get_max('time') def get_current_screen(self): # little check if self._current in self._screens: return self._screens[self._current] else: return None def set_current_screen(self, name, screen): # udpate current name self._previous = self._current self._current = name # little check self.add_screen(name, screen) def _update_slider(self): # sync time if self._thread is None: pass else: self._toolbar.update_slider(self._thread._time, self._thread._pause) def add_screen(self, name, screen): if name in self._screens: pass else: self._screens[name] = screen def remove_screen(self, name): if name in self._screens: self._screens[name].destroy() del self._screens[name] else: pass def has_screen(self, name): return name in self._screens def get_screen(self, name): if name in self._screens: return self._screens[name] else: return None def change_screen(self, name): self._updating = True # update current screen name self._previous = self._current self._current = name # already exist if self._current == 'edit': if self._splash is None: self._splash = screen.Splash(self) else: self._splash._show() glib.idle_add(self.__idle_change) else: self.__idle_change() def __idle_change(self): # init toolbar if self._toolbar: self._toolbar.pause() self._toolbox.remove_toolbar(1) if self._current != 'activity': self._toolbar = toolbar.Toolbar(self, self._current) self._toolbox.set_current_toolbar(1) # help specific - need rebuild if self._current == 'help': if 'help' in self._screens: del self._screens['help'] _scr = screen.ScreenHelp(self) # already exist elif self._current in self._screens: _scr = self._screens[self._current] # refresh if self._current in ['story', 'edit']: # update all self._thread.set_time() # init screen elif self._current == 'activity': _scr = screen.ScreenActivity(self) # screen factory elif self._current == 'edit': _scr = screen.ScreenEdit(self) elif self._current == 'story': _scr = screen.ScreenStory(self, set_canvas=True) else: return # update slider if self._current in ['edit', 'story']: self._update_slider() # update screens dict self._screens[self._current] = _scr # show _scr._show() self._updating = False def read_file(self, file_path): if not file_path or not os.path.exists(file_path): return # close db story.DB().close() # save content _f_in = open(file_path) _f_ou = open(storage.get_db_path('default'), 'wb') try: _f_ou.write(_f_in.read()) finally: _f_in.close() _f_ou.close() # reload db story.DB(force=True) # update max time self.update_max_time() # clear screens if 'story' in self._screens: self._screens['story'].set_clear(True) if 'edit' in self._screens: self._screens['edit'].scene.set_clear(True) def write_file(self, file_path): self.metadata['mime_type'] = 'atoidejouer/db' # close db story.DB().close() # save content _f_in = open(storage.get_db_path('default')) _f_ou = open(file_path, 'wb') try: _f_ou.write(_f_in.read()) finally: _f_in.close() _f_ou.close() # reload db story.DB(force=True) def close(self, skip_save=False): # stop the thread self._thread.kill() # sound preview _screen = self.get_screen('sounds_add') if _screen is None: pass elif _screen.item_preview._thread is None: pass else: _screen.item_preview._thread.kill() activity.Activity.close(self, skip_save=True)