changeset 809:7f1aef5fbddb

session cmdline support. KC saves current row in the session Ignore-this: 966fcd0308fb9fd2a496ffaaecd7fb19
author drewp@bigasterisk.com
date Thu, 19 Jul 2012 04:54:29 +0000
parents a631e075a5bf
children f29788d1c8c9
files bin/keyboardcomposer light9/rdfdb/clientsession.py light9/rdfdb/syncedgraph.py
diffstat 3 files changed, 66 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/bin/keyboardcomposer	Thu Jul 19 04:23:06 2012 +0000
+++ b/bin/keyboardcomposer	Thu Jul 19 04:54:29 2012 +0000
@@ -20,6 +20,7 @@
 from light9.uihelpers import toplevelat, bindkeys
 from light9.namespaces import L9
 from light9.tkdnd import initTkdnd, dragSourceRegister
+from light9.rdfdb import clientsession
 from light9.rdfdb.syncedgraph import SyncedGraph
 from light9.rdfdb.patch import Patch
 
@@ -62,8 +63,9 @@
     this object owns the level of the submaster (the rdf graph is the
     real authority)
     """
-    def __init__(self, master, sub):
+    def __init__(self, master, sub, session):
         self.sub = sub
+        self.session = session
         bg = sub.graph.value(sub.uri, L9.color, default='#000000')
         rgb = webcolors.hex_to_rgb(bg)
         hsv = colorsys.rgb_to_hsv(*[x/255 for x in rgb])
@@ -115,33 +117,36 @@
     def updateGraphWithLevel(self, uri, level):
         """in our per-session graph, we maintain SubSetting objects like this:
 
