From 2c869945f0e7dec9cd49ac0f0a20cad7b6c1d932 Mon Sep 17 00:00:00 2001 From: wurstsalat Date: Tue, 26 Oct 2021 22:08:31 +0200 Subject: [PATCH] [whiteboard] Remove plugin (may be ported later) --- whiteboard/__init__.py | 1 - whiteboard/brush_tool.png | Bin 806 -> 0 bytes whiteboard/line_tool.png | Bin 1054 -> 0 bytes whiteboard/manifest.ini | 9 - whiteboard/oval_tool.png | Bin 989 -> 0 bytes whiteboard/plugin.py | 494 -------------------------------- whiteboard/whiteboard.png | Bin 1550 -> 0 bytes whiteboard/whiteboard_widget.py | 454 ----------------------------- whiteboard/whiteboard_widget.ui | 197 ------------- 9 files changed, 1155 deletions(-) delete mode 100644 whiteboard/__init__.py delete mode 100644 whiteboard/brush_tool.png delete mode 100644 whiteboard/line_tool.png delete mode 100644 whiteboard/manifest.ini delete mode 100644 whiteboard/oval_tool.png delete mode 100644 whiteboard/plugin.py delete mode 100644 whiteboard/whiteboard.png delete mode 100644 whiteboard/whiteboard_widget.py delete mode 100644 whiteboard/whiteboard_widget.ui diff --git a/whiteboard/__init__.py b/whiteboard/__init__.py deleted file mode 100644 index e6ad0ee..0000000 --- a/whiteboard/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .plugin import WhiteboardPlugin diff --git a/whiteboard/brush_tool.png b/whiteboard/brush_tool.png deleted file mode 100644 index 266c321718d6e7a72245367223e7892de1fc9faa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 806 zcmV+>1KIqEP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00^)E00^)FDVDUh00007bV*G`2igk( z4Hhd1;T%~200O2-L_t(Y$F-KfZxUe`$G^{U?_I4xfS5o?3LYfYeM(V;qVt}L#&=ktAgS*#3K(BWPhm|*Za>+gS z+~<9s=Y76;iF1x+tgSmMa9)uhIe@oc+tc^rvS6}E*j!^++ivQ7!ZKizgOIo-8(_9G zBqCcd&N)PZ@Zg4w==(EMKh5f)U69?)SY~JivfA9djRhaRw(g->Fy|bzDzW~22d_ST zGxgov`~XQ^H3wdV%>x0z%eyO(F+lp+ZBzgE&oAule)4{nZLQ0AbAQ!#4>{-NJ)F_2 zS?SWnc(e8p=UnIbN7(eUMxy~mQKrB^AfO)`n{#Ma|9HROr*5|kMNy_;%M34>9RT3t zmmgHFHsIg`IK?5ZU%QGY@z`P+F0y_$6jVU90N@Jlub79BF$2dGZL@t*@KA+bGr&1~FQ);39H2$&aYBrlxEEdsfwEzGc8yh;m z$K%l-nt38U&YCV-CX=B~r$hC69RT2TIuVb@b+Ls)0dBWje`vztFrv{Y_V)H{YbyXS z#-M2$dc7WEv6#WXySocTQQ&g9KtvFTXj(!u*rdc(CP@-pE*Bz^h#_u&e;=YKVl*1T z>-8d$Nc>iKhrHq)$07*qoM6N<$g0%!=)&Kwi diff --git a/whiteboard/line_tool.png b/whiteboard/line_tool.png deleted file mode 100644 index 151f584849108687627deacb1ecff87e29008c92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1054 zcmV+(1mXLMP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00^)E00^)FDVDUh00007bV*G`2igk( z4H7GCjoDoQ00W*$L_t(Y$F!13>!|Fb)r?5?YcyO;zbh=&#;IoK7gx8lKL z4nlLyzf;v1BuEmW7(xx`!9$ONLNp+F2o(x7np1-(3u-`7YghAc8?#Gxva>VuJj9Jz zXY;3R^58MU@OYnjzu)h@86lJ&)4j)e%Jb&Rl z9qp}5y!KoK%f31#PBo+n8=lBC$Ie~8E{q^{dN~|^!NR1v2k43OgKL1j@l==@aNZ*0C`^1+IkZ3kp6U96&*tVH4IIi_ByEMO zH{A$UEEdJ;>M8(22wuK;k>%UBA08aaTR5g*=2jH*eP67ttx>5|@H`LC^Ds@5OeXVi z;85Pe)&;YRyAkZCKeoh1smhHz+x%K6qRJ|cR^zEm9NkVlc+p&)dV^%=IX?I{ip?$k zE`I!ThkM0c?iM`?TUCCzSLW88b>_bL8COj*I5>E6aDILsCzWMp?z;%~=IEFRft_8S zt(_YG-v*_fDzSKia=Co+kQV;B%j;L(ieQ5mOc4qd{ssTmJi@SXSj`U*s*a*4Cj)0c zoMH6J+Y#*Du>mnLbDgpA2|6FMsI_V&ZI!Op6t$|!b~(vbX@_45MNC7*w(aA=>FH_4 z$HybswQEyibaWB`OM{-S1fJ*N`#!t7I<9MwwBX5Bm8aV*Y}@AhMdNs|88$Wb9|oZ7 zdVRAK1Odfjk&TTFVzC&OW$lkKjAK9{L{n^Xad0ZWAx~?OoWOH*90LO8VQWAzCVHo1NE|z7{($dlhc6WD^ z%jF&jtAq849mgREf`%T3A)e=vNF)$Kpa>xlVsE~sr6t)sx_e`qb;B^IR;$G0abmF; zwryis7N%)p7zUcA;rl+RREoa7J_LZOssuq0!E(8rC=?2Z7S+he2pt_A#N%=5zbaD7 z$bCJ;g+gI3q|LBwHhUxnkWQ!R@9*Ew*KvJ$c^Lu7CV3IHTJ6{qXkcJ~&dyE%!Z2)D zUH$WP@VdUf-V_ukJ -homepage = https://dev.gajim.org/gajim/gajim-plugins/wikis/WhiteboardPlugin -min_gajim_version: 1.4.0-dev1 -max_gajim_version: 1.4.90 diff --git a/whiteboard/oval_tool.png b/whiteboard/oval_tool.png deleted file mode 100644 index efd6f0ca18d8fca110d7290a2f71b0bd17ff40a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 989 zcmV<310wv1P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00^)E00^)FDVDUh00007bV*G`2igk( z4HY&($|FMn00Uh~L_t(Y$F-JEXd`75z<+NtlSy|IHZ4MHP%8A~VJ+QTS6X_gprFSd zgcWbydaK%9uqe$Iu`a6+4<0J7mJOCEhVhh`oDMxyOL^3v(dCo+R4m(9=0i+ z%uJgo{opb1-Z$^}-uu4yW<)8)S*)qcG2&fOq7hj5a_2~|pB2p1g)2h_L+?NE*tD~N zMI*w*Q>G8rc7`I-R^63SqHDr)PnwK;_)m}>Iq3}B1qHnt1PjeD45XBjHutOJ;M5E0 z@G}g8DWxO~1~B~c2QvHdcR_Y_@ybU;opZs!R@iAEfLET5VRFDbFI{S8IIlio|Cl#-U=?SY16Y#0VgDYmz_0f@)rjE#+XHm|L%$@22D7dS95 zz{tpm5u~;Ou zRH;;o&CSh@z=c9VT-PN`^7(u)&@c=djmD{f$;nCj`}+ZKU63~mcKX}jjJ(Z%RsjA5a^oXOoDVmr00000 LNkvXXu0mjf&koYC diff --git a/whiteboard/plugin.py b/whiteboard/plugin.py deleted file mode 100644 index ae7fe42..0000000 --- a/whiteboard/plugin.py +++ /dev/null @@ -1,494 +0,0 @@ -# Copyright (C) 2009 Jeff Ling -# Copyright (C) 2010 Yann Leboulanger -# -# This file is part of the Whiteboard Plugin. -# -# 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 . -# - -''' -Whiteboard plugin. - -:author: Yann Leboulanger -:since: 1st November 2010 -:copyright: Copyright (2010) Yann Leboulanger -:license: GPL -''' - -from urllib.parse import quote -from gi.repository import Gio -from gi.repository import GLib -from nbxmpp import Message - -from gajim import common - -from gajim.common import app -from gajim.common import ged -from gajim.common import helpers -from gajim.common.jingle_session import JingleSession -from gajim.common.jingle_content import JingleContent -from gajim.common.jingle_transport import JingleTransport -from gajim.common.jingle_transport import TransportType - -from gajim.gui.dialogs import DialogButton -from gajim.gui.dialogs import ConfirmationDialog - -from gajim.plugins import GajimPlugin -from gajim.plugins.gajimplugin import GajimPluginException -from gajim.plugins.helpers import log_calls -from gajim.plugins.helpers import log -from gajim.plugins.plugins_i18n import _ - -from whiteboard.whiteboard_widget import Whiteboard -from whiteboard.whiteboard_widget import HAS_GOOCANVAS - -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': (self.connect_with_chat_control, - self.disconnect_from_chat_control), - 'chat_control_base_update_toolbar': (self.update_button_state, - None), - 'update_caps': (self._update_caps, None), - } - self.controls = [] - self.sid = None - self.announce_caps = True - - @log_calls('WhiteboardPlugin') - def _update_caps(self, _account, features): - if not self.announce_caps: - return - - features.append(NS_JINGLE_SXE) - features.append(NS_SXE) - - @log_calls('WhiteboardPlugin') - def activate(self): - if not HAS_GOOCANVAS: - raise GajimPluginException('python-pygoocanvas is missing!') - - self.announce_caps = True - for con in app.connections.values(): - con.get_module('Caps').update_caps() - - @log_calls('WhiteboardPlugin') - def deactivate(self): - self.announce_caps = False - for con in app.connections.values(): - con.get_module('Caps').update_caps() - - @log_calls('WhiteboardPlugin') - def connect_with_chat_control(self, control): - for base in self.controls: - if base.chat_control == control: - self.controls.remove(base) - - if control.is_chat: - base = Base(self, control) - self.controls.append(base) - self.update_button_state(control) - - @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.enable_action(True) - else: - base.enable_action(False) - - @log_calls('WhiteboardPlugin') - def show_request_dialog(self, account, fjid, jid, sid, content_types): - def _on_accept(): - session = app.connections[account].get_module( - 'Jingle').get_jingle_session(fjid, sid) - self.sid = session.sid - if not session.accepted: - session.approve_session() - for content in content_types: - session.approve_content('xhtml') - for _jid in (fjid, jid): - ctrl = app.window.get_control(account, _jid) - if ctrl: - break - if not ctrl: - # Create it - app.interface.start_chat_from_jid(account, jid) - ctrl = app.window.get_control(account, jid) - session = session.contents[('initiator', 'xhtml')] - ctrl.draw_whiteboard(session) - - def _on_decline(): - session = app.connections[account].get_module( - 'Jingle').get_jingle_session(fjid, sid) - session.decline_session() - - client = app.get_client(account) - contact = client.get_module('Contacts').get_contact(jid) - - ConfirmationDialog( - _('Incoming Whiteboard'), - _('Incoming Whiteboard Request'), - _('%(name)s (%(jid)s) wants to start a whiteboard with ' - 'you.') % {'name': contact.name, 'jid': jid}, - [DialogButton.make('Cancel', - text=_('_Decline'), - callback=_on_decline), - DialogButton.make('OK', - text=_('_Accept'), - callback=_on_accept)], - transient_for=app.window).show() - - @log_calls('WhiteboardPlugin') - def _nec_jingle_received(self, obj): - if not HAS_GOOCANVAS: - return - content_types = obj.contents.media - if content_types != 'xhtml': - 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): - if not HAS_GOOCANVAS: - return - account = obj.conn.name - ctrl = app.window.get_control(account, obj.jid) - if not ctrl: - return - session = app.connections[obj.conn.name].get_module( - 'Jingle').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(reason=obj.reason) - - @log_calls('WhiteboardPlugin') - def _nec_raw_message(self, obj): - if not HAS_GOOCANVAS: - return - 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 XMPP Address'), - _('A message from a non-valid XMPP address ' - 'arrived. It has been ignored.'))) - - jid = app.get_jid_without_resource(fjid) - ctrl = app.window.get_control(account, jid) - if not ctrl: - return - sxe = obj.stanza.getTag('sxe') - if not sxe: - return - sid = sxe.getAttr('session') - if (jid, sid) not in obj.conn.get_module('Jingle')._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_module('Jingle').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.jid - - self.add_action() - self.whiteboard = None - self.sid = None - - def add_action(self): - action_name = 'toggle-whiteboard-' + self.chat_control.control_id - act = Gio.SimpleAction.new_stateful( - action_name, None, GLib.Variant.new_boolean(False)) - act.connect('change-state', self.on_whiteboard_button_toggled) - app.window.add_action(act) - - self.chat_control.control_menu.append( - 'WhiteBoard', 'win.' + action_name) - - def enable_action(self, state): - action_name = 'toggle-whiteboard-' + self.chat_control.control_id - app.window.lookup_action(action_name).set_enabled(state) - - def draw_whiteboard(self, content): - hbox = self.chat_control.xml.get_object('chat_control_hbox') - if len(hbox.get_children()) == 1: - self.whiteboard = Whiteboard(self.account, self.contact, content, - self.plugin) - # Set minimum size - self.whiteboard.hbox.set_size_request(300, 0) - hbox.pack_start(self.whiteboard.hbox, False, False, 0) - self.whiteboard.hbox.show_all() - self.enable_action(True) - content.control = self - self.sid = content.session.sid - - def on_whiteboard_button_toggled(self, action, param): - """ - Popup whiteboard - """ - action.set_state(param) - state = param.get_boolean() - if state: - if not self.whiteboard: - self.start_whiteboard() - else: - self.stop_whiteboard() - - def start_whiteboard(self): - conn = app.connections[self.chat_control.account] - jingle = JingleSession(conn, weinitiate=True, jid=self.jid) - self.sid = jingle.sid - conn.get_module('Jingle')._sessions[jingle.sid] = jingle - content = JingleWhiteboard(jingle) - content.control = self - jingle.add_content('xhtml', content) - jingle.start_session() - - def stop_whiteboard(self, reason=None): - conn = app.connections[self.chat_control.account] - self.sid = None - session = conn.get_module('Jingle').get_jingle_session(self.jid, - media='xhtml') - if session: - session.end_session() - self.enable_action(False) - if reason: - txt = _('Whiteboard stopped: %(reason)s') % {'reason': reason} - self.chat_control.add_info_message(txt) - if not self.whiteboard: - return - hbox = self.chat_control.xml.get_object('chat_control_hbox') - if self.whiteboard.hbox in hbox.get_children(): - if hasattr(self.whiteboard, 'hbox'): - hbox.remove(self.whiteboard.hbox) - self.whiteboard = None - - def disconnect_from_chat_control(self): - menu = self.chat_control.control_menu - for i in range(menu.get_n_items()): - label = menu.get_item_attribute_value(i, 'label') - if label.get_string() == 'WhiteBoard': - menu.remove(i) - break - - -class JingleWhiteboard(JingleContent): - ''' Jingle Whiteboard sessions consist of xhtml content''' - def __init__(self, session, transport=None, senders=None): - if not transport: - transport = JingleTransportSXE() - JingleContent.__init__(self, session, transport, senders) - self.media = 'xhtml' - self.negotiated = True # There is nothing to negotiate - self.last_rid = 0 - self.callbacks['session-accept'] += [self._sessionAcceptCB] - self.callbacks['session-terminate'] += [self._stop] - self.callbacks['session-terminate-sent'] += [self._stop] - self.callbacks['edit'] = [self._EditCB] - - @log_calls('WhiteboardPlugin') - def _EditCB(self, stanza, content, error, action): - new_tags = content.getTags('new') - remove_tags = content.getTags('remove') - if not self.control.whiteboard: - return - - if new_tags is not None: - # Process new elements - for tag in new_tags: - if tag.getAttr('type') == 'element': - self.control.whiteboard.recieve_element(tag) - elif tag.getAttr('type') == 'attr': - self.control.whiteboard.recieve_attr(tag) - self.control.whiteboard.apply_new() - - if remove_tags is not None: - # Delete rids - for tag in remove_tags: - target = tag.getAttr('target') - self.control.whiteboard.image.del_rid(target) - - @log_calls('WhiteboardPlugin') - def _sessionAcceptCB(self, stanza, content, error, action): - log.debug('session accepted') - self.session.connection.dispatch( - 'WHITEBOARD_ACCEPTED', (self.session.peerjid, self.session.sid)) - - def generate_rids(self, x): - # Generates x number of rids and returns in list - rids = [] - for x in range(x): - rids.append(str(self.last_rid)) - self.last_rid += 1 - return rids - - @log_calls('WhiteboardPlugin') - def send_whiteboard_node(self, items, rids): - # Takes int rid and dict items and sends it as a node - # sends new item - jid = self.session.peerjid - sid = self.session.sid - message = Message(to=jid) - sxe = message.addChild(name='sxe', attrs={'session': sid}, - namespace=NS_SXE) - - for x in rids: - if items[x]['type'] == 'element': - parent = x - attrs = {'rid': x, - 'name': items[x]['data'][0].getName(), - 'type': items[x]['type']} - sxe.addChild(name='new', attrs=attrs) - if items[x]['type'] == 'attr': - attr_name = items[x]['data'] - chdata = items[parent]['data'][0].getAttr(attr_name) - attrs = {'rid': x, - 'name': attr_name, - 'type': items[x]['type'], - 'chdata': chdata, - 'parent': parent} - sxe.addChild(name='new', attrs=attrs) - self.session.connection.connection.send(message) - - @log_calls('WhiteboardPlugin') - def delete_whiteboard_node(self, rids): - message = Message(to=self.session.peerjid) - sxe = message.addChild(name='sxe', attrs={'session': self.session.sid}, - namespace=NS_SXE) - - for x in rids: - sxe.addChild(name='remove', attrs={'target': x}) - self.session.connection.connection.send(message) - - def send_items(self, items, rids): - # Receives dict items and a list of rids of items to send - # TODO: Is there a less clumsy way that doesn't involve passing - # whole list? - self.send_whiteboard_node(items, rids) - - def del_item(self, rids): - self.delete_whiteboard_node(rids) - - def encode(self, xml): - # Encodes it sendable string - return 'data:text/xml,' + quote(xml) - - def _fill_content(self, content): - content.addChild(NS_JINGLE_XHTML + ' description') - - def _stop(self, *things): - pass - - def __del__(self): - pass - - -def get_content(desc): - return JingleWhiteboard - - -common.jingle_content.contents[NS_JINGLE_XHTML] = get_content - - -class JingleTransportSXE(JingleTransport): - def __init__(self, node=None): - JingleTransport.__init__(self, TransportType.SOCKS5) - - def make_transport(self, candidates=None): - transport = JingleTransport.make_transport(self, candidates) - transport.setNamespace(NS_JINGLE_SXE) - transport.setTagData('host', 'TODO') - return transport - - -common.jingle_transport.transports[NS_JINGLE_SXE] = JingleTransportSXE diff --git a/whiteboard/whiteboard.png b/whiteboard/whiteboard.png deleted file mode 100644 index 13318e3a7e87e7e97fab65a2d009900f86c02d66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1550 zcmV+p2J!icP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00^)E00^)FDVDUh00007bV*G`2igiB z6)QX7Ex%U)00oXoL_t(Y$F-JgY!p=#$Ny($?mYIr3d;vXjHo0& z(26FaCX!H)7y&Wr2Wyl-NJK@Eh<+g^3I-oh6Q6--1cVwZk0`dj*veMicDL;=J3BkG z_g+7+OQ=ueG08tOx%b@ryXTzAxrd~bI2%uA!ZZSw{;sYfzUq_Q<<)WJEWtEGqYv-8 zlwBiuIog>peP<2WnJ`IL>79;A#`G_KF6DEMSoP8_$3AO7O`+GWzu1^HWJ~?~borYN zJDpcfoToF9!}{4z`(t7KIg4j+44O(z1y^!~QYkOPA92AJ^uD)z=!^m<&U?Ol>ai!LEMd+a7gAS|+N-Ml8ZK)ckJ{!a zn8q-e9YONf0r}>^OtQr;51lq}QNo-R3n(w%G1;trD|ZCT9^C+4*Z*ur7qz_I{Kl3o zH2|`w4D3vpQ^J<=>U~#O^&cJbVa|%DplKRB&qF?+hwHk>XhgVb#*BvUJ$qgUaNQ{Z zI}_%FfI)BHpYV;_-S6RBy8&~eF?gN_P1E2w4s6?o>$-4V7lvUV7K=5XQb;=!X0yfU zgC)~_=k}yL>`8iHje+8jtyuP85h1^h4-bsumsAF-EFqwI7$5V4S;5f%{!3RrvFzS( z^Tgc?uC$uJ`<-KVzXuTVuwp;-4RRbDDBy6$L4U?YYPf{&4(GA`KpI;<{}Dws99p<= zq3@)DTeogi1Ceo^Z8t26e;HpOyMI&Qmf;E^w<(eH`UHT2Q^s(?gT&ZEk}H(p^9NZz zpKm&8VCuL2br)WE@#ML;-l3j5X(reuw+JC+kL}6Z1*uU~fFlJLLW~7^We!rArYK6& zN#$_ux;3-Mk87DX^~z~RPfrgbo;ZxDwU4ja zm<9k-gK}w05U%T@TrR_L7>Y$5VH0Qwskordgk@RS|Cv7FzdWQs(0Z$5?!5Dp$t3pe z+v^-HqjS2tx{lv(j4>Smq?F*CBa_KsaBvVlpAV*KR&Ai`dh5Re*R5N-@}`?_ zojN=`j2%0_7%jQQ_lGmNd%C*1#EEvMX|gJ?x3?F$Tn+$GEEb`vDk6~xIOhn5!;!xL z+uPe&eSQ5Se!su1uDWa*QCcQD47E~UiK(6MqE2m~Odgb)Hk z2o#G&n5K!EnwsDkU~6k@sIjr})261TDQ#_S*tTsO)~|mdHECkoiU%KDzWJXb!5CxJ zjRS!IIOk&|gn;Y12nK_GA|i!|7!d^lyc3Vdr=-(qY~Q{eg+c-Q_Z|3p>C%TjC!z)- zswbj25k-lphKPJb#B^O}rBVrgzaKuI50+)YG))+W0bSRjX&TDqG9rh-|Ddk_jDiqtWx`&!4YW^YtI1 z?(Xhd4ZvOix7oHWY}@9BVF)3_VbAl9RyVGAC;+IHyej~-bUOX}rcIj|01`q#N?GlZ zWaWC20A%HjbUN*fX`+aTPAKa1Cty_y00V##jYj=-b#-yhxyCuyq?FY)Qc)D4C`wt= zG> -# Copyright (C) 2010-2017 Yann Leboulanger -# -# This file is part of the Whiteboard Plugin. -# -# 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 . -# - -from nbxmpp import Node -from gi.repository import Gtk - -from gajim.common import app - -from gajim.gui.filechoosers import NativeFileChooserDialog -from gajim.gui.filechoosers import Filter - -from gajim.plugins.helpers import get_builder -from gajim.plugins.plugins_i18n import _ - -try: - import gi - gi.require_version('GooCanvas', '2.0') - from gi.repository import GooCanvas - HAS_GOOCANVAS = True -except ValueError: - HAS_GOOCANVAS = False - - -class SvgSaveDialog(NativeFileChooserDialog): - - _title = _('Save File as…') - _filters = [Filter(_('All files'), '*', False), - Filter(_('SVG files'), '*.svg', True)] - _action = Gtk.FileChooserAction.SAVE - - -''' -A whiteboard widget made for Gajim. -- Ummu -''' - - -class Whiteboard(object): - def __init__(self, account, contact, session, plugin): - self.plugin = plugin - path = plugin.local_file_path('whiteboard_widget.ui') - self._ui = get_builder(path) - - self.canvas = GooCanvas.Canvas() - self.hbox = self._ui.whiteboard_hbox - self._ui.whiteboard_hbox.pack_start(self.canvas, True, True, 0) - self._ui.whiteboard_hbox.reorder_child(self.canvas, 0) - self.root = self.canvas.get_root_item() - self.tool_buttons = [ - self._ui.brush_button, - self._ui.oval_button, - self._ui.line_button, - self._ui.delete_button - ] - self._ui.brush_button.set_active(True) - - # Events - self.canvas.connect('button-press-event', self.button_press_event) - self.canvas.connect('button-release-event', self.button_release_event) - self.canvas.connect('motion-notify-event', self.motion_notify_event) - self.canvas.connect('item-created', self.item_created) - - # Config - self.line_width = 2 - self._ui.size_scale.set_value(2) - c = self._ui.fg_color_button.get_rgba() - self.color = int(c.red*255*256*256*256 + - c.green*255*256*256 + - c.blue*255*256 + 255) - - # SVG Storage - self.image = SVGObject(self.root, session) - - self._ui.connect_signals(self) - - # Temporary Variables for items - self.item_temp = None - self.item_temp_coords = (0, 0) - self.item_data = None - - # Will be instance of {ID: {type:'element' - # data:[node, goocanvas]}, - # ID2: {}} - self.receiving = {} - - def _on_tool_button_toggled(self, widget): - for btn in self.tool_buttons: - if btn == widget: - continue - btn.set_active(False) - - def _on_brush_button_toggled(self, widget): - if widget.get_active(): - self.image.draw_tool = 'brush' - self._on_tool_button_toggled(widget) - - def _on_oval_button_toggled(self, widget): - if widget.get_active(): - self.image.draw_tool = 'oval' - self._on_tool_button_toggled(widget) - - def _on_line_button_toggled(self, widget): - if widget.get_active(): - self.image.draw_tool = 'line' - self._on_tool_button_toggled(widget) - - def _on_delete_button_toggled(self, widget): - if widget.get_active(): - self.image.draw_tool = 'delete' - self._on_tool_button_toggled(widget) - - def _on_clear_button_clicked(self, widget): - self.image.clear_canvas() - - def _on_fg_color_button_color_set(self, widget): - c = self._ui.fg_color_button.get_rgba() - self.color = int( - c.red*255*256*256*256 + - c.green*255*256*256 + - c.blue*255*256 + 255) - - def _on_size_scale_format_value(self, widget): - self.line_width = int(widget.get_value()) - - def _on_export_button_clicked(self, widget): - SvgSaveDialog(self.image.export_svg, - file_name=_('whiteboard.svg'), - path=app.settings.get('last_save_dir'), - transient_for=app.app.get_active_window()) - - def item_created(self, canvas, item, model): - item.connect('button-press-event', self.item_button_press_events) - - def item_button_press_events(self, item, target_item, event): - if self.image.draw_tool == 'delete': - self.image.del_item(item) - - def button_press_event(self, widget, event): - x = event.x - y = event.y - self.item_temp_coords = (x, y) - - if self.image.draw_tool == 'brush': - self.item_temp = GooCanvas.CanvasEllipse( - parent=self.root, - center_x=x, - center_y=y, - radius_x=1, - radius_y=1, - stroke_color_rgba=self.color, - fill_color=self.color, - line_width=self.line_width) - self.item_data = 'M %s,%s L ' % (x, y) - - elif self.image.draw_tool == 'oval': - self.item_data = True - - if self.image.draw_tool == 'line': - self.item_data = 'M %s,%s L' % (x, y) - - def motion_notify_event(self, widget, event): - x = event.x - y = event.y - if self.item_temp is not None: - self.item_temp.remove() - - if self.item_data is not None: - if self.image.draw_tool == 'brush': - self.item_data = self.item_data + '%s,%s ' % (x, y) - self.item_temp = GooCanvas.CanvasPath( - parent=self.root, - data=self.item_data, - line_width=self.line_width, - stroke_color_rgba=self.color) - elif self.image.draw_tool == 'oval': - self.item_temp = GooCanvas.CanvasEllipse( - parent=self.root, - center_x=self.item_temp_coords[0] + - (x - self.item_temp_coords[0]) / 2, - center_y=self.item_temp_coords[1] + - (y - self.item_temp_coords[1]) / 2, - radius_x=abs(x - self.item_temp_coords[0]) / 2, - radius_y=abs(y - self.item_temp_coords[1]) / 2, - stroke_color_rgba=self.color, - line_width=self.line_width) - elif self.image.draw_tool == 'line': - self.item_data = 'M %s,%s L' % self.item_temp_coords - self.item_data = self.item_data + ' %s,%s' % (x, y) - self.item_temp = GooCanvas.CanvasPath( - parent=self.root, - data=self.item_data, - line_width=self.line_width, - stroke_color_rgba=self.color) - - def button_release_event(self, widget, event): - x = event.x - y = event.y - - if self.image.draw_tool == 'brush': - self.item_data = self.item_data + '%s,%s' % (x, y) - if x == self.item_temp_coords[0] and y == self.item_temp_coords[1]: - GooCanvas.CanvasEllipse( - parent=self.root, - center_x=x, - center_y=y, - radius_x=1, - radius_y=1, - stroke_color_rgba=self.color, - fill_color=self.color, - line_width=self.line_width) - self.image.add_path(self.item_data, self.line_width, self.color) - - if self.image.draw_tool == 'oval': - cx = self.item_temp_coords[0] + (x - self.item_temp_coords[0]) / 2 - cy = self.item_temp_coords[1] + (y - self.item_temp_coords[1]) / 2 - rx = abs(x - self.item_temp_coords[0]) / 2 - ry = abs(y - self.item_temp_coords[1]) / 2 - self.image.add_ellipse(cx, cy, rx, ry, self.line_width, self.color) - - if self.image.draw_tool == 'line': - self.item_data = 'M %s,%s L' % self.item_temp_coords - self.item_data = self.item_data + ' %s,%s' % (x, y) - if x == self.item_temp_coords[0] and y == self.item_temp_coords[1]: - GooCanvas.CanvasEllipse( - parent=self.root, - center_x=x, - center_y=y, - radius_x=1, - radius_y=1, - stroke_color_rgba=self.color, - fill_color_rgba=self.color, - line_width=self.line_width) - self.image.add_path(self.item_data, self.line_width, self.color) - - if self.image.draw_tool == 'delete': - pass - - self.item_data = None - if self.item_temp is not None: - self.item_temp.remove() - self.item_temp = None - - def recieve_element(self, element): - node = self.image.g.addChild(name=element.getAttr('name')) - self.image.g.addChild(node=node) - self.receiving[element.getAttr('rid')] = {'type': 'element', - 'data': [node], - 'children': []} - - def recieve_attr(self, element): - node = self.receiving[element.getAttr('parent')]['data'][0] - node.setAttr(element.getAttr('name'), element.getAttr('chdata')) - - self.receiving[element.getAttr('rid')] = {'type': 'attr', - 'data': element.getAttr( - 'name'), - 'parent': node} - self.receiving[element.getAttr('parent')]['children'].append( - element.getAttr('rid')) - - def apply_new(self): - for x in self.receiving.keys(): - if self.receiving[x]['type'] == 'element': - self.image.add_recieved(x, self.receiving) - - self.receiving = {} - - -class SVGObject(): - ''' A class to store the svg document and make changes to it.''' - def __init__(self, root, session, height=300, width=300): - # Will be instance of {ID: {type:'element', - # data:[node, goocanvas]}, - # ID2: {}} - self.items = {} - self.root = root - self.draw_tool = 'brush' - - # SXE session - self.session = session - - # Initialize svg document - self.svg = Node(node='') - self.svg.setAttr('version', '1.1') - self.svg.setAttr('height', str(height)) - self.svg.setAttr('width', str(width)) - self.svg.setAttr('xmlns', 'http://www.w3.org/2000/svg') - # TODO: Make this settable - self.g = self.svg.addChild(name='g') - self.g.setAttr('fill', 'none') - self.g.setAttr('stroke-linecap', 'round') - - def add_path(self, data, line_width, color): - ''' - Adds the path to the items listing, both minidom node and goocanvas - object in a tuple - ''' - goocanvas_obj = GooCanvas.CanvasPath( - parent=self.root, - data=data, - line_width=line_width, - stroke_color_rgba=color) - goocanvas_obj.connect('button-press-event', - self.item_button_press_events) - - node = self.g.addChild(name='path') - node.setAttr('d', data) - node.setAttr('stroke-width', str(line_width)) - node.setAttr('stroke', str(color)) - self.g.addChild(node=node) - - rids = self.session.generate_rids(4) - self.items[rids[0]] = {'type': 'element', - 'data': [node, goocanvas_obj], - 'children': rids[1:]} - self.items[rids[1]] = {'type': 'attr', - 'data': 'd', - 'parent': node} - self.items[rids[2]] = {'type': 'attr', - 'data': 'stroke-width', - 'parent': node} - self.items[rids[3]] = {'type': 'attr', - 'data': 'stroke', - 'parent': node} - - self.session.send_items(self.items, rids) - - def add_recieved(self, parent_rid, new_items): - ''' - Adds the path to the items listing, both minidom node and goocanvas - object in a tuple - ''' - node = new_items[parent_rid]['data'][0] - - self.items[parent_rid] = new_items[parent_rid] - for x in new_items[parent_rid]['children']: - self.items[x] = new_items[x] - - if node.getName() == 'path': - goocanvas_obj = GooCanvas.CanvasPath( - parent=self.root, - data=node.getAttr('d'), - line_width=int(node.getAttr('stroke-width')), - stroke_color_rgba=int(node.getAttr('stroke'))) - - if node.getName() == 'ellipse': - goocanvas_obj = GooCanvas.CanvasEllipse( - parent=self.root, - center_x=float(node.getAttr('cx')), - center_y=float(node.getAttr('cy')), - radius_x=float(node.getAttr('rx')), - radius_y=float(node.getAttr('ry')), - stroke_color_rgba=int(node.getAttr('stroke')), - line_width=float(node.getAttr('stroke-width'))) - - self.items[parent_rid]['data'].append(goocanvas_obj) - goocanvas_obj.connect('button-press-event', - self.item_button_press_events) - - def add_ellipse(self, cx, cy, rx, ry, line_width, stroke_color): - ''' - Adds the ellipse to the items listing, both minidom node and goocanvas - object in a tuple - ''' - goocanvas_obj = GooCanvas.CanvasEllipse( - parent=self.root, - center_x=cx, - center_y=cy, - radius_x=rx, - radius_y=ry, - stroke_color_rgba=stroke_color, - line_width=line_width) - goocanvas_obj.connect('button-press-event', - self.item_button_press_events) - - node = self.g.addChild(name='ellipse') - node.setAttr('cx', str(cx)) - node.setAttr('cy', str(cy)) - node.setAttr('rx', str(rx)) - node.setAttr('ry', str(ry)) - node.setAttr('stroke-width', str(line_width)) - node.setAttr('stroke', str(stroke_color)) - self.g.addChild(node=node) - - rids = self.session.generate_rids(7) - self.items[rids[0]] = {'type': 'element', - 'data': [node, goocanvas_obj], - 'children': rids[1:]} - self.items[rids[1]] = {'type': 'attr', - 'data': 'cx', - 'parent': node} - self.items[rids[2]] = {'type': 'attr', - 'data': 'cy', - 'parent': node} - self.items[rids[3]] = {'type': 'attr', - 'data': 'rx', - 'parent': node} - self.items[rids[4]] = {'type': 'attr', - 'data': 'ry', - 'parent': node} - self.items[rids[5]] = {'type': 'attr', - 'data': 'stroke-width', - 'parent': node} - self.items[rids[6]] = {'type': 'attr', - 'data': 'stroke', - 'parent': node} - - self.session.send_items(self.items, rids) - - def del_item(self, item): - rids = [] - for x in list(self.items.keys()): - if self.items[x]['type'] == 'element': - if self.items[x]['data'][1] == item: - for y in self.items[x]['children']: - rids.append(y) - self.del_rid(y) - rids.append(x) - self.del_rid(x) - break - self.session.del_item(rids) - - def clear_canvas(self): - for x in list(self.items.keys()): - if self.items[x]['type'] == 'element': - self.del_rid(x) - - def del_rid(self, rid): - if self.items[rid]['type'] == 'element': - self.items[rid]['data'][1].remove() - del self.items[rid] - - def export_svg(self, filename): - f = open(filename, 'w') - f.writelines(str(self.svg)) - f.close() - - def item_button_press_events(self, item, target_item, event): - self.del_item(item) diff --git a/whiteboard/whiteboard_widget.ui b/whiteboard/whiteboard_widget.ui deleted file mode 100644 index 28dbc3b..0000000 --- a/whiteboard/whiteboard_widget.ui +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - 1 - 110 - 2 - 1 - 10 - 10 - - - True - False - 3 - 6 - - - - - - True - False - 6 - vertical - 6 - - - True - True - True - Draw freehand lines - - - - True - False - brush_tool.png - - - - - False - False - 0 - - - - - True - True - True - Draw circles and ellipses - - - - True - False - oval_tool.png - - - - - False - False - 1 - - - - - True - True - True - Draw straight lines - - - - True - False - line_tool.png - - - - - False - False - 2 - - - - - 68 - True - True - Line width - vertical - adjustment1 - True - 0 - bottom - - - - False - False - 3 - - - - - True - True - True - Foreground color - rgb(0,0,0) - - - - False - False - 4 - - - - - True - True - True - Remove individual figures - - - - True - False - edit-delete - - - - - False - False - 5 - - - - - True - True - True - Cleanup canvas - - - - True - False - edit-clear - - - - - False - False - 6 - - - - - True - True - True - Export image to SVG file - 6 - - - - True - False - document-save-as - - - - - False - False - 7 - - - - - False - False - 1 - - - -