~ubuntu-branches/ubuntu/precise/screenlets/precise

« back to all changes in this revision

Viewing changes to src/share/screenlets/Tomboy/TomboyScreenlet.py

  • Committer: Bazaar Package Importer
  • Author(s): Julien Lavergne
  • Date: 2011-02-24 00:51:35 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110224005135-p65cxwmpfwwy3woi
Tags: 0.1.2+bzr616-0ubuntu1
* New upstream snapshot.
 - Move individual screenlets into another source package.
 - Many bug fixes since 0.1.2.
* Convert to source format 3.0 (quilt).
* debian/patches
 - Removed all patches, merged upstream.
* debian/rules:
 - Convert to dh7.
 - Don't remove copies of feedparser, not in this package.
 - Don't remove empty directory for the individual screenlets.
* debian/screenlets.install:
 - Update installed files.
* debian/compat
 - Bump to level 7.
* debian/control:
 - Rewrite Depends and build-depends.
* README.Debian :
 - Mention mutter as a composite manager.
* debian/README.source:
 - Remove the README.source.
* debian/screenlets.manpages:
 - Add the manpages.
* debian/copyright:
 - Rewrite with dep5 style.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python
2
 
 
3
 
# This application is released under the GNU General Public License 
4
 
# v3 (or, at your option, any later version). You can find the full 
5
 
# text of the license under http://www.gnu.org/licenses/gpl.txt. 
6
 
# By using, editing and/or distributing this software you agree to 
7
 
# the terms and conditions of this license. 
8
 
# Thank you for using free software!
9
 
 
10
 
#  TomboyScreenlet (c) Whise 2007 
11
 
 
12
 
import screenlets
13
 
from screenlets import utils
14
 
from screenlets.options import StringOption , BoolOption , IntOption , FontOption, ColorOption
15
 
from screenlets import DefaultMenuItem
16
 
import pango
17
 
import gobject
18
 
import gtk
19
 
import os
20
 
from xml.dom.minidom import parse
21
 
from xml.parsers.expat import ExpatError
22
 
import re
23
 
import gnomevfs
24
 
 
25
 
 
26
 
class TomboyScreenlet (screenlets.Screenlet):
27
 
        """Displays Tomboy Notes"""
28
 
        
29
 
        # default meta-info for Screenlets (should be removed and put into metainfo)
30
 
        __name__        = 'TomboyScreenlet'
31
 
        __version__     = '0.1'
32
 
        __author__      = 'Helder Fraga aka Whise'
33
 
        __desc__        = __doc__       # set description to docstring of class
34
 
 
35
 
        # editable options (options that are editable through the UI)
36
 
 
37
 
        
38
 
        color_odd = (0, 0, 0, 0.55)
39
 
        color_even = (0, 0, 0, 0.65)
40
 
        color_title = (0.0, 0.0, 0.0, 1)
41
 
        color_text = (1,1,1,1)
42
 
        color_back = (1.0, 1.0, 1.0, 0.65)
43
 
        color_hover = (0, 0, 1.0, 0.65)
44
 
        font = "FreeSans"
45
 
        font_title = "FreeSans"
46
 
        show_shadow = True
47
 
        expanded = True
48
 
        hover = False
49
 
        number = 0
50
 
 
51
 
 
52
 
        mouse_is_over = False
53
 
        places = []
54
 
        old_places = []
55
 
        selected = 0
56
 
        mousesel = 0
57
 
        notes = None
58
 
        if os.environ.has_key("TOMBOY_PATH"):
59
 
                note_path = os.environ["TOMBOY_PATH"]
60
 
        else:
61
 
                note_path = "~/.tomboy"
62
 
        note_path = os.path.expanduser(note_path)
63
 
 
64
 
        # constructor
65
 
        def __init__ (self, **keyword_args):
66
 
                #call super (width/height MUST match the size of graphics in the theme)
67
 
                screenlets.Screenlet.__init__(self, width=200, height=200, 
68
 
                        uses_theme=True,ask_on_option_override = False,  **keyword_args)
69
 
                # set theme
70
 
                self.theme_name = "yellow"
71
 
                # add option group
72
 
                self.add_options_group('Options', 'Options')
73
 
                # add editable option to the group
74
 
 
75
 
                self.add_option(FontOption('Options','font_title', 
76
 
                        self.font_title, 'Title Font', 
77
 
                        ''))
