# Copyright (C) 2009, Tutorius.org # Greatly influenced by sugar/activity/namingalert.py # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (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 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # 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 from gettext import gettext as _ from .gtkutils import register_signals_numbered, get_children class WidgetIdentifier(gtk.Window): """ Tool that allows identifying widgets. """ __gtype_name__ = 'TutoriusWidgetIdentifier' def __init__(self, activity): gtk.Window.__init__(self) self._activity = activity 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) self.set_modal(False) self.connect('realize', self.__realize_cb) self._expander = gtk.Expander(_("Widget Identifier")) self._expander.set_expanded(True) self.add(self._expander) self._expander.connect("notify::expanded", self.__expander_cb) self._expander.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() swd = gtk.ScrolledWindow() swd.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) swd.add(self.logview) self.logview.show() 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 ) 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() ############################### # GObject Explorer Page ############################### tree2 = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING) explorer2 = gtk.TreeView(tree2) pathrendr2 = gtk.CellRendererText() pathrendr2.set_properties(background="#ffffff", foreground="#000000") pathcol2 = gtk.TreeViewColumn(_("Path"), pathrendr2, text=0, background=0, foreground=0) explorer2.append_column(pathcol2) typerendr2 = gtk.CellRendererText() typerendr2.set_properties(background="#ffffff", foreground="#000000") typecol2 = gtk.TreeViewColumn(_("Widget"), typerendr2, text=1, background=1, foreground=1) explorer2.append_column(typecol2) self.__populate_gobject_treestore( tree2, #tree tree2.append(None, ["activity",self._activity.get_name()]), #parent self._activity, #widget "activity" #path ) explorer2.set_expander_column(typecol2) swd3 = gtk.ScrolledWindow() swd3.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) swd3.add(explorer2) explorer2.show() nbk.append_page(swd3, gtk.Label(_("GObject Explorer"))) swd3.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 __populate_gobject_treestore(self, tree, parent, widget, path, listed=None): """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 """ listed = listed or [] if widget in listed: return listed.append(widget) #DEBUG: show parameters in log window gehehe #self._handle_events((path,str(type(widget)))) #Add a child node children = tree.append(parent, ["","children"]) for i in dir(widget): #Add if a gobject try: child = getattr(widget, i) except: continue if isinstance(child,gobject.GObject): childpath = ".".join([path, i]) child = getattr(widget, i) self.__populate_gobject_treestore( tree, #tree tree.append(children, [childpath, i]), #parent child, #widget path + "." + i, #path, listed ) widgets = tree.append(parent, ["","widgets"]) wchildren = get_children(widget) for i in xrange(len(wchildren)): childpath = ".".join([path, str(i)]) child = wchildren[i] self.__populate_gobject_treestore( tree, #tree tree.append(widgets, [childpath, (hasattr(child,"get_name") and child.get_name()) or i]), #parent child, #widget childpath, #path, listed ) #Add signals and attributes nodes signals = tree.append(parent, ["","signals"]) for signame in gobject.signal_list_names(widget): tree.append(signals, ["",signame]) attributes = tree.append(parent, ["","properties"]) for prop in gobject.list_properties(widget): tree.append(attributes, ["",prop]) 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): """Move the window to it's expanded position""" width = 500 height = 300 swidth = gtk.gdk.screen_width() sheight = gtk.gdk.screen_height() self.set_size_request(width, height) self.move((swidth-width)/2, sheight-height) def __move_collapsed(self): """Move the window to it's collapsed position""" width = 150 height = 40 swidth = gtk.gdk.screen_width() sheight = gtk.gdk.screen_height() self.set_size_request(width, 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): """ 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)] + self._textbuffer.get_text(*(self._textbuffer.get_bounds()) ).split("\r\n"))[:80] ) self._textbuffer.set_text(text)