~ubuntu-branches/debian/experimental/dogtail/experimental

« back to all changes in this revision

Viewing changes to sniff/sniff

  • Committer: Package Import Robot
  • Author(s): Alessio Treglia
  • Date: 2013-02-09 16:01:44 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20130209160144-k2yk35tll4eew9wg
Tags: 0.8.1-1
* New maintainer. (Closes: #696136) (Closes: #553898)
* Set packaging format to 3.0 (quilt).
* New upstream release (Closes: #486452):
  - String exceptions are not used anymore. (Closes: #585287)
  - Fix missing check in findChildren(), tree.py (Closes: #485758)
* ACK NMUs:
  - Convert APT's API patch into the quilt format. (Closes: #572087)
  - Convert Ludovico Gardenghi's patch into the quilt
    format. (Closes: #485752)
* Fix desktop file as Freedesktop.org's per-spec.
* Migrate from CDBS + python-support to DH short-form + dh_python2.
* Move to section python.
* Refresh {,Build-}Depends lists.
* Remove xbase-clients from Depends. (Closes: #601486)
* Add Homepage field. (Closes: #572570)
* Add watch file.
* Add gbp config file.
* Refresh debian/copyright to meet copyright format 1.0.
* Install NEWS as upstream changelog.
* Bump Standards.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/env python
2
2
# -*- coding: UTF8 -*-
3
 
 
4
 
appName = 'Sniff'
5
 
appAuthors = ['Zack Cerza <zcerza@redhat.com>', 'David Malcolm <dmalcolm@redhat.com']
6
 
 
7
 
from dogtail.utils import checkForA11yInteractively
8
 
checkForA11yInteractively()
9
 
 
10
 
from dogtail import tree
11
 
from dogtail import utils
12
 
import gobject
13
 
import gnome
14
 
import atspi
15
 
program = gnome.program_init(appName, '0.1')
16
 
import gtk.glade
17
 
 
18
 
import os
19
 
if os.path.exists('sniff.glade'):
20
 
    x = gtk.glade.XML('sniff.glade')
21
 
else:
22
 
    import sys
23
 
    exec_root = sys.argv[0].split("/bin/")[0]
24
 
    if exec_root[0] is not '/':
25
 
        exec_root = "/usr"
26
 
    x = gtk.glade.XML(exec_root + '/share/dogtail/glade/sniff.glade')
27
 
 
28
 
sniff = x.get_widget(appName)
29
 
 
30
 
try:
31
 
    sniff.set_icon_from_file('../icons/dogtail-head.svg')
32
 
except:
33
 
    sniff.set_icon_from_file('/usr/share/icons/hicolor/scalable/apps/dogtail-head.svg')
34
 
 
35
 
view = x.get_widget('treeTreeView')
36
 
 
37
 
nameTextLabel = x.get_widget('nameTextLabel')
38
 
roleNameTextLabel = x.get_widget('roleNameTextLabel')
39
 
descTextLabel = x.get_widget('descTextLabel')
40
 
actionsTextLabel = x.get_widget('actionsTextLabel')
41
 
textLabel = x.get_widget('textLabel')
42
 
textTextView = x.get_widget('textTextView')
43
 
 
44
 
# Indices of the various fields of the tree model:
45
 
MODEL_FIELD_NODE = 0
46
 
MODEL_FIELD_NAME = 1
47
 
MODEL_FIELD_ROLENAME = 2
48
 
MODEL_FIELD_DESCRIPTION = 3
49
 
MODEL_FIELD_PIXBUF = 4
50
 
 
51
 
def quit(*args):
52
 
    gtk.main_quit()
53
 
 
54
 
def expandAll(widget, *args):
55
 
    global view
56
 
    if args[0] == True: view.expand_all()
57
 
    elif args[0] == False: view.collapse_all()
58
 
 
59
 
def showAbout(*args):
60
 
    about = gtk.AboutDialog()
61
 
    about.set_name(appName)
62
 
    about.set_authors(appAuthors)
63
 
    about.set_comments('Explore your desktop with Dogtail')
64
 
    about.set_website('http://people.redhat.com/zcerza/dogtail/')
65
 
    about.show_all()
66
 
 
67
 
def connectSignals():
68
 
    sniff.connect('delete_event', quit)
69
 
 
70
 
    quit1 = x.get_widget('quit1')
71
 
    quit1.connect('activate', quit)
72
 
 
73
 
    expand_all1 = x.get_widget('expand_all1')
74
 
    expand_all1.connect('activate', expandAll, True)
75
 
    collapse_all1 = x.get_widget('collapse_all1')
76
 
    collapse_all1.connect('activate', expandAll, False)
77
 
 
78
 
    about1 = x.get_widget('about1')
79
 
    about1.connect('activate', showAbout)
80
 
 
81
 
    refreshMenuItem = x.get_widget('refresh1')
82
 
    refreshMenuItem.connect('activate', refreshAll)
83
 
 
84
 
    view.connect('button-press-event', buttonPress)
85
 
    view.connect('row-expanded', rowExpanded)
86
 
    view.connect('row-collapsed', rowCollapsed)
87
 
    treeSelection = view.get_selection()
88
 
    treeSelection.connect('changed', selectionChanged)
89
 
 
90
 
def buttonPress(widget, event, *userParams):
91
 
    global model
92
 
    try: path, treeViewCol, relX, relY = \
93
 
                    view.get_path_at_pos(int(event.x), int(event.y))
94
 
    except TypeError: return
95
 
    node = model[path][0]
96
 
    setUpTable(node)
97
 
 
98
 
    if event.button == 3:
99
 
        menu = gtk.Menu()
100
 
        menuItem = None
101
 
        if node.actions:
102
 
            for action in node.actions.values():
103
 
                menuItem = gtk.MenuItem(action.name.capitalize())
104
 
                menuItem.connect('activate', menuItemActivate, action.do)
105
 
                menuItem.show()
106
 
                menu.append(menuItem)
107
 
        if not menuItem: return
108
 
        menu.show()
109
 
        menu.popup(None, None, None, event.button, event.time)
110
 
 
111
 
# I hate globals too. I think we need one here, though.
112
 
# Make it a non-integer, so we can know if it has been set yet (later).
113
 
textTextViewBufferChangedLastHandlerID = 3.141592654
114
 
 
115
 
def setUpTable(node):
116
 
    """Generic code for setting up the table under the TreeView"""
117
 
    nameTextLabel.set_text(node.name)
118
 
    roleNameTextLabel.set_text(node.roleName)
119
 
    descTextLabel.set_text(node.description)
120
 
    if node.actions:
 
3
"""
 
4
http://en.wikipedia.org/wiki/Model-view-controller
 
5
 
 
6
The SniffApp class sets up all of sniff's widgets.
 
7
 
 
8
Data storage is handled by the SniffModel class.
 
9
There is no SniffView class; we just use a GtkTreeView.
 
10
Data display is handled by the SniffController class.
 
11
"""
 
12
import gi
 
13
gi.require_version('Gtk', '3.0')
 
14
gi.require_version('Gdk', '3.0')
 
15
import sys
 
16
from dogtail.config import config
 
17
 
 
18
if config.checkForA11y:
 
19
    from dogtail.utils import checkForA11yInteractively
 
20
    checkForA11yInteractively()
 
21
 
 
22
config.logDebugToFile = False
 
23
config.childrenLimit = 100000
 
24
 
 
25
import pyatspi
 
26
import Accessibility
 
27
from gi.repository import Gtk
 
28
from gi.repository import Gdk
 
29
from gi.repository import Gio
 
30
from gi.repository import GdkPixbuf
 
31
from gi.repository import GObject
 
32
 
 
33
builder = Gtk.Builder()
 
34
 
 
35
class SniffApp(object):
 
36
    appName = 'Sniff'
 
37
    appAuthors = ['Zack Cerza <zcerza@redhat.com>', \
 
38
            'David Malcolm <dmalcolm@redhat.com']
 
39
 
 
40
    def __init__(self):
 
41
        self.builder = builder
 
42
        import os
 
43
        if os.path.exists('sniff.ui'):
 
44
            self.builder.add_from_file('sniff.ui')
 
45
        else:
 
46
            import sys
 
47
            exec_root = sys.argv[0].split("/bin/")[0]
 
48
            if exec_root[0] is not '/':
 
49
                exec_root = "/usr"
 
50
            self.builder.add_from_file(exec_root + \
 
51
                    '/share/dogtail/glade/sniff.ui')
 
52
        self.app = self.builder.get_object(self.appName)
 
53
        try:
 
54
            self.app.set_icon_from_file('../icons/dogtail-head.svg')
 
55
        except Exception:
 
56
            import os
 
57
            path = os.path.abspath (os.path.join(__file__, os.path.pardir, os.path.pardir))
 
58
            self.app.set_icon_from_file( os.path.join( path, \
 
59
                    'share/icons/hicolor/scalable/apps/dogtail-head.svg'))
 
60
        self.setUpWidgets()
 
61
        self.connectSignals()
 
62
        self.app.show_all()
 
63
        Gtk.main()
 
64
 
 
65
    def setUpWidgets(self):
 
66
        self.quit1 = self.builder.get_object('quit1')
 
67
        self.expand_all1 = self.builder.get_object('expand_all1')
 
68
        self.collapse_all1 = self.builder.get_object('collapse_all1')
 
69
        self.about1 = self.builder.get_object('about1')
 
70
        self.refreshMenuItem = self.builder.get_object('refresh1')
 
71
        self.autoRefreshMenuItem = self.builder.get_object('autorefresh')
 
72
        self.setRootMenuItem = self.builder.get_object('setRootMenuItem')
 
73
        self.unsetRootMenuItem = self.builder.get_object('unsetRootMenuItem')
 
74
        self.about = None
 
75
 
 
76
        self.tree = SniffController()
 
77
 
 
78
    def connectSignals(self):
 
79
        self.app.connect('delete_event', self.quit, self)
 
80
        self.quit1.connect('activate', self.quit, self)
 
81
        self.expand_all1.connect('activate', self.tree.expandAll, True)
 
82
        self.collapse_all1.connect('activate', self.tree.expandAll, False)
 
83
        self.about1.connect('activate', self.showAbout, self)
 
84
        self.refreshMenuItem.connect('activate', self.tree.refresh)
 
85
        self.autoRefreshMenuItem.connect('toggled', self.tree.toggleAutoRefresh)
 
86
        self.setRootMenuItem.connect('activate', self.tree.changeRoot, True)
 
87
        self.unsetRootMenuItem.connect('activate', self.tree.changeRoot, False)
 
88
 
 
89
        self.setStartupAutoRefresh()
 
90
 
 
91
    def setStartupAutoRefresh(self):
 
92
        import os
 
93
        if not os.path.exists('/tmp/sniff_refresh.lock'):
 
94
            self.autoRefreshMenuItem.set_active(True)
 
95
 
 
96
    def showAbout(self, *args):
 
97
        if not self.about:
 
98
            self.about = Gtk.AboutDialog()
 
99
            self.about.set_name(self.appName)
 
100
            self.about.set_authors(self.appAuthors)
 
101
            self.about.set_comments('Explore your desktop with Dogtail')
 
102
            self.about.set_website('http://people.redhat.com/zcerza/dogtail/')
 
103
            self.about.connect("response", self.hideAbout)
 
104
        self.about.show_all()
 
105
 
 
106
    def hideAbout(self, window, response):
 
107
        if response == Gtk.ResponseType.CANCEL: window.hide()
 
108
 
 
109
    def quit(self, *args):
 
110
        Gtk.main_quit()
 
111
 
 
112
 
 
113
class SniffController(object):
 
114
    invalidBufferCallbackID = None
 
115
 
 
116
    def __init__(self):
 
117
        self.builder = builder
 
118
        self.nameTextLabel = self.builder.get_object('nameTextLabel')
 
119
        self.nameTextLabel.set_text('')
 
120
        self.roleNameTextLabel = self.builder.get_object('roleNameTextLabel')
 
121
        self.roleNameTextLabel.set_text('')
 
122
        self.descTextLabel = self.builder.get_object('descTextLabel')
 
123
        self.descTextLabel.set_text('')
 
124
        self.actionsTextLabel = self.builder.get_object('actionsTextLabel')
 
125
        self.actionsTextLabel.set_text('')
 
126
        self.textTextView = self.builder.get_object('textTextView')
 
127
        self.textTextViewBufferCallbackID = self.invalidBufferCallbackID
 
128
        self.textTextView.set_sensitive(False)
 
129
        self.textTextView.get_buffer().set_text('')
 
130
        self.labelerButton = self.builder.get_object('labelerButton')
 
131
        self.labelerButton.set_sensitive(False)
 
132
        self.labeleeButton = self.builder.get_object('labeleeButton')
 
133
        self.labeleeButton.set_sensitive(False)
 
134
        self.stateView = self.builder.get_object('stateTreeView')
 
135
        self.highlight1 = self.builder.get_object('highlight1')
 
136
        self.autorefresh = self.builder.get_object('autorefresh')
 
137
        self.stateModel = StateModel()
 
138
        self.setUpStateView()
 
139
        self.treeView = self.builder.get_object('treeTreeView')
 
140
        self.treeSelection = self.treeView.get_selection()
 
141
        self.treeModel = SniffModel()
 
142
        self.setUpTreeView()
 
143
        self.connectSignals()
 
144
        self.refresh()
 
145
 
 
146
    def setUpStateView(self):
 
147
        self.stateView.set_model(self.stateModel)
 
148
        cellRenderer = Gtk.CellRendererText()
 
149
        col = Gtk.TreeViewColumn('Present States', cellRenderer, \
 
150
                text=self.stateModel.stateColumn)
 
151
        col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
 
152
        self.stateView.insert_column(col, -1)
 
153
 
 
154
    def setUpTreeView(self):
 
155
        self.treeView.set_enable_tree_lines(True)
 
156
 
 
157
        self.treeView.set_model(self.treeModel)
 
158
 
 
159
        col = Gtk.TreeViewColumn()
 
160
        cellRenderer = Gtk.CellRendererPixbuf()
 
161
        col.pack_start(cellRenderer, expand = False)
 
162
        col.add_attribute(cellRenderer, 'pixbuf', self.treeModel.pixbufColumn)
 
163
 
 
164
        cellRenderer = Gtk.CellRendererText()
 
165
        col.pack_end(cellRenderer, expand = False)
 
166
        col.add_attribute(cellRenderer, 'text', self.treeModel.nameColumn)
 
167
 
 
168
        col.set_title('Name')
 
169
 
 
170
        self.treeView.insert_column(col, -1)
 
171
 
 
172
        for column in self.treeView.get_columns():
 
173
            column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
 
174
            column.set_resizable(True)
 
175
        self.treeView.show()
 
176
        path = 0
 
177
        self.treeView.expand_all()
 
178
        #self.rowExpanded(self.treeView, self.treeModel.get_iter(path), path)
 
179
 
 
180
    def changeRoot(self, menuItem, toSelected = True, *args):
 
181
        if toSelected: node = self.getSelectedNode()
 
182
        if toSelected and node: self.treeModel.changeRoot(node)
 
183
        elif not toSelected: self.treeModel.reset()
 
184
        else: return
 
185
        self.refresh(refreshModel = False)
 
186
 
 
187
    def refresh(self, menuItem = None, refreshModel = True, *args):
 
188
        if refreshModel: self.treeModel.refresh()
 
189
        rootPath = self.treeModel.get_path(self.treeModel.get_iter_first())
 
190
        self.treeView.expand_all()
 
191
        self.treeView.expand_row(rootPath, False)
 
192
 
 
193
    def toggleAutoRefresh(self, *args):
 
194
        if self.autorefresh.get_active() is True:
 
195
            pyatspi.Registry.registerEventListener(self.treeModel.nodeChanged, \
 
196
                'object:children-changed')
 
197
            pyatspi.Registry.registerEventListener(self.treeModel.nodeChanged, \
 
198
                'object:property-change:accessible-name')
 
199
            pyatspi.Registry.registerEventListener(self.treeModel.nodeChanged, \
 
200
                'object:property-change:accessible-state')
 
201
            pyatspi.Registry.registerEventListener(self.treeModel.nodeChanged, \
 
202
                'object:state-changed')
 
203
            self.refresh()
 
204
        else:
 
205
            pyatspi.Registry.deregisterEventListener(self.treeModel.nodeChanged, \
 
206
                'object:children-changed')
 
207
            pyatspi.Registry.deregisterEventListener(self.treeModel.nodeChanged, \
 
208
                'object:property-change:accessible-name')
 
209
            pyatspi.Registry.deregisterEventListener(self.treeModel.nodeChanged, \
 
210
                'object:property-change:accessible-state')
 
211
            pyatspi.Registry.deregisterEventListener(self.treeModel.nodeChanged, \
 
212
                'object:state-changed')
 
213
 
 
214
    def connectSignals(self):
 
215
        self.labelerButton.connect('clicked', self.showRelationTarget, \
 
216
                'labeler')
 
217
        self.labeleeButton.connect('clicked', self.showRelationTarget, \
 
218
                'labelee')
 
219
        self.treeView.connect('button-press-event', self.buttonPress)
 
220
        self.treeView.connect('key-press-event', self.keyPress)
 
221
        self.treeView.connect('row-expanded', self.rowExpanded, self.treeModel)
 
222
        self.treeView.connect('row-collapsed', self.rowCollapsed)
 
223
        self.treeSelection.connect('changed', self.selectionChanged)
 
224
        self.refresh()
 
225
 
 
226
    def selectionChanged(self, treeSelection):
 
227
        node = self.getSelectedNode()
 
228
        if node:
 
229
            self.setUpBottomPane(node)
 
230
            if self.highlight1.get_active() is True:
 
231
                node.blink()
 
232
 
 
233
    def getSelectedNode(self):
 
234
        (store, iter) = self.treeView.get_selection().get_selected()
 
235
        if not iter: node = None
 
236
        else: node = self.treeModel.getNode(iter)
 
237
        return node
 
238
 
 
239
    def expandAll(self, widget, *args):
 
240
        if args[0] == True: self.treeView.expand_all()
 
241
        elif args[0] == False: self.treeView.collapse_all()
 
242
 
 
243
    def rowExpanded(self, treeview, iter, path, *userParams):
 
244
        row = self.treeModel[path]
 
245
        childRows = row.iterchildren()
 
246
        while True:
 
247
            try:
 
248
                childRow = childRows.next()
 
249
                self.treeModel.populateChildren(childRow.iter)
 
250
            except StopIteration: break
 
251
 
 
252
    def rowCollapsed(self, treeview, iter, path, *userParams):
 
253
        row = self.treeModel[path]
 
254
        childRows = row.iterchildren()
 
255
        try:
 
256
            while True:
 
257
                childRow = childRows.next()
 
258
                grandChildRows = childRow.iterchildren()
 
259
                try:
 
260
                    while True:
 
261
                        grandChildRow = grandChildRows.next()
 
262
                        self.treeModel.remove(grandChildRow.iter)
 
263
                except StopIteration: pass
 
264
        except StopIteration: pass
 
265
 
 
266
    def menuItemActivate(self, menuItem, *userParams):
 
267
        if len(userParams) < 2: return
 
268
        method = userParams[0]
 
269
        arg = userParams[1]
 
270
        method(arg)
 
271
 
 
272
    def keyPress(self, widget, event, *userParams):
 
273
        if event.keyval == Gdk.KEY_Return:
 
274
            path = self.treeSelection.get_selected_rows()[1][0]
 
275
            if self.treeView.row_expanded(path):
 
276
                self.treeView.collapse_row(path)
 
277
            else:
 
278
                self.treeView.expand_row(path, False)
 
279
        return False
 
280
 
 
281
    def buttonPress(self, widget, event, *userParams):
 
282
        try: path, treeViewCol, relX, relY = \
 
283
                        self.treeView.get_path_at_pos(int(event.x), \
 
284
                        int(event.y))
 
285
        except TypeError: return
 
286
        node = self.treeModel.getNode(self.treeModel.get_iter(path))
 
287
        if node == None: return
 
288
 
 
289
        if event.button == 3:
 
290
            self.menu = Gtk.Menu()
 
291
            menuItem = None
 
292
            if node.actions:
 
293
                for action in node.actions.keys():
 
294
                    menuItem = Gtk.MenuItem(action.capitalize())
 
295
                    menuItem.connect('activate', self.menuItemActivate, node.doActionNamed, action)
 
296
                    menuItem.show()
 
297
                    self.menu.append(menuItem)
 
298
            if not menuItem: return
 
299
            self.menu.show_all()
 
300
            self.menu.popup(None, None, None, None, event.button, event.time)
 
301
 
 
302
    def showRelationTarget(self, button, relation, *args):
 
303
        target = getattr(self.getSelectedNode(), relation)
 
304
        if not target: return
 
305
        try: target.blink()
 
306
        except:
 
307
            import traceback
 
308
            traceback.print_exc()
 
309
 
 
310
    def setUpBottomPane(self, node):
 
311
        """Generic code for setting up the table under the TreeView"""
 
312
        if node == None: return
 
313
        self.nameTextLabel.set_text(node.name)
 
314
        self.roleNameTextLabel.set_text(node.roleName)
 
315
        self.descTextLabel.set_text(node.description)
121
316
        str = ''
122
 
        for action in node.actions.values(): str = ' '.join([str, action.name]).strip()
123
 
        actionsTextLabel.set_text(str)
124
 
 
125
 
    global textTextViewBufferChangedLastHandlerID
126
 
    # Have we connected this signal yet? If so, disconnect it before proceeding.
127
 
    if int(textTextViewBufferChangedLastHandlerID) == \
128
 
            textTextViewBufferChangedLastHandlerID:
129
 
        textTextView.get_buffer().disconnect(textTextViewBufferChangedLastHandlerID)
130
 
 
131
 
    if node.text is not None:
132
 
        buffer = textTextView.get_buffer()
133
 
        buffer.set_text(node.text)
134
 
        # Eeew! I'm touching tree's privates.
135
 
        if node._Node__editableText:
136
 
            # Remember the handler ID of this connection.
137
 
            textTextView.set_sensitive(True)
138
 
            textTextViewBufferChangedLastHandlerID = \
139
 
                    buffer.connect('changed', changeText, node)
140
 
        else:
141
 
            textTextView.set_sensitive(False)
142
 
    else:
143
 
        textTextView.get_buffer().set_text('')
144
 
        textTextView.set_sensitive(False)
145
 
 
146
 
def changeText(textBuffer, node):
147
 
    node.text = textBuffer.get_text(textBuffer.get_start_iter(), \
148
 
                    textBuffer.get_end_iter())
149
 
 
150
 
def rowExpanded(treeview, iter, path, *userParams):
151
 
    global model
152
 
    row = model[path]
153
 
    childRows = row.iterchildren()
154
 
    node = row[0]
155
 
    childNodes = node.children
156
 
    for childNode in childNodes:
157
 
        childRow = childRows.next()
158
 
        addChildren(childNode, childRow.iter)
159
 
 
160
 
def rowCollapsed(treeview, iter, path, *userParams):
161
 
    global model
162
 
    row = model[path]
163
 
    childRows = row.iterchildren()
164
 
    try:
165
 
        while True:
166
 
            childRow = childRows.next()
167
 
            grandChildRows = childRow.iterchildren()
168
 
            try:
169
 
                while True:
170
 
                    grandChildRow = grandChildRows.next()
171
 
                    model.remove(grandChildRow.iter)
172
 
            except StopIteration: pass
173
 
    except StopIteration: pass
174
 
 
175
 
def selectionChanged(treeSelection):
176
 
    # print "selection changed"
177
 
    node = getSelectedNode()
178
 
    if node: node.blink()
179
 
 
180
 
def getSelectedNode():
181
 
    global model
182
 
    global view
183
 
    (store, iter) = view.get_selection().get_selected()
184
 
    if not iter: node = None
185
 
    else: node = model[iter][0]
186
 
    return node
187
 
 
188
 
def menuItemActivate(menuItem, *userParams):
189
 
    method = userParams[0]
190
 
    if method: method()
191
 
 
192
 
def refreshAll(menuItem, *userParams):
193
 
    global model
194
 
    resetModel()
195
 
 
196
 
def addNodeToModel(node, parentInTreeView = None):
197
 
    global model
198
 
    iter = model.insert_before(parentInTreeView, None)
199
 
    model.set_value(iter, MODEL_FIELD_NODE, node)
200
 
    return iter
201
 
 
202
 
def addChildren(node, parentInTreeView = None):
203
 
    global model
204
 
    for child in node.children:
205
 
        iter = addNodeToModel(child, parentInTreeView)
206
 
 
207
 
def showNode(node, parentInTreeView = None):
208
 
    global model
209
 
    iter = addNodeToModel(node, parentInTreeView)
210
 
    addChildren(node, iter)
211
 
 
212
 
def resetModel():
213
 
    global model
214
 
    model.clear()
215
 
    showNode(tree.root)
216
 
    rootPath = model.get_path(model.get_iter_root())
217
 
    view.expand_row(rootPath, False)
 
317
        if node.actions: str = ' '.join(node.actions.keys())
 
318
        self.actionsTextLabel.set_text(str)
 
319
 
 
320
        # Have we connected this signal yet?
 
321
        # If so, disconnect it before proceeding.
 
322
        if self.textTextViewBufferCallbackID != self.invalidBufferCallbackID:
 
323
            self.textTextView.get_buffer().disconnect( \
 
324
                    self.textTextViewBufferCallbackID)
 
325
            self.textTextViewBufferCallbackID = self.invalidBufferCallbackID
 
326
 
 
327
        if node.text is not None:
 
328
            buffer = self.textTextView.get_buffer()
 
329
            buffer.set_text(node.text)
 
330
            try:
 
331
                node.queryEditableText()
 
332
                # Remember the handler ID of this connection.
 
333
                self.textTextView.set_sensitive(True)
 
334
                self.textTextViewBufferCallbackID = \
 
335
                        buffer.connect('changed', self.changeText, node)
 
336
            except NotImplementedError:
 
337
                self.textTextView.set_sensitive(False)
 
338
        else:
 
339
            self.textTextView.get_buffer().set_text('')
 
340
            self.textTextView.set_sensitive(False)
 
341
 
 
342
        if node.labeler and not node.labeler.dead:
 
343
            self.labelerButton.set_sensitive(True)
 
344
            self.labelerButton.show()
 
345
        #elif node.labeler and node.labeler.dead:
 
346
        #    print "labeler is dead", node.labeler
 
347
        else:
 
348
            self.labelerButton.set_sensitive(False)
 
349
            self.labelerButton.hide()
 
350
        if node.labelee and not node.labelee.dead:
 
351
            self.labeleeButton.set_sensitive(True)
 
352
            self.labeleeButton.show()
 
353
        #elif node.labelee and node.labelee.dead:
 
354
        #    print "labelee is dead", node.labelee
 
355
        else:
 
356
            self.labeleeButton.set_sensitive(False)
 
357
            self.labeleeButton.hide()
 
358
 
 
359
        self.stateModel.setNode(node)
 
360
 
 
361
    def changeText(self, textBuffer, node):
 
362
        if node == None: return
 
363
        node.text = textBuffer.get_text(textBuffer.get_start_iter(), \
 
364
                        textBuffer.get_end_iter())
 
365
 
 
366
class SniffModel(Gtk.TreeStore):
 
367
    nodeColumn = 0
 
368
    nameColumn = 1
 
369
    pixbufColumn = 2
 
370
    eventQueue = []
 
371
    cache = {}
 
372
 
 
373
    def __init__(self):
 
374
        self.builder = builder
 
375
        #self.autorefresh = self.builder.get_object('autorefresh')
 
376
        Gtk.TreeStore.__init__(self, GObject.TYPE_PYOBJECT, \
 
377
                GObject.TYPE_STRING, GdkPixbuf.Pixbuf)
 
378
        root = pyatspi.Registry.getDesktop(0)
 
379
        self.rootNode = self.initialRootNode = root
 
380
        self.appendAndPopulate(None, self.rootNode)
 
381
 
 
382
    def __contains__(self, item):
 
383
        from dogtail.tree import Node
 
384
        if isinstance(item, Node):
 
385
            if item in self.cache:
 
386
                row = self.cache[item]
 
387
                # If row is None, we need to call getPath() to be sure
 
388
                if not row:
 
389
                    path = self.getPath(item)
 
390
                    return path is not None
 
391
                elif row in self: return True
 
392
            return False
 
393
        elif isinstance(item, Gtk.TreeIter):
 
394
            return self.iter_is_valid(item)
 
395
        elif isinstance(item, list) or isinstance(item, tuple):
 
396
            try: iter = self.get_iter(item)
 
397
            except ValueError: return False
 
398
            return iter in self
 
399
        elif isinstance(item, Gtk.TreeRowReference):
 
400
            return item.valid() and item.get_path() in self
 
401
        else:
 
402
            raise TypeError
 
403
 
 
404
    def changeRoot(self, node):
 
405
        self.rootNode = node
 
406
        self.refresh()
 
407
 
 
408
    def reset(self):
 
409
        self.rootNode = self.initialRootNode
 
410
        self.refresh()
 
411
 
 
412
    def refresh(self):
 
413
        self.cache.clear()
 
414
        self.clear()
 
415
        self.appendAndPopulate(None, self.rootNode)
 
416
 
 
417
    def append(self, parentIter, node):
 
418
        if node: self.cache[node] = None
 
419
        pb = self.getPixbufForNode(node)
 
420
        return Gtk.TreeStore.append(self, parentIter, (node, node.name, pb))
 
421
 
 
422
    def remove(self, iter):
 
423
        node = self.getNode(iter)
 
424
        try: del self.cache[node]
 
425
        finally: return Gtk.TreeStore.remove(self, iter)
 
426
 
 
427
    def populateChildren(self, iter):
 
428
        if not iter in self:
 
429
            return False
 
430
        result = True
 
431
        node = self.getNode(iter)
 
432
        for child in node.children:
 
433
            if child in self: continue
 
434
            result = result and self.append(iter, child)
 
435
        return result
 
436
 
 
437
    def appendAndPopulate(self, iter, node):
 
438
        childIter = self.append(iter, node)
 
439
        return self.populateChildren(childIter)
 
440
 
 
441
    def getNode(self, iter):
 
442
        if not iter in self: return None
 
443
        return self.get_value(iter, self.nodeColumn)
 
444
 
 
445
    def getPath(self, node):
 
446
        if not node: raise ValueError
 
447
        try: indexInParent = node.indexInParent
 
448
        except LookupError: return None
 
449
        root = pyatspi.Registry.getDesktop(0)
 
450
        row = self.cache.get(node, None)
 
451
        path = []
 
452
        needParent = True
 
453
        if row:
 
454
            if row in self: path = row.get_path()
 
455
            else: del self.cache[node]
 
456
        elif node == self.rootNode:
 
457
            indexInParent = 0
 
458
            needParent = False
 
459
        elif node.role == pyatspi.ROLE_APPLICATION or node.roleName == \
 
460
                'application':
 
461
            path = [0]
 
462
            indexInParent = list(root.children).index(node)
 
463
            needParent = False
 
464
        elif not node.parent: return None
 
465
        elif (0 <= indexInParent <= (len(node.parent) - 1)) and \
 
466
                node.parent[indexInParent] != node:
 
467
            return None
 
468
            siblings = node.parent.children
 
469
            sibIndex = siblings.index(node)
 
470
            try:
 
471
                if siblings[sibIndex] != node: return None
 
472
                else: indexInParent = sibIndex
 
473
            except ValueError: return None
 
474
        if type(path) == list:
 
475
            if needParent:
 
476
                parentPath = self.getPath(node.parent)
 
477
                if parentPath is None: return None
 
478
                else: path = list(parentPath)
 
479
            path.append(indexInParent)
 
480
 
 
481
        path = tuple(path)
 
482
        try:
 
483
            nodeByPath = self.getNode(self.get_iter(path))
 
484
            if node != nodeByPath:
 
485
                #print "%s is not %s!" % (node, nodeByPath)
 
486
                return None
 
487
        except ValueError:
 
488
            #print "I smell a bug in %s..." % node.getApplication()
 
489
            return None
 
490
 
 
491
        #self.cache[node] = Gtk.TreeRowReference(self, path)
 
492
        return path
 
493
 
 
494
    def processEvents(self):
 
495
        if not len(self.eventQueue): return
 
496
        queueCopy = self.eventQueue[:]
 
497
        for event in queueCopy:
 
498
            self.processChangedNode(event)
 
499
            self.eventQueue.remove(event)
 
500
        return False
 
501
 
 
502
    def nodeChanged(self, event):
 
503
        #if self.autorefresh.get_active() is False: return
 
504
        node = event.source
 
505
        if not node or not node in self: return
 
506
        app = event.host_application
 
507
        if app and app.name == 'sniff': return
 
508
        self.eventQueue.append(event)
 
509
        GObject.idle_add(self.processEvents)
 
510
 
 
511
    def processChangedNode(self, event):
 
512
        node = event.source
 
513
        if not node or not node in self: return
 
514
        path = self.getPath(node)
 
515
        try:
 
516
            iter = self.get_iter(path)
 
517
        except (ValueError, TypeError):
 
518
            return
 
519
        if event.type.major == "property-change":
 
520
            if event.type.minor == "accessible-name":
 
521
                node = self.getNode(iter)
 
522
                self.set_value(iter, self.nameColumn, node.name)
 
523
            elif event.type.minor == "accessible-state":
 
524
                print str(event)
 
525
        elif event.type.major == "state-changed":
 
526
            print str(event)
 
527
        elif event.type.major == "children-changed":
 
528
            if event.type.minor == 'add':
 
529
                for child in node.children:
 
530
                    if not child in self:
 
531
                        if len(child) > 0:
 
532
                            self.appendAndPopulate(iter, child)
 
533
                        else:
 
534
                            # If it has no children now, give it a sec
 
535
                            # to come up with some.
 
536
                            GObject.timeout_add(1000, \
 
537
                                    self.__addNodeCB, iter, child)
 
538
            elif event.type.minor == 'remove':
 
539
                self.__removeNodeCB(iter, node, path)
 
540
 
 
541
    def __addNodeCB(self, iter, parent):
 
542
        self.appendAndPopulate(iter, parent)
 
543
        return False
 
544
 
 
545
    def __removeNodeCB(self, iter, parent, path):
 
546
        childRow = self.iter_children(iter)
 
547
        while childRow is not None:
 
548
            node = self.getNode(childRow)
 
549
            if node is None: break
 
550
            if node and self.getNode(childRow) not in parent:
 
551
                self.remove(childRow)
 
552
            else: childRow = self.iter_next(childRow)
 
553
 
 
554
    def __populateCB(self, iter):
 
555
        self.populateChildren(iter)
 
556
        return False
 
557
 
 
558
    def getPixbufForNode(self, node):
 
559
        theme = Gtk.IconTheme().get_default()
 
560
        try:
 
561
            if node.role == pyatspi.ROLE_APPLICATION:
 
562
                # FIXME: Use the pixbuf from libwcnk (if available):
 
563
                # wnckApp = Application(node).getWnckApplication()
 
564
                # if wnckApp
 
565
                try:
 
566
                    return theme.load_icon(node.name, 24, \
 
567
                            Gtk.IconLookupFlags.USE_BUILTIN)
 
568
                except GObject.GError:
 
569
                    try:
 
570
                        return theme.load_icon(node.name.lower(), 24, \
 
571
                            Gtk.IconLookupFlags.USE_BUILTIN)
 
572
                    except GObject.GError:
 
573
                        return None
 
574
            elif node.parent:
 
575
                return iconForRole[node.role]
 
576
            else:
 
577
                return theme.load_icon("gnome-fs-desktop", 24, \
 
578
                        Gtk.IconLookupFlags.USE_BUILTIN)
 
579
        except Exception:
 
580
            return theme.load_icon("gtk-dialog-error", 24, \
 
581
                    Gtk.IconLookupFlags.USE_BUILTIN)
 
582
 
 
583
class StateModel(Gtk.ListStore):
 
584
    stateColumn = 0
 
585
    statesSupported = ['checked', 'focusable', 'focused', 'sensitive', \
 
586
            'showing']
 
587
 
 
588
    def __init__(self):
 
589
        Gtk.ListStore.__init__(self, GObject.TYPE_STRING)
 
590
 
 
591
    def setNode(self, node):
 
592
        self.clear()
 
593
        for stateName in self.statesSupported:
 
594
            if getattr(node, stateName) is True:
 
595
                self.append((stateName.capitalize(),))
 
596
 
218
597
 
219
598
def loadIcon(iconName):
220
599
    try:
221
 
        pixbuf = gtk.gdk.pixbuf_new_from_file('icons/' + iconName)
222
 
    except gobject.GError:
223
 
        iconName = '/usr/share/dogtail/icons/' + iconName
224
 
        pixbuf = gtk.gdk.pixbuf_new_from_file(iconName)
 
600
        pixbuf = GdkPixbuf.Pixbuf.new_from_file('icons/' + iconName)
 
601
    except GObject.GError:
 
602
        import os
 
603
        path = os.path.abspath (os.path.join(__file__, os.path.pardir, os.path.pardir))
 
604
        iconName = os.path.join(path, 'share/dogtail/icons/', iconName)
 
605
        pixbuf = GdkPixbuf.Pixbuf.new_from_file(iconName)
225
606
    return pixbuf
226
607
 
227
608
button_xpm = loadIcon("button.xpm")
250
631
window_xpm = loadIcon("window.xpm")
251
632
 
252
633
iconForRole = { \
253
 
        atspi.SPI_ROLE_INVALID : None, \
254
 
        atspi.SPI_ROLE_ACCEL_LABEL : label_xpm, \
255
 
        atspi.SPI_ROLE_ALERT : None, \
256
 
        atspi.SPI_ROLE_ANIMATION : None, \
257
 
        atspi.SPI_ROLE_ARROW : None, \
258
 
        atspi.SPI_ROLE_CALENDAR : None, \
259
 
        atspi.SPI_ROLE_CANVAS : None, \
260
 
        atspi.SPI_ROLE_CHECK_BOX : checkbutton_xpm, \
261
 
        atspi.SPI_ROLE_CHECK_MENU_ITEM : checkmenuitem_xpm, \
262
 
        atspi.SPI_ROLE_COLOR_CHOOSER : colorselection_xpm, \
263
 
        atspi.SPI_ROLE_COLUMN_HEADER : None, \
264
 
        atspi.SPI_ROLE_COMBO_BOX : combo_xpm, \
265
 
        atspi.SPI_ROLE_DATE_EDITOR : None, \
266
 
        atspi.SPI_ROLE_DESKTOP_ICON : None, \
267
 
        atspi.SPI_ROLE_DESKTOP_FRAME : None, \
268
 
        atspi.SPI_ROLE_DIAL : None, \
269
 
        atspi.SPI_ROLE_DIALOG : dialog_xpm, \
270
 
        atspi.SPI_ROLE_DIRECTORY_PANE : None, \
271
 
        atspi.SPI_ROLE_DRAWING_AREA : None, \
272
 
        atspi.SPI_ROLE_FILE_CHOOSER : None, \
273
 
        atspi.SPI_ROLE_FILLER : None, \
274
 
        atspi.SPI_ROLE_FONT_CHOOSER : None, \
275
 
        atspi.SPI_ROLE_FRAME : window_xpm, \
276
 
        atspi.SPI_ROLE_GLASS_PANE : None, \
277
 
        atspi.SPI_ROLE_HTML_CONTAINER : None, \
278
 
        atspi.SPI_ROLE_ICON : image_xpm, \
279
 
        atspi.SPI_ROLE_IMAGE : image_xpm, \
280
 
        atspi.SPI_ROLE_INTERNAL_FRAME : None, \
281
 
        atspi.SPI_ROLE_LABEL : label_xpm, \
282
 
        atspi.SPI_ROLE_LAYERED_PANE : viewport_xpm, \
283
 
        atspi.SPI_ROLE_LIST : None, \
284
 
        atspi.SPI_ROLE_LIST_ITEM : None, \
285
 
        atspi.SPI_ROLE_MENU : menuitem_xpm, \
286
 
        atspi.SPI_ROLE_MENU_BAR : menubar_xpm, \
287
 
        atspi.SPI_ROLE_MENU_ITEM : menuitem_xpm, \
288
 
        atspi.SPI_ROLE_OPTION_PANE : None, \
289
 
        atspi.SPI_ROLE_PAGE_TAB : notebook_xpm, \
290
 
        atspi.SPI_ROLE_PAGE_TAB_LIST : notebook_xpm, \
291
 
        atspi.SPI_ROLE_PANEL : viewport_xpm, \
292
 
        atspi.SPI_ROLE_PASSWORD_TEXT : None, \
293
 
        atspi.SPI_ROLE_POPUP_MENU : None, \
294
 
        atspi.SPI_ROLE_PROGRESS_BAR : None, \
295
 
        atspi.SPI_ROLE_PUSH_BUTTON : button_xpm, \
296
 
        atspi.SPI_ROLE_RADIO_BUTTON : None, \
297
 
        atspi.SPI_ROLE_RADIO_MENU_ITEM : None, \
298
 
        atspi.SPI_ROLE_ROOT_PANE : viewport_xpm, \
299
 
        atspi.SPI_ROLE_ROW_HEADER : None, \
300
 
        atspi.SPI_ROLE_SCROLL_BAR : vscrollbar_xpm, \
301
 
        atspi.SPI_ROLE_SCROLL_PANE : scrolledwindow_xpm, \
302
 
        atspi.SPI_ROLE_SEPARATOR : vseparator_xpm, \
303
 
        atspi.SPI_ROLE_SLIDER : None, \
304
 
        atspi.SPI_ROLE_SPIN_BUTTON : spinbutton_xpm, \
305
 
        atspi.SPI_ROLE_SPLIT_PANE : None, \
306
 
        atspi.SPI_ROLE_STATUS_BAR : statusbar_xpm, \
307
 
        atspi.SPI_ROLE_TABLE : table_xpm, \
308
 
        atspi.SPI_ROLE_TABLE_CELL : treeitem_xpm, \
309
 
        atspi.SPI_ROLE_TABLE_COLUMN_HEADER : None, \
310
 
        atspi.SPI_ROLE_TABLE_ROW_HEADER : None, \
311
 
        atspi.SPI_ROLE_TEAROFF_MENU_ITEM : None, \
312
 
        atspi.SPI_ROLE_TERMINAL : None, \
313
 
        atspi.SPI_ROLE_TEXT : text_xpm, \
314
 
        atspi.SPI_ROLE_TOGGLE_BUTTON : None, \
315
 
        atspi.SPI_ROLE_TOOL_BAR : toolbar_xpm, \
316
 
        atspi.SPI_ROLE_TOOL_TIP : None, \
317
 
        atspi.SPI_ROLE_TREE : tree_xpm, \
318
 
        atspi.SPI_ROLE_TREE_TABLE : tree_xpm, \
319
 
        atspi.SPI_ROLE_UNKNOWN : unknown_xpm, \
320
 
        atspi.SPI_ROLE_VIEWPORT : viewport_xpm, \
321
 
        atspi.SPI_ROLE_WINDOW : window_xpm, \
322
 
        atspi.SPI_ROLE_EXTENDED : None, \
323
 
        atspi.SPI_ROLE_HEADER : None, \
324
 
        atspi.SPI_ROLE_FOOTER : None, \
325
 
        atspi.SPI_ROLE_PARAGRAPH : None, \
326
 
        atspi.SPI_ROLE_RULER : None, \
327
 
        atspi.SPI_ROLE_APPLICATION : None, \
328
 
        atspi.SPI_ROLE_AUTOCOMPLETE : None, \
329
 
        atspi.SPI_ROLE_EDITBAR : None, \
330
 
        atspi.SPI_ROLE_EMBEDDED : None, \
331
 
        atspi.SPI_ROLE_LAST_DEFINED: None }
332
 
 
333
 
def getPixbufForNode(node):
334
 
    theme = gtk.icon_theme_get_default()
335
 
    try:
336
 
        if node.role==atspi.SPI_ROLE_APPLICATION:
337
 
            # FIXME: Use the pixbuf from libwcnk (if available):
338
 
            # wnckApp = Application(node).getWnckApplication()
339
 
            # if wnckApp
340
 
            try: return theme.load_icon(node.name, 24, gtk.ICON_LOOKUP_USE_BUILTIN)
341
 
            except gobject.GError:
342
 
                try: return theme.load_icon(node.name.lower(), 24, gtk.ICON_LOOKUP_USE_BUILTIN)
343
 
                except gobject.GError: return None
344
 
        elif node.parent:
345
 
            return iconForRole[node.role]
346
 
        else:
347
 
            return theme.load_icon("gnome-fs-desktop", 24, gtk.ICON_LOOKUP_USE_BUILTIN)
348
 
    except atspi.SpiException:
349
 
        return theme.load_icon("gtk-dialog-error", 24, gtk.ICON_LOOKUP_USE_BUILTIN)
350
 
 
351
 
def getNodeAttr(column, cell, model, iter, attr):
352
 
    node = model.get_value(iter, MODEL_FIELD_NODE)
353
 
    try:
354
 
        text = getattr(node, attr)
355
 
    except atspi.SpiException:
356
 
        text = "(broken node)"
357
 
    cell.set_property('text', text)
358
 
 
359
 
def getCellPixbufForNode(column, cell, model, iter):
360
 
    node = model.get_value(iter, MODEL_FIELD_NODE)
361
 
    pixbuf = getPixbufForNode(node)
362
 
    cell.set_property('pixbuf', pixbuf)
 
634
    pyatspi.ROLE_INVALID : None, \
 
635
    # pyatspi doesn't have the following... not even sure if it exists
 
636
    # anywhere.
 
637
    #atspi.SPI_ROLE_ACCEL_LABEL : label_xpm, \
 
638
    pyatspi.ROLE_ALERT : None, \
 
639
    pyatspi.ROLE_ANIMATION : None, \
 
640
    pyatspi.ROLE_ARROW : None, \
 
641
    pyatspi.ROLE_CALENDAR : None, \
 
642
    pyatspi.ROLE_CANVAS : None, \
 
643
    pyatspi.ROLE_CHECK_BOX : checkbutton_xpm, \
 
644
    pyatspi.ROLE_CHECK_MENU_ITEM : checkmenuitem_xpm, \
 
645
    pyatspi.ROLE_COLOR_CHOOSER : colorselection_xpm, \
 
646
    pyatspi.ROLE_COLUMN_HEADER : None, \
 
647
    pyatspi.ROLE_COMBO_BOX : combo_xpm, \
 
648
    pyatspi.ROLE_DATE_EDITOR : None, \
 
649
    pyatspi.ROLE_DESKTOP_ICON : None, \
 
650
    pyatspi.ROLE_DESKTOP_FRAME : None, \
 
651
    pyatspi.ROLE_DIAL : None, \
 
652
    pyatspi.ROLE_DIALOG : dialog_xpm, \
 
653
    pyatspi.ROLE_DIRECTORY_PANE : None, \
 
654
    pyatspi.ROLE_DRAWING_AREA : None, \
 
655
    pyatspi.ROLE_FILE_CHOOSER : None, \
 
656
    pyatspi.ROLE_FILLER : None, \
 
657
    pyatspi.ROLE_FONT_CHOOSER : None, \
 
658
    pyatspi.ROLE_FRAME : window_xpm, \
 
659
    pyatspi.ROLE_GLASS_PANE : None, \
 
660
    pyatspi.ROLE_HTML_CONTAINER : None, \
 
661
    pyatspi.ROLE_ICON : image_xpm, \
 
662
    pyatspi.ROLE_IMAGE : image_xpm, \
 
663
    pyatspi.ROLE_INTERNAL_FRAME : None, \
 
664
    pyatspi.ROLE_LABEL : label_xpm, \
 
665
    pyatspi.ROLE_LAYERED_PANE : viewport_xpm, \
 
666
    pyatspi.ROLE_LIST : None, \
 
667
    pyatspi.ROLE_LIST_ITEM : None, \
 
668
    pyatspi.ROLE_MENU : menuitem_xpm, \
 
669
    pyatspi.ROLE_MENU_BAR : menubar_xpm, \
 
670
    pyatspi.ROLE_MENU_ITEM : menuitem_xpm, \
 
671
    pyatspi.ROLE_OPTION_PANE : None, \
 
672
    pyatspi.ROLE_PAGE_TAB : notebook_xpm, \
 
673
    pyatspi.ROLE_PAGE_TAB_LIST : notebook_xpm, \
 
674
    pyatspi.ROLE_PANEL : viewport_xpm, \
 
675
    pyatspi.ROLE_PASSWORD_TEXT : None, \
 
676
    pyatspi.ROLE_POPUP_MENU : None, \
 
677
    pyatspi.ROLE_PROGRESS_BAR : None, \
 
678
    pyatspi.ROLE_PUSH_BUTTON : button_xpm, \
 
679
    pyatspi.ROLE_RADIO_BUTTON : None, \
 
680
    pyatspi.ROLE_RADIO_MENU_ITEM : None, \
 
681
    pyatspi.ROLE_ROOT_PANE : viewport_xpm, \
 
682
    pyatspi.ROLE_ROW_HEADER : None, \
 
683
    pyatspi.ROLE_SCROLL_BAR : vscrollbar_xpm, \
 
684
    pyatspi.ROLE_SCROLL_PANE : scrolledwindow_xpm, \
 
685
    pyatspi.ROLE_SEPARATOR : vseparator_xpm, \
 
686
    pyatspi.ROLE_SLIDER : None, \
 
687
    pyatspi.ROLE_SPIN_BUTTON : spinbutton_xpm, \
 
688
    pyatspi.ROLE_SPLIT_PANE : None, \
 
689
    pyatspi.ROLE_STATUS_BAR : statusbar_xpm, \
 
690
    pyatspi.ROLE_TABLE : table_xpm, \
 
691
    pyatspi.ROLE_TABLE_CELL : treeitem_xpm, \
 
692
    pyatspi.ROLE_TABLE_COLUMN_HEADER : None, \
 
693
    pyatspi.ROLE_TABLE_ROW_HEADER : None, \
 
694
    pyatspi.ROLE_TEAROFF_MENU_ITEM : None, \
 
695
    pyatspi.ROLE_TERMINAL : None, \
 
696
    pyatspi.ROLE_TEXT : text_xpm, \
 
697
    pyatspi.ROLE_TOGGLE_BUTTON : None, \
 
698
    pyatspi.ROLE_TOOL_BAR : toolbar_xpm, \
 
699
    pyatspi.ROLE_TOOL_TIP : None, \
 
700
    pyatspi.ROLE_TREE : tree_xpm, \
 
701
    pyatspi.ROLE_TREE_TABLE : tree_xpm, \
 
702
    pyatspi.ROLE_UNKNOWN : unknown_xpm, \
 
703
    pyatspi.ROLE_VIEWPORT : viewport_xpm, \
 
704
    pyatspi.ROLE_WINDOW : window_xpm, \
 
705
    pyatspi.ROLE_EXTENDED : None, \
 
706
    pyatspi.ROLE_HEADER : None, \
 
707
    pyatspi.ROLE_FOOTER : None, \
 
708
    pyatspi.ROLE_PARAGRAPH : None, \
 
709
    pyatspi.ROLE_RULER : None, \
 
710
    pyatspi.ROLE_APPLICATION : None, \
 
711
    pyatspi.ROLE_AUTOCOMPLETE : None, \
 
712
    pyatspi.ROLE_EDITBAR : None, \
 
713
    pyatspi.ROLE_EMBEDDED : None, \
 
714
    pyatspi.ROLE_LAST_DEFINED: None }
 
715
 
363
716
 
364
717
def main():
365
 
    connectSignals()
366
 
 
367
 
    nameTextLabel.set_text('')
368
 
    roleNameTextLabel.set_text('')
369
 
    descTextLabel.set_text('')
370
 
    actionsTextLabel.set_text('')
371
 
    textTextView.set_sensitive(False)
372
 
    textTextView.get_buffer().set_text('')
373
 
 
374
 
    global sniff, view, model
375
 
 
376
 
    col = gtk.TreeViewColumn()
377
 
    cellRenderer = gtk.CellRendererPixbuf()
378
 
    col.pack_start(cellRenderer, expand = False)
379
 
    col.set_cell_data_func(cellRenderer, getCellPixbufForNode)
380
 
 
381
 
    cellRenderer = gtk.CellRendererText()
382
 
    col.pack_end(cellRenderer, expand = False)
383
 
    col.set_cell_data_func(cellRenderer, getNodeAttr, 'name')
384
 
 
385
 
    col.set_title('Name')
386
 
 
387
 
    view.insert_column(col, -1)
388
 
    #view.insert_column_with_data_func(-1, "Role Name", \
389
 
    #               gtk.CellRendererText(), getNodeAttr, 'roleName')
390
 
    #view.insert_column_with_data_func(-1, "Description", \
391
 
    #               gtk.CellRendererText(), getNodeAttr, 'description')
392
 
    for column in view.get_columns():
393
 
        column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
394
 
        column.set_resizable(True)
395
 
    view.show()
396
 
    sniff.show_all ()
397
 
 
398
 
    model = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, \
399
 
                    gobject.TYPE_STRING, gobject.TYPE_STRING)
400
 
    view.set_model(model)
401
 
 
402
 
    resetModel()
403
 
 
404
 
    gtk.main()
405
 
 
406
 
if __name__ == '__main__': main()
 
718
    from dogtail.utils import Lock
 
719
    #We need this to prohibit sniff making(and removing on exit) sniff_refresh lock when importing Node
 
720
    sniff_running = Lock(lockname='sniff_running.lock',randomize=False)
 
721
    try:
 
722
        sniff_running.lock()
 
723
    except OSError:
 
724
        pass 
 
725
    sniff = SniffApp()
 
726
 
 
727
if __name__ == '__main__':
 
728
    main()