Implement links. Require new gecko-embed
This commit is contained in:
parent
e5cd418e7e
commit
1676e5edcc
@ -3,5 +3,5 @@ DEPENDENCIES
|
|||||||
|
|
||||||
gecko-embed
|
gecko-embed
|
||||||
|
|
||||||
http://gnome.org/~marco/gecko-embed-0.1-4.i386.rpm
|
http://gnome.org/~marco/gecko-embed-0.1-5.i386.rpm
|
||||||
http://gnome.org/~marco/gecko-embed-0.1-4.src.rpm
|
http://gnome.org/~marco/gecko-embed-0.1-5.src.rpm
|
||||||
|
@ -23,8 +23,7 @@ class AddressToolbar(gtk.Toolbar):
|
|||||||
address_item.show()
|
address_item.show()
|
||||||
|
|
||||||
def __open_address_cb(self, address):
|
def __open_address_cb(self, address):
|
||||||
browser = BrowserActivity(address)
|
browser_shell.open_browser(address)
|
||||||
browser.activity_connect_to_shell()
|
|
||||||
|
|
||||||
class AddressItem(gtk.ToolItem):
|
class AddressItem(gtk.ToolItem):
|
||||||
def __init__(self, callback):
|
def __init__(self, callback):
|
||||||
@ -140,7 +139,7 @@ class NavigationToolbar(gtk.Toolbar):
|
|||||||
self._update_sensitivity()
|
self._update_sensitivity()
|
||||||
|
|
||||||
def __open_address_cb(self, address):
|
def __open_address_cb(self, address):
|
||||||
self.embed.load_url(address)
|
self.embed.load_address(address)
|
||||||
|
|
||||||
class BrowserActivity(activity.Activity):
|
class BrowserActivity(activity.Activity):
|
||||||
def __init__(self, uri):
|
def __init__(self, uri):
|
||||||
@ -159,7 +158,7 @@ class BrowserActivity(activity.Activity):
|
|||||||
vbox.pack_start(self.embed)
|
vbox.pack_start(self.embed)
|
||||||
|
|
||||||
self.embed.show()
|
self.embed.show()
|
||||||
self.embed.load_url(self.uri)
|
self.embed.load_address(self.uri)
|
||||||
|
|
||||||
nav_toolbar = NavigationToolbar(self.embed)
|
nav_toolbar = NavigationToolbar(self.embed)
|
||||||
vbox.pack_start(nav_toolbar, False)
|
vbox.pack_start(nav_toolbar, False)
|
||||||
@ -171,6 +170,9 @@ class BrowserActivity(activity.Activity):
|
|||||||
|
|
||||||
vbox.show()
|
vbox.show()
|
||||||
|
|
||||||
|
def get_embed(self):
|
||||||
|
return self.embed
|
||||||
|
|
||||||
def __title_cb(self, embed):
|
def __title_cb(self, embed):
|
||||||
self.activity_set_tab_text(embed.get_title())
|
self.activity_set_tab_text(embed.get_title())
|
||||||
|
|
||||||
@ -201,18 +203,44 @@ class WebActivity(activity.Activity):
|
|||||||
|
|
||||||
vbox.show()
|
vbox.show()
|
||||||
|
|
||||||
self.embed.load_url("http://www.google.com")
|
self.embed.load_address("http://www.google.com")
|
||||||
|
|
||||||
def __open_address(self, embed, uri, data=None):
|
def __open_address(self, embed, uri, data=None):
|
||||||
if uri.startswith("http://www.google.com"):
|
if uri.startswith("http://www.google.com"):
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
browser = BrowserActivity(uri)
|
browser_shell.open_browser(uri)
|
||||||
browser.activity_connect_to_shell()
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
class BrowserShell(dbus.service.Object):
|
||||||
|
def __init__(self, bus_name, object_path='/com/redhat/Sugar/Browser'):
|
||||||
|
dbus.service.Object.__init__(self, bus_name, object_path)
|
||||||
|
self.__browsers = []
|
||||||
|
|
||||||
|
@dbus.service.method('com.redhat.Sugar.BrowserShell')
|
||||||
|
def get_links(self):
|
||||||
|
links = []
|
||||||
|
for browser in self.__browsers:
|
||||||
|
embed = browser.get_embed()
|
||||||
|
link = {}
|
||||||
|
link['title'] = embed.get_title()
|
||||||
|
link['address'] = embed.get_address()
|
||||||
|
links.append(link)
|
||||||
|
return links
|
||||||
|
|
||||||
|
@dbus.service.method('com.redhat.Sugar.BrowserShell')
|
||||||
|
def open_browser(self, uri):
|
||||||
|
browser = BrowserActivity(uri)
|
||||||
|
self.__browsers.append(browser)
|
||||||
|
browser.activity_connect_to_shell()
|
||||||
|
|
||||||
web_activity = WebActivity()
|
web_activity = WebActivity()
|
||||||
web_activity.activity_connect_to_shell()
|
web_activity.activity_connect_to_shell()
|
||||||
|
|
||||||
|
session_bus = dbus.SessionBus()
|
||||||
|
bus_name = dbus.service.BusName('com.redhat.Sugar.Browser', bus=session_bus)
|
||||||
|
browser_shell = BrowserShell(bus_name)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
gtk.main()
|
gtk.main()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
42
chat/chat.py
42
chat/chat.py
@ -142,6 +142,13 @@ class ChatActivity(activity.Activity):
|
|||||||
self._buddy_list = BuddyList.BuddyList(self._realname)
|
self._buddy_list = BuddyList.BuddyList(self._realname)
|
||||||
self._buddy_list.add_buddy_listener(self._on_buddy_presence_event)
|
self._buddy_list.add_buddy_listener(self._on_buddy_presence_event)
|
||||||
|
|
||||||
|
bus = dbus.SessionBus()
|
||||||
|
proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser')
|
||||||
|
self.browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell')
|
||||||
|
|
||||||
|
def __link_clicked_cb(self, view, address):
|
||||||
|
self.browser_shell.open_browser(address)
|
||||||
|
|
||||||
def _create_chat(self):
|
def _create_chat(self):
|
||||||
chat_vbox = gtk.VBox()
|
chat_vbox = gtk.VBox()
|
||||||
chat_vbox.set_spacing(6)
|
chat_vbox.set_spacing(6)
|
||||||
@ -154,7 +161,8 @@ class ChatActivity(activity.Activity):
|
|||||||
sw = gtk.ScrolledWindow()
|
sw = gtk.ScrolledWindow()
|
||||||
sw.set_shadow_type(gtk.SHADOW_IN)
|
sw.set_shadow_type(gtk.SHADOW_IN)
|
||||||
sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
||||||
self._chat_view = gtk.TextView()
|
self._chat_view = richtext.RichTextView()
|
||||||
|
self._chat_view.connect("link-clicked", self.__link_clicked_cb)
|
||||||
sw.add(self._chat_view)
|
sw.add(self._chat_view)
|
||||||
self._chat_view.show()
|
self._chat_view.show()
|
||||||
chat_vbox.pack_start(sw)
|
chat_vbox.pack_start(sw)
|
||||||
@ -164,7 +172,7 @@ class ChatActivity(activity.Activity):
|
|||||||
chat_view_sw = gtk.ScrolledWindow()
|
chat_view_sw = gtk.ScrolledWindow()
|
||||||
chat_view_sw.set_shadow_type(gtk.SHADOW_IN)
|
chat_view_sw.set_shadow_type(gtk.SHADOW_IN)
|
||||||
chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||||
self._editor = gtk.TextView(rich_buf)
|
self._editor = richtext.RichTextView(rich_buf)
|
||||||
self._editor.connect("key-press-event", self.__key_press_event_cb)
|
self._editor.connect("key-press-event", self.__key_press_event_cb)
|
||||||
self._editor.set_size_request(-1, 50)
|
self._editor.set_size_request(-1, 50)
|
||||||
chat_view_sw.add(self._editor)
|
chat_view_sw.add(self._editor)
|
||||||
@ -229,6 +237,34 @@ class ChatActivity(activity.Activity):
|
|||||||
|
|
||||||
return vbox
|
return vbox
|
||||||
|
|
||||||
|
def _create_toolbar(self, rich_buf):
|
||||||
|
toolbar = richtext.RichTextToolbar(rich_buf)
|
||||||
|
|
||||||
|
item = gtk.MenuToolButton(None, "Links")
|
||||||
|
item.set_menu(gtk.Menu())
|
||||||
|
item.connect("show-menu", self.__show_link_menu_cb)
|
||||||
|
toolbar.insert(item, -1)
|
||||||
|
item.show()
|
||||||
|
|
||||||
|
return toolbar
|
||||||
|
|
||||||
|
def __link_activate_cb(self, item, link):
|
||||||
|
buf = self._editor.get_buffer()
|
||||||
|
buf.append_link(link['title'], link['address'])
|
||||||
|
|
||||||
|
def __show_link_menu_cb(self, button):
|
||||||
|
menu = gtk.Menu()
|
||||||
|
|
||||||
|
links = self.browser_shell.get_links()
|
||||||
|
|
||||||
|
for link in links:
|
||||||
|
item = gtk.MenuItem(link['title'], False)
|
||||||
|
item.connect("activate", self.__link_activate_cb, link)
|
||||||
|
menu.append(item)
|
||||||
|
item.show()
|
||||||
|
|
||||||
|
button.set_menu(menu)
|
||||||
|
|
||||||
def _ui_setup(self, plug):
|
def _ui_setup(self, plug):
|
||||||
vbox = gtk.VBox(False, 6)
|
vbox = gtk.VBox(False, 6)
|
||||||
|
|
||||||
@ -246,7 +282,7 @@ class ChatActivity(activity.Activity):
|
|||||||
vbox.pack_start(hbox)
|
vbox.pack_start(hbox)
|
||||||
hbox.show()
|
hbox.show()
|
||||||
|
|
||||||
toolbar = richtext.RichTextToolbar(rich_buf)
|
toolbar = self._create_toolbar(rich_buf)
|
||||||
vbox.pack_start(toolbar, False);
|
vbox.pack_start(toolbar, False);
|
||||||
toolbar.show()
|
toolbar.show()
|
||||||
|
|
||||||
|
@ -1,11 +1,43 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import pygtk
|
import pygtk
|
||||||
|
import gobject
|
||||||
pygtk.require('2.0')
|
pygtk.require('2.0')
|
||||||
import gtk
|
import gtk
|
||||||
import pango
|
import pango
|
||||||
import xml.sax
|
import xml.sax
|
||||||
|
|
||||||
|
class RichTextView(gtk.TextView):
|
||||||
|
|
||||||
|
__gsignals__ = {
|
||||||
|
'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||||
|
([gobject.TYPE_STRING]))
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, rich_buf = None):
|
||||||
|
gtk.TextView.__init__(self, rich_buf)
|
||||||
|
# self.connect("motion-notify-event", self.__motion_notify_cb)
|
||||||
|
self.connect("button-press-event", self.__button_press_cb)
|
||||||
|
|
||||||
|
# def __motion_notify_cb(self, widget, event):
|
||||||
|
# if event.is_hint:
|
||||||
|
# [x, y, state] = event.window.get_pointer();
|
||||||
|
|
||||||
|
def __button_press_cb(self, widget, event):
|
||||||
|
buf = self.get_buffer()
|
||||||
|
it = self.get_iter_at_location(int(event.x), int(event.y))
|
||||||
|
if it.has_tag(buf.get_tag_table().lookup("link")):
|
||||||
|
address_tag = buf.get_tag_table().lookup("link-address")
|
||||||
|
|
||||||
|
address_end = it.copy()
|
||||||
|
address_end.backward_to_tag_toggle(address_tag)
|
||||||
|
|
||||||
|
address_start = address_end.copy()
|
||||||
|
address_start.backward_to_tag_toggle(address_tag)
|
||||||
|
|
||||||
|
address = buf.get_text(address_start, address_end)
|
||||||
|
self.emit("link-clicked", address)
|
||||||
|
|
||||||
class RichTextBuffer(gtk.TextBuffer):
|
class RichTextBuffer(gtk.TextBuffer):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
gtk.TextBuffer.__init__(self)
|
gtk.TextBuffer.__init__(self)
|
||||||
@ -15,6 +47,11 @@ class RichTextBuffer(gtk.TextBuffer):
|
|||||||
self.__create_tags()
|
self.__create_tags()
|
||||||
self.active_tags = []
|
self.active_tags = []
|
||||||
|
|
||||||
|
def append_link(self, title, address):
|
||||||
|
it = self.get_iter_at_mark(self.get_insert())
|
||||||
|
self.insert_with_tags_by_name(it, address, "link", "link-address")
|
||||||
|
self.insert_with_tags_by_name(it, title, "link")
|
||||||
|
|
||||||
def apply_tag(self, tag_name):
|
def apply_tag(self, tag_name):
|
||||||
self.active_tags.append(tag_name)
|
self.active_tags.append(tag_name)
|
||||||
|
|
||||||
@ -32,6 +69,13 @@ class RichTextBuffer(gtk.TextBuffer):
|
|||||||
self.remove_tag_by_name(tag_name, start, end)
|
self.remove_tag_by_name(tag_name, start, end)
|
||||||
|
|
||||||
def __create_tags(self):
|
def __create_tags(self):
|
||||||
|
tag = self.create_tag("link")
|
||||||
|
tag.set_property("underline", pango.UNDERLINE_SINGLE)
|
||||||
|
tag.set_property("foreground", "#0000FF")
|
||||||
|
|
||||||
|
tag = self.create_tag("link-address")
|
||||||
|
tag.set_property("invisible", True)
|
||||||
|
|
||||||
tag = self.create_tag("bold")
|
tag = self.create_tag("bold")
|
||||||
tag.set_property("weight", pango.WEIGHT_BOLD)
|
tag.set_property("weight", pango.WEIGHT_BOLD)
|
||||||
|
|
||||||
@ -137,6 +181,8 @@ class RichTextHandler(xml.sax.handler.ContentHandler):
|
|||||||
if name != "richtext":
|
if name != "richtext":
|
||||||
tag = self.serializer.deserialize_element(name, attrs)
|
tag = self.serializer.deserialize_element(name, attrs)
|
||||||
self.tags.append(tag)
|
self.tags.append(tag)
|
||||||
|
if name == "link":
|
||||||
|
self.href = attrs['href']
|
||||||
|
|
||||||
def characters(self, data):
|
def characters(self, data):
|
||||||
start_it = it = self.buf.get_end_iter()
|
start_it = it = self.buf.get_end_iter()
|
||||||
@ -146,6 +192,9 @@ class RichTextHandler(xml.sax.handler.ContentHandler):
|
|||||||
|
|
||||||
for tag in self.tags:
|
for tag in self.tags:
|
||||||
self.buf.apply_tag_by_name(tag, start_it, it)
|
self.buf.apply_tag_by_name(tag, start_it, it)
|
||||||
|
if tag == "link":
|
||||||
|
self.buf.insert_with_tags_by_name(start_it, self.href,
|
||||||
|
"link", "link-address")
|
||||||
|
|
||||||
def endElement(self, name):
|
def endElement(self, name):
|
||||||
if name != "richtext":
|
if name != "richtext":
|
||||||
@ -162,15 +211,25 @@ class RichTextSerializer:
|
|||||||
return "italic"
|
return "italic"
|
||||||
elif el_name == "font":
|
elif el_name == "font":
|
||||||
return "font-size-" + attributes["size"]
|
return "font-size-" + attributes["size"]
|
||||||
|
elif el_name == "link":
|
||||||
|
return "link"
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def serialize_tag_start(self, tag):
|
def serialize_tag_start(self, tag, it):
|
||||||
name = tag.get_property("name")
|
name = tag.get_property("name")
|
||||||
if name == "bold":
|
if name == "bold":
|
||||||
return "<bold>"
|
return "<bold>"
|
||||||
elif name == "italic":
|
elif name == "italic":
|
||||||
return "<italic>"
|
return "<italic>"
|
||||||
|
elif name == "link":
|
||||||
|
address_tag = self.buf.get_tag_table().lookup("link-address")
|
||||||
|
end = it.copy()
|
||||||
|
end.forward_to_tag_toggle(address_tag)
|
||||||
|
address = self.buf.get_text(it, end)
|
||||||
|
return "<link " + "href=\"" + address + "\">"
|
||||||
|
elif name == "link-address":
|
||||||
|
return ""
|
||||||
elif name.startswith("font-size-"):
|
elif name.startswith("font-size-"):
|
||||||
tag_name = name.replace("font-size-", "", 1)
|
tag_name = name.replace("font-size-", "", 1)
|
||||||
return "<font size=\"" + tag_name + "\">"
|
return "<font size=\"" + tag_name + "\">"
|
||||||
@ -179,16 +238,22 @@ class RichTextSerializer:
|
|||||||
|
|
||||||
def serialize_tag_end(self, tag):
|
def serialize_tag_end(self, tag):
|
||||||
name = tag.get_property("name")
|
name = tag.get_property("name")
|
||||||
if tag.get_property("name") == "bold":
|
if name == "bold":
|
||||||
return "</bold>"
|
return "</bold>"
|
||||||
elif tag.get_property("name") == "italic":
|
elif name == "italic":
|
||||||
return "</italic>"
|
return "</italic>"
|
||||||
|
elif name == "link":
|
||||||
|
return "</link>"
|
||||||
|
elif name == "link-address":
|
||||||
|
return ""
|
||||||
elif name.startswith("font-size-"):
|
elif name.startswith("font-size-"):
|
||||||
return "</font>"
|
return "</font>"
|
||||||
else:
|
else:
|
||||||
return "</unknown>"
|
return "</unknown>"
|
||||||
|
|
||||||
def serialize(self, buf):
|
def serialize(self, buf):
|
||||||
|
self.buf = buf
|
||||||
|
|
||||||
xml = "<richtext>"
|
xml = "<richtext>"
|
||||||
|
|
||||||
next_it = buf.get_start_iter()
|
next_it = buf.get_start_iter()
|
||||||
@ -207,11 +272,15 @@ class RichTextSerializer:
|
|||||||
break
|
break
|
||||||
tags_to_reopen.append(open_tag)
|
tags_to_reopen.append(open_tag)
|
||||||
|
|
||||||
for tag in tags_to_reopen + it.get_toggled_tags(True):
|
for tag in tags_to_reopen:
|
||||||
self._open_tags.append(tag)
|
self._open_tags.append(tag)
|
||||||
xml += self.serialize_tag_start(tag)
|
xml += self.serialize_tag_start(tag, it)
|
||||||
|
|
||||||
xml += buf.get_text(it, next_it)
|
for tag in it.get_toggled_tags(True):
|
||||||
|
self._open_tags.append(tag)
|
||||||
|
xml += self.serialize_tag_start(tag, it)
|
||||||
|
|
||||||
|
xml += buf.get_text(it, next_it, False)
|
||||||
|
|
||||||
if next_it.is_end():
|
if next_it.is_end():
|
||||||
self._open_tags.reverse()
|
self._open_tags.reverse()
|
||||||
@ -233,6 +302,9 @@ def test_quit(window, rich_buf):
|
|||||||
print RichTextSerializer().serialize(rich_buf)
|
print RichTextSerializer().serialize(rich_buf)
|
||||||
gtk.main_quit()
|
gtk.main_quit()
|
||||||
|
|
||||||
|
def link_clicked(view, address):
|
||||||
|
print "Link clicked " + address
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
window = gtk.Window()
|
window = gtk.Window()
|
||||||
window.set_default_size(400, 300)
|
window.set_default_size(400, 300)
|
||||||
@ -246,12 +318,13 @@ if __name__ == "__main__":
|
|||||||
xml_string += "<bold><italic>Test</italic>one</bold>\n"
|
xml_string += "<bold><italic>Test</italic>one</bold>\n"
|
||||||
xml_string += "<bold><italic>Test two</italic></bold>"
|
xml_string += "<bold><italic>Test two</italic></bold>"
|
||||||
xml_string += "<font size=\"xx-small\">Test three</font>"
|
xml_string += "<font size=\"xx-small\">Test three</font>"
|
||||||
|
xml_string += "<link href=\"http://www.gnome.org\">Test link</link>"
|
||||||
xml_string += "</richtext>"
|
xml_string += "</richtext>"
|
||||||
|
|
||||||
RichTextSerializer().deserialize(xml_string, rich_buf)
|
RichTextSerializer().deserialize(xml_string, rich_buf)
|
||||||
|
|
||||||
view = gtk.TextView(rich_buf)
|
view = RichTextView(rich_buf)
|
||||||
|
view.connect("link-clicked", link_clicked)
|
||||||
vbox.pack_start(view)
|
vbox.pack_start(view)
|
||||||
view.show()
|
view.show()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user