78
 
 
79
 
                self.add_option(ColorOption('Options','color_title', 
80
 
                        self.color_title, 'Title Color', 
81
 
                        ''))
82
 
 
83
 
                self.add_option(ColorOption('Options','color_back', 
84
 
                        self.color_back, 'Title Background Color', 
85
 
                        ''))
86
 
 
87
 
                self.add_option(FontOption('Options','font', 
88
 
                        self.font, 'Text Font', 
89
 
                        ''))
90
 
 
91
 
                self.add_option(ColorOption('Options','color_text', 
92
 
                        self.color_text, 'Text Color', 
93
 
                        ''))
94
 
 
95
 
                self.add_option(ColorOption('Options','color_even', 
96
 
                        self.color_even, 'Even Color', 
97
 
                        ''))
98
 
 
99
 
                self.add_option(ColorOption('Options','color_odd', 
100
 
                        self.color_odd, 'Odd Color', 
101
 
                        ''))
102
 
 
103
 
                self.add_option(ColorOption('Options','color_hover', 
104
 
                        self.color_hover, 'Hover Color', 
105
 
                        ''))
106
 
 
107
 
                self.add_option(BoolOption('Options','show_shadow', 
108
 
                        self.show_shadow, 'Show Shadow', '',))
109
 
 
110
 
                self.add_option(BoolOption('Options','expanded', 
111
 
                        self.expanded, 'Expanded', '',hidden=True))
112
 
 
113
 
                # ADD a 1 second (1000) TIMER
114
 
 
115
 
                self.ask_on_option_override = False
116
 
                
117
 
                #fstab = self.readFile('/etc/fstab')
118
 
                #mounts = self.readFile('/proc/mounts')
119
 
 
120
 
 
121
 
 
122
 
 
123
 
                self.notes = {}
124
 
 
125
 
                self.note_path_monitor = utils.FileMonitor(self.note_path)
126
 
                self.note_path_monitor.connect("event", self._file_event)
127
 
                self.note_path_monitor.open()
128
 
 
129
 
        # Load notes in an idle handler
130
 
                gobject.idle_add(self._idle_load_notes().next, priority=gobject.PRIORITY_LOW)
131
 
 
132
 
 
133
 
        def get_note(self,path):
134
 
                try:
135
 
                        note_doc = parse(path)
136
 
                except (IOError, ExpatError), err:
137
 
                        print " !!! Error parsing note '%s': %s" % (path, err)
138
 
                        return
139
 
 
140
 
                try:
141
 
                        title_node = note_doc.getElementsByTagName("title")[0]
142
 
                        self.title = title_node.childNodes[0].data
143
 
                except (ValueError, IndexError, AttributeError):
144
 
                        pass
145
 
 
146
 
                try:
147
 
                # Parse the ISO timestamp format .NET's XmlConvert class uses:
148
 
                # yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz, where f* is a 7-digit partial
149
 
                # second, and z* is the timezone offset from UTC in the form -08:00.
150
 
                        changed_node = note_doc.getElementsByTagName("last-change-date")[0]
151
 
                        changed_str = changed_node.childNodes[0].data
152
 
                        changed_str = re.sub("\.[0-9]*", "", changed_str) # W3Date chokes on partial seconds
153
 
                        #self.timestamp = W3CDate.W3CDate(changed_str).getSeconds()
154
 
                except (ValueError, IndexError, AttributeError):
155
 
                        pass
156
 
 
157
 
                try:
158
 
                        content_node = note_doc.getElementsByTagName("note-content")[0]
159
 
                        self.content_text = self._get_text_from_node(content_node).lower()
160
 
                except (ValueError, IndexError, AttributeError):
161
 
                        pass
162
 
 
163
 
                return self.title
164
 
 
165
 
                note_doc.unlink()
166
 
 
167
 
        def _get_text_from_node(self, node):
168
 
                if node.nodeType == node.TEXT_NODE:
169
 
                        return node.data
170
 
                else:
171
 
                        return "".join([self._get_text_from_node(x) for x in node.childNodes])
172
 
 
173
 
        def _idle_load_notes(self):
174
 
                notes = {}
175
 
 
176
 
                try: 
177
 
                        for filename in os.listdir(self.note_path):
178
 
                                if filename.endswith(".note"):
179
 
                                        notepath = os.path.join(self.note_path, filename)
180
 
                                        notes[filename] = self.get_note(notepath)
