File: treetips.py

package info (click to toggle)
qa-assistant 0.4.90.5-4
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 1,068 kB
  • ctags: 368
  • sloc: python: 4,067; sh: 552; xml: 523; makefile: 167
file content (227 lines) | stat: -rw-r--r-- 8,513 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File: treetips.py
# Author: Toshio Kuratomi <toshio@tiki-lounge.com>
# Date: 6 April, 2004
# Copyright: Toshio Kuratomi
# License: GPL
# Id: $Id: treetips.py 188 2005-06-14 00:55:59Z badger $
"""A tooltip class for TreeViews
"""
__revision__ = "$Rev: 188 $"

import gtk
import gobject

class TreeTips(gtk.Widget):
    ''' A tooltips widget specialized to work with gtk.TreeView's.

    TreeTips associates a column in a TreeStore with tooltips that will be
    displayed when the mouse is over the row the column is for.  Each row can
    have one treetip.
    ''' 
    __gproperties__ = {
        'tip_window' : (gobject.TYPE_PYOBJECT,
                'The window that the tooltip is displayed in.',
                'The window that the tooltip is displayed in.',
                gobject.PARAM_READABLE),
        'tip_label' : (gobject.TYPE_PYOBJECT,
                'The label that displays the tooltip text.',
                'The label that displays the tooltip text.',
                gobject.PARAM_READABLE),
        'active_tips_data' : (gobject.TYPE_PYOBJECT,
                'The data associated with the active tooltip.',
                'The data associated with the active tooltip.',
                gobject.PARAM_READABLE),
        'delay' : (gobject.TYPE_INT,
                'MSecs before displaying the tooltip.',
                'The delay between the mouse pausing over the widget and the'
                ' display of the tooltip in msec.',
                0, 60000, 500,
                gobject.PARAM_READWRITE),
        'enabled' : (gobject.TYPE_BOOLEAN,
                'If TRUE the tooltips are enabled',
                'If TRUE the tooltips are enabled',
                True,
                gobject.PARAM_READABLE),
        'view' : (gobject.TYPE_PYOBJECT,
                'gtk.TreeView that we get our data from.',
                'The tip data comes from a column in a gtk.TreeView.',
                gobject.PARAM_READWRITE),
        'column' : (gobject.TYPE_INT,
                'Column from the gtk.TreeView that holds tip data.',
                'The tip data for each row is held by a column in the row.'
                '  This specifies which column that data is in.',
                0, 32000, 0,
                gobject.PARAM_READWRITE)
    }

    def __init__(self, treeview=None, column=None):
        '''Create a new TreeTips Group.

        :Parameters:
            treeview : gtk.TreeView === Treeview for which the tips display,
                default is None.
            column : integer === Column id in the Treemodel holding the treetip
                    text, default is None.
        '''
        if treeview:
            try:
                treeview.connect('leave-notify-event', self.__tree_leave_notify)
                treeview.connect('motion-notify-event',
                        self.__tree_motion_notify)
            except (AttributeError, TypeError):
                raise TypeError, ('The value of view must be an object that'
                        'implements leave-notify-event and motion-notify-event '
                        'gsignals such as gtk.TreeStore.')

        gobject.GObject.__init__(self)

        self.view = treeview or None
        self.delay = 500
        self.enabled = True
        self.column = column or 0
        self.tip_window = gtk.Window(gtk.WINDOW_POPUP)
        self.tip_window.set_app_paintable(True)
        self.tip_window.set_border_width(4)
        self.tip_window.connect('expose-event', self.__paint_window)
        self.tip_label = gtk.Label('')
        self.tip_label.set_line_wrap(True)
        self.tip_label.set_alignment(0.5, 0.5)
        self.active_tips_data = ''
        self.tip_window.add(self.tip_label)
        self.unique = 1 # Unique number used for timeouts
        self.timeoutID = 0
        self.path = None
        self.screenWidth = gtk.gdk.screen_width()
        self.screenHeight = gtk.gdk.screen_height()

    def enable(self):
        '''Enable showing of tooltips'''
        self.enabled = True

    def disable(self):
        '''Disable showing tooltips'''
        self.enabled = False
       
    def do_get_property(self, prop):
        '''Return the gproperty's value.'''
        if prop.name == 'delay':
            return self.delay
        elif prop.name == 'enabled':
            return self.enabled
        elif prop.name == 'view':
            return self.view
        elif prop.name == 'column':
            return self.column
        elif prop.name == 'active-tips-data':
            return self.active_tips_data
        elif prop.name == 'tip-label':
            return self.tip_label
        elif prop.name == 'tip-window':
            return self.tip_window
        else:
            raise AttributeError, 'unknown property %s' % prop.name

    def do_set_property(self, prop, value):
        '''Set the property of writable properties.

        '''
        if prop.name == 'delay':
            self.delay = value
        elif prop.name == 'view':
            try:
                value.connect('leave-notify-event', self.__tree_leave_notify)
                value.connect('motion-notify-event', self.__tree_motion_notify)
            except (AttributeError, TypeError):
                raise TypeError, ('The value of view must be an object that'
                        'implements leave-notify-event and motion-notify-event '
                        'gsignals')
            self.view = value
        elif prop.name == 'column':
            self.column = value
        else:
            raise AttributeError, 'unknown or read only property %s' % prop.name

    def __paint_window(self, window, event):
        window.style.paint_flat_box(window.window, gtk.STATE_NORMAL,
                gtk.SHADOW_OUT, None, window,
                'tooltip', 0, 0, -1, -1)
        
    def __tree_leave_notify(self, tree, event):
        '''Hide tooltips when we leave the tree.'''

        self.timeoutID = 0
        self.path = None
        self.tip_window.hide()

    def __tree_motion_notify(self, tree, event):
        '''Decide which tooltip to display when we move within the tree.'''

        if not self.enabled:
            return
        self.tip_window.hide()
        self.path = None
        self.unique += 1
        self.timeoutID = self.unique
        gobject.timeout_add(self.delay, self.__treetip_show, tree,
                int(event.x), int(event.y), self.timeoutID)

    def __treetip_show(self, tree, xEvent, yEvent, ID):
        '''Show the treetip window.'''
        if self.timeoutID != ID:
            return False
        pathReturn = tree.get_path_at_pos(xEvent, yEvent)
        model = tree.get_model()
        if pathReturn == None:
            self.path = None
        elif self.path != pathReturn[0]:
            self.path = pathReturn[0]
            rowIter = model.get_iter(self.path)
            text = model.get_value(rowIter, self.column)
            self.active_tips_data = text
            if not text:
                self.tip_label.set_text('')
                return False
            self.tip_label.set_text(text)
            x, y = self.tip_label.size_request()
            self.tip_window.resize(x, y)
            windowWidth, windowHeight = self.tip_window.get_size()
            cellInfo = tree.get_cell_area(self.path, pathReturn[1])
            x, y = self.__compute_tooltip_position(cellInfo, windowWidth,
                    windowHeight)
            self.tip_window.move(int(x), int(y))
            self.tip_window.show_all()

        return False

    def __compute_tooltip_position(self, cellInfo, popupWidth, popupHeight):
        '''Figures out where the tooltip should be placed on the page::

          [p] = pointer
          x =      [p]
               +---------+
          (half on each side)
  
          y =      [p]
              +------------+
              |____________|
          If it fits else:
              +------------+
              |____________|
                   [p]
        '''

        xOrigin, yOrigin = self.view.get_bin_window().get_origin()
        x = xOrigin + cellInfo.x + cellInfo.width/2 - popupWidth/2
        if x < 0:
            x = 0
        elif x + popupWidth > self.screenWidth:
            x = self.screenWidth - popupWidth

        y = yOrigin + cellInfo.y + cellInfo.height + 3
        if y + popupHeight > self.screenHeight:
            y = yOrigin + cellInfo.y - 3 - popupHeight
            if y < 0:
                y = 0

        return x, y
gobject.type_register(TreeTips)