diff options
author | flavio <fdanesse@gmail.com> | 2012-12-04 18:18:11 (GMT) |
---|---|---|
committer | flavio <fdanesse@gmail.com> | 2012-12-04 18:18:11 (GMT) |
commit | e393db2c8fdee35ba472d5ce337585e18c29f61a (patch) | |
tree | c02f1bce422b11a21f504526f186a9b4e207bdfe | |
parent | 229786ba9aeeba958a878406a935d3f31bd9895b (diff) |
The activity starts.
-rw-r--r-- | edit_app.py | 110 | ||||
-rw-r--r-- | groupthink/gtk_tools.py | 89 | ||||
-rw-r--r-- | groupthink/sugar_tools.py | 3 |
3 files changed, 134 insertions, 68 deletions
diff --git a/edit_app.py b/edit_app.py index 7f08b09..12360a8 100644 --- a/edit_app.py +++ b/edit_app.py @@ -3,34 +3,29 @@ Written mostly by Nate Theis Some GTK code borrowed from Pippy ''' -from groupthink import sugar_tools, gtk_tools - +import time from gettext import gettext as _ from gi.repository import Gtk from gi.repository import Pango -import time from gi.repository import GtkSource -from sugar3.activity import activity - -try: # Can use 'New' toolbar design? - from sugar3.graphics.toolbarbox import ToolbarBox - _HAVE_TOOLBOX = True -except ImportError: - _HAVE_TOOLBOX = False - -if _HAVE_TOOLBOX: - from sugar3.activity.widgets import ActivityToolbarButton, StopButton - from sugar3.graphics.toolbarbox import ToolbarButton +from groupthink.sugar_tools import GroupActivity +# Fixme: There is an error that I have not even given: TextBufferSharePoint +#from groupthink.gtk_tools import TextBufferSharePoint +from sugar3.activity import activity +from sugar3.graphics.toolbarbox import ToolbarBox +from sugar3.activity.widgets import ActivityToolbarButton +from sugar3.activity.widgets import StopButton +from sugar3.graphics.toolbarbox import ToolbarButton from sugar3.graphics import style -from sugar3.activity.activity import EditToolbar +from sugar3.activity.widgets import EditToolbar import mdnames -class EditActivity(sugar_tools.GroupActivity): +class EditActivity(GroupActivity): '''A text editor for Sugar pylint says I need a docstring. Here you go. ''' @@ -57,12 +52,13 @@ class EditActivity(sugar_tools.GroupActivity): self.buffer = GtkSource.Buffer() self.refresh_buffer = False - self.text_view = GtkSource.View(self.buffer) + self.text_view = GtkSource.View() + self.text_view.set_buffer(self.buffer) self.scrollwindow = Gtk.ScrolledWindow() - self.scrollwindow.add(self.text_view) + self.scrollwindow.add_with_viewport(self.text_view) - sugar_tools.GroupActivity.__init__(self, handle) + GroupActivity.__init__(self, handle) def fix_mimetype(self): '''We must have a mimetype. Sometimes, we don't (when we get launched @@ -73,68 +69,60 @@ class EditActivity(sugar_tools.GroupActivity): def setup_toolbar(self): '''Setup the top toolbar. Groupthink needs some work here.''' + + toolbox = ToolbarBox() + + activity_button = ActivityToolbarButton(self) + toolbox.toolbar.insert(activity_button, 0) + activity_button.show() + + self.set_toolbar_box(toolbox) + toolbox.show() + toolbar = toolbox.toolbar - if _HAVE_TOOLBOX: # 'New' Sugar toolbar design - toolbox = ToolbarBox() - - activity_button = ActivityToolbarButton(self) - toolbox.toolbar.insert(activity_button, 0) - activity_button.show() - - self.set_toolbar_box(toolbox) - toolbox.show() - toolbar = toolbox.toolbar - - self.edit_toolbar = EditToolbar() - edit_toolbar_button = ToolbarButton( - page=self.edit_toolbar, - icon_name='toolbar-edit') - self.edit_toolbar.show() - toolbar.insert(edit_toolbar_button, -1) - edit_toolbar_button.show() - - else: # 'Old' Sugar toolbar design - self.edit_toolbar = EditToolbar() - toolbox = activity.ActivityToolbox(self) - self.set_toolbox(toolbox) - toolbox.add_toolbar(_('Edit'), self.edit_toolbar) - toolbox.show() - toolbox.set_current_toolbar(1) - toolbar = self.edit_toolbar + self.edit_toolbar = EditToolbar() + edit_toolbar_button = ToolbarButton( + page=self.edit_toolbar, + icon_name='toolbar-edit') + self.edit_toolbar.show() + toolbar.insert(edit_toolbar_button, -1) + edit_toolbar_button.show() self.edit_toolbar.undo.connect('clicked', self.undobutton_cb) self.edit_toolbar.redo.connect('clicked', self.redobutton_cb) self.edit_toolbar.copy.connect('clicked', self.copybutton_cb) self.edit_toolbar.paste.connect('clicked', self.pastebutton_cb) - - if _HAVE_TOOLBOX: - separator = Gtk.SeparatorToolItem() - separator.props.draw = False - separator.set_expand(True) - toolbar.insert(separator, -1) - separator.show() - - stop_button = StopButton(self) - stop_button.props.accelerator = '<Ctrl>q' - toolbox.toolbar.insert(stop_button, -1) - stop_button.show() + + separator = Gtk.SeparatorToolItem() + separator.props.draw = False + separator.set_expand(True) + toolbar.insert(separator, -1) + separator.show() + + stop_button = StopButton(self) + stop_button.props.accelerator = '<Ctrl>q' + toolbox.toolbar.insert(stop_button, -1) + stop_button.show() def initialize_display(self): '''Set up GTK and friends''' self.fix_mimetype() - - self.cloud.shared_buffer = gtk_tools.TextBufferSharePoint(self.buffer) + # Fixme: There is an error that I have not even given: TextBufferSharePoint + #self.cloud.shared_buffer = TextBufferSharePoint(self.buffer) self.setup_toolbar() #Some graphics code borrowed from Pippy lang_manager = GtkSource.LanguageManager.get_default() + if hasattr(lang_manager, 'list_languages'): langs = lang_manager.list_languages() + else: lang_ids = lang_manager.get_language_ids() langs = [lang_manager.get_language(lang_id) \ for lang_id in lang_ids] + for lang in langs: for mtype in lang.get_mime_types(): if mtype == self.metadata[mdnames.mimetype_md]: @@ -149,9 +137,11 @@ class EditActivity(sugar_tools.GroupActivity): self.text_view.set_wrap_mode(Gtk.WrapMode.WORD) font = Pango.FontDescription("Bitstream Vera Sans " + str(style.FONT_SIZE)) + else: if hasattr(self.buffer, 'set_highlight'): self.buffer.set_highlight(True) + else: self.buffer.set_highlight_syntax(True) diff --git a/groupthink/gtk_tools.py b/groupthink/gtk_tools.py index c88d27e..938c7a0 100644 --- a/groupthink/gtk_tools.py +++ b/groupthink/gtk_tools.py @@ -1,3 +1,4 @@ +import gi from gi.repository import Gtk import groupthink_base as groupthink import logging @@ -6,8 +7,11 @@ import stringtree class RecentEntry(groupthink.UnorderedHandlerAcceptor, Gtk.Entry): """RecentEntry is an extension of gtk.Entry that, when attached to a group, creates a unified Entry field for all participants""" - def __init__(self, *args, **kargs): - Gtk.Entry.__init__(self, *args, **kargs) + + def __init__(self): + + Gtk.Entry.__init__(self) + self.logger = logging.getLogger('RecentEntry') self.add_events(Gdk.EventMask.PROPERTY_CHANGE_MASK) self._text_changed_handler = self.connect('changed', self._local_change_cb) @@ -23,7 +27,9 @@ class RecentEntry(groupthink.UnorderedHandlerAcceptor, Gtk.Entry): self._recent.set_handler(handler) def _remote_change_cb(self, text): + self.logger.debug("_remote_change_cb(%s)" % text) + if self.get_text() != text: #The following code will break if running in any thread other than #the main thread. I do not know how to make code that works with @@ -33,11 +39,15 @@ class RecentEntry(groupthink.UnorderedHandlerAcceptor, Gtk.Entry): self.handler_unblock(self._text_changed_handler) class SharedTreeStore(groupthink.CausalHandlerAcceptor, Gtk.TreeModel): + def __init__(self, columntypes=(), translators=()): + self._columntypes = columntypes self._causaltree = groupthink.CausalTree() + if len(translators) != 0 and len(translators) != len(columntypes): raise #Error: translators must be empty or match columntypes in length + if len(translators) == len(self._columntypes): self._columndicts = [groupthink.CausalDict( key_translator = self._causaltree.node_trans, @@ -47,12 +57,16 @@ class SharedTreeStore(groupthink.CausalHandlerAcceptor, Gtk.TreeModel): self._columndicts = [groupthink.CausalDict( key_translator = self._causaltree.node_trans) for i in xrange(len(translators))] + self._causaltree.register_listener(self._tree_listener) + for i in xrange(len(self._columndicts)): self._columndicts[i].register_listener(self._generate_dictlistener(i)) def set_handler(self, handler): + self._causaltree.set_handler(handler) + for i in xrange(len(self._columndicts)): #Make a new handler for each columndict #Not very future-proof: how do we serialize out and reconstitute @@ -63,7 +77,7 @@ class SharedTreeStore(groupthink.CausalHandlerAcceptor, Gtk.TreeModel): ### Methods necessary to implement gtk.GenericTreeModel ### def on_get_flags(self): - return Gtk.TREE_MODEL_ITERS_PERSIST + return Gtk.TreeModelFlags.ITERS_PERSIST def on_get_n_columns(self): return len(self._columntypes) @@ -72,19 +86,26 @@ class SharedTreeStore(groupthink.CausalHandlerAcceptor, Gtk.TreeModel): return self._columntypes[index] def on_get_iter(self, path): + node = self._causaltree.ROOT + for k in path: c = list(self._causaltree.get_children(node)) + if len(c) <= k: return None #Invalid path + else: c.sort() node = c[k] + return node def on_get_path(self, rowref): + revpath = [] node = rowref + if rowref in self._causaltree: while node != self._causaltree.ROOT: p = self._causaltree.get_parent(node) @@ -92,29 +113,38 @@ class SharedTreeStore(groupthink.CausalHandlerAcceptor, Gtk.TreeModel): c.sort() revpath.append(c.index(node)) # could be done "faster" using bisect node = p + return tuple(revpath[::-1]) + else: return None - + def on_get_value(self, rowref, column): return self._columndicts[column][rowref] def on_iter_next(self, rowref): + p = self._causaltree.get_parent(rowref) c = list(self._causaltree.get_children(p)) c.sort() i = c.index(rowref) + 1 + if i < len(c): return c[i] + else: return None def on_iter_children(self, parent): + if parent is None: parent = self._causaltree.ROOT + c = self._causaltree.get_children(parent) + if len(c) > 0: return min(c) + else: return None @@ -125,39 +155,50 @@ class SharedTreeStore(groupthink.CausalHandlerAcceptor, Gtk.TreeModel): return len(self._causaltree.get_children(rowref)) def on_iter_nth_child(self, parent, n): + if parent is None: parent = self._causaltree.ROOT + c = self._causaltree.get_children(parent) + if len(c) > n: c = list(c) c.sort() return c[n] + else: return None - + def on_iter_parent(self, child): + p = self._causaltree.get_parent(child) if p == self._causaltree.ROOT: return None + else: return p ### Methods for passing changes from remote users ### def _dict_listener(self, i, added, removed): + s = set() s.update(added.keys()) s.update(removed.keys()) + for node in s: path = self.on_get_path(node) if path is not None: it = self.create_tree_iter(node) self.row_changed(path, it) + self.emit('changed') def _generate_dict_listener(self, i): + def temp(added,removed): self._dict_listener(i,added,removed) + return temp def _tree_listener(self, forward, reverse): @@ -183,8 +224,10 @@ class SharedTreeStore(groupthink.CausalHandlerAcceptor, Gtk.TreeModel): inserted.add(cmd[1]) else: unknown_change = True + for cmd in reverse: clean = True + if cmd[0] == self._causaltree.SET_PARENT: if (clean and cmd[2] in self._causaltree and @@ -205,18 +248,22 @@ class SharedTreeStore(groupthink.CausalHandlerAcceptor, Gtk.TreeModel): self.row_deleted(p) else: unknown_change = True + if unknown_change: self.emit('unknown-change') + for node in inserted: path = self.on_get_path(node) if path is not None: it = self.create_tree_iter(node) self.row_inserted(path, it) + for node in haschild: path = self.on_get_path(node) if path is not None: it = self.create_tree_iter(node) self.row_has_child_toggled(path, it) + self.emit('changed') ### Methods for resembling gtk.TreeStore ### @@ -225,7 +272,7 @@ class SharedTreeStore(groupthink.CausalHandlerAcceptor, Gtk.TreeModel): node = self.get_user_data(it) self._columndicts[i][node] = value - def set(self, it, *args): + def set(self, it): for i in xrange(0,len(args),2): self.set_value(it,args[i],args[i+1]) @@ -237,41 +284,56 @@ class SharedTreeStore(groupthink.CausalHandlerAcceptor, Gtk.TreeModel): del d[node] def append(self, parent, row=None): + if parent is not None: node = self.get_user_data(it) + else: node = self._causaltree.ROOT + node = self._causaltree.new_child(node) + if row is not None: if len(row) != len(columndicts): raise IndexError("row had the wrong length") + else: for i in xrange(len(row)): self._columndicts[i][node] = row[i] + return self.create_tree_iter(node) def is_ancestor(self, it, descendant): + node = self.get_user_data(it) d = self.get_user_data(descendant) d = self._causaltree.get_parent(d) + while d != self._causaltree.ROOT: if d == node: return True + else: d = self._causaltree.get_parent(d) + return False def iter_depth(self, it): + node = self.get_user_data(it) i = 0 node = self._causaltree.get_parent(node) + while node != self._causaltree.ROOT: i = i + 1 node = self._causaltree.get_parent(node) + return i def clear(self): + self._causaltree.clear() + for d in self._columndicts: d.clear() @@ -281,12 +343,15 @@ class SharedTreeStore(groupthink.CausalHandlerAcceptor, Gtk.TreeModel): ### Additional Methods ### def move(self, it, newparent): + node = self.get_user_data(row) p = self.get_user_data(newparent) self._causaltree.change_parent(node,p) class TextBufferUnorderedStringLinker: + def __init__(self,tb,us): + self._tb = tb self._us = us self._us.register_listener(self._netupdate_cb) @@ -295,34 +360,42 @@ class TextBufferUnorderedStringLinker: self._logger = logging.getLogger('the Linker') def _insert_cb(self, tb, itr, text, length): + self._logger.debug('user insert: %s' % text) pos = itr.get_offset() self._us.insert(text,pos) def _delete_cb(self, tb, start_itr, end_itr): + self._logger.debug('user delete') k = start_itr.get_offset() n = end_itr.get_offset()-k self._us.delete(k,n) def _netupdate_cb(self, edits): + self._logger.debug('update from network: %s' % str(edits)) self._tb.handler_block(self._insert_handler) self._tb.handler_block(self._delete_handler) + for e in edits: if isinstance(e, stringtree.Insertion): itr = self._tb.get_iter_at_offset(e.position) self._tb.insert(itr, e.text) + elif isinstance(e, stringtree.Deletion): itr1 = self._tb.get_iter_at_offset(e.position) itr2 = self._tb.get_iter_at_offset(e.position + e.length) self._tb.delete(itr1,itr2) + self._tb.handler_unblock(self._insert_handler) self._tb.handler_unblock(self._delete_handler) class TextBufferSharePoint(groupthink.UnorderedHandlerAcceptor): + def __init__(self, buff): + self._us = groupthink.UnorderedString(buff.get_text(buff.get_start_iter(), buff.get_end_iter())) self._linker = TextBufferUnorderedStringLinker(buff, self._us) @@ -330,8 +403,10 @@ class TextBufferSharePoint(groupthink.UnorderedHandlerAcceptor): self._us.set_handler(handler) class SharedTextView(groupthink.UnorderedHandlerAcceptor, Gtk.TextView): + def __init__(self, *args, **kargs): - Gtk.TextView.__init__(self, *args, **kargs) + + Gtk.TextView.__init__(self) self._link = TextBufferSharePoint(self.get_buffer()) def set_handler(self, handler): diff --git a/groupthink/sugar_tools.py b/groupthink/sugar_tools.py index 14a8cee..fdd4d98 100644 --- a/groupthink/sugar_tools.py +++ b/groupthink/sugar_tools.py @@ -26,6 +26,7 @@ from sugar3.presence.tubeconn import TubeConnection from sugar3.graphics.window import Window from gi.repository import Gtk +from gi.repository import Gdk from gi.repository import GObject import groupthink_base as groupthink @@ -72,7 +73,7 @@ class GroupActivity(Activity): # top toolbar with share and close buttons: toolbox = ToolbarBox(self) - self.set_toolbox(toolbox) + self.toolbox = toolbox toolbox.show() v = Gtk.VBox() |