changeset ecbc91b24883 in /home/hg/repos/gajim details:http://hg.gajim.org/gajim?cmd=changeset;node=ecbc91b24883 description: plugin to add whiteboard feature. Fixes #2970
diffstat: plugins/whiteboard/__init__.py | 1 + plugins/whiteboard/brush_tool.png | 0 plugins/whiteboard/line_tool.png | 0 plugins/whiteboard/manifest.ini | 7 + plugins/whiteboard/oval_tool.png | 0 plugins/whiteboard/plugin.py | 453 ++++++++++++++++++++++++++++++++ plugins/whiteboard/whiteboard.png | 0 plugins/whiteboard/whiteboard_widget.py | 416 +++++++++++++++++++++++++++++ plugins/whiteboard/whiteboard_widget.ui | 324 ++++++++++++++++++++++ 9 files changed, 1201 insertions(+), 0 deletions(-) diffs (truncated from 1229 to 300 lines): diff -r a27c12733243 -r ecbc91b24883 plugins/whiteboard/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/whiteboard/__init__.py Mon Nov 01 14:30:23 2010 +0100 @@ -0,0 +1,1 @@ +from plugin import WhiteboardPlugin diff -r a27c12733243 -r ecbc91b24883 plugins/whiteboard/brush_tool.png Binary file plugins/whiteboard/brush_tool.png has changed diff -r a27c12733243 -r ecbc91b24883 plugins/whiteboard/line_tool.png Binary file plugins/whiteboard/line_tool.png has changed diff -r a27c12733243 -r ecbc91b24883 plugins/whiteboard/manifest.ini --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/whiteboard/manifest.ini Mon Nov 01 14:30:23 2010 +0100 @@ -0,0 +1,7 @@ +[info] +name: Whiteboard +short_name: whiteboard +version: 0.1 +description: Shows a whiteboard in chat. +authors = Yann Leboulanger <[email protected]> +homepage = www.gajim.org diff -r a27c12733243 -r ecbc91b24883 plugins/whiteboard/oval_tool.png Binary file plugins/whiteboard/oval_tool.png has changed diff -r a27c12733243 -r ecbc91b24883 plugins/whiteboard/plugin.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/whiteboard/plugin.py Mon Nov 01 14:30:23 2010 +0100 @@ -0,0 +1,453 @@ +## plugins/whiteboard/plugin.py +## +## Copyright (C) 2009 Jeff Ling <jeff.ummu AT gmail.com> +## Copyright (C) 2010 Yann Leboulanger <asterix AT lagaule.org> +## +## This file is part of Gajim. +## +## Gajim is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 3 only. +## +## Gajim is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Gajim. If not, see <http://www.gnu.org/licenses/>. +## + +''' +Whiteboard plugin. + +:author: Yann Leboulanger <[email protected]> +:since: 1st November 2010 +:copyright: Copyright (2010) Yann Leboulanger <[email protected]> +:license: GPL +''' + + +from common import helpers +from common import gajim +from plugins import GajimPlugin +from plugins.helpers import log_calls, log +import common.xmpp +import gtk +import chat_control +from common import ged +from common.jingle_session import JingleSession +from common.jingle_content import JingleContent +from common.jingle_transport import JingleTransport, TransportType +import dialogs +from whiteboard_widget import Whiteboard +from common import xmpp +from common import caps_cache + +NS_JINGLE_XHTML = 'urn:xmpp:tmp:jingle:apps:xhtml' +NS_JINGLE_SXE = 'urn:xmpp:tmp:jingle:transports:sxe' +NS_SXE = 'urn:xmpp:sxe:0' + +class WhiteboardPlugin(GajimPlugin): + @log_calls('WhiteboardPlugin') + def init(self): + self.config_dialog = None + self.events_handlers = { + 'jingle-request-received': (ged.GUI1, self._nec_jingle_received), + 'jingle-connected-received': (ged.GUI1, self._nec_jingle_connected), + 'jingle-disconnected-received': (ged.GUI1, + self._nec_jingle_disconnected), + 'raw-message-received': (ged.GUI1, self._nec_raw_message), + } + self.gui_extension_points = { + 'chat_control_base' : (self.connect_with_chat_control, + self.disconnect_from_chat_control), + 'chat_control_base_update_toolbar': (self.update_button_state, + None), + } + self.controls = [] + self.sid = None + + @log_calls('WhiteboardPlugin') + def _compute_caps_hash(self): + for a in gajim.connections: + gajim.caps_hash[a] = caps_cache.compute_caps_hash([ + gajim.gajim_identity], gajim.gajim_common_features + gajim.gajim_optional_features[a]) + # re-send presence with new hash + connected = gajim.connections[a].connected + if connected > 1 and gajim.SHOW_LIST[connected] != 'invisible': + gajim.connections[a].change_status(gajim.SHOW_LIST[connected], + gajim.connections[a].status) + + @log_calls('WhiteboardPlugin') + def activate(self): + if NS_JINGLE_SXE not in gajim.gajim_common_features: + gajim.gajim_common_features.append(NS_JINGLE_SXE) + if NS_SXE not in gajim.gajim_common_features: + gajim.gajim_common_features.append(NS_SXE) + self._compute_caps_hash() + + @log_calls('WhiteboardPlugin') + def deactivate(self): + if NS_JINGLE_SXE in gajim.gajim_common_features: + gajim.gajim_common_features.remove(NS_JINGLE_SXE) + if NS_SXE in gajim.gajim_common_features: + gajim.gajim_common_features.remove(NS_SXE) + self._compute_caps_hash() + + @log_calls('WhiteboardPlugin') + def connect_with_chat_control(self, control): + if isinstance(control, chat_control.ChatControl): + base = Base(self, control) + self.controls.append(base) + + @log_calls('WhiteboardPlugin') + def disconnect_from_chat_control(self, chat_control): + for base in self.controls: + base.disconnect_from_chat_control() + self.controls = [] + + @log_calls('WhiteboardPlugin') + def update_button_state(self, control): + for base in self.controls: + if base.chat_control == control: + if control.contact.supports(NS_JINGLE_SXE) and \ + control.contact.supports(NS_SXE): + base.button.set_sensitive(True) + else: + base.button.set_sensitive(False) + + @log_calls('WhiteboardPlugin') + def show_request_dialog(self, account, fjid, jid, sid, content_types): + def on_ok(): + session = gajim.connections[account].get_jingle_session(fjid, sid) + self.sid = session.sid + if not session.accepted: + session.approve_session() + for content in content_types: + session.approve_content(content) + for _jid in (fjid, jid): + ctrl = gajim.interface.msg_win_mgr.get_control(_jid, account) + if ctrl: + break + if not ctrl: + # create it + gajim.interface.new_chat_from_jid(account, jid) + ctrl = gajim.interface.msg_win_mgr.get_control(jid, account) + session = session.contents[('initiator', 'xhtml')] + ctrl.draw_whiteboard(session) + + def on_cancel(): + session = gajim.connections[account].get_jingle_session(fjid, sid) + session.decline_session() + + contact = gajim.contacts.get_first_contact_from_jid(account, jid) + if contact: + name = contact.get_shown_name() + else: + name = jid + pritext = _('Incoming Whiteboard') + sectext = _('%(name)s (%(jid)s) wants to start a whiteboard with ' + 'you. Do you want to accept?') % {'name': name, 'jid': jid} + dialog = dialogs.NonModalConfirmationDialog(pritext, sectext=sectext, + on_response_ok=on_ok, on_response_cancel=on_cancel) + dialog.popup() + + @log_calls('WhiteboardPlugin') + def _nec_jingle_received(self, obj): + content_types = set(c[0] for c in obj.contents) + if 'xhtml' not in content_types: + return + self.show_request_dialog(obj.conn.name, obj.fjid, obj.jid, obj.sid, + content_types) + + @log_calls('WhiteboardPlugin') + def _nec_jingle_connected(self, obj): + account = obj.conn.name + ctrl = (gajim.interface.msg_win_mgr.get_control(obj.fjid, account) + or gajim.interface.msg_win_mgr.get_control(obj.jid, account)) + if not ctrl: + return + session = gajim.connections[obj.conn.name].get_jingle_session(obj.fjid, + obj.sid) + + if ('initiator', 'xhtml') not in session.contents: + return + + session = session.contents[('initiator', 'xhtml')] + ctrl.draw_whiteboard(session) + + @log_calls('WhiteboardPlugin') + def _nec_jingle_disconnected(self, obj): + for base in self.controls: + if base.sid == obj.sid: + base.stop_whiteboard() + + @log_calls('WhiteboardPlugin') + def _nec_raw_message(self, obj): + if obj.stanza.getTag('sxe', namespace=NS_SXE): + account = obj.conn.name + + try: + fjid = helpers.get_full_jid_from_iq(obj.stanza) + except helpers.InvalidFormat: + obj.conn.dispatch('ERROR', (_('Invalid Jabber ID'), + _('A message from a non-valid JID arrived, it has been ' + 'ignored.'))) + + jid = gajim.get_jid_without_resource(fjid) + ctrl = (gajim.interface.msg_win_mgr.get_control(fjid, account) + or gajim.interface.msg_win_mgr.get_control(jid, account)) + if not ctrl: + return + sxe = obj.stanza.getTag('sxe') + if not sxe: + return + sid = sxe.getAttr('session') + if (jid, sid) not in obj.conn._sessions: + pass +# newjingle = JingleSession(con=self, weinitiate=False, jid=jid, sid=sid) +# self.addJingle(newjingle) + + # we already have such session in dispatcher... + session = obj.conn.get_jingle_session(fjid, sid) + cn = session.contents[('initiator', 'xhtml')] + error = obj.stanza.getTag('error') + if error: + action = 'iq-error' + else: + action = 'edit' + + cn.on_stanza(obj.stanza, sxe, error, action) +# def __editCB(self, stanza, content, error, action): + #new_tags = sxe.getTags('new') + #remove_tags = sxe.getTags('remove') + + #if new_tags is not None: + ## Process new elements + #for tag in new_tags: + #if tag.getAttr('type') == 'element': + #ctrl.whiteboard.recieve_element(tag) + #elif tag.getAttr('type') == 'attr': + #ctrl.whiteboard.recieve_attr(tag) + #ctrl.whiteboard.apply_new() + + #if remove_tags is not None: + ## Delete rids + #for tag in remove_tags: + #target = tag.getAttr('target') + #ctrl.whiteboard.image.del_rid(target) + + # Stop propagating this event, it's handled + return True + + +class Base(object): + def __init__(self, plugin, chat_control): + self.plugin = plugin + self.chat_control = chat_control + self.chat_control.draw_whiteboard = self.draw_whiteboard + self.contact = self.chat_control.contact + self.account = self.chat_control.account + self.jid = self.contact.get_full_jid() + self.create_buttons() + self.whiteboard = None + self.sid = None + + def create_buttons(self): + # create juick button + actions_hbox = self.chat_control.xml.get_object('actions_hbox') + self.button = gtk.ToggleButton(label=None, use_underline=True) + self.button.set_property('relief', gtk.RELIEF_NONE) + self.button.set_property('can-focus', False) + img = gtk.Image() + img_path = self.plugin.local_file_path('whiteboard.png') + pixbuf = gtk.gdk.pixbuf_new_from_file(img_path) + iconset = gtk.IconSet(pixbuf=pixbuf) + factory = gtk.IconFactory() + factory.add('whiteboard', iconset) + factory.add_default() + img.set_from_stock('whiteboard', gtk.ICON_SIZE_BUTTON) + self.button.set_image(img) + send_button = self.chat_control.xml.get_object('send_button') + send_button_pos = actions_hbox.child_get_property(send_button, + 'position') _______________________________________________ Commits mailing list [email protected] http://lists.gajim.org/cgi-bin/listinfo/commits