-           [a :SubSetting; :sub ?s; :level ?l]
+           ?session :subSetting [a :SubSetting; :sub ?s; :level ?l]
         """
-        ctx = URIRef("http://example.com/kc/session1")
-        with self.sub.graph.currentState(context=ctx) as graph:
+
+        with self.sub.graph.currentState() as graph:
             adds = set([])
-            for setting in graph.subjects(RDF.type, L9['SubSetting']):
+            for setting in graph.objects(self.session, L9['subSetting']):
                 if graph.value(setting, L9['sub']) == uri:
                     break
             else:
-                setting = URIRef("http://example.com/subsetting/%s" %
+                setting = URIRef(self.session + "/setting/%s" %
                                  random.randrange(999999))
                 adds.update([
-                    (setting, RDF.type, L9['SubSetting'], ctx),
-                    (setting, L9['sub'], uri, ctx),
+                    (self.session, L9['subSetting'], setting, self.session),
+                    (setting, RDF.type, L9['SubSetting'], self.session),
+                    (setting, L9['sub'], uri, self.session),
                     ])
             dels = set([])
             for prev in graph.objects(setting, L9['level']):
-                dels.add((setting, L9['level'], prev, ctx))
-            adds.add((setting, L9['level'], Literal(level), ctx))
+                dels.add((setting, L9['level'], prev, self.session))
+            adds.add((setting, L9['level'], Literal(level), self.session))
 
             if adds != dels:
                 self.sub.graph.patch(Patch(delQuads=dels, addQuads=adds))
 
     def updateLevelFromGraph(self):
         """read rdf level, write it to subbox.slider_var"""
+        
         graph = self.sub.graph
-        for setting in graph.subjects(RDF.type, L9['SubSetting']):
+
+        for setting in graph.objects(self.session, L9['subSetting']):
             if graph.value(setting, L9['sub']) == self.sub.uri:
                 self.pauseTrace = True # don't bounce this update back to server
                 try:
@@ -156,11 +161,12 @@
         subprocess.Popen(["bin/subcomposer", "--no-geometry", self.name])
 
 class KeyboardComposer(Frame, SubClient):
-    def __init__(self, root, graph,
+    def __init__(self, root, graph, session,
                  hw_sliders=True):
         Frame.__init__(self, root, bg='black')
         SubClient.__init__(self)
         self.graph = graph
+        self.session = session
         self.submasters = Submasters(graph)
         self.subbox = {} # sub uri : SubmasterBox
         self.slider_table = {} # coords : SubmasterBox
@@ -176,6 +182,7 @@
 
         self.graph.addHandler(self.redraw_sliders)
         self.send_levels_loop()
+        self.graph.addHandler(self.rowFromGraph)
 
     def make_buttons(self):
         self.buttonframe = Frame(self, bg='black')
@@ -250,7 +257,7 @@
                 rowcount += 1
                 col = 0
 
-            subbox = SubmasterBox(row, sub)
+            subbox = SubmasterBox(row, sub, self.session)
             subbox.place(relx=col / 8, rely=0, relwidth=1 / 8, relheight=1)
             self.subbox[sub.uri] = self.slider_table[(rowcount, col)] = subbox
 
@@ -327,16 +334,32 @@
             diff = -1
         self.change_row(self.current_row + diff)
 
-    def change_row(self, row):
+    def rowFromGraph(self):
+        self.change_row(int(self.graph.value(self.session, L9['currentRow'], default=0)), fromGraph=True)
+
+    def change_row(self, row, fromGraph=False):
         old_row = self.current_row
         self.current_row = row
         self.current_row = max(0, self.current_row)
         self.current_row = min(len(self.rows) - 1, self.current_row)
+        try:
+            row = self.rows[self.current_row]
+        except IndexError:
+            # if we're mid-load, this row might appear soon. If we
+            # changed interactively, the user is out of bounds and
+            # needs to be brought back in
+            if fromGraph:
+                return
+            raise
+
         self.unhighlight_row(old_row)
         self.highlight_row(self.current_row)
-        row = self.rows[self.current_row]
         self.keyhints.pack_configure(before=row)
 
+        if not fromGraph:
+            self.graph.patchObject(self.session, self.session, L9['currentRow'],
+                                   Literal(self.current_row))
+
         for col in range(1, 9):
             try:
                 subbox = self.slider_table[(self.current_row, col - 1)]
@@ -421,10 +444,6 @@
         sub.temporary = 0
         sub.save()
 
-    def save(self):
-        pickle.dump((self.get_levels(), self.current_row),
-                    file('.keyboardcomposer.savedlevels', 'w'))
-
     def send_frequent_updates(self):
         """called when we get a fade -- send events as quickly as possible"""
         if time.time() <= self.stop_frequent_update_time:
@@ -518,6 +537,7 @@
     parser = OptionParser()
     parser.add_option('--no-sliders', action='store_true',
                       help="don't attach to hardware sliders")
+    clientsession.add_option(parser)
     parser.add_option('-v', action='store_true', help="log info level")
     opts, args = parser.parse_args()
 
@@ -529,9 +549,12 @@
     root = Tk()
     initTkdnd(root.tk, 'tkdnd/trunk/')
     
-    tl = toplevelat("Keyboard Composer", existingtoplevel=root)
+    tl = toplevelat("Keyboard Composer - %s" % opts.session,
+                    existingtoplevel=root)
 
-    kc = KeyboardComposer(tl, graph, 
+    session = clientsession.getUri('keyboardcomposer', opts)
+
+    kc = KeyboardComposer(tl, graph, session,
                           hw_sliders=not opts.no_sliders)
     kc.pack(fill=BOTH, expand=1)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/rdfdb/clientsession.py	Thu Jul 19 04:54:29 2012 +0000
@@ -0,0 +1,16 @@
+"""
+some clients will support the concept of a named session that keeps
+multiple instances of that client separate
+"""
+from rdflib import URIRef
+from urllib import quote
+
+def add_option(parser):
+    parser.add_option(
+        '-s', '--session',
+        help="name of session used for levels and window position",
+        default='default')
+
+def getUri(appName, opts):
+    return URIRef("http://example.com/session/%s/%s" %
+                  (appName, quote(opts.session, safe='')))
--- a/light9/rdfdb/syncedgraph.py	Thu Jul 19 04:23:06 2012 +0000
+++ b/light9/rdfdb/syncedgraph.py	Thu Jul 19 04:54:29 2012 +0000
@@ -212,11 +212,14 @@
     def patchObject(self, context, subject, predicate, newObject):
         """send a patch which removes existing values for (s,p,*,c)
         and adds (s,p,newObject,c). Values in other graphs are not affected"""
-        raise NotImplementedError
+
         existing = []
-        
+        for spo in self._graph.triples((subject, predicate, None),
+                                     context=context):
+            existing.append(spo+(context,))
+        # what layer is supposed to cull out no-op changes?
         self.patch(Patch(
-            delQuads=[],
+            delQuads=existing,
             addQuads=[(subject, predicate, newObject, context)]))
 
     def addHandler(self, func):