diff options
author | Benjamin Schwartz <bens@alum.mit.edu> | 2008-02-08 02:16:39 (GMT) |
---|---|---|
committer | Benjamin Schwartz <bens@alum.mit.edu> | 2008-02-08 02:16:39 (GMT) |
commit | 0845a67272127be0971930cde496f3eeaeb36345 (patch) | |
tree | bc84c687f93bf882c0b35012d0d4c897a253cbbd /stopwatch.py | |
parent | 8ff827e0e9e7147e9cc2cc28b1a11d9dce17b098 (diff) |
Refactored to create dobject, inc. version to 2
Diffstat (limited to 'stopwatch.py')
-rw-r--r-- | stopwatch.py | 516 |
1 files changed, 187 insertions, 329 deletions
diff --git a/stopwatch.py b/stopwatch.py index 4526653..a32ddbf 100644 --- a/stopwatch.py +++ b/stopwatch.py @@ -6,7 +6,7 @@ # (at your option) any later version. # # This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of +# but WITHOUT ANY WARRANTY; without even the implied warranty ofwa # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # @@ -14,12 +14,11 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +import dbus import gtk import gtk.gdk import gobject -import dbus -import dbus.service -import dbus.gobject_service +import dobject import logging import time import thread @@ -34,364 +33,183 @@ from gettext import gettext IFACE = "org.laptop.StopWatch" PATH = "/org/laptop/StopWatch" -class TubeHandler(dbus.gobject_service.ExportedGObject): - def __init__(self, tube_conn, initiating, model, controller): - dbus.gobject_service.ExportedGObject.__init__(self, tube_conn, PATH) - self._logger = logging.getLogger('stopwatch.TubeHandler') - self.tube = tube_conn - self.is_initiator = initiating - self.model = model - self.controller = controller - - self._know_offset = self.is_initiator - self._offset_lock = threading.Lock() - self._history_lock = threading.Lock() - - self.tube.add_signal_receiver(self.tell_time, signal_name='What_time_is_it', dbus_interface=IFACE, sender_keyword='sender') - self.tube.add_signal_receiver(self.tell_history, signal_name='What_has_happened', dbus_interface=IFACE, sender_keyword='sender') - self.tube.add_signal_receiver(self.tell_names, signal_name='What_are_the_names', dbus_interface=IFACE, sender_keyword='sender') - self.tube.add_signal_receiver(self.receive_history, signal_name='event_broadcast', dbus_interface=IFACE, byte_arrays=True) - self.tube.add_signal_receiver(self.receive_name, signal_name='name_change_broadcast', dbus_interface=IFACE, sender_keyword='sender', utf8_strings=True) - - self.controller.register_time_listener(self.event_listener) - self.controller.register_name_listener(self.name_listener) - - if not self._know_offset: - self.ask_time() - - if not self.is_initiator: - self.ask_history() - self.ask_names() - - @dbus.service.signal(dbus_interface=IFACE, signature='d') - def What_time_is_it(self, asktime): - return +class NameModel(): + def __init__(self, name, handler): + self._logger = logging.getLogger('stopwatch.NameModel') + self._lock = threading.Lock() + self._name = name + self._time = float('-inf') + self._handler = handler + self._handler.register(self) - def ask_time(self): - self.What_time_is_it(time.time()) - - def tell_time(self, asktime, sender=None): - start_time = time.time() - if sender == self.tube.get_unique_name(): - return - if self._know_offset: - remote = self.tube.get_object(sender, PATH) - offset = self.model.get_offset() - start_time += offset - remote.receive_time(asktime, start_time, time.time() + offset) - - @dbus.service.method(dbus_interface=IFACE, in_signature='ddd', out_signature='') - def receive_time(self, asktime, start_time, finish_time): - rtime = time.time() - thread.start_new_thread(self._handle_incoming_time, (asktime, start_time, finish_time, rtime)) - - def _handle_incoming_time(self, ask, start, finish, receive): - self._offset_lock.acquire() - if not self._know_offset: - offset = ((start + finish)/2) - ((ask + receive)/2) - self.model.set_offset(offset) - self._know_offset = True - self._offset_lock.release() + self._view_listener = None - @dbus.service.signal(dbus_interface=IFACE, signature='') - def What_has_happened(self): - return - - def ask_history(self): - self.What_has_happened() + def get_history(self): + return dbus.Struct((self._name, self._time), signature='sd') - def tell_history(self, sender=None): - if sender == self.tube.get_unique_name(): - return - remote = self.tube.get_object(sender, PATH) - h = self.model.get_history() - remote.receive_history(cPickle.dumps(h)) + def set_name_from_net(self, name, t): + self._logger.debug("set_name_from_net " + name) + if self.set_name(name, t): + self._trigger() - @dbus.service.method(dbus_interface=IFACE, in_signature='ay', out_signature='', byte_arrays=True, utf8_strings=True) - def receive_history(self, hist_string): - thread.start_new_thread(self._handle_incoming_history, (hist_string,)) + def receive_message(self, message): + self.set_name_from_net(str(message[0]), float(message[1])) - def _handle_incoming_history(self, hist_string): - self._history_lock.acquire() - h = cPickle.loads(hist_string) - self.model.add_history(h) - self._history_lock.release() - - @dbus.service.signal(dbus_interface=IFACE, signature='') - def What_are_the_names(self): - return - - def ask_names(self): - self._logger.debug("ask_names") - self.What_are_the_names() - - def tell_names(self, sender=None): - self._logger.debug("tell_names") - if sender == self.tube.get_unique_name(): - return - remote = self.tube.get_object(sender, PATH) - n = self.model.get_all_names() - remote.receive_all_names(n) - - @dbus.service.method(dbus_interface=IFACE, in_signature='(asad)', out_signature='', utf8_strings=True) - def receive_all_names(self, names_and_times): - self._logger.debug("receive_names") - thread.start_new_thread(self._handle_incoming_names, (names_and_times,)) - - def _handle_incoming_names(self, names): - self._logger.debug("_handle_incoming_names") - self.model.set_all_names(names) - - @dbus.service.signal(dbus_interface=IFACE, signature='ay') - def event_broadcast(self, hist_string): - return - - def event_listener(self, h): - self.event_broadcast(cPickle.dumps(h)) - - @dbus.service.signal(dbus_interface=IFACE, signature='isd') - def name_change_broadcast(self, i, name, t): - self._logger.debug("name_change_broadcast") - return - - def name_listener(self, i, name, t): - self._logger.debug("name_listener") - self.name_change_broadcast(i, name, t) - return - - def receive_name(self, i, name, t, sender=None): - self._logger.debug("receive_name " + name) - if sender != self.tube.get_unique_name(): - self.model.set_name(i, name, t) + add_history = receive_message -class WatchEvent(): - RUN_EVENT = 1 - PAUSE_EVENT = 2 - RESET_EVENT = 3 - def __init__(self, event_time, event_type, watch_id): - self._event_time = event_time - self._event_type = event_type - self._watch_id = watch_id - - def get_time(self): - return self._event_time - - def get_type(self): - return self._event_type + def set_name_from_UI(self, name, t): + self._logger.debug("set_name_from_UI " + name) + if self.set_name(name, t): + self._handler.send(self.get_history()) + + def set_name(self, name, t): + self._logger.debug("set_name " + name) + self._lock.acquire() + if self._time < t: + self._name = str(name) + self._time = float(t) + self._lock.release() + return True + else: + self._lock.release() + return False - def get_watch(self): - return self._watch_id + def get_name(self): + return (self._name, self._time) - def _tuple(self): - return (self._event_time, self._event_type, self._watch_id) - - def __cmp__(self, other): - return cmp(self._tuple(), other) - - def __hash__(self): - return hash(self._tuple()) + def register_view_listener(self, L): + self._view_listener = L + self._trigger() + def _trigger(self): + if self._view_listener is not None: + thread.start_new_thread(self._view_listener, (self._name,)) -class Model(): - NUM_WATCHES = 10 - +class WatchModel(): STATE_PAUSED = 1 STATE_RUNNING = 2 + + RUN_EVENT = 1 + PAUSE_EVENT = 2 + RESET_EVENT = 3 - def __init__(self): - self._logger = logging.getLogger('stopwatch.Model') + def __init__(self, handler): + self._logger = logging.getLogger('stopwatch.WatchModel') self._known_events = sets.Set() - self._history = [[] for i in xrange(Model.NUM_WATCHES)] + self._history = [] self._history_lock = threading.RLock() - self._offset = 0.0 - - self._init_state = [(Model.STATE_PAUSED, 0) for i in xrange(Model.NUM_WATCHES)] - self._state = [(Model.STATE_PAUSED, 0) for i in xrange(Model.NUM_WATCHES)] - self._names = [gettext("Stopwatch") + " " + locale.str(i+1) for i in xrange(Model.NUM_WATCHES)] - self._name_times = [float('-inf')] * Model.NUM_WATCHES - self._name_lock = threading.RLock() + self._view_listener = None #This must be done before _update_state - self._time_listeners = [[] for i in xrange(Model.NUM_WATCHES)] - self._name_listeners = [[] for i in xrange(Model.NUM_WATCHES)] + self._init_state = (WatchModel.STATE_PAUSED, 0.0) + self._state = () + self._update_state() #This must be done before registering with the handler + + self._handler = handler + self._handler.register(self) - def get_all(self): - return (self.get_all_names(), self._state, self._offset) + def get_history(self): + return dbus.Struct((self._init_state, self._history), signature='(id)a(di)') + + def get_state(self): + return self._state - def reset(self, trio): + def reset(self, init_state): self._history_lock.acquire() - self.set_all_names(trio[0]) - self._init_state = trio[1] - self._offset = trio[2] - self._history = [[] for i in xrange(Model.NUM_WATCHES)] - self._state = [() for i in xrange(Model.NUM_WATCHES)] - for i in xrange(Model.NUM_WATCHES): - self._update_state(i) + self._init_state = init_state + self._history = [] + self._state = () + self._update_state() self._history_lock.release() - def get_offset(self): - return self._offset - - def set_offset(self, x): - self._offset = x - for i in xrange(Model.NUM_WATCHES): - self._trigger(i) - - def get_history(self): - return self._history - - def get_name(self, i): - return self._names[i] + def add_history(self, (init, hist)): + self._logger.debug("add_history") + self._history_lock.acquire() + self._init_state = (int(init[0]), float(init[1])) + changed = False + for ev in hist: + if self.add_event((float(ev[0]), int(ev[1]))): + changed = True + if changed: + self._update_state() + self._history_lock.release() - def set_name(self, i, name, t): - self._logger.debug("set_name" + str(i) + " " + name) - if self.set_name_silent(i, name, t): - self._name_trigger(i) - - def set_name_silent(self, i, name, t): - self._logger.debug("set_name_silent" + str(i) + " " + name) - self._name_lock.acquire() - if self._name_times[i] <= t: - self._names[i] = str(name) - self._name_times[i] = float(t) - self._name_lock.release() + def add_event(self, ev): + if ev not in self._known_events: + self._known_events.add(ev) + bisect.insort(self._history, ev) return True else: - self._name_lock.release() return False - def get_all_names(self): - return (self._names, self._name_times) + def add_event_from_net(self, ev): + if self.add_event(ev): + self._update_state() - def set_all_names(self, n): - for i in xrange(Model.NUM_WATCHES): - self.set_name(i, n[0][i], n[1][i]) + def receive_message(self, msg): + self.add_event_from_net((float(msg[0]), int(msg[1]))) - def add_history(self, h): - self._logger.debug("add_history") - assert len(h) == Model.NUM_WATCHES - self._history_lock.acquire() - for i in xrange(Model.NUM_WATCHES): - w = h[i] - changed = False - for ev in w: - if ev not in self._known_events: - self._known_events.add(ev) - bisect.insort(self._history[i], ev) - changed = True - if changed: - self._update_state(i) - self._history_lock.release() + def add_event_from_view(self, ev): + if self.add_event(ev): + self._update_state() + self._handler.send(dbus.Struct(ev, signature='di')) - def _update_state(self, i): + def _update_state(self): self._logger.debug("_update_state") - w = self._history[i] - L = len(w) - s = self._init_state[i][0] - timeval = self._init_state[i][1] + L = len(self._history) + s = self._init_state[0] + timeval = self._init_state[1] #state machine - for ev in w: - event_type = ev.get_type() - if s == Model.STATE_PAUSED: - if event_type == WatchEvent.RUN_EVENT: - s = Model.STATE_RUNNING - timeval = ev.get_time() - timeval - elif event_type == WatchEvent.RESET_EVENT: - timeval = 0 - elif s == Model.STATE_RUNNING: - if event_type == WatchEvent.RESET_EVENT: - timeval = ev.get_time() - elif event_type == WatchEvent.PAUSE_EVENT: - s = Model.STATE_PAUSED - timeval = ev.get_time() - timeval + for ev in self._history: + event_time = ev[0] + event_type = ev[1] + if s == WatchModel.STATE_PAUSED: + if event_type == WatchModel.RUN_EVENT: + s = WatchModel.STATE_RUNNING + timeval = event_time - timeval + elif event_type == WatchModel.RESET_EVENT: + timeval = 0.0 + elif s == WatchModel.STATE_RUNNING: + if event_type == WatchModel.RESET_EVENT: + timeval = event_time + elif event_type == WatchModel.PAUSE_EVENT: + s = WatchModel.STATE_PAUSED + timeval = event_time - timeval - self._set_state(i, (s, timeval)) + self._set_state((s, timeval)) - def _set_state(self, i, q): + def _set_state(self, q): self._logger.debug("_set_state") - if self._state[i] != q: - self._state[i] = q - self._trigger(i) - - def _name_trigger(self, i): - self._logger.debug("_name_trigger") - for l in self._name_listeners[i]: - thread.start_new_thread(l, (self._names[i],)) - - def _trigger(self, i): - self._logger.debug("_trigger") - for l in self._time_listeners[i]: - thread.start_new_thread(l, (self._state[i],)) - - def register_time_listener(self, i, l): - self._logger.debug("register_time_listener " + str(i) + " " + str(l)) - self._time_listeners[i].append(l) - self._logger.debug(str(self._time_listeners)) - - def register_name_listener(self, i, l): - self._logger.debug("register_name_listener " + str(i) + " " + str(l)) - self._name_listeners[i].append(l) - self._logger.debug(str(self._name_listeners)) + if self._state != q: + self._state = q + self._trigger() + + def register_view_listener(self, L): + self._logger.debug("register_view_listener ") + self._view_listener = L + self._trigger() -class Controller(): - def __init__(self, model): - self._logger = logging.getLogger('stopwatch.Controller') - self._model = model - self._time_listeners = [self._model.add_history] - self._name_listeners = [self._model.set_name_silent] - - def register_time_listener(self, l): - self._time_listeners.append(l) - - def register_name_listener(self, l): - self._name_listeners.append(l) - - def _trigger(self, h): - self._logger.debug("_trigger") - for l in self._time_listeners: - thread.start_new_thread(l, (h,)) - - def _do_event(self, i, time, event_type): - ev = WatchEvent(time, event_type, i) - h = [[] for k in xrange(Model.NUM_WATCHES)] - h[i].append(ev) - self._trigger(h) - - def run(self, i, time): - self._logger.debug("run "+ str(time)) - self._do_event(i, time, WatchEvent.RUN_EVENT) - - def pause(self, i, time): - self._logger.debug("pause "+ str(time)) - self._do_event(i, time, WatchEvent.PAUSE_EVENT) - - def reset(self, i, time): - self._logger.debug("reset "+ str(time)) - self._do_event(i, time, WatchEvent.RESET_EVENT) - - def set_name(self, i, name, t): - self._logger.debug("set_name "+ name) - for f in self._name_listeners: - thread.start_new_thread(f, (i, name, t)) + def _trigger(self): + if self._view_listener is not None: + thread.start_new_thread(self._view_listener, (self._state,)) class OneWatchView(): - def __init__(self, watch_id, model, controller): - self._logger = logging.getLogger('stopwatch.OneWatchView'+str(watch_id)) - self._watch_id = watch_id - self._model = model - self._controller = controller + def __init__(self, mywatch, myname, timer): + self._logger = logging.getLogger('stopwatch.OneWatchView') + self._watch_model = mywatch + self._name_model = myname + self._timer = timer - self._state = Model.STATE_PAUSED + self._update_lock = threading.Lock() + self._state = self._watch_model.get_state() self._timeval = 0 - - self._model.register_time_listener(self._watch_id, self.update_state) - self._offset = self._model.get_offset() + + self._offset = self._timer.get_offset() self._name = gtk.Entry() - self._name.set_text(self._model.get_name(self._watch_id)) self._name_changed_handler = self._name.connect('changed', self._name_cb) - self._model.register_name_listener(self._watch_id, self.update_name) self._name_lock = threading.Lock() + self._name_model.register_view_listener(self.update_name) check = gtk.Image() check.set_from_file('check.svg') @@ -452,6 +270,8 @@ class OneWatchView(): self.display.connect('key-press-event', self._keypress_cb) #self.display.connect('key-release-event', self._keyrelease_cb) + self._watch_model.register_view_listener(self.update_state) + thread.start_new_thread(self._start_running, ()) def update_state(self, q): @@ -459,8 +279,8 @@ class OneWatchView(): self._update_lock.acquire() self._logger.debug("acquired update_lock") self._state = q[0] - self._offset = self._model.get_offset() - if self._state == Model.STATE_RUNNING: + self._offset = self._timer.get_offset() + if self._state == WatchModel.STATE_RUNNING: self._timeval = q[1] self._set_run_button_active(True) self._should_update.set() @@ -518,9 +338,10 @@ class OneWatchView(): t = time.time() self._logger.debug("run button pressed: " + str(t)) if self._run_button.get_active(): #button has _just_ been set active - self._controller.run(self._watch_id, self._offset + t) + action = WatchModel.RUN_EVENT else: - self._controller.pause(self._watch_id, self._offset + t) + action = WatchModel.PAUSE_EVENT + self._watch_model.add_event_from_view((self._timer.get_offset() + t, action)) return True def _set_run_button_active(self, v): @@ -533,12 +354,12 @@ class OneWatchView(): def _reset_cb(self, widget): t = time.time() self._logger.debug("reset button pressed: " + str(t)) - self._controller.reset(self._watch_id, self._offset + t) + self._watch_model.add_event_from_view((self._timer.get_offset() + t, WatchModel.RESET_EVENT)) return True def _name_cb(self, widget): t = time.time() - self._controller.set_name(self._watch_id, widget.get_text(), self._offset + t) + self._name_model.set_name_from_UI(widget.get_text(), self._offset + t) return True def pause(self): @@ -575,23 +396,60 @@ class OneWatchView(): return False class GUIView(): - def __init__(self, model, controller): - self._watches = [OneWatchView(i, model, controller) for i in xrange(Model.NUM_WATCHES)] + NUM_WATCHES = 10 + + def __init__(self, tubebox, timer): + self.timer = timer + self._views = [] + self._names = [] + self._watches = [] + for i in xrange(GUIView.NUM_WATCHES): + name_handler = dobject.UnorderedHandler("name"+str(i), tubebox) + name_model = NameModel(gettext("Stopwatch") + " " + locale.str(i+1), name_handler) + self._names.append(name_model) + watch_handler = dobject.UnorderedHandler("watch"+str(i), tubebox) + watch_model = WatchModel(watch_handler) + self._watches.append(watch_model) + watch_view = OneWatchView(watch_model, name_model, timer) + self._views.append(watch_view) + self.display = gtk.VBox() - for x in self._watches: + for x in self._views: self.display.pack_start(x.display, expand=True, fill=True) self._pause_lock = threading.Lock() + def get_names(self): + return [n.get_name() for n in self._names] + + def set_names(self, namestate): + for i in xrange(GUIView.NUM_WATCHES): + self._names[i].add_history(namestate[i]) + + def get_state(self): + return [w.get_state() for w in self._watches] + + def set_state(self,states): + for i in xrange(GUIView.NUM_WATCHES): + self._watches[i].reset(states[i]) + + def get_all(self): + return (self.timer.get_offset(), self.get_names(), self.get_state()) + + def set_all(self, q): + self.timer.set_offset(q[0]) + self.set_names(q[1]) + self.set_state(q[2]) + def pause(self): self._pause_lock.acquire() - for w in self._watches: + for w in self._views: w.pause() self._pause_lock.release() def resume(self): self._pause_lock.acquire() - for w in self._watches: + for w in self._views: w.resume() self._pause_lock.release() |