Imported Upstream version 2008.1+svn1553
[opeanno-debian-packaging.git] / game / scheduler.py
blobe6d5f40a0910e791c1b55838a88dbce4d182a68b
1 # ###################################################
2 # Copyright (C) 2008 The OpenAnno Team
3 # team@openanno.org
4 # This file is part of OpenAnno.
6 # OpenAnno is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the
18 # Free Software Foundation, Inc.,
19 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 # ###################################################
22 import game.main
23 from game.util import livingObject, WeakMethod
24 import weakref
26 class Scheduler(livingObject):
27 """"Class providing timed callbacks.
28 To start a timed callback, call add_new_object() to make the TimingThread Class create a CallbackObject for you.
29 @param timer: Timer instance the schedular registers itself with.
30 """
31 def begin(self, timer):
32 super(Scheduler, self).begin()
33 self.schedule = {}
34 self.cur_tick = 0
35 self.timer = timer
36 self.timer.add_call(self.tick)
38 def tick(self, tick_id):
39 """Threads main loop
40 @param tick_id: int id of the tick.
41 """
42 self.cur_tick = tick_id
43 if self.cur_tick in self.schedule:
44 for callback in self.schedule[self.cur_tick]:
45 callback.callback()
46 assert callback.loops >= -1
47 if callback.loops is not 0:
48 self.add_object(callback) # readd object
49 del self.schedule[self.cur_tick]
50 assert (len(self.schedule) == 0) or self.schedule.keys()[0] > self.cur_tick
52 def add_object(self, callback_obj):
53 """Adds a new CallbackObject instance to the callbacks list
54 @param callback_obj: CallbackObject type object, containing all neccessary information
55 """
56 if not (self.cur_tick + callback_obj.runin) in self.schedule:
57 self.schedule[self.cur_tick + callback_obj.runin] = []
58 if callback_obj.loops > 0:
59 callback_obj.loops -= 1
60 self.schedule[self.cur_tick + callback_obj.runin].append(callback_obj)
62 def add_new_object(self, callback, class_instance, runin=1, loops=1):
63 """Creates a new CallbackObject instance and calls the self.add_object() function.
64 @param callback: lambda function callback, which is called runin ticks.
65 @param class_instance: class instance the function belongs to.
66 @param runin: int number of ticks after which the callback is called. Standard is 1, run next tick.
67 @param loops: How often the callback is called. -1 = infinit times. Standard is 1, run once."""
69 callback_obj = CallbackObject(self, callback, class_instance, runin, loops)
70 self.add_object(callback_obj)
72 def rem_object(self, callback_obj):
73 """Removes a CallbackObject from all callback lists
74 @param callback_obj: CallbackObject to remove
75 """
76 for key in self.schedule:
77 for i in xrange(0, self.schedule[key].count(callback_obj)):
78 self.schedule[key].remove(callback_obj)
81 #TODO: Check if this is still necessary for weak referenced objects
82 def rem_all_classinst_calls(self, class_instance):
83 """Removes all callbacks from the scheduler that belong to the class instance class_inst."""
84 for key in self.schedule:
85 for callback_obj in self.schedule[key]:
86 if callback_obj.class_instance is class_instance:
87 self.schedule[key].remove(callback_obj)
89 def rem_call(self, instance, callback):
90 """Removes all callbacks of 'instance' that are 'callback'
91 @param instance: the instance that would execute the call
92 @param callback: the function to remove
93 """
94 for key in self.schedule:
95 for callback_obj in self.schedule[key]:
96 if callback_obj.class_instance() is instance and callback_obj.callback == WeakMethod(callback):
97 self.schedule[key].remove(callback_obj)
99 def end(self):
100 self.schedule = {}
101 self._is_ended = True
102 self.timer.remove_call(self.tick)
103 self.timer = None
105 class CallbackObject(object):
106 """Class used by the TimerManager Class to organize callbacks."""
107 def __init__(self, scheduler, callback, class_instance, runin=1, loops=1):
108 """Creates the CallbackObject instance.
109 @param scheduler: reference to the scheduler, necessary to react properly on weak reference callbacks
110 @param callback: lambda function callback, which is called runin ticks.
111 @param class_instance: class instance the original function(not the lambda function!) belongs to.
112 @param runin: int number of ticks after which the callback is called. Standard is 1, run next tick.
113 @param loops: How often the callback is called. -1 = infinit times. Standard is 1, run once.
114 @param weakref_aciton: A callback to register with the weak reference
117 # Do some input validation, otherwise errors occure long after wrong data was added
119 if runin < 1:
120 raise ValueError("Can't schedule callbacks in the past, runin must be a positive number")
122 if (loops < -1) or (loops is 0):
123 raise ValueError("Loop count must be a positive number or -1 for infinite repeat")
125 self.callback = WeakMethod(callback)
127 # Check for persisting strong references
128 if __debug__:
129 import gc
130 if (class_instance in gc.get_referents(self.callback)):
131 del self.callback
132 raise ValueError("callback has strong reference to class_instance")
134 self.scheduler = scheduler
135 self.runin = runin
136 self.loops = loops
137 self.class_instance = weakref.ref(class_instance, lambda ref: self.scheduler.rem_object(self))