From f14b5e3e41af68866edd706c9d48db61f3e0da4f Mon Sep 17 00:00:00 2001 From: Vincent Vinet Date: Wed, 25 Mar 2009 18:26:30 +0000 Subject: Add the filters and treeview in the editor, and get_children in gtkutils --- diff --git a/src/sugar/tutorius/editor.py b/src/sugar/tutorius/editor.py index 1a1eb61..bf70216 100644 --- a/src/sugar/tutorius/editor.py +++ b/src/sugar/tutorius/editor.py @@ -14,17 +14,22 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" Tutorial Editor Module +""" import gtk import gobject -import hippo -import gconf +#import hippo +#import gconf from gettext import gettext as _ +from sugar.tutorius.gtkutils import register_signals_numbered, get_children + class WidgetIdentifier(gtk.Window): """ - Tool that allows identifying widgets + Tool that allows identifying widgets. + """ __gtype_name__ = 'TutoriusWidgetIdentifier' @@ -32,7 +37,19 @@ class WidgetIdentifier(gtk.Window): gtk.Window.__init__(self) self._activity = activity - self._handlers = [] + self._handlers = {} + # dict of signals to register on the widgets. + # key : signal name + # value : initial checkbox status + signals = { + "focus":True, + "button-press-event":True, + "enter-notify-event":False, + "leave-notify-event":False, + "key-press-event":True, + "text-selected":True, + "clicked":True, + } self.set_decorated(False) self.set_resizable(False) @@ -47,63 +64,164 @@ class WidgetIdentifier(gtk.Window): self._expander.show() - vbox = gtk.VBox() - self._expander.add(vbox) - vbox.show() - + nbk = gtk.Notebook() + self._expander.add(nbk) + nbk.show() + ############################### + # Event log viewer page + ############################### self.logview = gtk.TextView() self.logview.set_editable(False) self.logview.set_cursor_visible(False) self.logview.set_wrap_mode(gtk.WRAP_NONE) self._textbuffer = self.logview.get_buffer() - sw = gtk.ScrolledWindow() - sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - sw.add(self.logview) + swd = gtk.ScrolledWindow() + swd.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + swd.add(self.logview) self.logview.show() - vbox.pack_start(sw) - sw.show() - - from sugar.tutorius.gtkutils import register_signals_numbered - self._handlers = register_signals_numbered(self._activity, self._handle_events) + nbk.append_page(swd, gtk.Label(_("Log"))) + swd.show() + + ############################### + # Filters page + ############################### + filters = gtk.Table( (len(signals)+1)/2, 2) + + xpos, ypos = 0, 0 + for key, active in signals.items(): + cbtn = gtk.CheckButton(label=key) + filters.attach(cbtn, xpos, xpos+1, ypos, ypos+1) + cbtn.show() + cbtn.set_active(active) + if active: + self._handlers[key] = register_signals_numbered( \ + self._activity, self._handle_events, events=(key,)) + else: + self._handlers[key] = [] + + cbtn.connect("toggled", self.__filter_toggle_cb, key) + + #Follow lines then columns + xpos, ypos = (xpos+1)%2, ypos+(xpos%2) + + nbk.append_page(filters, gtk.Label(_("Events"))) + filters.show() + + ############################### + # Explorer Page + ############################### + tree = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING) + explorer = gtk.TreeView(tree) + + pathrendr = gtk.CellRendererText() + pathrendr.set_properties(background="#ffffff", foreground="#000000") + pathcol = gtk.TreeViewColumn(_("Path"), pathrendr, text=0, background=0, foreground=0) + explorer.append_column(pathcol) + + typerendr = gtk.CellRendererText() + typerendr.set_properties(background="#ffffff", foreground="#000000") + typecol = gtk.TreeViewColumn(_("Widget"), typerendr, text=1, background=1, foreground=1) + explorer.append_column(typecol) + + self.__populate_treestore( + tree, #tree + tree.append(None, ["0",self._activity.get_name()]), #parent + self._activity, #widget + "0" #path + ) - def __expander_cb(self, *args): + explorer.set_expander_column(typecol) + + swd2 = gtk.ScrolledWindow() + swd2.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + swd2.add(explorer) + explorer.show() + nbk.append_page(swd2, gtk.Label(_("Explorer"))) + swd2.show() + + def __populate_treestore(self, tree, parent, widget, path): + """Populates the treestore with the widget's children recursively + @param tree gtk.TreeStore to populate + @param parent gtk.TreeIter to append to + @param widget gtk.Widget to check for children + @param path treeish of the widget + """ + #DEBUG: show parameters in log window gehehe + #self._handle_events((path,str(type(widget)))) + children = get_children(widget) + for i in xrange(len(children)): + childpath = ".".join([path, str(i)]) + child = children[i] + self.__populate_treestore( + tree, #tree + tree.append(parent, [childpath, child.get_name()]), #parent + child, #widget + childpath #path + ) + + + def __filter_toggle_cb(self, btn, eventname): + """Callback for signal name checkbuttons' toggling""" + #Disconnect existing handlers on key + self.__disconnect_handlers(eventname) + if btn.get_active(): + #if checked, reconnect + self._handlers[eventname] = register_signals_numbered( \ + self._activity, self._handle_events, events=(eventname,)) + + + def __expander_cb(self, *args): + """Callback for the window expander toggling""" if self._expander.get_expanded(): self.__move_expanded() else: self.__move_collapsed() def __move_expanded(self): - width = 400 + """Move the window to it's expanded position""" + width = 500 height = 300 - ww = gtk.gdk.screen_width() - wh = gtk.gdk.screen_height() + swidth = gtk.gdk.screen_width() + sheight = gtk.gdk.screen_height() self.set_size_request(width, height) - self.move((ww-width)/2, wh-height) + self.move((swidth-width)/2, sheight-height) def __move_collapsed(self): + """Move the window to it's collapsed position""" width = 150 height = 40 - ww = gtk.gdk.screen_width() - wh = gtk.gdk.screen_height() + swidth = gtk.gdk.screen_width() + sheight = gtk.gdk.screen_height() self.set_size_request(width, height) - self.move((ww-width)/2, wh-height) + self.move((swidth-width)/2, sheight-height) def __realize_cb(self, widget): + """Callback for realize""" self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window.set_accept_focus(True) self.__move_expanded() def _disconnect_handlers(self): - for widget, handlerid in self._handlers: - widget.handler_disconnect(handlerid) - self._handlers = [] - - def _handle_events(self,*args): + """ Disconnect all event handlers """ + for key in self._handlers: + self.__disconnect_handlers(key) + + def __disconnect_handlers(self, key): + """ Disconnect event handlers associated to signal name "key" """ + if self._handlers.has_key(key): + for widget, handlerid in self._handlers[key]: + widget.handler_disconnect(handlerid) + del self._handlers[key] + + def _handle_events(self, *args): + """ Event handler for subscribed widget events. + Accepts variable length argument list. Last must be + a two-tuple containing (event name, widget name) """ sig, name = args[-1] text = "\r\n".join( (["%s event received from %s" % (sig, name)] + diff --git a/src/sugar/tutorius/gtkutils.py b/src/sugar/tutorius/gtkutils.py index 1870dc4..bbd8863 100644 --- a/src/sugar/tutorius/gtkutils.py +++ b/src/sugar/tutorius/gtkutils.py @@ -47,13 +47,13 @@ def find_widget(base, target_fqdn): while len(path) > 0: try: - obj = obj.get_children()[int(path.pop(0))] + obj = get_children(obj)[int(path.pop(0))] except: break return obj -EVENTS = [ +EVENTS = ( "focus", "button-press-event", "enter-notify-event", @@ -61,9 +61,9 @@ EVENTS = [ "key-press-event", "text-selected", "clicked", -] +) -IGNORED_WIDGETS = [ +IGNORED_WIDGETS = ( "GtkVBox", "GtkHBox", "GtkAlignment", @@ -71,9 +71,9 @@ IGNORED_WIDGETS = [ "GtkButton", "GtkToolItem", "GtkToolbar", -] +) -def register_signals_numbered(target, handler, prefix="0", max_depth=None): +def register_signals_numbered(target, handler, prefix="0", max_depth=None, events=None): """ Recursive function to register event handlers on an target and it's children. The event handler is called with an extra @@ -96,25 +96,24 @@ def register_signals_numbered(target, handler, prefix="0", max_depth=None): @returns list of (object, handler_id) """ ret = [] + evts = events or EVENTS #Gtk Containers have a get_children() function - if hasattr(target, "get_children") and \ - hasattr(target.get_children, "__call__"): - children = target.get_children() - for i in range(len(children)): - child = children[i] - if max_depth is None or max_depth > 0: - #Recurse with a prefix on all children - pre = ".".join( \ - [p for p in (prefix, str(i)) if not p is None] - ) - if max_depth is None: - dep = None - else: - dep = max_depth - 1 - ret+=register_signals_numbered(child, handler, pre, dep) + children = get_children(target) + for i in range(len(children)): + child = children[i] + if max_depth is None or max_depth > 0: + #Recurse with a prefix on all children + pre = ".".join( \ + [p for p in (prefix, str(i)) if not p is None] + ) + if max_depth is None: + dep = None + else: + dep = max_depth - 1 + ret+=register_signals_numbered(child, handler, pre, dep, evts) #register events on the target if a widget XXX necessary to check this? if isinstance(target, gtk.Widget): - for sig in EVENTS: + for sig in evts: try: ret.append( \ (target, target.connect(sig, handler, (sig, prefix) ))\ @@ -124,7 +123,7 @@ def register_signals_numbered(target, handler, prefix="0", max_depth=None): return ret -def register_signals(target, handler, prefix=None, max_depth=None): +def register_signals(target, handler, prefix=None, max_depth=None, events=None): """ Recursive function to register event handlers on an target and it's children. The event handler is called with an extra @@ -148,28 +147,27 @@ def register_signals(target, handler, prefix=None, max_depth=None): @returns list of (object, handler_id) """ ret = [] + evts = events or EVENTS #Gtk Containers have a get_children() function - if hasattr(target, "get_children") and \ - hasattr(target.get_children, "__call__"): - for child in target.get_children(): - if max_depth is None or max_depth > 0: - #Recurse with a prefix on all children - pre = ".".join( \ - [p for p in (prefix, target.get_name()) \ - if not (p is None or p in IGNORED_WIDGETS)] \ - ) - if max_depth is None: - dep = None - else: - dep = max_depth - 1 - ret += register_signals(child, handler, pre, dep) + for child in get_children(target): + if max_depth is None or max_depth > 0: + #Recurse with a prefix on all children + pre = ".".join( \ + [p for p in (prefix, target.get_name()) \ + if not (p is None or p in IGNORED_WIDGETS)] \ + ) + if max_depth is None: + dep = None + else: + dep = max_depth - 1 + ret += register_signals(child, handler, pre, dep, evts) name = ".".join( \ [p for p in (prefix, target.get_name()) \ if not (p is None or p in IGNORED_WIDGETS)] \ ) #register events on the target if a widget XXX necessary to check this? if isinstance(target, gtk.Widget): - for sig in EVENTS: + for sig in evts: try: ret.append( \ (target, target.connect(sig, handler, (sig, name) )) \ @@ -179,3 +177,19 @@ def register_signals(target, handler, prefix=None, max_depth=None): return ret +def get_children(widget): + """Lists widget's children""" + #widgets with multiple children + try: + return widget.get_children() + except (AttributeError,TypeError): + pass + + #widgets with a single child + try: + return [widget.get_child(),] + except (AttributeError,TypeError): + pass + + #otherwise return empty list + return [] -- cgit v0.9.1