181
 
                                        yield True
182
 
                except (OSError, IOError), err:
183
 
                        print " !!! Error loading Tomboy notes:", err
184
 
 
185
 
                self.notes = notes
186
 
                self.redraw_canvas()
187
 
                yield False
188
 
 
189
 
        def _file_event(self, monitor, info_uri, ev):
190
 
                filename = os.path.basename(info_uri)
191
 
 
192
 
                if ev == gnomevfs.MONITOR_EVENT_CREATED:
193
 
                        notepath = os.path.join(self.note_path, filename)
194
 
                        self.notes[filename] = self.get_note(notepath)
195
 
                        if self.height != 20 + (len(self.notes)*20) +20:
196
 
                                self.height = 20 + (len(self.notes)*20) +20             
197
 
                                self.redraw_canvas()
198
 
 
199
 
                elif self.notes.has_key(filename):
200
 
                        if ev == gnomevfs.MONITOR_EVENT_DELETED:
201
 
                                del self.notes[filename]
202
 
                                if self.height != 20 + (len(self.notes)*20) +20:
203
 
                                        self.height = 20 + (len(self.notes)*20) +20             
204
 
                                        self.redraw_canvas()
205
 
                        else:
206
 
                                if self.height != 20 + (len(self.notes)*20) +20:
207
 
                                        self.height = 20 + (len(self.notes)*20) +20             
208
 
                                        self.redraw_canvas()
209
 
 
210
 
 
211
 
        def menuitem_callback(self, widget, id):
212
 
                screenlets.Screenlet.menuitem_callback(self, widget, id)
213
 
                if id=="new":
214
 
                        os.system("tomboy --new-note")
215
 
 
216
 
        def get_items_uncached(self):
217
 
                return [self.new_note_item] + self.notes.values()
218
 
 
219
 
 
220
 
 
221
 
        def get_items(self):
222
 
        # Avoid ItemSource's caching
223
 
                return self.get_items_uncached()
224
 
 
225
 
        def __setattr__(self, name, value):
226
 
                # call Screenlet.__setattr__ in baseclass (ESSENTIAL!!!!)
227
 
                screenlets.Screenlet.__setattr__(self, name, value)
228
 
                if name == 'notes':
229
 
                        if self.height != 20 + (len(self.notes)*20) +20:
230
 
                                self.height = 20 + (len(self.notes)*20) +20             
231
 
                                self.redraw_canvas()
232
 
                
233
 
        
234
 
        # ONLY FOR TESTING!!!!!!!!!
235
 
        def init_options_from_metadata (self):
236
 
                """Try to load metadata-file with options. The file has to be named
237
 
                like the Screenlet, with the extension ".xml" and needs to be placed
238
 
                in the Screenlet's personal directory. 
239
 
                NOTE: This function always uses the metadata-file relative to the 
240
 
                          Screenlet's location, not the ones in SCREENLETS_PATH!!!"""
241
 
                print __file__
242
 
                p = __file__.rfind('/')
243
 
                mypath = __file__[:p]
244
 
                print mypath
245
 
                self.add_options_from_file( mypath + '/' + \
246
 
                        self.__class__.__name__ + '.xml')
247
 
 
248
 
 
249
 
 
250
 
 
251
 
 
252
 
        def on_after_set_atribute(self,name, value):
253
 
                """Called after setting screenlet atributes"""
254
 
                
255
 
                pass
256
 
 
257
 
        def on_before_set_atribute(self,name, value):
258
 
                """Called before setting screenlet atributes"""
259
 
                
260
 
                pass
261
 
 
262
 
 
263
 
        def on_create_drag_icon (self):
264
 
                """Called when the screenlet's drag-icon is created. You can supply
265
 
                your own icon and mask by returning them as a 2-tuple."""
266
 
                return (None, None)
267
 
 
268
 
        def on_composite_changed(self):
269
 
                """Called when composite state has changed"""
270
 
                pass
271
 
 
272
 
        def on_drag_begin (self, drag_context):
273
 
                """Called when the Screenlet gets dragged."""
274
 
                pass
275
 
        
276
 
        def on_drag_enter (self, drag_context, x, y, timestamp):
277
 
                """Called when something gets dragged into the Screenlets area."""
278
 
                pass
279
 
        
280
 
        def on_drag_leave (self, drag_context, timestamp):
281
 
                """Called when something gets dragged out of the Screenlets area."""
