Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/stopwatch.py
diff options
context:
space:
mode:
authorBenjamin 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)
commit0845a67272127be0971930cde496f3eeaeb36345 (patch)
treebc84c687f93bf882c0b35012d0d4c897a253cbbd /stopwatch.py
parent8ff827e0e9e7147e9cc2cc28b1a11d9dce17b098 (diff)
Refactored to create dobject, inc. version to 2
Diffstat (limited to 'stopwatch.py')
-rw-r--r--stopwatch.py516
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()