1
# -.- coding: utf-8 -.-
3
# GNOME Activity Journal
5
# Copyright © 2009-2010 Seif Lotfy <seif@lotfy.com>
6
# Copyright © 2010 Siegfried Gevatter <siegfried@gevatter.com>
7
# Copyright © 2010 Markus Korn <thekorn@gmx.de>
8
# Copyright © 2010 Randal Barlow <email.tehk@gmail.com>
10
# This program is free software: you can redistribute it and/or modify
11
# it under the terms of the GNU General Public License as published by
12
# the Free Software Foundation, either version 3 of the License, or
13
# (at your option) any later version.
15
# This program is distributed in the hope that it will be useful,
16
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
# GNU General Public License for more details.
20
# You should have received a copy of the GNU General Public License
21
# along with this program. If not, see <http://www.gnu.org/licenses/>.
23
from __future__ import with_statement
34
from dbus.exceptions import DBusException
40
from zeitgeist.client import ZeitgeistClient
41
from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation, \
44
from common import shade_gdk_color, combine_gdk_color, is_command_available, \
46
from config import BASE_PATH, VERSION, settings, get_icon_path, get_data_path
47
from sources import Source, SUPPORTED_SOURCES
48
from gio_file import GioFile, SIZE_NORMAL, SIZE_LARGE
49
from bookmarker import bookmarker
51
from tracker_wrapper import tracker
53
print "Tracker disabled."
55
import content_objects
58
CLIENT = ZeitgeistClient()
62
class DayLabel(gtk.DrawingArea):
66
gtk.gdk.ENTER_NOTIFY_MASK | gtk.gdk.LEAVE_NOTIFY_MASK |
67
gtk.gdk.KEY_PRESS_MASK | gtk.gdk.BUTTON_MOTION_MASK |
68
gtk.gdk.POINTER_MOTION_HINT_MASK | gtk.gdk.BUTTON_RELEASE_MASK |
69
gtk.gdk.BUTTON_PRESS_MASK
72
def __init__(self,date=None):
73
super(DayLabel, self).__init__()
74
self.set_events(self._events)
75
self.connect("expose_event", self.expose)
79
self.date = datetime.date.today()
80
self.set_size_request(100, 60)
83
def date_string(self):
84
return self.date.strftime("%x")
87
def weekday_string(self):
88
return self.date.strftime("%A")
92
if self.date == datetime.date.today():
95
def set_date(self, date):
99
def expose(self, widget, event):
100
context = widget.window.cairo_create()
101
self.context = context
103
bg = self.style.bg[0]
104
red, green, blue = bg.red/65535.0, bg.green/65535.0, bg.blue/65535.0
105
self.font_name = self.style.font_desc.get_family()
107
widget.style.set_background(widget.window, gtk.STATE_NORMAL)
109
# set a clip region for the expose event
110
context.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
112
self.draw(widget, event, context)
113
self.day_text(widget, event, context)
116
def day_text(self, widget, event, context):
117
actual_y = self.get_size_request()[1]
118
if actual_y > event.area.height:
121
y = event.area.height
123
gc = self.style.fg_gc[gtk.STATE_SELECTED if self.leading else gtk.STATE_NORMAL]
124
layout = widget.create_pango_layout(self.weekday_string)
125
layout.set_font_description(pango.FontDescription(self.font_name + " Bold 15"))
126
w, h = layout.get_pixel_size()
127
widget.window.draw_layout(gc, (x-w)/2, (y)/2 - h + 5, layout)
128
self.date_text(widget, event, context, (y)/2 + 5)
130
def date_text(self, widget, event, context, lastfontheight):
131
gc = self.style.fg_gc[gtk.STATE_SELECTED if self.leading else gtk.STATE_INSENSITIVE]
132
layout = widget.create_pango_layout(self.date_string)
133
layout.set_font_description(pango.FontDescription(self.font_name + " 10"))
134
w, h = layout.get_pixel_size()
135
widget.window.draw_layout(gc, (event.area.width-w)/2, lastfontheight, layout)
137
def draw(self, widget, event, context):
139
bg = self.style.bg[gtk.STATE_SELECTED]
140
red, green, blue = bg.red/65535.0, bg.green/65535.0, bg.blue/65535.0
142
bg = self.style.bg[gtk.STATE_NORMAL]
143
red = (bg.red * 125 / 100)/65535.0
144
green = (bg.green * 125 / 100)/65535.0
145
blue = (bg.blue * 125 / 100)/65535.0
148
w, h = event.area.width, event.area.height
149
context.set_source_rgba(red, green, blue, 1)
150
context.new_sub_path()
151
context.arc(r+x, r+y, r, math.pi, 3 * math.pi /2)
152
context.arc(w-r, r+y, r, 3 * math.pi / 2, 0)
154
context.rectangle(0, r, w, h)
155
context.fill_preserve()
158
class DayButton(gtk.DrawingArea):
164
bg_color = (0, 0, 0, 0)
165
header_color = (1, 1, 1, 1)
166
leading_header_color = (1, 1, 1, 1)
167
internal_color = (0, 1, 0, 1)
168
arrow_color = (1,1,1,1)
169
arrow_color_selected = (1, 1, 1, 1)
172
"clicked": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,()),
175
gtk.gdk.ENTER_NOTIFY_MASK | gtk.gdk.LEAVE_NOTIFY_MASK |
176
gtk.gdk.KEY_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.BUTTON_PRESS_MASK |
177
gtk.gdk.MOTION_NOTIFY | gtk.gdk.POINTER_MOTION_MASK
179
def __init__(self, side = 0, leading = False):
180
super(DayButton, self).__init__()
181
self.set_events(self._events)
182
self.set_flags(gtk.CAN_FOCUS)
183
self.leading = leading
185
self.connect("button_press_event", self.on_press)
186
self.connect("button_release_event", self.clicked_sender)
187
self.connect("key_press_event", self.keyboard_clicked_sender)
188
self.connect("motion_notify_event", self.on_hover)
189
self.connect("leave_notify_event", self._enter_leave_notify, False)
190
self.connect("expose_event", self.expose)
191
self.connect("style-set", self.change_style)
192
self.set_size_request(20, -1)
194
def set_sensitive(self, case):
195
self.sensitive = case
198
def _enter_leave_notify(self, widget, event, bol):
202
def on_hover(self, widget, event):
203
if event.y > self.header_size:
213
def on_press(self, widget, event):
214
if event.y > self.header_size:
218
def keyboard_clicked_sender(self, widget, event):
219
if event.keyval in (gtk.keysyms.Return, gtk.keysyms.space):
227
def clicked_sender(self, widget, event):
228
if event.y > self.header_size:
235
def change_style(self, *args, **kwargs):
236
self.bg_color = common.get_gtk_rgba(self.style, "bg", 0)
237
self.header_color = common.get_gtk_rgba(self.style, "bg", 0, 1.25)
238
self.leading_header_color = common.get_gtk_rgba(self.style, "bg", 3)
239
self.internal_color = common.get_gtk_rgba(self.style, "bg", 0, 1.02)
240
self.arrow_color = common.get_gtk_rgba(self.style, "text", 0, 0.6)
241
self.arrow_color_selected = common.get_gtk_rgba(self.style, "bg", 3)
242
self.arrow_color_insensitive = common.get_gtk_rgba(self.style, "text", 4)
244
def expose(self, widget, event):
245
context = widget.window.cairo_create()
247
context.set_source_rgba(*self.bg_color)
248
context.set_operator(cairo.OPERATOR_SOURCE)
250
context.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
255
w, h = event.area.width, event.area.height
258
context.set_source_rgba(*(self.leading_header_color if self.leading else self.header_color))
259
context.new_sub_path()
260
context.move_to(x+r,y)
261
context.line_to(x+w-r,y)
262
context.curve_to(x+w,y,x+w,y,x+w,y+r)
263
context.line_to(x+w,y+h-r)
264
context.curve_to(x+w,y+h,x+w,y+h,x+w-r,y+h)
265
context.line_to(x+r,y+h)
266
context.curve_to(x,y+h,x,y+h,x,y+h-r)
267
context.line_to(x,y+r)
268
context.curve_to(x,y,x,y,x+r,y)
269
context.set_source_rgba(*(self.leading_header_color if self.leading else self.header_color))
271
context.rectangle(0, r, w, self.header_size)
273
context.set_source_rgba(*self.internal_color)
274
context.rectangle(0, self.header_size, w, h)
277
widget.style.paint_box(widget.window, gtk.STATE_PRELIGHT, gtk.SHADOW_OUT,
278
event.area, widget, "button",
279
event.area.x, self.header_size,
280
w, h-self.header_size)
282
if not self.sensitive:
283
state = gtk.STATE_INSENSITIVE
284
elif self.is_focus() or self.pressed:
285
widget.style.paint_focus(widget.window, gtk.STATE_ACTIVE, event.area,
286
widget, None, event.area.x, self.header_size,
287
w, h-self.header_size)
288
state = gtk.STATE_SELECTED
290
state = gtk.STATE_NORMAL
291
arrow = gtk.ARROW_RIGHT if self.side else gtk.ARROW_LEFT
292
self.style.paint_arrow(widget.window, state, gtk.SHADOW_NONE, None,
293
self, "arrow", arrow, True,
294
w/2-size/2, h/2 + size/2, size, size)
297
class SearchBox(gtk.EventBox):
300
"clear" : (gobject.SIGNAL_RUN_FIRST,
303
"search" : (gobject.SIGNAL_RUN_FIRST,
305
(gobject.TYPE_PYOBJECT,))
309
gtk.EventBox.__init__(self)
313
self.set_border_width(3)
314
self.hbox = gtk.HBox()
319
self.search = SearchEntry()
321
self.hbox.pack_start(self.search)
322
self.hbox.set_border_width(6)
326
for source in SUPPORTED_SOURCES.keys():
327
s = SUPPORTED_SOURCES[source]._desc_pl
328
self.category[s] = source
330
self._init_combobox()
333
def change_style(widget, style):
335
rc_style = self.style
336
color = rc_style.bg[gtk.STATE_NORMAL]
337
color = shade_gdk_color(color, 102/100.0)
338
self.modify_bg(gtk.STATE_NORMAL, color)
340
color = rc_style.bg[gtk.STATE_NORMAL]
341
fcolor = rc_style.fg[gtk.STATE_NORMAL]
342
color = combine_gdk_color(color, fcolor)
344
self.search.modify_text(gtk.STATE_NORMAL, color)
346
self.hbox.connect("style-set", change_style)
347
self.search.connect("search", self.set_search)
348
self.search.connect("clear", self.clear)
350
def clear(self, widget):
351
if self.text.strip() != "" and self.text.strip() != self.search.default_text:
356
def _init_combobox(self):
358
self.clearbtn = gtk.Button()
360
#label.set_markup("<span><b>X</b></span>")
362
img = gtk.image_new_from_stock("gtk-close", gtk.ICON_SIZE_MENU)
363
self.clearbtn.add(img)
364
self.clearbtn.set_focus_on_click(False)
365
self.clearbtn.set_relief(gtk.RELIEF_NONE)
366
self.hbox.pack_end(self.clearbtn, False, False)
367
self.clearbtn.connect("clicked", lambda button: self.hide())
368
self.clearbtn.connect("clicked", lambda button: self.search.set_text(""))
370
self.combobox = gtk.combo_box_new_text()
371
self.combobox.set_focus_on_click(False)
372
self.hbox.pack_end(self.combobox, False, False, 6)
373
self.combobox.append_text("All activities")
374
self.combobox.set_active(0)
375
for cat in self.category.keys():
376
self.combobox.append_text(cat)
378
def set_search(self, widget, text=None):
379
if not self.text.strip() == text.strip():
381
def callback(results):
382
self.results = [s[1] for s in results]
383
self.emit("search", results)
386
text = self.search.get_text()
387
if text == self.search.default_text or text.strip() == "":
390
cat = self.combobox.get_active()
392
interpretation = None
394
cat = self.category[self.combobox.get_active_text()]
395
interpretation = self.category[self.combobox.get_active_text()]
396
if "tracker" in globals().keys():
397
tracker.search(text, interpretation, callback)
400
class SearchEntry(gtk.Entry):
403
"clear" : (gobject.SIGNAL_RUN_FIRST,
406
"search" : (gobject.SIGNAL_RUN_FIRST,
408
(gobject.TYPE_STRING,))
411
default_text = _("Type here to search...")
413
# The font style of the text in the entry.
416
# TODO: What is this?
419
def __init__(self, accel_group = None):
420
gtk.Entry.__init__(self)
422
self.set_width_chars(30)
423
self.set_text(self.default_text)
424
self.set_size_request(-1, 32)
425
self.connect("changed", lambda w: self._queue_search())
426
self.connect("focus-in-event", self._entry_focus_in)
427
self.connect("focus-out-event", self._entry_focus_out)
428
#self.connect("icon-press", self._icon_press)
431
def _icon_press(self, widget, pos, event):
432
# Note: GTK_ENTRY_ICON_SECONDARY does not seem to be bound in PyGTK.
433
if int(pos) == 1 and not self.get_text() == self.default_text:
434
self._entry_clear_no_change_handler()
436
def _entry_focus_in(self, widget, x):
437
if self.get_text() == self.default_text:
439
#self.modify_font(self.font_style)
441
def _entry_focus_out(self, widget, x):
442
if self.get_text() == "":
443
self.set_text(self.default_text)
444
#self.modify_font(self.font_style)
446
def _entry_clear_no_change_handler(self):
447
if not self.get_text() == self.default_text:
450
def _queue_search(self):
451
if self.search_timeout != 0:
452
gobject.source_remove(self.search_timeout)
453
self.search_timeout = 0
455
if self.get_text() == self.default_text or len(self.get_text()) == 0:
458
self.search_timeout = gobject.timeout_add(200, self._typing_timeout)
460
def _typing_timeout(self):
461
if len(self.get_text()) > 0:
462
self.emit("search", self.get_text())
464
self.search_timeout = 0
468
class PreviewTooltip(gtk.Window):
470
# per default we are using thumbs at a size of 128 * 128 px
471
# in tooltips. For preview of text files we are using 256 * 256 px
472
# which is dynamically defined in StaticPreviewTooltip.preview()
473
TOOLTIP_SIZE = SIZE_NORMAL
476
gtk.Window.__init__(self, type=gtk.WINDOW_POPUP)
478
def preview(self, gio_file):
482
class StaticPreviewTooltip(PreviewTooltip):
485
super(StaticPreviewTooltip, self).__init__()
486
self.__current = None
487
self.__monitor = None
489
def replace_content(self, content):
490
children = self.get_children()
492
self.remove(children[0])
493
# hack to force the tooltip to have the exact same size
498
def preview(self, gio_file):
499
if gio_file == self.__current:
500
return bool(self.__current)
501
if self.__monitor is not None:
502
self.__monitor.cancel()
503
self.__current = gio_file
504
self.__monitor = gio_file.get_monitor()
505
self.__monitor.connect("changed", self._do_update_preview)
506
# for text previews we are always using SIZE_LARGE
507
if "text-x-generic" in gio_file.icon_names or "text-x-script" in gio_file.icon_names:
510
size = self.TOOLTIP_SIZE
511
if not isinstance(gio_file, GioFile): return False
512
pixbuf = gio_file.get_thumbnail(size=size, border=1)
514
self.__current = None
516
img = gtk.image_new_from_pixbuf(pixbuf)
517
img.set_alignment(0.5, 0.5)
519
self.replace_content(img)
523
def _do_update_preview(self, monitor, file, other_file, event_type):
524
if event_type == gio.FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
525
if self.__current is not None:
526
self.__current.refresh()
527
self.__current = None
528
gtk.tooltip_trigger_tooltip_query(gtk.gdk.display_get_default())
531
class VideoPreviewTooltip(PreviewTooltip):
534
PreviewTooltip.__init__(self)
536
self.movie_window = gtk.DrawingArea()
537
hbox.pack_start(self.movie_window)
539
self.player = gst.element_factory_make("playbin", "player")
540
bus = self.player.get_bus()
541
bus.add_signal_watch()
542
bus.enable_sync_message_emission()
543
bus.connect("message", self.on_message)
544
bus.connect("sync-message::element", self.on_sync_message)
545
self.connect("hide", self._handle_hide)
546
self.connect("show", self._handle_show)
547
self.set_default_size(*self.TOOLTIP_SIZE)
549
def _handle_hide(self, widget):
550
self.player.set_state(gst.STATE_NULL)
552
def _handle_show(self, widget):
553
self.player.set_state(gst.STATE_PLAYING)
555
def preview(self, gio_file):
556
if gio_file.uri == self.player.get_property("uri"):
558
self.player.set_property("uri", gio_file.uri)
561
def on_message(self, bus, message):
563
if t == gst.MESSAGE_EOS:
564
self.player.set_state(gst.STATE_NULL)
566
elif t == gst.MESSAGE_ERROR:
567
self.player.set_state(gst.STATE_NULL)
568
err, debug = message.parse_error()
569
print "Error: %s" % err, debug
571
def on_sync_message(self, bus, message):
572
if message.structure is None:
574
message_name = message.structure.get_name()
575
if message_name == "prepare-xwindow-id":
576
imagesink = message.src
577
imagesink.set_property("force-aspect-ratio", True)
578
gtk.gdk.threads_enter()
581
imagesink.set_xwindow_id(self.movie_window.window.xid)
583
gtk.gdk.threads_leave()
586
class AnimatedImage(gtk.Image):
591
def __init__(self, uri, speed = 0):
592
super(AnimatedImage, self).__init__()
593
if speed: self.speed = speed
595
for i in (6, 5, 4, 3, 2, 1, 0):
596
self.frames.append(gtk.gdk.pixbuf_new_from_file_at_size(get_icon_path(uri % i), 16, 16))
597
self.set_from_pixbuf(self.frames[0])
603
self.set_from_pixbuf(self.frames[self.i % self.mod])
609
start the image's animation
611
if self.animating: gobject.source_remove(self.animating)
612
self.animating = gobject.timeout_add(self.speed, self.next)
616
stop the image's animation
618
if self.animating: gobject.source_remove(self.animating)
619
self.animating = None
622
def animate_for_seconds(self, seconds):
624
:param seconds: int seconds for the amount of time when you want
628
gobject.timeout_add_seconds(seconds, self.stop)
631
class Throbber(gtk.ToolButton):
633
super(Throbber, self).__init__()
634
self.image = AnimatedImage(get_data_path("zlogo/zg%d.png"), 150)
635
self.image.set_tooltip_text(_("Powered by Zeitgeist"))
636
#self.image.set_alignment(0.9, 0.98)
637
self.set_icon_widget(self.image)
640
class AboutDialog(gtk.AboutDialog):
641
name = "Activity Journal"
643
"Seif Lotfy <seif@lotfy.com>",
644
"Randal Barlow <email.tehk@gmail.com>",
645
"Siegfried-Angel Gevatter <siegfried@gevatter.com>",
646
"Peter Lund <peterfirefly@gmail.com>",
647
"Hylke Bons <hylkebons@gmail.com>",
648
"Markus Korn <thekorn@gmx.de>",
649
"Mikkel Kamstrup <mikkel.kamstrup@gmail.com>"
652
"Hylke Bons <hylkebons@gmail.com>",
653
"Thorsten Prante <thorsten@prante.eu>"
655
copyright_ = "Copyright © 2009-2010 Activity Journal authors"
656
comment = "A viewport into the past powered by Zeitgeist"
659
super(AboutDialog, self).__init__()
660
self.set_name(self.name)
661
self.set_version(self.version)
662
self.set_comments(self.comment)
663
self.set_copyright(self.copyright_)
664
self.set_authors(self.authors)
665
self.set_artists(self.artists)
668
for name in ("/usr/share/common-licenses/GPL",
669
os.path.join(BASE_PATH, "COPYING")):
670
if os.path.isfile(name):
671
with open(name) as licensefile:
672
license = licensefile.read()
675
license = "GNU General Public License, version 3 or later."
677
self.set_license(license)
678
#self.set_logo_icon_name("gnome-activity-journal")
679
self.set_logo(gtk.gdk.pixbuf_new_from_file_at_size(get_icon_path(
680
"hicolor/scalable/apps/gnome-activity-journal.svg"), 48, 48))
683
class ContextMenu(gtk.Menu):
684
subjects = []# A list of Zeitgeist event uris
685
informationwindow = None
687
super(ContextMenu, self).__init__()
689
"open" : gtk.ImageMenuItem(gtk.STOCK_OPEN),
690
"unpin" : gtk.MenuItem(_("Remove Pin")),
691
"pin" : gtk.MenuItem(_("Pin to Today")),
692
"delete" : gtk.MenuItem(_("Delete item from Journal")),
693
"delete_uri" : gtk.MenuItem(_("Delete all events with this URI")),
694
"info" : gtk.MenuItem(_("More Information")),
697
"open" : self.do_open,
698
"unpin" : self.do_unbookmark,
699
"pin" : self.do_bookmark,
700
"delete" : self.do_delete,
701
"delete_uri" : self.do_delete_events_with_shared_uri,
702
"info" : self.do_show_info,
704
names = ["open", "unpin", "pin", "delete", "delete_uri", "info"]
705
if is_command_available("nautilus-sendto"):
706
self.menuitems["sendto"] = gtk.MenuItem(_("Send To..."))
707
callbacks["sendto"] = self.do_send_to
708
names.append("sendto")
710
item = self.menuitems[name]
712
item.connect("activate", callbacks[name])
715
def do_popup(self, time, subjects):
717
Call this method to popup the context menu
719
:param time: the event time from the button press event
720
:param subjects: a list of uris
722
self.subjects = subjects
723
if len(subjects) == 1:
725
if bookmarker.is_bookmarked(uri):
726
self.menuitems["pin"].hide()
727
self.menuitems["unpin"].show()
729
self.menuitems["pin"].show()
730
self.menuitems["unpin"].hide()
732
self.popup(None, None, None, 3, time)
734
def do_open(self, menuitem):
735
for obj in self.subjects:
738
def do_show_info(self, menuitem):
739
if self.subjects and self.informationwindow:
740
self.informationwindow.set_content_object(self.subjects[0])
742
def do_bookmark(self, menuitem):
743
for obj in self.subjects:
746
isbookmarked = bookmarker.is_bookmarked(uri)
748
bookmarker.bookmark(uri)
750
def do_unbookmark(self, menuitem):
751
for obj in self.subjects:
754
isbookmarked = bookmarker.is_bookmarked(uri)
756
bookmarker.unbookmark(uri)
758
def do_delete(self, menuitem):
759
for obj in self.subjects:
760
CLIENT.delete_events([obj.event.id])
762
def do_delete_events_with_shared_uri(self, menuitem):
763
for uri in map(lambda obj: obj.uri, self.subjects):
764
CLIENT.find_event_ids_for_template(
765
Event.new_for_values(subject_uri=uri),
766
lambda ids: CLIENT.delete_events(map(int, ids)))
769
def do_send_to(self, menuitem):
770
launch_command("nautilus-sendto", map(lambda obj: obj.uri, self.subjects))
773
class Toolbar(gtk.Toolbar):
775
def get_toolbutton(path, label_string):
776
button = gtk.ToolButton()
777
pixbuf = gtk.gdk.pixbuf_new_from_file(path)
779
image.set_from_pixbuf(pixbuf)
780
button.set_icon_widget(image)
781
button.set_label(label_string)
786
super(Toolbar, self).__init__()
787
#self.set_style(gtk.TOOLBAR_BOTH)
788
self.multiview_button = mv = self.get_toolbutton(
789
get_data_path("multiview_icon.png"),
791
self.thumbview_button = tbv = self.get_toolbutton(
792
get_data_path("thumbview_icon.png"),
794
self.timelineview_button = tlv = self.get_toolbutton(
795
get_data_path("timelineview_icon.png"),
799
self.pin_button = pin = self.get_toolbutton(
800
get_icon_path("hicolor/24x24/status/pin.png"),
801
_("Show Pinned Pane"))
802
separator = gtk.SeparatorToolItem()
803
for item in (pin, separator, tlv, tbv, mv):
806
separator = gtk.SeparatorToolItem()
807
separator.set_expand(True)
808
separator.set_draw(False)
809
self.goto_today_button = today = gtk.ToolButton(gtk.STOCK_GOTO_LAST)
810
today.set_label( _("Goto Today"))
811
self.throbber = Throbber()
812
for item in (separator, today, self.throbber):
813
self.insert(item, -1)
816
self.throbber.image.animate_for_seconds(1)
819
class StockIconButton(gtk.Button):
820
def __init__(self, stock_id, size=gtk.ICON_SIZE_BUTTON):
821
super(StockIconButton, self).__init__()
822
self.set_alignment(0, 0)
823
self.set_relief(gtk.RELIEF_NONE)
824
image = gtk.image_new_from_stock(stock_id, size)
828
class Pane(gtk.Frame):
833
super(Pane, self).__init__()
834
#self.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
835
close_button = StockIconButton(gtk.STOCK_CLOSE)
836
self.set_label_widget(close_button)#, False, False)
837
self.connect("delete-event", self.hide_on_delete)
838
close_button.connect("clicked", self.hide_on_delete)
839
self.set_label_align(0,0)
842
def hide_on_delete(self, widget, *args):
847
searchbox = SearchBox()
849
VideoPreviewTooltip = VideoPreviewTooltip()
851
VideoPreviewTooltip = None
852
StaticPreviewTooltip = StaticPreviewTooltip()
853
ContextMenu = ContextMenu()