282
 
                pass
283
 
 
284
 
        def on_drop (self, x, y, sel_data, timestamp):
285
 
                """Called when a selection is dropped on this Screenlet."""
286
 
                return False
287
 
                
288
 
        def on_focus (self, event):
289
 
                """Called when the Screenlet's window receives focus."""
290
 
                pass
291
 
        
292
 
        def on_hide (self):
293
 
                """Called when the Screenlet gets hidden."""
294
 
                pass
295
 
        
296
 
        def on_init (self):
297
 
                """Called when the Screenlet's options have been applied and the 
298
 
                screenlet finished its initialization. If you want to have your
299
 
                Screenlet do things on startup you should use this handler."""
300
 
                self.add_menuitem("new", "Make new note")               
301
 
                # add default menu items
302
 
                self.add_default_menuitems()
303
 
                if self.notes != None:
304
 
                        if self.height != 20 + (len(self.notes)*20) +20:
305
 
                                self.height = 20 + (len(self.notes)*20) +20             
306
 
                                self.redraw_canvas()
307
 
                #print utils.LoadBookmarks()
308
 
                
309
 
        def on_key_down(self, keycode, keyvalue, event):
310
 
                """Called when a keypress-event occured in Screenlet's window."""
311
 
                #key = gtk.gdk.keyval_name(event.keyval)
312
 
                
313
 
                pass
314
 
        
315
 
        def on_load_theme (self):
316
 
                """Called when the theme is reloaded (after loading, before redraw)."""
317
 
                pass
318
 
        
319
 
        def on_menuitem_select (self, id):
320
 
                """Called when a menuitem is selected."""
321
 
                
322
 
                pass
323
 
        
324
 
        def on_mouse_down (self, event):
325
 
                """Called when a buttonpress-event occured in Screenlet's window. 
326
 
                Returning True causes the event to be not further propagated."""
327
 
                
328
 
                x = event.x / self.scale
329
 
                y = event.y / self.scale
330
 
                if event.button == 1:
331
 
                        if event.type == gtk.gdk._2BUTTON_PRESS and y < 30: 
332
 
                                self.expanded = not self.expanded
333
 
                         
334
 
                        if y > (30) and self.notes != None:
335
 
                                click = int((y -10 )/ (20)) -1
336
 
                                a = 0
337
 
                                for note in self.notes:
338
 
                                        if click == a:
339
 
                                                
340
 
                                                os.system("tomboy --open-note %s/%s " % (self.note_path,note))
341
 
                                        a = a+1
342
 
 
343
 
                                
344
 
                return False
345
 
        
346
 
        def on_mouse_enter (self, event):
347
 
                """Called when the mouse enters the Screenlet's window."""
348
 
        
349
 
 
350
 
                
351
 
        def on_mouse_leave (self, event):
352
 
                """Called when the mouse leaves the Screenlet's window."""
353
 
                
354
 
                self.redraw_canvas()
355
 
 
356
 
        def on_mouse_move(self, event):
357
 
                """Called when the mouse moves in the Screenlet's window."""
358
 
                x = event.x / self.scale
359
 
                y = event.y / self.scale
360
 
                if y > (30):
361
 
                        self.__dict__['mousesel'] = int((y -10 )/ (20)) -1
362
 
                        if self.selected != self.mousesel or y > 20 + (len(self.notes)*20) +20:                         
363
 
                                self.redraw_canvas()
364
 
                                
365
 
        def on_mouse_up (self, event):
366
 
                """Called when a buttonrelease-event occured in Screenlet's window. 
367
 
                Returning True causes the event to be not further propagated."""
368
 
                return False
369
 
        
370
 
        def on_quit (self):
371
 
                """Callback for handling destroy-event. Perform your cleanup here!"""
372
 
                
373
 
                return True
374
 
                
375
 
        def on_realize (self):
376
 
                """"Callback for handling the realize-event."""
377
 
        
378
 
        def on_scale (self):
379
 
                """Called when Screenlet.scale is changed."""
380
 
                pass
381
 
        
382
 
        def on_scroll_up (self):
383
 
                """Called when mousewheel is scrolled up (button4)."""
384
 
                pass
385
 
 
386
 
        def on_scroll_down (self):
387
 
                """Called when mousewheel is scrolled down (button5)."""
388
 
                pass
389
 
        
390
 
        def on_show (self):
