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 266c321..0000000 Binary files a/whiteboard/brush_tool.png and /dev/null differ diff --git a/whiteboard/line_tool.png b/whiteboard/line_tool.png deleted file mode 100644 index 151f584..0000000 Binary files a/whiteboard/line_tool.png and /dev/null differ diff --git a/whiteboard/manifest.ini b/whiteboard/manifest.ini deleted file mode 100644 index 322c874..0000000 --- a/whiteboard/manifest.ini +++ /dev/null @@ -1,9 +0,0 @@ -[info] -name: Whiteboard -short_name: whiteboard -version: 1.4.0 -description: Shows a whiteboard in chat. python-pygoocanvas is required. -authors = Yann Leboulanger -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 efd6f0c..0000000 Binary files a/whiteboard/oval_tool.png and /dev/null differ 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 13318e3..0000000 Binary files a/whiteboard/whiteboard.png and /dev/null differ diff --git a/whiteboard/whiteboard_widget.py b/whiteboard/whiteboard_widget.py deleted file mode 100644 index 6ddfed4..0000000 --- a/whiteboard/whiteboard_widget.py +++ /dev/null @@ -1,454 +0,0 @@ -# Copyright (C) 2009 Jeff Ling -# 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 - - - -