]>
Commit | Line | Data |
---|---|---|
1 | from transitions.extensions import HierarchicalMachine as Machine | |
2 | from .helpers import debug_print, error_print | |
3 | from . import actions | |
4 | ||
5 | class Action: | |
6 | STATES = [ | |
7 | 'initial', | |
8 | 'loading', | |
9 | 'failed', | |
10 | { | |
11 | 'name': 'loaded', | |
12 | 'children': ['running'] | |
13 | } | |
14 | ] | |
15 | ||
16 | TRANSITIONS = [ | |
17 | { | |
18 | 'trigger': 'load', | |
19 | 'source': 'initial', | |
20 | 'dest': 'loading' | |
21 | }, | |
22 | { | |
23 | 'trigger': 'fail', | |
24 | 'source': 'loading', | |
25 | 'dest': 'failed', | |
26 | 'after': 'poll_loaded' | |
27 | }, | |
28 | { | |
29 | 'trigger': 'success', | |
30 | 'source': 'loading', | |
31 | 'dest': 'loaded', | |
32 | 'after': 'poll_loaded' | |
33 | }, | |
34 | { | |
35 | 'trigger': 'run', | |
36 | 'source': 'loaded', | |
37 | 'dest': 'loaded_running', | |
38 | 'after': 'finish_action', | |
39 | # if a child has no transitions, then it is bubbled to the parent, | |
40 | # and we don't want that. Not useful in that machine precisely. | |
41 | 'conditions': ['is_loaded'] | |
42 | }, | |
43 | { | |
44 | 'trigger': 'finish_action', | |
45 | 'source': 'loaded_running', | |
46 | 'dest': 'loaded' | |
47 | } | |
48 | ] | |
49 | ||
50 | def __init__(self, action, key, **kwargs): | |
51 | Machine(model=self, states=self.STATES, | |
52 | transitions=self.TRANSITIONS, initial='initial', | |
53 | ignore_invalid_triggers=True, queued=True) | |
54 | ||
55 | self.action = action | |
56 | self.key = key | |
57 | self.mapping = key.parent | |
58 | self.arguments = kwargs | |
59 | self.sleep_event = None | |
60 | self.waiting_music = None | |
61 | ||
62 | def is_loaded_or_failed(self): | |
63 | return self.is_loaded(allow_substates=True) or self.is_failed() | |
64 | ||
65 | def callback_music_loaded(self, success): | |
66 | if success: | |
67 | self.success() | |
68 | else: | |
69 | self.fail() | |
70 | ||
71 | # Machine states / events | |
72 | def on_enter_loading(self): | |
73 | if hasattr(actions, self.action): | |
74 | if 'music' in self.arguments: | |
75 | self.arguments['music'].subscribe_loaded( | |
76 | self.callback_music_loaded) | |
77 | else: | |
78 | self.success() | |
79 | else: | |
80 | error_print("Unknown action {}".format(self.action)) | |
81 | self.fail() | |
82 | ||
83 | def on_enter_loaded_running(self, key_start_time): | |
84 | debug_print(self.description()) | |
85 | if hasattr(actions, self.action): | |
86 | getattr(actions, self.action).run(self, | |
87 | key_start_time=key_start_time, **self.arguments) | |
88 | ||
89 | def poll_loaded(self): | |
90 | self.key.callback_action_ready(self, | |
91 | self.is_loaded(allow_substates=True)) | |
92 | ||
93 | # This one cannot be in the Machine state since it would be queued to run | |
94 | # *after* the wait is ended... | |
95 | def interrupt(self): | |
96 | if getattr(actions, self.action, None) and\ | |
97 | hasattr(getattr(actions, self.action), 'interrupt'): | |
98 | return getattr(getattr(actions, self.action), 'interrupt')( | |
99 | self, **self.arguments) | |
100 | ||
101 | # Helpers | |
102 | def music_list(self, music): | |
103 | if music is not None: | |
104 | return [music] | |
105 | else: | |
106 | return self.mapping.open_files.values() | |
107 | ||
108 | def description(self): | |
109 | if hasattr(actions, self.action): | |
110 | return getattr(actions, self.action)\ | |
111 | .description(self, **self.arguments) | |
112 | else: | |
113 | return _("unknown action {}").format(self.action) |