391
 
                """Called when the Screenlet gets shown after being hidden."""
392
 
                pass
393
 
        
394
 
        def on_switch_widget_state (self, state):
395
 
                """Called when the Screenlet enters/leaves "Widget"-state."""
396
 
                pass
397
 
        
398
 
        def on_unfocus (self, event):
399
 
                """Called when the Screenlet's window loses focus."""
400
 
                pass
401
 
        
402
 
        def on_draw (self, ctx):
403
 
                """In here we draw"""
404
 
                ctx.scale(self.scale, self.scale)
405
 
                y = 0
406
 
 
407
 
                if self.expanded:
408
 
                        if self.show_shadow:self.draw_shadow(ctx, 0, 0, self.width-12, self.height-5,6,[0,0,0,0.3])     
409
 
                else:
410
 
                        if self.show_shadow:self.draw_shadow(ctx, 0, 0, self.width-12,40-5,6,[0,0,0,0.3])       
411
 
                ctx.translate(10,10)
412
 
                ctx.set_source_rgba(self.color_back[0],self.color_back[1],self.color_back[2],self.color_back[3])
413
 
                self.draw_rounded_rectangle(ctx,0,y,5,self.width-20,20,round_bottom_right= False,round_bottom_left= False)
414
 
                ctx.set_source_rgba(self.color_title[0],self.color_title[1],self.color_title[2],self.color_title[3])
415
 
                self.draw_text(ctx, 'Notes',14,y+2,self.font_title.split(' ')[0],10,self.width-20,pango.ALIGN_LEFT)
416
 
                if self.expanded:
417
 
                        ctx.rotate(3.14)
418
 
                        self.draw_triangle(ctx,-15,-(y+17),10,10)
419
 
                        ctx.rotate(-3.14)
420
 
                        
421
 
                else:
422
 
                        ctx.rotate(3.14/2)
423
 
                        self.draw_triangle(ctx,3,-(y+15),10,10)
424
 
                        ctx.rotate(-3.14/2)
425
 
                ctx.translate(0,20)                     
426
 
                if self.expanded and self.notes != None:
427
 
                        x = 0
428
 
                        
429
 
                        
430
 
                        for app  in self.notes:
431
 
                                if x % 2:
432
 
                                        ctx.set_source_rgba(self.color_even[0],self.color_even[1],self.color_even[2],self.color_even[3])
433
 
                                        #is_mounted = 'Mounted'
434
 
                                else:
435
 
                                        ctx.set_source_rgba(self.color_odd[0],self.color_odd[1],self.color_odd[2],self.color_odd[3])
436
 
                                if self.check_for_icon(app):
437
 
                                        ico = 'tomboy'
438
 
                                else:
439
 
                                        ico = 'stock_search-and-replace'
440
 
 
441
 
 
442
 
                                if self.mousesel == x and self.mouse_is_over:
443
 
                                        ctx.set_source_rgba(self.color_hover[0],self.color_hover[1],self.color_hover[2],self.color_hover[3])
444
 
                                        self.__dict__['selected'] = x
445
 
 
446
 
                                if y +60== self.height:
447
 
                                        self.draw_rounded_rectangle(ctx,0,y,5,self.width-20,20,round_top_right= False,round_top_left= False)    
448
 
                                else:
449
 
                                        self.draw_rectangle(ctx,0,y,self.width -20,20)
450
 
 
451
 
                                ctx.set_source_rgba(self.color_text[0],self.color_text[1],self.color_text[2],self.color_text[3])
452
 
                        
453
 
                                self.draw_text(ctx,self.notes[app],5,y+2,self.font.split(' ')[0],10,self.width-20,pango.ALIGN_LEFT)
454
 
                                a = self.get_screenlet_dir() + '/themes/' + self.theme_name + '/icon.png'
455
 
                                self.draw_scaled_image(ctx,self.width-40,y+2,a,16,16)
456
 
                                x = x+1
457
 
                                y = y +20
458
 
                        
459
 
                
460
 
                        
461
 
 
462
 
        def on_draw_shape (self, ctx):
463
 
                self.on_draw(ctx)
464
 
        
465
 
# If the program is run directly or passed as an argument to the python
466
 
# interpreter then create a Screenlet instance and show it
467
 
if __name__ == "__main__":
468
 
        # create new session
469
 
        import screenlets.session
470
 
        screenlets.session.create_session(TomboyScreenlet)
471