38
39
except ImportError:
41
from zeitgeist.client import ZeitgeistClient
42
from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation, \
42
from zeitgeist.datamodel import Event, Subject, StorageState
45
45
import content_objects
46
from common import shade_gdk_color, combine_gdk_color, is_command_available, \
47
launch_command, get_gtk_rgba, SIZE_NORMAL, SIZE_LARGE, GioFile
48
46
from config import BASE_PATH, VERSION, settings, PluginManager, get_icon_path, get_data_path, bookmarker, SUPPORTED_SOURCES
49
48
from store import STORE, get_related_events_for_uri, CLIENT
50
from external import TRACKER
53
51
class DayLabel(gtk.DrawingArea):
120
116
self.date_text(widget, event, context, (y)/2 + 5)
122
118
def date_text(self, widget, event, context, lastfontheight):
119
gx, gy, gw, gh, gq = widget.window.get_geometry()
123
120
gc = self.style.fg_gc[gtk.STATE_SELECTED if self.leading else gtk.STATE_INSENSITIVE]
124
121
layout = widget.create_pango_layout(self.date_string)
125
122
layout.set_font_description(pango.FontDescription(self.font_name + " 10"))
126
123
w, h = layout.get_pixel_size()
127
widget.window.draw_layout(gc, (event.area.width-w)/2, lastfontheight, layout)
124
widget.window.draw_layout(gc, (gw-w)/2, lastfontheight, layout)
129
126
def draw(self, widget, event, context):
127
gx, gy, w, h, gq = widget.window.get_geometry()
131
129
bg = self.style.bg[gtk.STATE_SELECTED]
132
130
red, green, blue = bg.red/65535.0, bg.green/65535.0, bg.blue/65535.0
150
147
class DayButton(gtk.DrawingArea):
150
today_pressed = False
156
155
bg_color = (0, 0, 0, 0)
157
156
header_color = (1, 1, 1, 1)
158
157
leading_header_color = (1, 1, 1, 1)
159
158
internal_color = (0, 1, 0, 1)
160
arrow_color = (1,1,1,1)
159
arrow_color = (1, 1, 1, 1)
161
160
arrow_color_selected = (1, 1, 1, 1)
164
163
"clicked": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,()),
164
"jump-to-today": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,()),
167
167
gtk.gdk.ENTER_NOTIFY_MASK | gtk.gdk.LEAVE_NOTIFY_MASK |
168
168
gtk.gdk.KEY_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.BUTTON_PRESS_MASK |
169
169
gtk.gdk.MOTION_NOTIFY | gtk.gdk.POINTER_MOTION_MASK
173
def new(cls, side = 0, sensitive=True):
174
button = DayButton(side, sensitive)
175
def query_tooltip(widget, x, y, keyboard_mode, tooltip, ebutton):
176
if not ebutton.sensitive:
178
elif y < ebutton.header_size and ebutton.side == 1:
179
text = _("Go to Today")
180
elif y >= ebutton.header_size:
181
text = _("Go to the previous day ") if ebutton.side == 0 else _("Go to the next day")
184
tooltip.set_text(text)
186
evbox = gtk.EventBox()
187
evbox.connect("query-tooltip", query_tooltip, button)
188
evbox.set_property("has-tooltip", True)
171
193
def __init__(self, side = 0, sensitive=True):
172
194
super(DayButton, self).__init__()
173
195
self.set_events(self._events)
287
324
self.style.paint_arrow(widget.window, state, gtk.SHADOW_NONE, None,
288
325
self, "arrow", arrow, True,
289
326
w/2-size/2, h/2 + size/2, size, size)
329
# Paint today button arrows.
330
if self.sensitive and self.side > 0:
332
if self.today_pressed:
333
self.style.paint_arrow(widget.window, gtk.STATE_SELECTED, gtk.SHADOW_NONE, None,
334
self, "arrow", arrow, True,
335
w/2, self.header_size/2 - size/2, size, size)
336
self.style.paint_arrow(widget.window, gtk.STATE_SELECTED, gtk.SHADOW_OUT, None,
337
self, "arrow", arrow, True,
338
w/2-size/2, self.header_size/2 - size/2, size, size)
341
self.style.paint_arrow(widget.window, state, gtk.SHADOW_NONE, None,
342
self, "arrow", arrow, True,
343
w/2, self.header_size/2 - size/2, size, size)
344
self.style.paint_arrow(widget.window, state, gtk.SHADOW_OUT, None,
345
self, "arrow", arrow, True,
346
w/2-size/2, self.header_size/2 - size/2, size, size)
348
self.style.paint_arrow(widget.window, gtk.STATE_SELECTED, gtk.SHADOW_NONE, None,
349
self, "arrow", arrow, True,
350
w/2, self.header_size/2 - size/2, size, size)
351
self.style.paint_arrow(widget.window, gtk.STATE_SELECTED, gtk.SHADOW_OUT, None,
352
self, "arrow", arrow, True,
353
w/2-size/2, self.header_size/2 - size/2, size, size)
292
357
class SearchBox(gtk.ToolItem):
312
383
self.search = SearchEntry()
313
384
self.hbox.pack_start(self.search)
314
385
self.category = {}
386
#if STORE.fts_search_enabled:
387
# self.fts_checkbutton = gtk.CheckButton(_("Use Zeitgeist FTS"))
316
389
for source in SUPPORTED_SOURCES.keys():
317
390
s = SUPPORTED_SOURCES[source]._desc_pl
318
391
self.category[s] = source
392
self.combobox = gtk.combo_box_new_text()
393
self.combobox.set_focus_on_click(False)
394
self.hbox.pack_start(self.combobox, False, False, 6)
395
#if STORE.fts_search_enabled:
396
# self.hbox.pack_end(self.fts_checkbutton)
397
self.combobox.append_text("All activities")
398
self.combobox.set_active(0)
399
for cat in self.category.keys():
400
self.combobox.append_text(cat)
320
self._init_combobox()
323
404
def change_style(widget, style):
377
451
def do_search(self, text, callback=None, interpretation=None):
378
452
if not callback: return
379
if TRACKER and 1==2: #DISABLED FOR NOW. Causes a crash in zeitgeist
380
self.do_search_tracker(text, callback, interpretation)
382
self.do_search_objs(text, callback, interpretation)
385
def do_search_tracker(text, callback, interpretation=None):
386
TRACKER.search(text, interpretation, callback)
389
def do_search_objs(text, callback, interpretation=None):
453
self.do_search_objs(text, callback, interpretation)
455
def do_search_objs(self, text, callback, interpretation=None):
390
456
def _search(text, callback):
392
for obj in content_objects.ContentObject.instances:
393
subject = obj.event.subjects[0]
394
if text.lower() in subject.text.lower() or text in subject.uri:
397
if subject.interpretation != interpretation:
457
if STORE.fts_search_enabled and self.use_fts:
458
matching = STORE.search_using_zeitgeist_fts(text, [Event.new_for_values(subject_interpretation=interpretation)] if interpretation else [])
460
def matching_test_function(obj):
461
subject = obj.event.subjects[0]
462
if text.lower() in subject.text.lower() or text in subject.uri:
465
if subject.interpretation != interpretation:
471
matching = STORE.search_store_using_matching_function(matching_test_function)
401
472
gtk.gdk.threads_enter()
402
473
callback(matching)
403
474
gtk.gdk.threads_leave()
617
693
imagesink.set_property("force-aspect-ratio", True)
618
694
gtk.gdk.threads_enter()
621
696
imagesink.set_xwindow_id(self.movie_window.window.xid)
623
698
gtk.gdk.threads_leave()
700
class AudioPreviewTooltip(PreviewTooltip):
703
PreviewTooltip.__init__(self)
704
#Playing label stuffs
705
screen = self.get_screen()
706
map_ = screen.get_rgba_colormap()
708
map_ = screen.get_rgb_colormap()
709
self.set_colormap(map_)
710
self.set_app_paintable(True)
711
img = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY,gtk.ICON_SIZE_LARGE_TOOLBAR)
712
self.image = AnimatedImage(get_data_path("zlogo/zg%d.png"), 150, size=20)
715
label.set_markup(_("<b>Playing...</b>"))
717
hal = gtk.Alignment()
718
hal.set_padding(0,0,5,0)
720
hbox.pack_start(self.image)
725
self.player = gst.element_factory_make("playbin2", "player")
726
fakesink = gst.element_factory_make("fakesink", "fakesink")
727
self.player.set_property("video-sink", fakesink)
728
bus = self.player.get_bus()
729
bus.add_signal_watch()
730
bus.connect("message", self.on_message)
731
self.connect("hide", self._handle_hide)
732
self.connect("show", self._handle_show)
733
self.connect("expose-event", self.transparent_expose)
735
def transparent_expose(self, widget, event):
736
cr = widget.window.cairo_create()
737
cr.set_operator(cairo.OPERATOR_CLEAR)
738
region = gtk.gdk.region_rectangle(event.area)
743
def _handle_hide(self, widget):
745
self.player.set_state(gst.STATE_NULL)
747
def _handle_show(self, widget):
750
self.player.set_state(gst.STATE_PLAYING)
752
def preview(self, gio_file):
753
if gio_file.uri == self.player.get_property("uri"):
755
self.player.set_property("uri", gio_file.uri)
758
def on_message(self, bus, message):
760
if t == gst.MESSAGE_EOS:
761
self.player.set_state(gst.STATE_NULL)
762
elif t == gst.MESSAGE_ERROR:
763
self.player.set_state(gst.STATE_NULL)
764
err, debug = message.parse_error()
765
print "Error: %s" % err, debug
767
def replace_content(self, content):
768
children = self.get_children()
770
self.remove(children[0])
771
# hack to force the tooltip to have the exact same size
626
776
class AnimatedImage(gtk.Image):
631
def __init__(self, uri, speed = 0):
781
def __init__(self, uri, speed = 0, size = 16):
632
782
super(AnimatedImage, self).__init__()
633
783
if speed: self.speed = speed
635
785
for i in (6, 5, 4, 3, 2, 1, 0):
636
self.frames.append(gtk.gdk.pixbuf_new_from_file_at_size(get_icon_path(uri % i), 16, 16))
786
self.frames.append(gtk.gdk.pixbuf_new_from_file_at_size(get_icon_path(uri % i), size, size))
637
787
self.set_from_pixbuf(self.frames[0])
668
818
gobject.timeout_add_seconds(seconds, self.stop)
671
class Throbber(gtk.ToolButton):
821
class ThrobberPopupButton(gtk.ToolItem):
824
"toggle-erase-mode" : (gobject.SIGNAL_RUN_FIRST,
672
829
def __init__(self):
673
super(Throbber, self).__init__()
674
self.image = AnimatedImage(get_data_path("zlogo/zg%d.png"), 150)
675
self.image.set_tooltip_text(_("Powered by Zeitgeist"))
676
#self.image.set_alignment(0.9, 0.98)
677
self.set_icon_widget(self.image)
830
super(ThrobberPopupButton, self).__init__()
832
self.button = button = gtk.ToggleButton()
833
button.set_relief(gtk.RELIEF_NONE)
834
self.image = image = AnimatedImage(get_data_path("zlogo/zg%d.png"), 150)
835
image.set_tooltip_text(_("Preferences"))
836
arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_NONE)
837
arrow.set_size_request(10, 10)
838
box.pack_start(image, True, True, 1)
839
box.pack_start(arrow, True, True, 1)
843
self.menu = gtk.Menu()
844
self.about = get_menu_item_with_stock_id_and_text(gtk.STOCK_ABOUT, _("About"))
845
self.preferences = get_menu_item_with_stock_id_and_text(gtk.STOCK_PREFERENCES, _("Preferences"))
846
self.erase_mode = get_menu_item_with_stock_id_and_text(gtk.STOCK_CANCEL, _("Toggle Erase Mode"))
847
for item in (self.about, self.erase_mode, self.preferences): self.menu.insert(item, 0)
848
self.about.connect("activate", self.show_about_window)
849
self.erase_mode.connect("activate", lambda x: self.emit("toggle-erase-mode"))
851
button.connect("toggled", self.on_toggle)
852
self.preferences.connect("activate", lambda *args: self.preferences.toggle())
853
self.menu.connect("hide", self.on_hide)
855
def on_hide(self, *args):
856
self.button.set_active(False)
860
def on_toggle(self, widget):
861
alloc = self.get_allocation()
862
x, y = self.window.get_position()
863
func = lambda a:(x+alloc.x, y+alloc.y+alloc.height, True)
865
self.menu.popup(None, None, func, 0, 0)
867
def show_about_window(self, *etc):
868
aboutwindow = AboutDialog()
869
window = self.get_toplevel()
870
aboutwindow.set_transient_for(window)
872
aboutwindow.destroy()
873
self.preferences.toggle()
680
876
class AboutDialog(gtk.AboutDialog):
801
997
uri = unicode(uri)
802
998
isbookmarked = bookmarker.is_bookmarked(uri)
804
1000
bookmarker.unbookmark(uri)
806
1002
def do_delete(self, menuitem):
807
1003
for obj in self.subjects:
808
CLIENT.delete_events([obj.event.id])
1004
CLIENT.find_event_ids_for_template(
1005
Event.new_for_values(subject_uri=obj.uri),
1006
lambda ids: CLIENT.delete_events(map(int, ids)),
1007
timerange=DayParts.get_day_part_range_for_item(obj))
1009
def do_delete_object(self, obj):
1010
if obj is None: return
1011
CLIENT.find_event_ids_for_template(
1012
Event.new_for_values(subject_uri=obj.uri),
1013
lambda ids: CLIENT.delete_events(map(int, ids)))
810
1016
def do_delete_events_with_shared_uri(self, menuitem):
811
1017
for uri in map(lambda obj: obj.uri, self.subjects):
816
1022
def do_send_to(self, menuitem):
817
1023
launch_command("nautilus-sendto", map(lambda obj: obj.uri, self.subjects))
820
class ToolButton(gtk.ToolButton):
1025
def set_parent_window(self, parent):
1026
self.parent_window = parent
1028
class ContextMenuMolteplicity(gtk.Menu):
1029
subjects = []# A list of Zeitgeist event uris
1031
parent_window = None
1034
super(ContextMenuMolteplicity, self).__init__()
1036
"delete" : get_menu_item_with_stock_id_and_text(gtk.STOCK_DELETE, _("Delete items from Journal")),
1037
"info" : get_menu_item_with_stock_id_and_text(gtk.STOCK_INFO, _("Show all grouped items"))
1040
"delete" : self.do_delete,
1041
"info" : self.do_show_info
1043
names = ["delete", "info"]
1045
item = self.menuitems[name]
1047
item.connect("activate", callbacks[name])
1050
def do_popup(self, time, subjects):
1052
Call this method to popup the context menu
1054
:param time: the event time from the button press event
1055
:param subjects: a list of uris
1057
self.subjects = subjects
1058
if len(subjects) == 1:
1059
uri = subjects[0].uri
1061
self.popup(None, None, None, 3, time)
1063
def do_show_info(self, menuitem):
1065
self.do_show_molteplicity_list(self.subjects)
1067
def do_show_molteplicity_list(self, item_list):
1070
self.infowindow.destroy()
1071
self.infowindow = MolteplicityInformationContainer(parent=self.parent_window)
1072
self.infowindow.set_item_list(item_list)
1073
self.infowindow.show_all()
1075
def do_delete(self, menuitem):
1076
for obj_ in self.subjects:
1077
obj = obj_.content_object
1078
CLIENT.find_event_ids_for_template(
1079
Event.new_for_values(subject_uri=obj.uri),
1080
lambda ids: CLIENT.delete_events(map(int, ids)),
1081
timerange=DayParts.get_day_part_range_for_item(obj))
1083
def do_delete_list(self, list_):
1085
obj = obj_.content_object
1086
CLIENT.find_event_ids_for_template(
1087
Event.new_for_values(subject_uri=obj.uri),
1088
lambda ids: CLIENT.delete_events(map(int, ids)),
1089
timerange=DayParts.get_day_part_range_for_item(obj))
1092
def set_parent_window(self, parent):
1093
self.parent_window = parent
1096
class ToolButton(gtk.RadioToolButton):
821
1097
def __init__(self, *args, **kwargs):
822
1098
super(ToolButton, self).__init__(*args, **kwargs)
828
1104
def set_tooltip_text(self, text):
829
1105
gtk.Widget.set_tooltip_text(self, text)
1107
class InformationToolButton(gtk.ToolButton):
1108
def __init__(self, *args, **kwargs):
1109
super(InformationToolButton, self).__init__(*args, **kwargs)
1111
def set_label(self, text):
1112
super(InformationToolButton, self).set_label(text)
1113
self.set_tooltip_text(text)
1115
def set_tooltip_text(self, text):
1116
gtk.Widget.set_tooltip_text(self, text)
832
1119
class Toolbar(gtk.Toolbar):
1122
"previous" : (gobject.SIGNAL_RUN_FIRST,
1125
"jump-to-today" : (gobject.SIGNAL_RUN_FIRST,
1128
"next" : (gobject.SIGNAL_RUN_FIRST,
834
def get_toolbutton(path, label_string):
835
button = ToolButton()
1134
def get_toolbutton(path, label_string, radio=True):
1136
button = ToolButton()
1138
button = InformationToolButton()
836
1139
pixbuf = gtk.gdk.pixbuf_new_from_file(path)
837
1140
image = gtk.Image()
838
1141
image.set_from_pixbuf(pixbuf)
843
1146
def __init__(self):
844
1147
super(Toolbar, self).__init__()
845
#self.set_style(gtk.TOOLBAR_BOTH)
848
1149
self.search_button = sb = gtk.ToolButton(gtk.STOCK_FIND)
849
self.search_button.set_tooltip_text(_("Search"))
850
1150
self.search_dialog = sdialog = SearchBox
851
1151
self.search_dialog.search.connect("close", self.toggle_searchbox_visibility)
852
1152
self.search_button.connect("clicked", self.toggle_searchbox_visibility)
1153
#Previuos-day button
1154
self.previousd_button = pdb = gtk.ToolButton(gtk.STOCK_GO_BACK)
1155
self.previousd_button.connect("clicked", lambda x: self.emit("previous"))
1156
#Jump-to-today button
1157
self.home_button = hb = gtk.ToolButton(gtk.STOCK_HOME)
1158
self.home_button.connect("clicked", lambda x: self.emit("jump-to-today"))
1159
self.home_button.set_sensitive(False)
1160
#Next-day button button
1161
self.nextd_button = ndb = gtk.ToolButton(gtk.STOCK_GO_FORWARD)
1162
self.nextd_button.connect("clicked", lambda x: self.emit("next"))
1163
self.nextd_button.set_sensitive(False)
854
1165
sep1 = gtk.SeparatorToolItem()
855
sep2 = gtk.SeparatorToolItem()
856
for item in (sdialog, sb, sep1):
1166
sep2 = gtk.SeparatorToolItem()
1167
for item in (sdialog, sb, sep1, ndb, hb, pdb, sep2):
857
1168
self.insert(item, 0)
859
self.preference_button = gtk.ToolButton(gtk.STOCK_PREFERENCES)
860
self.preference_button.set_tooltip_text(_("Preferences"))
861
1170
separator = gtk.SeparatorToolItem()
862
1171
separator.set_expand(True)
863
separator.set_draw(False)
864
self.goto_today_button = today = gtk.ToolButton(gtk.STOCK_GOTO_LAST)
865
today.set_label( _("Go to Today"))
866
today.set_tooltip_text( _("Go to Today"))
867
self.throbber = Throbber()
868
for item in (separator, today, self.preference_button, self.throbber):
869
self.insert(item, -1)
872
self.throbber.image.animate_for_seconds(1)
1172
separator.set_draw(False)
1173
self.insert(separator, -1)
874
1175
def toggle_searchbox_visibility(self, w):
875
1176
result = self.search_dialog.toggle_visibility()
882
1183
self.insert(button, i)
886
class TagCloud(gtk.VBox):
888
"add-tag": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,)),
889
"remove-tag": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,)),
892
max_font_size = 11000.0
893
min_font_size = 6000.0
894
mid_font_size = 8500.0
895
_size_diff = max_font_size - min_font_size
897
class SelectTagMenu(gtk.Menu):
899
for item in self.get_children():
903
def set_tags(self, tags, callback):
906
item = gtk.MenuItem(label=tag)
908
item.connect("activate", callback, tag)
912
super(TagCloud, self).__init__()
914
self.label = gtk.Label()
915
self.pack_start(self.label, True, True)
916
self.label.set_line_wrap(True)
917
self.label.set_line_wrap_mode(pango.WRAP_WORD)
918
self.label.set_justify(gtk.JUSTIFY_CENTER)
919
self.label.connect( "size-allocate", self.size_allocate )
920
self.button_box = box = gtk.HBox()
921
self.entry_box = entry_box = gtk.HBox()
922
self.pack_end(self.button_box, False, False)
923
self.add_button = add = StockIconButton(gtk.STOCK_CANCEL)
924
self.finish_button = finish = StockIconButton(gtk.STOCK_OK)
925
self.remove_button = remove = StockIconButton(gtk.STOCK_REMOVE)
926
self.entry = entry = gtk.Entry()
927
box.pack_start(add, False, False)
928
box.pack_start(entry_box)
929
box.pack_end(remove, False, False)
930
entry_box.pack_start(entry)
931
entry_box.pack_end(finish, False, False)
932
finish.connect("clicked", self._add_tag)
933
entry.connect("activate", self._add_tag)
934
self.add_button.connect("clicked", self.toggle_tag_entry_box)
935
self.remove_button.connect("button-press-event", self.show_remove_menu)
937
entry_box.set_no_show_all(True)
939
self.tag_menu = tag_menu = self.SelectTagMenu()
940
tag_menu.attach_to_widget(remove, lambda *args:None)
942
self.toggle_tag_entry_box()
943
self.label.connect("activate-link", self.on_tag_activated)
945
def show_remove_menu(self, w, event):
946
if event.button == 1 and self.tag_dict:
947
self.tag_menu.set_tags(self.tag_dict.keys(), self.remove_tag)
948
self.tag_menu.popup(None, None, None, event.button, event.time)
950
def toggle_tag_entry_box(self, *args):
951
if self.entry_box.get_property("visible"):
952
self.entry_box.hide()
953
self.entry.set_text("")
954
self.add_button.set_stock(gtk.STOCK_ADD)
956
self.entry_box.show()
957
self.add_button.set_stock(gtk.STOCK_CANCEL)
959
def remove_tag(self, w, tag):
961
self.emit("remove-tag", tag)
963
def _add_tag(self, *args):
964
tag = self.entry.get_text()
966
self.emit("add-tag", tag)
967
self.toggle_tag_entry_box()
970
return self.label.get_text()
972
def set_text(self, text):
973
return self.label.set_text(text)
975
def set_markup(self, markup):
976
return self.label.set_markup(markup)
978
def size_allocate(self, label, alloc):
979
label.set_size_request(alloc.width - 2, -1 )
984
def make_tag(self, tag, value, min_value, max_value):
985
if (min_value+max_value+value)/3 == value:
986
size = self.mid_font_size
988
value = (value-min_value)/(max_value-min_value)
989
size = (value * self._size_diff) + self.min_font_size
990
return "<a href='" + tag + "'><span size='" + str(int(size)) + "'>" + tag + "</span></a>"
992
def on_tag_activated(self, widget, tag):
995
files = TRACKER.get_uris_for_tag(tag)
998
for obj in content_objects.ContentObject.instances:
1001
SearchBox.emit("search", results)
1002
thread = threading.Thread(target=_thread)
1006
def set_tags(self, tag_dict):
1007
self.tag_dict = tag_dict
1008
if not tag_dict: return self.set_text("")
1010
min_value = min(float(min(1, *tag_dict.values())), 1)
1011
max_value = max(float(max(1, *tag_dict.values())), 1)
1012
for tag in tag_dict.keys():
1013
text_lst.append(self.make_tag(tag, tag_dict[tag], min_value, max_value))
1014
self.set_markup(" ".join(text_lst))
1017
1186
class StockIconButton(gtk.Button):
1018
1187
def __init__(self, stock_id, label=None, size=gtk.ICON_SIZE_BUTTON):
1019
1188
super(StockIconButton, self).__init__()
1063
1239
self.label = gtk.Label()
1064
1240
self.pathlabel = gtk.Label()
1065
1241
self.pathlabel.modify_font(pango.FontDescription("Monospace 7"))
1242
self.box_label = gtk.EventBox()
1243
self.box_label.add(self.pathlabel)
1244
self.box_label.connect("button-press-event", self.on_path_label_clicked)
1245
self.box_label.connect("enter-notify-event", self.on_path_label_enter)
1246
self.box_label.connect("leave-notify-event", self.on_path_label_leave)
1247
self.box_label.connect("realize", self.on_realize_event)
1066
1248
labelvbox = gtk.VBox()
1067
1249
labelvbox.pack_start(self.label)
1068
labelvbox.pack_end(self.pathlabel)
1250
labelvbox.pack_end(self.box_label)
1069
1251
self.pack_start(labelvbox, True, True, 5)
1070
1252
self.box.set_shadow_type(gtk.SHADOW_NONE)
1071
1253
vbox.pack_start(self.box, True, True)
1086
1268
def set_content_object(self, obj):
1088
1270
self.set_displaytype(obj)
1089
self.label.set_markup("<span size='10336'>" + obj.text.replace("&", "&") + "</span>")
1090
self.pathlabel.set_markup("<span color='#979797'>" + obj.uri.replace("&", "&") + "</span>")
1271
text = get_text_or_uri(obj,molteplicity=self.is_molteplicity)
1272
self.label.set_markup("<span size='10336'>" + text + "</span>")
1273
path = obj.uri.replace("&", "&").replace("%20", " ")
1274
self.is_file = path.startswith("file://")
1276
self.textpath = os.path.dirname(path)[7:]
1278
if self.is_molteplicity:
1279
path = text.split(" ")[-1] #take only the uri
1280
self.textpath = path
1282
self.pathlabel.set_markup("<span color='#979797'>" + self.textpath + "</span>")
1284
def on_realize_event(self, parms):
1286
hand = gtk.gdk.Cursor(gtk.gdk.HAND2)
1287
self.box_label.window.set_cursor(hand)
1289
def on_path_label_clicked(self, wid, e):
1291
os.system('xdg-open "%s"' % self.textpath)
1293
def on_path_label_enter(self, wid, e):
1295
self.pathlabel.set_markup("<span color='#970000'><b>" + self.textpath+ "</b></span>")
1297
def on_path_label_leave(self, wid, e):
1299
self.pathlabel.set_markup("<span color='#999797'>" + self.textpath + "</span>")
1093
1301
class _RelatedPane(gtk.TreeView):
1187
1395
def __init__(self):
1188
1396
gtk.Toolbar.__init__(self)
1189
1397
self.set_icon_size(gtk.ICON_SIZE_SMALL_TOOLBAR)
1190
self.open_button = ob = ToolButton(gtk.STOCK_OPEN)
1398
self.open_button = ob = InformationToolButton(gtk.STOCK_OPEN)
1191
1399
ob.set_label(_("Launch this subject"))
1192
self.delete_button = del_ = ToolButton(gtk.STOCK_DELETE)
1400
self.delete_button = del_ = InformationToolButton(gtk.STOCK_DELETE)
1193
1401
del_.set_label(_("Delete this subject"))
1194
1402
self.pin_button = pin = Toolbar.get_toolbutton(
1195
1403
get_icon_path("hicolor/24x24/status/pin.png"),
1404
_("Add Pin"),radio=False)
1405
self.note_button = note = Toolbar.get_toolbutton(
1406
get_icon_path("hicolor/24x24/status/note.png"),
1407
_("Edit Note"),radio=False)
1197
1408
sep = gtk.SeparatorToolItem()
1198
for item in (del_, pin, sep, ob):
1409
for item in (del_, note, pin, sep, ob):
1200
1411
self.insert(item, 0)
1413
class _EditNoteWindow(gtk.Window):
1415
def __init__(self, parent, obj):
1416
gtk.Window.__init__(self)
1418
self.set_title(_("Edit Note"))
1419
self.set_transient_for(parent)
1420
self.set_destroy_with_parent(True)
1421
self.set_size_request(400, 400)
1422
self.connect("destroy", self.on_save_note)
1423
sw = gtk.ScrolledWindow()
1424
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
1425
textview = gtk.TextView()
1426
self.textbuffer = textview.get_buffer()
1427
self.textbuffer.set_text("" if self.obj.annotation is None else self.obj.annotation)
1432
def on_save_note(self, *arg):
1433
self.obj.annotation = self.textbuffer.get_text(self.textbuffer.get_start_iter (),
1434
self.textbuffer.get_end_iter())
1436
def __init__(self, parent=None):
1203
1437
super(gtk.Window, self).__init__()
1438
if parent: self.set_transient_for(parent)
1439
self.set_destroy_with_parent(True)
1440
self.set_size_request(400, 400)
1204
1441
self.connect("destroy", self.hide_on_delete)
1205
1442
box1 = gtk.VBox()
1206
1443
box2 = gtk.VBox()
1207
1444
vbox = gtk.VBox()
1208
1445
self.toolbar = self._InformationToolbar()
1209
1446
self.infopane = InformationBox()
1211
self.tag_cloud_frame = frame = gtk.Frame()
1212
frame.set_label( _("Tags"))
1213
self.tag_cloud = TagCloud()
1214
frame.add(self.tag_cloud)
1215
self.relatedpane = _RelatedPane()
1447
self.relatedpane = _RelatedPane("Used With")
1216
1448
scrolledwindow = gtk.ScrolledWindow()
1217
1449
box2.set_border_width(5)
1218
1450
box1.pack_start(self.toolbar, False, False)
1219
1451
box2.pack_start(self.infopane, False, False, 4)
1221
box2.pack_start(frame, False, False, 4)
1222
1452
scrolledwindow.set_shadow_type(gtk.SHADOW_IN)
1223
1453
scrolledwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
1224
1454
scrolledwindow.add(self.relatedpane)
1225
1455
vbox.pack_end(scrolledwindow, True, True)
1456
scrolledwindow.set_size_request(50, 100)
1226
1457
box2.pack_end(vbox, True, True, 10)
1458
box1.pack_start(box2, True, True)
1459
area = self.get_content_area()
1229
1461
def _launch(w):
1230
1462
self.obj.launch()
1231
1463
self.toolbar.open_button.connect("clicked", _launch)
1232
1464
self.toolbar.delete_button.connect("clicked", self.do_delete_events_with_shared_uri)
1233
1465
self.toolbar.pin_button.connect("clicked", self.do_toggle_bookmark)
1235
self.tag_cloud.connect("add-tag", self.on_add_tag)
1236
self.tag_cloud.connect("remove-tag", self.on_remove_tag)
1466
self.toolbar.note_button.connect("clicked", self.do_edit_note)
1237
1467
self.connect("size-allocate", self.size_allocate)
1238
1468
# Remove the close button
1239
1469
separator = gtk.SeparatorToolItem()
1248
1478
self.infopane.display_widget.show()
1250
1480
def do_toggle_bookmark(self, *args):
1251
if bookmarker.is_bookmarked(self.obj.uri):
1252
bookmarker.unbookmark(self.obj.uri)
1481
uri = unicode(self.obj.uri)
1482
if bookmarker.is_bookmarked(uri):
1483
bookmarker.unbookmark(uri)
1254
bookmarker.bookmark(self.obj.uri)
1256
def on_remove_tag(self, w, text):
1258
TRACKER.remove_tag_from_uri(text, self.obj.uri)
1259
self.set_tags(self.obj)
1261
def on_add_tag(self, w, text):
1263
TRACKER.add_tag_to_uri(text, self.obj.uri)
1264
self.set_tags(self.obj)
1485
bookmarker.bookmark(uri)
1487
def do_edit_note(self, *args):
1488
window = self._EditNoteWindow(self, self.obj)
1266
1490
def do_delete_events_with_shared_uri(self, *args):
1267
1491
CLIENT.find_event_ids_for_template(
1272
1496
def set_content_object(self, obj):
1498
if not isinstance(self.obj, GioFile):
1499
self.toolbar.note_button.set_sensitive(False)
1274
1500
def _callback(events):
1275
1501
self.relatedpane.set_model_from_list(events)
1276
1502
get_related_events_for_uri(obj.uri, _callback)
1277
1503
self.infopane.set_content_object(obj)
1504
self.set_title(_("More Information"))
1281
1506
self.emit("content-object-set")
1283
def set_tags(self, obj):
1285
tags = TRACKER.get_tag_dict_for_uri(obj.uri)
1286
self.tag_cloud.set_tags(tags)
1288
1508
def hide_on_delete(self, widget, *args):
1289
1509
super(InformationContainer, self).hide_on_delete(widget)
1512
class MolteplicityInformationContainer(gtk.Dialog):
1520
. . <--- Similar items (same basename)
1524
A pane which holds the information pane and grouped items pane
1526
def __init__(self, parent=None):
1527
super(gtk.Window, self).__init__()
1528
if parent: self.set_transient_for(parent)
1529
self.set_destroy_with_parent(True)
1530
self.set_size_request(400, 400)
1531
self.connect("destroy", self.hide_on_delete)
1534
self.infopane = InformationBox()
1535
self.infopane.is_molteplicity = True
1536
self.relatedpane = _RelatedPane("Grouped items")
1537
scrolledwindow = gtk.ScrolledWindow()
1538
box2.set_border_width(5)
1539
box2.pack_start(self.infopane, False, False, 4)
1540
scrolledwindow.set_shadow_type(gtk.SHADOW_IN)
1541
scrolledwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
1542
scrolledwindow.add(self.relatedpane)
1543
vbox.pack_end(scrolledwindow, True, True)
1544
scrolledwindow.set_size_request(50, 100)
1545
box2.pack_end(vbox, True, True, 10)
1546
area = self.get_content_area()
1548
self.connect("size-allocate", self.size_allocate)
1550
def size_allocate(self, widget, allocation):
1551
if allocation.height < 400:
1552
self.infopane.display_widget.hide()
1554
self.infopane.display_widget.show()
1556
def set_item_list(self, list_):
1557
self.infopane.set_content_object(list_[0].content_object)
1558
self.relatedpane.set_model_from_list(list_)
1559
self.set_title(_("More Information"))
1562
def hide_on_delete(self, widget, *args):
1563
super(MolteplicityInformationContainer, self).hide_on_delete(widget)
1293
1567
class PreferencesDialog(gtk.Dialog):
1363
1640
scroll_win.add(self.plug_tree)
1364
1641
plugbox.add(scroll_win)
1365
1642
notebook.append_page(plugbox, gtk.Label( _("Plugins")))
1645
vbox.set_border_width(5)
1646
hbox_tray = gtk.HBox()
1647
label = gtk.Label(_("Show icon in system tray"))
1648
self.check_button = gtk.CheckButton()
1649
self.check_button.set_active(settings.get("tray_icon", False))
1650
self.check_button.connect("toggled", self.on_check_toggled)
1651
hbox_tray.pack_start(self.check_button,False,False)
1652
hbox_tray.pack_start(label, False,False)
1653
vbox.pack_start(hbox_tray,False,False)
1654
notebook.append_page(vbox, gtk.Label( _("Configuration")))
1366
1656
self.connect("delete-event", lambda *args: (True, self.hide())[0])
1367
1657
close_button = gtk.Button(stock=gtk.STOCK_CLOSE)
1368
1658
self.add_action_widget(close_button, gtk.RESPONSE_DELETE_EVENT)
1369
1659
close_button.connect("clicked", lambda *args: (True, self.hide())[0])
1661
def on_check_toggled(self, button, *args):
1662
settings.set("tray_icon", button.get_active())
1665
#Code adapted from Emesene2 source. Get it at: https://github.com/emesene/emesene
1666
#Thanks Emesene's team
1667
class NiceBar(gtk.EventBox):
1668
'''A class used to display messages in a non-intrusive bar'''
1670
NORMALBACKGROUND = gtk.gdk.Color(65025,65025,46155)
1671
NORMALFOREGROUND = "black"
1672
ALERTBACKGROUND = gtk.gdk.Color(57600,23040,19712)
1673
ALERTFOREGROUND = NORMALFOREGROUND
1675
def __init__(self, default_background=ALERTBACKGROUND, default_foreground=None):
1677
gtk.EventBox.__init__(self)
1679
self.message_label = gtk.Label()
1680
self.message_label.set_line_wrap(True)
1681
self.message_label.set_ellipsize(pango.ELLIPSIZE_END)
1682
self.message_image = gtk.Image()
1683
self.message_hbox = gtk.HBox()
1684
self.message_hbox.set_border_width(2)
1686
if default_background is None:
1687
default_background = self.NORMALBACKGROUND
1688
if default_foreground is None:
1689
default_foreground = self.NORMALFOREGROUND
1691
self.default_back = default_background
1692
self.default_fore = default_foreground
1694
self.markup = '<span foreground="%s" font-weight="550" >%s</span>'
1695
self.modify_bg(gtk.STATE_NORMAL, default_background)
1697
self.message_hbox.pack_end(self.message_label)
1698
self.add(self.message_hbox)
1700
def new_message(self, message, stock=None, background=None, \
1702
''' Adds the actual message to the queue and show a new one '''
1704
if self.actual_message != '':
1705
self.messages_queue.append([self.actual_message, \
1706
self.actual_image, self.actual_background,
1707
self.actual_foreground])
1709
self.display_message(message, stock, background, foreground)
1711
def remove_message(self):
1712
''' Removes the actual message and display the next if any '''
1714
message, stock, back, fore = self.messages_queue.pop()
1715
self.display_message(message, stock, back, fore)
1719
def display_message(self, message, stock=None, background=None, \
1722
Displays a message without modifying the queue
1723
A background, text color and a stock image are optional
1726
self.actual_message = message
1727
self.actual_image = stock
1728
self.actual_background = background or self.default_back
1729
self.actual_foreground = foreground or self.default_fore
1731
if self.message_image.get_parent() is not None:
1732
self.message_hbox.remove(self.message_image)
1734
if stock is not None:
1735
self.message_image = gtk.image_new_from_stock(stock, \
1736
gtk.ICON_SIZE_LARGE_TOOLBAR)
1737
self.message_hbox.pack_start(self.message_image, False, False)
1739
self.modify_bg(gtk.STATE_NORMAL, self.actual_background)
1740
self.message_label.set_markup(self.markup % (self.actual_foreground,
1741
self.actual_message))
1744
def empty_queue(self):
1745
''' Delets all messages and hide the bar '''
1747
self.messages_queue = list()
1748
self.actual_message = ''
1749
self.actual_image = None
1750
self.actual_background = self.default_back
1751
self.actual_foreground = self.default_fore
1373
1755
if gst is not None:
1374
1756
VideoPreviewTooltip = VideoPreviewTooltip()
1757
AudioPreviewTooltip = AudioPreviewTooltip()
1376
1759
VideoPreviewTooltip = None
1760
AudioPreviewTooltip = None
1377
1761
StaticPreviewTooltip = StaticPreviewTooltip()
1378
1762
ContextMenu = ContextMenu()
1763
ContextMenuMolteplicity = ContextMenuMolteplicity()
1379
1764
SearchBox = SearchBox()