Mercurial > libervia-desktop-kivy
annotate src/cagou/plugins/plugin_wid_chat.py @ 97:5d2289127bb7
menu (upload): better menu using dedicated widget:
upload menu now use a decicated widget instead of context menu.
The menu take half the size of the main window, and show each upload option as an icon. Use can select upload or P2P sending, and a short text message explains how the file will be transmitted.
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 29 Dec 2016 23:47:07 +0100 |
parents | 9a6121722669 |
children | 4d8c122b86a6 |
rev | line source |
---|---|
22 | 1 #!/usr/bin/python |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # Cagou: desktop/mobile frontend for Salut à Toi XMPP client | |
5 # Copyright (C) 2016 Jérôme Poisson (goffi@goffi.org) | |
6 | |
7 # This program is free software: you can redistribute it and/or modify | |
8 # it under the terms of the GNU Affero General Public License as published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (at your option) any later version. | |
11 | |
12 # This program is distributed in the hope that it will be useful, | |
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 # GNU Affero General Public License for more details. | |
16 | |
17 # You should have received a copy of the GNU Affero General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 | |
21 from sat.core import log as logging | |
22 log = logging.getLogger(__name__) | |
23 from sat.core.i18n import _ | |
24 from cagou.core.constants import Const as C | |
78 | 25 from kivy.uix.boxlayout import BoxLayout |
45 | 26 from kivy.uix.gridlayout import GridLayout |
57 | 27 from kivy.uix.stacklayout import StackLayout |
22 | 28 from kivy.uix.textinput import TextInput |
57 | 29 from kivy.uix.label import Label |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
30 from kivy.uix.image import AsyncImage |
45 | 31 from kivy.metrics import dp |
57 | 32 from kivy.utils import escape_markup |
22 | 33 from kivy import properties |
34 from sat_frontends.quick_frontend import quick_widgets | |
35 from sat_frontends.quick_frontend import quick_chat | |
57 | 36 from sat_frontends.tools import jid, css_color |
22 | 37 from cagou.core import cagou_widget |
44
7819e9efa250
chat: avatar and nick are now displayed, need further aesthetic improvments
Goffi <goffi@goffi.org>
parents:
42
diff
changeset
|
38 from cagou.core.image import Image |
22 | 39 from cagou import G |
57 | 40 from xml.etree import ElementTree as ET |
22 | 41 |
42 | |
43 PLUGIN_INFO = { | |
44 "name": _(u"chat"), | |
45 "main": "Chat", | |
46 "description": _(u"instant messaging with one person or a group"), | |
90
9a6121722669
chat, contact_list, selector: use of new icons from muchoslava
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
47 "icon_small": u"{media}/icons/muchoslava/png/chat_new_32.png", |
9a6121722669
chat, contact_list, selector: use of new icons from muchoslava
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
48 "icon_medium": u"{media}/icons/muchoslava/png/chat_new_44.png" |
22 | 49 } |
50 | |
51 | |
44
7819e9efa250
chat: avatar and nick are now displayed, need further aesthetic improvments
Goffi <goffi@goffi.org>
parents:
42
diff
changeset
|
52 class MessAvatar(Image): |
7819e9efa250
chat: avatar and nick are now displayed, need further aesthetic improvments
Goffi <goffi@goffi.org>
parents:
42
diff
changeset
|
53 pass |
7819e9efa250
chat: avatar and nick are now displayed, need further aesthetic improvments
Goffi <goffi@goffi.org>
parents:
42
diff
changeset
|
54 |
7819e9efa250
chat: avatar and nick are now displayed, need further aesthetic improvments
Goffi <goffi@goffi.org>
parents:
42
diff
changeset
|
55 |
57 | 56 class Escape(unicode): |
57 """Class used to mark that a message need to be escaped""" | |
58 | |
59 def __init__(self, text): | |
60 super(Escape, self).__init__(text) | |
61 | |
62 | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
63 class SimpleXHTMLWidgetEscapedText(Label): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
64 pass |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
65 |
59 | 66 |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
67 class SimpleXHTMLWidgetText(Label): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
68 pass |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
69 |
59 | 70 |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
71 class SimpleXHTMLWidgetImage(AsyncImage): |
59 | 72 # following properties are desired height/width |
73 # i.e. the ones specified in height/width attributes of <img> | |
74 # (or wanted for whatever reason) | |
75 # set to 0 to ignore them | |
76 target_height = properties.NumericProperty() | |
77 target_width = properties.NumericProperty() | |
78 | |
79 def _get_parent_container(self): | |
80 """get parent SimpleXHTMLWidget instance | |
81 | |
82 @param warning(bool): if True display a log.error if nothing found | |
83 @return (SimpleXHTMLWidget, None): found SimpleXHTMLWidget instance | |
84 """ | |
85 parent = self.parent | |
86 while parent and not isinstance(parent, SimpleXHTMLWidget): | |
87 parent = parent.parent | |
88 if parent is None: | |
89 log.error(u"no SimpleXHTMLWidget parent found") | |
90 return parent | |
91 | |
92 def _on_source_load(self, value): | |
93 # this method is called when image is loaded | |
94 super(SimpleXHTMLWidgetImage, self)._on_source_load(value) | |
95 if self.parent is not None: | |
96 container = self._get_parent_container() | |
97 # image is loaded, we need to recalculate size | |
98 self.on_container_width(container, container.width) | |
99 | |
100 def on_container_width(self, container, container_width): | |
101 """adapt size according to container width | |
102 | |
103 called when parent container (SimpleXHTMLWidget) width change | |
104 """ | |
105 target_size = (self.target_width or self.texture.width, self.target_height or self.texture.height) | |
106 padding = container.padding | |
107 padding_h = (padding[0] + padding[2]) if len(padding) == 4 else padding[0] | |
108 width = container_width - padding_h | |
109 if target_size[0] < width: | |
110 self.size = target_size | |
111 else: | |
112 height = width / self.image_ratio | |
113 self.size = (width, height) | |
114 | |
115 def on_parent(self, instance, parent): | |
116 if parent is not None: | |
117 container = self._get_parent_container() | |
118 container.bind(width=self.on_container_width) | |
119 | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
120 |
57 | 121 class SimpleXHTMLWidget(StackLayout): |
122 """widget handling simple XHTML parsing""" | |
123 xhtml = properties.StringProperty() | |
124 color = properties.ListProperty([1, 1, 1, 1]) | |
125 # XXX: bold is only used for escaped text | |
126 bold = properties.BooleanProperty(False) | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
127 content_width = properties.NumericProperty(0) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
128 |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
129 # text/XHTML input |
57 | 130 |
131 def on_xhtml(self, instance, xhtml): | |
132 """parse xhtml and set content accordingly | |
133 | |
134 if xhtml is an instance of Escape, a Label with not markup | |
135 will be used | |
136 """ | |
137 self.clear_widgets() | |
138 if isinstance(xhtml, Escape): | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
139 label = SimpleXHTMLWidgetEscapedText(text=xhtml, color=self.color) |
57 | 140 self.bind(color=label.setter('color')) |
141 self.bind(bold=label.setter('bold')) | |
142 self.add_widget(label) | |
143 else: | |
144 xhtml = ET.fromstring(xhtml.encode('utf-8')) | |
145 self.current_wid = None | |
146 self.styles = [] | |
147 self._callParseMethod(xhtml) | |
148 | |
149 def escape(self, text): | |
150 """mark that a text need to be escaped (i.e. no markup)""" | |
151 return Escape(text) | |
152 | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
153 # sizing |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
154 |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
155 def on_width(self, instance, width): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
156 if len(self.children) == 1: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
157 wid = self.children[0] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
158 if isinstance(wid, Label): |
68 | 159 # we have simple text |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
160 try: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
161 full_width = wid._full_width |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
162 except AttributeError: |
68 | 163 # on first time, we need the required size |
164 # for the full text, without width limit | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
165 wid.size_hint = (None, None) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
166 wid.texture_update() |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
167 full_width = wid._full_width = wid.texture_size[0] |
68 | 168 |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
169 if full_width > width: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
170 wid.text_size = width, None |
68 | 171 wid.width = width |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
172 else: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
173 wid.text_size = None, None |
68 | 174 wid.texture_update() |
175 wid.width = wid.texture_size[0] | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
176 self.content_width = wid.width + self.padding[0] + self.padding[2] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
177 else: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
178 wid.size_hint(1, None) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
179 wid.height = 100 |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
180 self.content_width = self.width |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
181 else: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
182 self._do_complexe_sizing(width) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
183 |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
184 def _do_complexe_sizing(self, width): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
185 try: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
186 self.splitted |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
187 except AttributeError: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
188 # XXX: to make things easier, we split labels in words |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
189 log.debug(u"split start") |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
190 children = self.children[::-1] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
191 self.clear_widgets() |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
192 for child in children: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
193 if isinstance(child, Label): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
194 log.debug(u"label before split: {}".format(child.text)) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
195 styles = [] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
196 tag = False |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
197 new_text = [] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
198 current_tag = [] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
199 current_value = [] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
200 current_wid = self._createText() |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
201 value = False |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
202 close = False |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
203 # we will parse the text and create a new widget |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
204 # on each new word (actually each space) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
205 # FIXME: handle '\n' and other white chars |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
206 for c in child.text: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
207 if tag: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
208 # we are parsing a markup tag |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
209 if c == u']': |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
210 current_tag_s = u''.join(current_tag) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
211 current_style = (current_tag_s, u''.join(current_value)) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
212 if close: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
213 for idx, s in enumerate(reversed(styles)): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
214 if s[0] == current_tag_s: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
215 del styles[len(styles) - idx - 1] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
216 break |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
217 else: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
218 styles.append(current_style) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
219 current_tag = [] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
220 current_value = [] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
221 tag = False |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
222 value = False |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
223 close = False |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
224 elif c == u'/': |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
225 close = True |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
226 elif c == u'=': |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
227 value = True |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
228 elif value: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
229 current_value.append(c) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
230 else: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
231 current_tag.append(c) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
232 new_text.append(c) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
233 else: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
234 # we are parsing regular text |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
235 if c == u'[': |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
236 new_text.append(c) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
237 tag = True |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
238 elif c == u' ': |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
239 # new word, we do a new widget |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
240 new_text.append(u' ') |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
241 for t, v in reversed(styles): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
242 new_text.append(u'[/{}]'.format(t)) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
243 current_wid.text = u''.join(new_text) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
244 new_text = [] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
245 self.add_widget(current_wid) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
246 log.debug(u"new widget: {}".format(current_wid.text)) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
247 current_wid = self._createText() |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
248 for t, v in styles: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
249 new_text.append(u'[{tag}{value}]'.format( |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
250 tag = t, |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
251 value = u'={}'.format(v) if v else u'')) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
252 else: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
253 new_text.append(c) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
254 if current_wid.text: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
255 # we may have a remaining widget after the parsing |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
256 close_styles = [] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
257 for t, v in reversed(styles): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
258 close_styles.append(u'[/{}]'.format(t)) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
259 current_wid.text = u''.join(close_styles) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
260 self.add_widget(current_wid) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
261 log.debug(u"new widget: {}".format(current_wid.text)) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
262 else: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
263 # non Label widgets, we just add them |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
264 self.add_widget(child) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
265 self.splitted = True |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
266 log.debug(u"split OK") |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
267 |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
268 # we now set the content width |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
269 # FIXME: for now we just use the full width |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
270 self.content_width = width |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
271 |
57 | 272 # XHTML parsing methods |
273 | |
274 def _callParseMethod(self, e): | |
275 """call the suitable method to parse the element | |
276 | |
277 self.xhtml_[tag] will be called if it exists, else | |
278 self.xhtml_generic will be used | |
279 @param e(ET.Element): element to parse | |
280 """ | |
281 try: | |
282 method = getattr(self, "xhtml_{}".format(e.tag)) | |
283 except AttributeError: | |
284 log.warning(u"Unhandled XHTML tag: {}".format(e.tag)) | |
285 method = self.xhtml_generic | |
286 method(e) | |
287 | |
288 def _addStyle(self, tag, value=None, append_to_list=True): | |
289 """add a markup style to label | |
290 | |
291 @param tag(unicode): markup tag | |
292 @param value(unicode): markup value if suitable | |
293 @param append_to_list(bool): if True style we be added to self.styles | |
294 self.styles is needed to keep track of styles to remove | |
295 should most probably be set to True | |
296 """ | |
297 label = self._getLabel() | |
298 label.text += u'[{tag}{value}]'.format( | |
299 tag = tag, | |
300 value = u'={}'.format(value) if value else '' | |
301 ) | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
302 if append_to_list: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
303 self.styles.append((tag, value)) |
57 | 304 |
305 def _removeStyle(self, tag, remove_from_list=True): | |
306 """remove a markup style from the label | |
307 | |
308 @param tag(unicode): markup tag to remove | |
309 @param remove_from_list(bool): if True, remove from self.styles too | |
310 should most probably be set to True | |
311 """ | |
312 label = self._getLabel() | |
313 label.text += u'[/{tag}]'.format( | |
314 tag = tag | |
315 ) | |
316 if remove_from_list: | |
317 for rev_idx, style in enumerate(reversed(self.styles)): | |
318 if style[0] == tag: | |
319 tag_idx = len(self.styles) - 1 - rev_idx | |
320 del self.styles[tag_idx] | |
321 break | |
322 | |
323 def _getLabel(self): | |
324 """get current Label if it exists, or create a new one""" | |
325 if not isinstance(self.current_wid, Label): | |
326 self._addLabel() | |
327 return self.current_wid | |
328 | |
329 def _addLabel(self): | |
330 """add a new Label | |
331 | |
332 current styles will be closed and reopened if needed | |
333 """ | |
334 self._closeLabel() | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
335 self.current_wid = self._createText() |
57 | 336 for tag, value in self.styles: |
337 self._addStyle(tag, value, append_to_list=False) | |
338 self.add_widget(self.current_wid) | |
339 | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
340 def _createText(self): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
341 label = SimpleXHTMLWidgetText(color=self.color, markup=True) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
342 self.bind(color=label.setter('color')) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
343 label.bind(texture_size=label.setter('size')) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
344 return label |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
345 |
57 | 346 def _closeLabel(self): |
347 """close current style tags in current label | |
348 | |
349 needed when you change label to keep style between | |
350 different widgets | |
351 """ | |
352 if isinstance(self.current_wid, Label): | |
353 for tag, value in reversed(self.styles): | |
354 self._removeStyle(tag, remove_from_list=False) | |
355 | |
356 def _parseCSS(self, e): | |
357 """parse CSS found in "style" attribute of element | |
358 | |
359 self._css_styles will be created and contained markup styles added by this method | |
360 @param e(ET.Element): element which may have a "style" attribute | |
361 """ | |
362 styles_limit = len(self.styles) | |
363 styles = e.attrib['style'].split(u';') | |
364 for style in styles: | |
365 try: | |
366 prop, value = style.split(u':') | |
367 except ValueError: | |
368 log.warning(u"can't parse style: {}".format(style)) | |
369 continue | |
370 prop = prop.strip().replace(u'-', '_') | |
371 value = value.strip() | |
372 try: | |
373 method = getattr(self, "css_{}".format(prop)) | |
374 except AttributeError: | |
375 log.warning(u"Unhandled CSS: {}".format(prop)) | |
376 else: | |
377 method(e, value) | |
378 self._css_styles = self.styles[styles_limit:] | |
379 | |
380 def _closeCSS(self): | |
381 """removed CSS styles | |
382 | |
383 styles in self._css_styles will be removed | |
384 and the attribute will be deleted | |
385 """ | |
386 for tag, dummy in reversed(self._css_styles): | |
387 self._removeStyle(tag) | |
388 del self._css_styles | |
389 | |
390 def xhtml_generic(self, elem, style=True, markup=None): | |
391 """generic method for adding HTML elements | |
392 | |
393 this method handle content, style and children parsing | |
394 @param elem(ET.Element): element to add | |
395 @param style(bool): if True handle style attribute (CSS) | |
396 @param markup(tuple[unicode, (unicode, None)], None): kivy markup to use | |
397 """ | |
398 # we first add markup and CSS style | |
399 if markup is not None: | |
400 if isinstance(markup, basestring): | |
401 tag, value = markup, None | |
402 else: | |
403 tag, value = markup | |
404 self._addStyle(tag, value) | |
405 style_ = 'style' in elem.attrib and style | |
406 if style_: | |
407 self._parseCSS(elem) | |
408 | |
409 # then content | |
410 if elem.text: | |
411 self._getLabel().text += escape_markup(elem.text) | |
412 | |
413 # we parse the children | |
414 for child in elem: | |
415 self._callParseMethod(child) | |
416 | |
417 # closing CSS style and markup | |
418 if style_: | |
419 self._closeCSS() | |
420 if markup is not None: | |
421 self._removeStyle(tag) | |
422 | |
423 # and the tail, which is regular text | |
424 if elem.tail: | |
425 self._getLabel().text += escape_markup(elem.tail) | |
426 | |
427 # method handling XHTML elements | |
428 | |
429 def xhtml_br(self, elem): | |
430 label = self._getLabel() | |
431 label.text+='\n' | |
432 self.xhtml_generic(style=False) | |
433 | |
434 def xhtml_em(self, elem): | |
435 self.xhtml_generic(elem, markup='i') | |
436 | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
437 def xhtml_img(self, elem): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
438 try: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
439 src = elem.attrib['src'] |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
440 except KeyError: |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
441 log.warning(u"<img> element without src: {}".format(ET.tostring(elem))) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
442 return |
59 | 443 try: |
444 target_height = int(elem.get(u'height', 0)) | |
445 except ValueError: | |
446 log.warning(u"Can't parse image height: {}".format(elem.get(u'height'))) | |
447 target_height = 0 | |
448 try: | |
449 target_width = int(elem.get(u'width', 0)) | |
450 except ValueError: | |
451 log.warning(u"Can't parse image width: {}".format(elem.get(u'width'))) | |
452 target_width = 0 | |
453 | |
454 img = SimpleXHTMLWidgetImage(source=src, target_height=target_height, target_width=target_width) | |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
455 self.current_wid = img |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
456 self.add_widget(img) |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
457 |
57 | 458 def xhtml_p(self, elem): |
58
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
459 if isinstance(self.current_wid, Label): |
7aa2ffff9067
chat: <img/> tag handling first draft:
Goffi <goffi@goffi.org>
parents:
57
diff
changeset
|
460 self.current_wid.text+="\n\n" |
57 | 461 self.xhtml_generic(elem) |
462 | |
463 def xhtml_span(self, elem): | |
464 self.xhtml_generic(elem) | |
465 | |
466 def xhtml_strong(self, elem): | |
467 self.xhtml_generic(elem, markup='b') | |
468 | |
469 # methods handling CSS properties | |
470 | |
471 def css_color(self, elem, value): | |
472 self._addStyle(u"color", css_color.parse(value)) | |
473 | |
474 def css_text_decoration(self, elem, value): | |
475 if value == u'underline': | |
476 log.warning(u"{} not handled yet, it needs Kivy 1.9.2 to be released".format(value)) | |
477 # FIXME: activate when 1.9.2 is out | |
478 # self._addStyle('u') | |
479 elif value == u'line-through': | |
480 log.warning(u"{} not handled yet, it needs Kivy 1.9.2 to be released".format(value)) | |
481 # FIXME: activate when 1.9.2 is out | |
482 # self._addStyle('s') | |
483 else: | |
484 log.warning(u"unhandled text decoration: {}".format(value)) | |
485 | |
486 | |
45 | 487 class MessageWidget(GridLayout): |
22 | 488 mess_data = properties.ObjectProperty() |
57 | 489 mess_xhtml = properties.ObjectProperty() |
45 | 490 mess_padding = (dp(5), dp(5)) |
47
abb81efef3bb
chat: update avatar following quick frontend improvments
Goffi <goffi@goffi.org>
parents:
46
diff
changeset
|
491 avatar = properties.ObjectProperty() |
abb81efef3bb
chat: update avatar following quick frontend improvments
Goffi <goffi@goffi.org>
parents:
46
diff
changeset
|
492 |
abb81efef3bb
chat: update avatar following quick frontend improvments
Goffi <goffi@goffi.org>
parents:
46
diff
changeset
|
493 def __init__(self, **kwargs): |
abb81efef3bb
chat: update avatar following quick frontend improvments
Goffi <goffi@goffi.org>
parents:
46
diff
changeset
|
494 super(MessageWidget, self).__init__(**kwargs) |
abb81efef3bb
chat: update avatar following quick frontend improvments
Goffi <goffi@goffi.org>
parents:
46
diff
changeset
|
495 self.mess_data.widgets.add(self) |
44
7819e9efa250
chat: avatar and nick are now displayed, need further aesthetic improvments
Goffi <goffi@goffi.org>
parents:
42
diff
changeset
|
496 |
7819e9efa250
chat: avatar and nick are now displayed, need further aesthetic improvments
Goffi <goffi@goffi.org>
parents:
42
diff
changeset
|
497 @property |
7819e9efa250
chat: avatar and nick are now displayed, need further aesthetic improvments
Goffi <goffi@goffi.org>
parents:
42
diff
changeset
|
498 def chat(self): |
7819e9efa250
chat: avatar and nick are now displayed, need further aesthetic improvments
Goffi <goffi@goffi.org>
parents:
42
diff
changeset
|
499 """return parent Chat instance""" |
7819e9efa250
chat: avatar and nick are now displayed, need further aesthetic improvments
Goffi <goffi@goffi.org>
parents:
42
diff
changeset
|
500 return self.mess_data.parent |
22 | 501 |
502 @property | |
503 def message(self): | |
504 """Return currently displayed message""" | |
505 return self.mess_data.main_message | |
506 | |
57 | 507 @property |
508 def message_xhtml(self): | |
509 """Return currently displayed message""" | |
510 return self.mess_data.main_message_xhtml | |
511 | |
45 | 512 def widthAdjust(self): |
22 | 513 """this widget grows up with its children""" |
57 | 514 pass |
515 # parent = self.mess_xhtml.parent | |
516 # padding_x = self.mess_padding[0] | |
517 # text_width, text_height = self.mess_xhtml.texture_size | |
518 # if text_width > parent.width: | |
519 # self.mess_xhtml.text_size = (parent.width - padding_x, None) | |
520 # self.text_max = text_width | |
521 # elif self.mess_xhtml.text_size[0] is not None and text_width < parent.width - padding_x: | |
522 # if text_width < self.text_max: | |
523 # self.mess_xhtml.text_size = (None, None) | |
524 # else: | |
525 # self.mess_xhtml.text_size = (parent.width - padding_x, None) | |
22 | 526 |
54
514c187afebc
chat: changed udpate to use dict instead of single key/value
Goffi <goffi@goffi.org>
parents:
47
diff
changeset
|
527 def update(self, update_dict): |
514c187afebc
chat: changed udpate to use dict instead of single key/value
Goffi <goffi@goffi.org>
parents:
47
diff
changeset
|
528 if 'avatar' in update_dict: |
514c187afebc
chat: changed udpate to use dict instead of single key/value
Goffi <goffi@goffi.org>
parents:
47
diff
changeset
|
529 self.avatar.source = update_dict['avatar'] |
47
abb81efef3bb
chat: update avatar following quick frontend improvments
Goffi <goffi@goffi.org>
parents:
46
diff
changeset
|
530 |
22 | 531 |
78 | 532 class MessageInputBox(BoxLayout): |
533 pass | |
534 | |
535 | |
22 | 536 class MessageInputWidget(TextInput): |
537 | |
538 def _key_down(self, key, repeat=False): | |
539 displayed_str, internal_str, internal_action, scale = key | |
540 if internal_action == 'enter': | |
541 self.dispatch('on_text_validate') | |
542 else: | |
543 super(MessageInputWidget, self)._key_down(key, repeat) | |
544 | |
545 | |
45 | 546 class MessagesWidget(GridLayout): |
547 pass | |
22 | 548 |
549 | |
550 class Chat(quick_chat.QuickChat, cagou_widget.CagouWidget): | |
78 | 551 message_input = properties.ObjectProperty() |
86 | 552 messages_widget = properties.ObjectProperty() |
22 | 553 |
46
d6a63942d5ad
chat: fixed MUC joining following changes in backend
Goffi <goffi@goffi.org>
parents:
45
diff
changeset
|
554 def __init__(self, host, target, type_=C.CHAT_ONE2ONE, nick=None, occupants=None, subject=None, profiles=None): |
d6a63942d5ad
chat: fixed MUC joining following changes in backend
Goffi <goffi@goffi.org>
parents:
45
diff
changeset
|
555 quick_chat.QuickChat.__init__(self, host, target, type_, nick, occupants, subject, profiles=profiles) |
22 | 556 cagou_widget.CagouWidget.__init__(self) |
67 | 557 self.header_input.hint_text = u"{}".format(target) |
78 | 558 self.host.addListener('progressError', self.onProgressError, profiles) |
559 self.host.addListener('progressFinished', self.onProgressFinished, profiles) | |
560 self._waiting_pids = {} # waiting progress ids | |
22 | 561 self.postInit() |
562 | |
563 @classmethod | |
564 def factory(cls, plugin_info, target, profiles): | |
565 profiles = list(profiles) | |
566 if len(profiles) > 1: | |
567 raise NotImplementedError(u"Multi-profiles is not available yet for chat") | |
568 if target is None: | |
569 target = G.host.profiles[profiles[0]].whoami | |
570 return G.host.widgets.getOrCreateWidget(cls, target, on_new_widget=None, on_existing_widget=C.WIDGET_RECREATE, profiles=profiles) | |
571 | |
572 def messageDataConverter(self, idx, mess_id): | |
573 return {"mess_data": self.messages[mess_id]} | |
574 | |
575 def _onHistoryPrinted(self): | |
576 """Refresh or scroll down the focus after the history is printed""" | |
577 # self.adapter.data = self.messages | |
578 for mess_data in self.messages.itervalues(): | |
579 self.appendMessage(mess_data) | |
580 super(Chat, self)._onHistoryPrinted() | |
581 | |
582 def createMessage(self, message): | |
583 self.appendMessage(message) | |
584 | |
585 def appendMessage(self, mess_data): | |
586 self.messages_widget.add_widget(MessageWidget(mess_data=mess_data)) | |
587 | |
588 def onSend(self, input_widget): | |
589 G.host.messageSend( | |
590 self.target, | |
591 {'': input_widget.text}, # TODO: handle language | |
592 mess_type = C.MESS_TYPE_GROUPCHAT if self.type == C.CHAT_GROUP else C.MESS_TYPE_CHAT, # TODO: put this in QuickChat | |
593 profile_key=self.profile | |
594 ) | |
595 input_widget.text = '' | |
596 | |
78 | 597 def onProgressFinished(self, progress_id, metadata, profile): |
598 try: | |
88
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
599 callback, cleaning_cb = self._waiting_pids.pop(progress_id) |
78 | 600 except KeyError: |
601 return | |
88
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
602 if cleaning_cb is not None: |
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
603 cleaning_cb() |
78 | 604 callback(metadata, profile) |
605 | |
606 def onProgressError(self, progress_id, err_msg, profile): | |
607 try: | |
88
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
608 dummy, cleaning_cb = self._waiting_pids[progress_id] |
78 | 609 except KeyError: |
610 return | |
88
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
611 else: |
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
612 del self._waiting_pids[progress_id] |
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
613 if cleaning_cb is not None: |
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
614 cleaning_cb() |
78 | 615 # TODO: display message to user |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
90
diff
changeset
|
616 log.warning(u"Can't transfer file: {}".format(err_msg)) |
78 | 617 |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
90
diff
changeset
|
618 def fileTransferDone(self, metadata, profile): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
90
diff
changeset
|
619 log.debug("file transfered: {}".format(metadata)) |
78 | 620 G.host.messageSend( |
621 self.target, | |
622 {'': metadata['url']}, | |
623 mess_type = C.MESS_TYPE_GROUPCHAT if self.type == C.CHAT_GROUP else C.MESS_TYPE_CHAT, | |
624 profile_key=profile | |
625 ) | |
626 | |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
90
diff
changeset
|
627 def fileTransferCb(self, progress_data, cleaning_cb): |
78 | 628 try: |
629 progress_id = progress_data['progress'] | |
630 except KeyError: | |
631 xmlui = progress_data['xmlui'] | |
632 G.host.showUI(xmlui) | |
633 else: | |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
90
diff
changeset
|
634 self._waiting_pids[progress_id] = (self.fileTransferDone, cleaning_cb) |
78 | 635 |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
90
diff
changeset
|
636 def onTransferOK(self, file_path, cleaning_cb): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
90
diff
changeset
|
637 G.host.bridge.fileTransfer( |
86 | 638 file_path, |
639 "", | |
640 "", | |
641 {"ignore_tls_errors": C.BOOL_TRUE}, # FIXME: should not be the default | |
642 self.profile, | |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
90
diff
changeset
|
643 callback = lambda progress_data: self.fileTransferCb(progress_data, cleaning_cb) |
86 | 644 ) |
78 | 645 |
46
d6a63942d5ad
chat: fixed MUC joining following changes in backend
Goffi <goffi@goffi.org>
parents:
45
diff
changeset
|
646 def _mucJoinCb(self, joined_data): |
d6a63942d5ad
chat: fixed MUC joining following changes in backend
Goffi <goffi@goffi.org>
parents:
45
diff
changeset
|
647 joined, room_jid_s, occupants, user_nick, subject, profile = joined_data |
d6a63942d5ad
chat: fixed MUC joining following changes in backend
Goffi <goffi@goffi.org>
parents:
45
diff
changeset
|
648 self.host.mucRoomJoinedHandler(*joined_data[1:]) |
d6a63942d5ad
chat: fixed MUC joining following changes in backend
Goffi <goffi@goffi.org>
parents:
45
diff
changeset
|
649 jid_ = jid.JID(room_jid_s) |
42
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
650 self.changeWidget(jid_) |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
651 |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
652 def _mucJoinEb(self, failure): |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
653 log.warning(u"Can't join room: {}".format(failure)) |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
654 |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
655 def changeWidget(self, jid_): |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
656 """change current widget for a new one with given jid |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
657 |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
658 @param jid_(jid.JID): jid of the widget to create |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
659 """ |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
660 plugin_info = G.host.getPluginInfo(main=Chat) |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
661 factory = plugin_info['factory'] |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
662 G.host.switchWidget(self, factory(plugin_info, jid_, profiles=[self.profile])) |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
663 self.header_input.text = '' |
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
664 |
22 | 665 def onHeaderInput(self): |
666 text = self.header_input.text.strip() | |
667 try: | |
668 if text.count(u'@') != 1 or text.count(u' '): | |
669 raise ValueError | |
670 jid_ = jid.JID(text) | |
671 except ValueError: | |
672 log.info(u"entered text is not a jid") | |
673 return | |
674 | |
675 def discoCb(disco): | |
676 # TODO: check if plugin XEP-0045 is activated | |
677 if "conference" in [i[0] for i in disco[1]]: | |
42
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
678 G.host.bridge.mucJoin(unicode(jid_), "", "", self.profile, callback=self._mucJoinCb, errback=self._mucJoinEb) |
22 | 679 else: |
42
286865bc013a
chat: joining MUC using header input is now working:
Goffi <goffi@goffi.org>
parents:
41
diff
changeset
|
680 self.changeWidget(jid_) |
22 | 681 |
682 def discoEb(failure): | |
683 log.warning(u"Disco failure, ignore this text: {}".format(failure)) | |
684 | |
685 G.host.bridge.discoInfos(jid_.domain, self.profile, callback=discoCb, errback=discoEb) | |
686 | |
78 | 687 def _onDelete(self): |
688 self.host.removeListener('progressFinished', self.onProgressFinished) | |
689 self.host.removeListener('progressError', self.onProgressError) | |
690 return super(Chat, self).onDelete() | |
691 | |
37
6cf08d0ee460
chat: forbid scrolling on X axis + don't delete widget until explicitly requested (with force attribute)
Goffi <goffi@goffi.org>
parents:
35
diff
changeset
|
692 def onDelete(self, force=False): |
6cf08d0ee460
chat: forbid scrolling on X axis + don't delete widget until explicitly requested (with force attribute)
Goffi <goffi@goffi.org>
parents:
35
diff
changeset
|
693 if force==True: |
78 | 694 return self._onDelete() |
37
6cf08d0ee460
chat: forbid scrolling on X axis + don't delete widget until explicitly requested (with force attribute)
Goffi <goffi@goffi.org>
parents:
35
diff
changeset
|
695 if len(list(G.host.widgets.getWidgets(self.__class__, self.target, profiles=self.profiles))) > 1: |
6cf08d0ee460
chat: forbid scrolling on X axis + don't delete widget until explicitly requested (with force attribute)
Goffi <goffi@goffi.org>
parents:
35
diff
changeset
|
696 # we don't keep duplicate widgets |
78 | 697 return self._onDelete() |
37
6cf08d0ee460
chat: forbid scrolling on X axis + don't delete widget until explicitly requested (with force attribute)
Goffi <goffi@goffi.org>
parents:
35
diff
changeset
|
698 return False |
22 | 699 |
700 | |
701 PLUGIN_INFO["factory"] = Chat.factory | |
702 quick_widgets.register(quick_chat.QuickChat, Chat) |