Mercurial > libervia-desktop-kivy
annotate cagou/plugins/plugin_wid_file_sharing.py @ 217:286f14127f61
plugin file sharing: started to limit line to 90 chars as a test
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 24 Jun 2018 22:08:57 +0200 |
parents | 6a98d70a3a66 |
children | a676cb07c1cb |
rev | line source |
---|---|
192 | 1 #!/usr/bin/python |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # Cagou: desktop/mobile frontend for Salut à Toi XMPP client | |
5 # Copyright (C) 2016-2018 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 from sat.core import exceptions | |
23 log = logging.getLogger(__name__) | |
24 from sat.core.i18n import _ | |
25 from sat.tools.common import files_utils | |
26 from sat_frontends.quick_frontend import quick_widgets | |
27 from sat_frontends.tools import jid | |
28 from cagou.core.constants import Const as C | |
29 from cagou.core import cagou_widget | |
198
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
30 from cagou.core.menu import EntitiesSelectorMenu |
196
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
31 from cagou.core.utils import FilterBehavior |
192 | 32 from cagou import G |
33 from kivy import properties | |
34 from kivy.uix.label import Label | |
35 from kivy.uix.button import Button | |
36 from kivy.uix.boxlayout import BoxLayout | |
37 from kivy.garden import modernmenu | |
38 from kivy.clock import Clock | |
39 from kivy.metrics import dp | |
205
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
40 from kivy import utils as kivy_utils |
192 | 41 from functools import partial |
42 import os.path | |
43 import json | |
44 | |
45 | |
46 PLUGIN_INFO = { | |
47 "name": _(u"file sharing"), | |
48 "main": "FileSharing", | |
49 "description": _(u"share/transfer files between devices"), | |
50 "icon_symbol": u"exchange", | |
51 } | |
52 MODE_VIEW = u"view" | |
53 MODE_LOCAL = u"local" | |
194
a68c9baa6694
plugin file sharing: use header hint to show current path, and open new path:
Goffi <goffi@goffi.org>
parents:
192
diff
changeset
|
54 SELECT_INSTRUCTIONS = _(u"Please select entities to share with") |
192 | 55 |
205
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
56 if kivy_utils.platform == "android": |
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
57 from jnius import autoclass |
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
58 Environment = autoclass("android.os.Environment") |
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
59 base_dir = Environment.getExternalStorageDirectory().getAbsolutePath() |
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
60 def expanduser(path): |
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
61 if path == u'~' or path.startswith(u'~/'): |
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
62 return path.replace(u'~', base_dir, 1) |
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
63 return path |
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
64 else: |
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
65 expanduser = os.path.expanduser |
192 | 66 |
67 | |
68 class ModeBtn(Button): | |
69 | |
70 def __init__(self, parent, **kwargs): | |
71 super(ModeBtn, self).__init__(**kwargs) | |
72 parent.bind(mode=self.on_mode) | |
73 self.on_mode(parent, parent.mode) | |
74 | |
75 def on_mode(self, parent, new_mode): | |
76 if new_mode == MODE_VIEW: | |
77 self.text = _(u"view shared files") | |
78 elif new_mode == MODE_LOCAL: | |
79 self.text = _(u"share local files") | |
80 else: | |
81 exceptions.InternalError(u"Unknown mode: {mode}".format(mode=new_mode)) | |
82 | |
83 | |
84 class Identities(object): | |
85 | |
86 def __init__(self, entity_ids): | |
87 identities = {} | |
88 for cat, type_, name in entity_ids: | |
89 identities.setdefault(cat, {}).setdefault(type_, []).append(name) | |
206
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
90 client = identities.get('client', {}) |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
91 if 'pc' in client: |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
92 self.type = 'desktop' |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
93 elif 'phone' in client: |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
94 self.type = 'phone' |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
95 elif 'web' in client: |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
96 self.type = 'web' |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
97 elif 'console' in client: |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
98 self.type = 'console' |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
99 else: |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
100 self.type = 'desktop' |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
101 |
192 | 102 self.identities = identities |
103 | |
104 @property | |
105 def name(self): | |
106 return self.identities.values()[0].values()[0][0] | |
107 | |
108 | |
109 class ItemWidget(BoxLayout): | |
110 click_timeout = properties.NumericProperty(0.4) | |
111 base_width = properties.NumericProperty(dp(100)) | |
112 | |
113 def __init__(self, sharing_wid, name): | |
114 self.sharing_wid = sharing_wid | |
115 self.name = name | |
116 super(ItemWidget, self).__init__() | |
117 | |
118 def on_touch_down(self, touch): | |
119 if not self.collide_point(*touch.pos): | |
120 return | |
121 t = partial(self.open_menu, touch) | |
122 touch.ud['menu_timeout'] = t | |
123 Clock.schedule_once(t, self.click_timeout) | |
124 return super(ItemWidget, self).on_touch_down(touch) | |
125 | |
126 def do_item_action(self, touch): | |
127 pass | |
128 | |
129 def on_touch_up(self, touch): | |
130 if touch.ud.get('menu_timeout'): | |
131 Clock.unschedule(touch.ud['menu_timeout']) | |
132 if self.collide_point(*touch.pos) and self.sharing_wid.menu is None: | |
133 self.do_item_action(touch) | |
134 return super(ItemWidget, self).on_touch_up(touch) | |
135 | |
136 def open_menu(self, touch, dt): | |
137 self.sharing_wid.open_menu(self, touch) | |
138 del touch.ud['menu_timeout'] | |
139 | |
140 def getMenuChoices(self): | |
141 """return choice adapted to selected item | |
142 | |
143 @return (list[dict]): choices ad expected by ModernMenu | |
144 """ | |
145 return [] | |
146 | |
147 | |
148 class PathWidget(ItemWidget): | |
149 | |
150 def __init__(self, sharing_wid, filepath): | |
151 name = os.path.basename(filepath) | |
152 self.filepath = os.path.normpath(filepath) | |
153 if self.filepath == u'.': | |
154 self.filepath = u'' | |
155 super(PathWidget, self).__init__(sharing_wid, name) | |
156 | |
157 @property | |
158 def is_dir(self): | |
159 raise NotImplementedError | |
160 | |
161 def do_item_action(self, touch): | |
162 if self.is_dir: | |
163 self.sharing_wid.current_dir = self.filepath | |
164 | |
165 def open_menu(self, touch, dt): | |
166 log.debug(_(u"opening menu for {path}").format(path=self.filepath)) | |
167 super(PathWidget, self).open_menu(touch, dt) | |
168 | |
169 | |
170 class LocalPathWidget(PathWidget): | |
171 | |
172 @property | |
173 def is_dir(self): | |
174 return os.path.isdir(self.filepath) | |
175 | |
176 def getMenuChoices(self): | |
177 choices = [] | |
178 if self.shared: | |
179 choices.append(dict(text=_(u'unshare'), | |
180 index=len(choices)+1, | |
181 callback=self.sharing_wid.unshare)) | |
182 else: | |
183 choices.append(dict(text=_(u'share'), | |
184 index=len(choices)+1, | |
185 callback=self.sharing_wid.share)) | |
186 return choices | |
187 | |
188 | |
189 class RemotePathWidget(PathWidget): | |
190 | |
191 def __init__(self, sharing_wid, filepath, type_): | |
192 self.type_ = type_ | |
193 super(RemotePathWidget, self).__init__(sharing_wid, filepath) | |
194 | |
195 @property | |
196 def is_dir(self): | |
197 return self.type_ == C.FILE_TYPE_DIRECTORY | |
198 | |
199 def do_item_action(self, touch): | |
200 if self.is_dir: | |
201 if self.filepath == u'..': | |
202 self.sharing_wid.remote_entity = u'' | |
203 else: | |
204 super(RemotePathWidget, self).do_item_action(touch) | |
205 else: | |
206 self.sharing_wid.request_item(self) | |
207 return True | |
208 | |
209 | |
210 class DeviceWidget(ItemWidget): | |
211 | |
212 def __init__(self, sharing_wid, entity_jid, identities): | |
213 self.entity_jid = entity_jid | |
214 self.identities = identities | |
211
b25d03403898
plugin file sharing: fixed name for service devices
Goffi <goffi@goffi.org>
parents:
206
diff
changeset
|
215 own_jid = next(G.host.profiles.itervalues()).whoami |
b25d03403898
plugin file sharing: fixed name for service devices
Goffi <goffi@goffi.org>
parents:
206
diff
changeset
|
216 self.own_device = entity_jid.bare == own_jid |
b25d03403898
plugin file sharing: fixed name for service devices
Goffi <goffi@goffi.org>
parents:
206
diff
changeset
|
217 if self.own_device: |
b25d03403898
plugin file sharing: fixed name for service devices
Goffi <goffi@goffi.org>
parents:
206
diff
changeset
|
218 name = self.identities.name |
b25d03403898
plugin file sharing: fixed name for service devices
Goffi <goffi@goffi.org>
parents:
206
diff
changeset
|
219 elif self.entity_jid.node: |
b25d03403898
plugin file sharing: fixed name for service devices
Goffi <goffi@goffi.org>
parents:
206
diff
changeset
|
220 name = self.entity_jid.node |
212
38b43ed18bb5
file sharing: use "your server" name when sharing component domain ends with our domain
Goffi <goffi@goffi.org>
parents:
211
diff
changeset
|
221 elif self.entity_jid.domain.endswith(own_jid.domain): |
211
b25d03403898
plugin file sharing: fixed name for service devices
Goffi <goffi@goffi.org>
parents:
206
diff
changeset
|
222 name = _(u"your server") |
b25d03403898
plugin file sharing: fixed name for service devices
Goffi <goffi@goffi.org>
parents:
206
diff
changeset
|
223 else: |
b25d03403898
plugin file sharing: fixed name for service devices
Goffi <goffi@goffi.org>
parents:
206
diff
changeset
|
224 name = _(u"sharing component") |
b25d03403898
plugin file sharing: fixed name for service devices
Goffi <goffi@goffi.org>
parents:
206
diff
changeset
|
225 |
192 | 226 super(DeviceWidget, self).__init__(sharing_wid, name) |
227 | |
206
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
228 def getSymbol(self): |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
229 if self.identities.type == 'desktop': |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
230 return 'desktop' |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
231 elif self.identities.type == 'phone': |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
232 return 'mobile' |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
233 elif self.identities.type == 'web': |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
234 return 'globe' |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
235 elif self.identities.type == 'console': |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
236 return 'terminal' |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
237 else: |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
238 return 'desktop' |
890b48e41998
plugin file sharing: use appropriate symbol when discovering devices
Goffi <goffi@goffi.org>
parents:
205
diff
changeset
|
239 |
192 | 240 def do_item_action(self, touch): |
241 self.sharing_wid.remote_entity = self.entity_jid | |
242 self.sharing_wid.remote_dir = u'' | |
243 | |
244 | |
245 class CategorySeparator(Label): | |
246 pass | |
247 | |
248 | |
249 class Menu(modernmenu.ModernMenu): | |
250 pass | |
251 | |
252 | |
196
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
253 class FileSharing(quick_widgets.QuickWidget, cagou_widget.CagouWidget, FilterBehavior): |
192 | 254 SINGLE=False |
255 float_layout = properties.ObjectProperty() | |
256 layout = properties.ObjectProperty() | |
257 mode = properties.OptionProperty(MODE_LOCAL, options=[MODE_VIEW, MODE_LOCAL]) | |
205
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
258 local_dir = properties.StringProperty(expanduser(u'~')) |
192 | 259 remote_dir = properties.StringProperty(u'') |
260 remote_entity = properties.StringProperty(u'') | |
261 shared_paths = properties.ListProperty() | |
262 signals_registered = False | |
263 | |
264 def __init__(self, host, target, profiles): | |
265 quick_widgets.QuickWidget.__init__(self, host, target, profiles) | |
266 cagou_widget.CagouWidget.__init__(self) | |
196
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
267 FilterBehavior.__init__(self) |
192 | 268 self.mode_btn = ModeBtn(self) |
269 self.mode_btn.bind(on_release=self.change_mode) | |
270 self.headerInputAddExtra(self.mode_btn) | |
271 self.bind(local_dir=self.update_view, | |
272 remote_dir=self.update_view, | |
273 remote_entity=self.update_view) | |
274 self.update_view() | |
275 self.menu = None | |
276 self.menu_item = None | |
277 self.float_layout.bind(children=self.clean_fl_children) | |
278 if not FileSharing.signals_registered: | |
279 # FIXME: we use this hack (registering the signal for the whole class) now | |
280 # as there is currently no unregisterSignal available in bridges | |
217
286f14127f61
plugin file sharing: started to limit line to 90 chars as a test
Goffi <goffi@goffi.org>
parents:
214
diff
changeset
|
281 G.host.registerSignal("FISSharedPathNew", |
286f14127f61
plugin file sharing: started to limit line to 90 chars as a test
Goffi <goffi@goffi.org>
parents:
214
diff
changeset
|
282 handler=FileSharing.shared_path_new, |
286f14127f61
plugin file sharing: started to limit line to 90 chars as a test
Goffi <goffi@goffi.org>
parents:
214
diff
changeset
|
283 iface="plugin") |
286f14127f61
plugin file sharing: started to limit line to 90 chars as a test
Goffi <goffi@goffi.org>
parents:
214
diff
changeset
|
284 G.host.registerSignal("FISSharedPathRemoved", |
286f14127f61
plugin file sharing: started to limit line to 90 chars as a test
Goffi <goffi@goffi.org>
parents:
214
diff
changeset
|
285 handler=FileSharing.shared_path_removed, |
286f14127f61
plugin file sharing: started to limit line to 90 chars as a test
Goffi <goffi@goffi.org>
parents:
214
diff
changeset
|
286 iface="plugin") |
192 | 287 FileSharing.signals_registered = True |
288 G.host.bridge.FISLocalSharesGet(self.profile, | |
289 callback=self.fill_paths, | |
290 errback=G.host.errback) | |
291 | |
292 @property | |
293 def current_dir(self): | |
294 return self.local_dir if self.mode == MODE_LOCAL else self.remote_dir | |
295 | |
296 @current_dir.setter | |
297 def current_dir(self, new_dir): | |
298 if self.mode == MODE_LOCAL: | |
299 self.local_dir = new_dir | |
300 else: | |
301 self.remote_dir = new_dir | |
302 | |
303 def fill_paths(self, shared_paths): | |
304 self.shared_paths.extend(shared_paths) | |
305 | |
306 def change_mode(self, mode_btn): | |
307 self.clear_menu() | |
308 opt = self.__class__.mode.options | |
309 new_idx = (opt.index(self.mode)+1) % len(opt) | |
310 self.mode = opt[new_idx] | |
311 | |
312 def on_mode(self, instance, new_mode): | |
313 self.update_view(None, self.local_dir) | |
314 | |
194
a68c9baa6694
plugin file sharing: use header hint to show current path, and open new path:
Goffi <goffi@goffi.org>
parents:
192
diff
changeset
|
315 def onHeaderInput(self): |
a68c9baa6694
plugin file sharing: use header hint to show current path, and open new path:
Goffi <goffi@goffi.org>
parents:
192
diff
changeset
|
316 if u'/' in self.header_input.text or self.header_input.text == u'~': |
205
9cefc9f8efc9
plugin file sharing: use external storage directory instead of home (which is "/data") on Android when expanding "~"
Goffi <goffi@goffi.org>
parents:
202
diff
changeset
|
317 self.current_dir = expanduser(self.header_input.text) |
194
a68c9baa6694
plugin file sharing: use header hint to show current path, and open new path:
Goffi <goffi@goffi.org>
parents:
192
diff
changeset
|
318 |
196
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
319 def onHeaderInputComplete(self, wid, text, **kwargs): |
192 | 320 """we filter items when text is entered in input box""" |
194
a68c9baa6694
plugin file sharing: use header hint to show current path, and open new path:
Goffi <goffi@goffi.org>
parents:
192
diff
changeset
|
321 if u'/' in text: |
a68c9baa6694
plugin file sharing: use header hint to show current path, and open new path:
Goffi <goffi@goffi.org>
parents:
192
diff
changeset
|
322 return |
196
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
323 self.do_filter(self.layout.children, |
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
324 text, |
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
325 lambda c: c.name, |
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
326 width_cb=lambda c: c.base_width, |
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
327 height_cb=lambda c: c.minimum_height, |
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
328 continue_tests=[lambda c: not isinstance(c, ItemWidget), |
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
329 lambda c: c.name == u'..']) |
519b3a29743c
utils, plugin file sharing: new utils module, with a FilterBehavior:
Goffi <goffi@goffi.org>
parents:
194
diff
changeset
|
330 |
192 | 331 |
332 ## remote sharing callback ## | |
333 | |
334 def _discoFindByFeaturesCb(self, data): | |
335 entities_services, entities_own, entities_roster = data | |
336 for entities_map, title in ((entities_services, | |
337 _(u'services')), | |
338 (entities_own, | |
339 _(u'your devices')), | |
340 (entities_roster, | |
341 _(u'your contacts devices'))): | |
342 if entities_map: | |
343 self.layout.add_widget(CategorySeparator(text=title)) | |
344 for entity_str, entity_ids in entities_map.iteritems(): | |
345 entity_jid = jid.JID(entity_str) | |
346 item = DeviceWidget(self, | |
347 entity_jid, | |
348 Identities(entity_ids)) | |
349 self.layout.add_widget(item) | |
214
6a98d70a3a66
file sharing: display a message when not sharing device has been found
Goffi <goffi@goffi.org>
parents:
213
diff
changeset
|
350 if not entities_services and not entities_own and not entities_roster: |
6a98d70a3a66
file sharing: display a message when not sharing device has been found
Goffi <goffi@goffi.org>
parents:
213
diff
changeset
|
351 self.layout.add_widget(Label( |
6a98d70a3a66
file sharing: display a message when not sharing device has been found
Goffi <goffi@goffi.org>
parents:
213
diff
changeset
|
352 size_hint=(1, 1), |
6a98d70a3a66
file sharing: display a message when not sharing device has been found
Goffi <goffi@goffi.org>
parents:
213
diff
changeset
|
353 halign='center', |
6a98d70a3a66
file sharing: display a message when not sharing device has been found
Goffi <goffi@goffi.org>
parents:
213
diff
changeset
|
354 text_size=self.size, |
6a98d70a3a66
file sharing: display a message when not sharing device has been found
Goffi <goffi@goffi.org>
parents:
213
diff
changeset
|
355 text=_(u"No sharing device found"))) |
192 | 356 |
357 def discover_devices(self): | |
358 """Looks for devices handling file "File Information Sharing" and display them""" | |
359 try: | |
360 namespace = self.host.ns_map['fis'] | |
361 except KeyError: | |
217
286f14127f61
plugin file sharing: started to limit line to 90 chars as a test
Goffi <goffi@goffi.org>
parents:
214
diff
changeset
|
362 msg = _(u"can't find file information sharing namespace, " |
286f14127f61
plugin file sharing: started to limit line to 90 chars as a test
Goffi <goffi@goffi.org>
parents:
214
diff
changeset
|
363 u"is the plugin running?") |
192 | 364 log.warning(msg) |
365 G.host.addNote(_(u"missing plugin"), msg, C.XMLUI_DATA_LVL_ERROR) | |
366 return | |
367 self.host.bridge.discoFindByFeatures( | |
199
b80d275e437f
plugin file sharing: use new local_device argument of discoFindByFeatures
Goffi <goffi@goffi.org>
parents:
198
diff
changeset
|
368 [namespace], [], False, True, True, True, False, self.profile, |
192 | 369 callback=self._discoFindByFeaturesCb, |
370 errback=partial(G.host.errback, | |
371 title=_(u"shared folder error"), | |
372 message=_(u"can't check sharing devices: {msg}"))) | |
373 | |
374 def FISListCb(self, files_data): | |
375 for file_data in files_data: | |
376 filepath = os.path.join(self.current_dir, file_data[u'name']) | |
377 item = RemotePathWidget( | |
378 self, | |
379 filepath=filepath, | |
380 type_=file_data[u'type']) | |
381 self.layout.add_widget(item) | |
382 | |
383 def FISListEb(self, failure_): | |
384 self.remote_dir = u'' | |
385 G.host.addNote( | |
386 _(u"shared folder error"), | |
387 _(u"can't list files for {remote_entity}: {msg}").format( | |
388 remote_entity=self.remote_entity, | |
389 msg=failure_), | |
390 level=C.XMLUI_DATA_LVL_WARNING) | |
391 | |
392 ## view generation ## | |
393 | |
394 def update_view(self, *args): | |
395 """update items according to current mode, entity and dir""" | |
396 log.debug(u'updating {}, {}'.format(self.current_dir, args)) | |
397 self.layout.clear_widgets() | |
398 self.header_input.text = u'' | |
194
a68c9baa6694
plugin file sharing: use header hint to show current path, and open new path:
Goffi <goffi@goffi.org>
parents:
192
diff
changeset
|
399 self.header_input.hint_text = self.current_dir |
a68c9baa6694
plugin file sharing: use header hint to show current path, and open new path:
Goffi <goffi@goffi.org>
parents:
192
diff
changeset
|
400 |
192 | 401 if self.mode == MODE_LOCAL: |
402 filepath = os.path.join(self.local_dir, u'..') | |
403 self.layout.add_widget(LocalPathWidget(sharing_wid=self, filepath=filepath)) | |
213
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
404 try: |
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
405 files = sorted(os.listdir(self.local_dir)) |
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
406 except OSError as e: |
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
407 msg = _(u"can't list files in \"{local_dir}\": {msg}").format( |
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
408 local_dir=self.local_dir, |
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
409 msg=e) |
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
410 G.host.addNote( |
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
411 _(u"shared folder error"), |
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
412 msg, |
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
413 level=C.XMLUI_DATA_LVL_WARNING) |
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
414 self.local_dir = expanduser(u'~') |
423d462ea739
file sharing: catch OS errors while trying to list files on a local dir
Goffi <goffi@goffi.org>
parents:
212
diff
changeset
|
415 return |
192 | 416 for f in files: |
417 filepath = os.path.join(self.local_dir, f) | |
217
286f14127f61
plugin file sharing: started to limit line to 90 chars as a test
Goffi <goffi@goffi.org>
parents:
214
diff
changeset
|
418 self.layout.add_widget(LocalPathWidget(sharing_wid=self, |
286f14127f61
plugin file sharing: started to limit line to 90 chars as a test
Goffi <goffi@goffi.org>
parents:
214
diff
changeset
|
419 filepath=filepath)) |
192 | 420 elif self.mode == MODE_VIEW: |
421 if not self.remote_entity: | |
422 self.discover_devices() | |
423 else: | |
424 # we always a way to go back | |
425 # so user can return to previous list even in case of error | |
426 parent_path = os.path.join(self.remote_dir, u'..') | |
427 item = RemotePathWidget( | |
428 self, | |
429 filepath = parent_path, | |
430 type_ = C.FILE_TYPE_DIRECTORY) | |
431 self.layout.add_widget(item) | |
432 self.host.bridge.FISList( | |
202
e20796eea873
plugin file sharing: transtype jid.Jid instance to unicode when using bridge, to avoid troubles with pb
Goffi <goffi@goffi.org>
parents:
199
diff
changeset
|
433 unicode(self.remote_entity), |
192 | 434 self.remote_dir, |
435 {}, | |
436 self.profile, | |
437 callback=self.FISListCb, | |
438 errback=self.FISListEb) | |
439 | |
440 ## menu methods ## | |
441 | |
442 def clean_fl_children(self, layout, children): | |
443 """insure that self.menu and self.menu_item are None when menu is dimissed""" | |
444 if self.menu is not None and self.menu not in children: | |
445 self.menu = self.menu_item = None | |
446 | |
447 def clear_menu(self): | |
448 """remove menu if there is one""" | |
449 if self.menu is not None: | |
450 self.menu.dismiss() | |
451 self.menu = None | |
452 self.menu_item = None | |
453 | |
454 def open_menu(self, item, touch): | |
455 """open menu for item | |
456 | |
457 @param item(PathWidget): item when the menu has been requested | |
458 @param touch(kivy.input.MotionEvent): touch data | |
459 """ | |
460 if self.menu_item == item: | |
461 return | |
462 self.clear_menu() | |
463 pos = self.to_widget(*touch.pos) | |
464 choices = item.getMenuChoices() | |
465 if not choices: | |
466 return | |
467 self.menu = Menu(choices=choices, | |
468 center=pos, | |
469 size_hint=(None, None)) | |
470 self.float_layout.add_widget(self.menu) | |
471 self.menu.start_display(touch) | |
472 self.menu_item = item | |
473 | |
474 ## Share methods ## | |
475 | |
198
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
476 def do_share(self, entities_jids, item): |
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
477 if entities_jids: |
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
478 access = {u'read': {u'type': 'whitelist', |
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
479 u'jids': entities_jids}} |
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
480 else: |
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
481 access = {} |
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
482 |
192 | 483 G.host.bridge.FISSharePath( |
484 item.name, | |
485 item.filepath, | |
198
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
486 json.dumps(access, ensure_ascii=False), |
192 | 487 self.profile, |
488 callback=lambda name: G.host.addNote( | |
489 _(u"sharing folder"), | |
490 _(u"{name} is now shared").format(name=name)), | |
491 errback=partial(G.host.errback, | |
492 title=_(u"sharing folder"), | |
493 message=_(u"can't share folder: {msg}"))) | |
494 | |
198
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
495 def share(self, menu): |
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
496 item = self.menu_item |
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
497 self.clear_menu() |
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
498 EntitiesSelectorMenu(instructions=SELECT_INSTRUCTIONS, |
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
499 callback=partial(self.do_share, item=item)).show() |
60b63c3e63a1
plugin file sharing: use new EntitiesSelectorMenu to select entities which can access shared files
Goffi <goffi@goffi.org>
parents:
196
diff
changeset
|
500 |
192 | 501 def unshare(self, menu): |
502 item = self.menu_item | |
503 self.clear_menu() | |
504 G.host.bridge.FISUnsharePath( | |
505 item.filepath, | |
506 self.profile, | |
507 callback=lambda: G.host.addNote( | |
508 _(u"sharing folder"), | |
509 _(u"{name} is not shared anymore").format(name=item.name)), | |
510 errback=partial(G.host.errback, | |
511 title=_(u"sharing folder"), | |
512 message=_(u"can't unshare folder: {msg}"))) | |
513 | |
514 def fileJingleRequestCb(self, progress_id, item, dest_path): | |
515 G.host.addNote( | |
516 _(u"file request"), | |
517 _(u"{name} download started at {dest_path}").format( | |
518 name = item.name, | |
519 dest_path = dest_path)) | |
520 | |
521 def request_item(self, item): | |
522 """Retrieve an item from remote entity | |
523 | |
524 @param item(RemotePathWidget): item to retrieve | |
525 """ | |
526 path, name = os.path.split(item.filepath) | |
527 assert name | |
528 assert self.remote_entity | |
529 extra = {'path': path} | |
530 dest_path = files_utils.get_unique_name(os.path.join(G.host.downloads_dir, name)) | |
202
e20796eea873
plugin file sharing: transtype jid.Jid instance to unicode when using bridge, to avoid troubles with pb
Goffi <goffi@goffi.org>
parents:
199
diff
changeset
|
531 G.host.bridge.fileJingleRequest(unicode(self.remote_entity), |
192 | 532 dest_path, |
533 name, | |
534 u'', | |
535 u'', | |
536 extra, | |
537 self.profile, | |
538 callback=partial(self.fileJingleRequestCb, | |
539 item=item, | |
540 dest_path=dest_path), | |
541 errback=partial(G.host.errback, | |
542 title = _(u"file request error"), | |
543 message = _(u"can't request file: {msg}"))) | |
544 | |
545 @classmethod | |
546 def shared_path_new(cls, shared_path, name, profile): | |
547 for wid in G.host.getVisibleList(cls): | |
548 if shared_path not in wid.shared_paths: | |
549 wid.shared_paths.append(shared_path) | |
550 | |
551 @classmethod | |
552 def shared_path_removed(cls, shared_path, profile): | |
553 for wid in G.host.getVisibleList(cls): | |
554 if shared_path in wid.shared_paths: | |
555 wid.shared_paths.remove(shared_path) | |
556 else: | |
557 log.warning(_(u"shared path {path} not found in {widget}".format( | |
558 path = shared_path, widget = wid))) |