|
2
by Rodney Dawes
Import the code |
1 |
#!/usr/bin/python
|
2 |
||
3 |
# ubuntuone-client-applet - Tray icon applet for managing Ubuntu One
|
|
4 |
#
|
|
5 |
# Author: Rodney Dawes <rodney.dawes@canonical.com>
|
|
6 |
#
|
|
7 |
# Copyright 2009 Canonical Ltd.
|
|
8 |
#
|
|
9 |
# This program is free software: you can redistribute it and/or modify it
|
|
10 |
# under the terms of the GNU General Public License version 3, as published
|
|
11 |
# by the Free Software Foundation.
|
|
12 |
#
|
|
13 |
# This program is distributed in the hope that it will be useful, but
|
|
14 |
# WITHOUT ANY WARRANTY; without even the implied warranties of
|
|
15 |
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
|
16 |
# PURPOSE. See the GNU General Public License for more details.
|
|
17 |
#
|
|
18 |
# You should have received a copy of the GNU General Public License along
|
|
19 |
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
20 |
||
21 |
from __future__ import with_statement |
|
22 |
||
23 |
import pygtk |
|
24 |
pygtk.require('2.0') |
|
25 |
import gobject |
|
26 |
import gtk |
|
27 |
import os |
|
28 |
import subprocess |
|
29 |
import sys |
|
|
5.3.3
by Rodrigo Moya
* bin/ubuntuone-client-applet: fixed gettext import and marked missing strings |
30 |
from gettext import gettext as _ |
|
2
by Rodney Dawes
Import the code |
31 |
|
32 |
import dbus.service |
|
33 |
||
34 |
# pylint: disable-msg=F0401
|
|
35 |
import pynotify |
|
36 |
||
37 |
from dbus.exceptions import DBusException |
|
38 |
from dbus.mainloop.glib import DBusGMainLoop |
|
39 |
from canonical.ubuntuone.oauthdesktop.main import Login |
|
40 |
from gobject.option import OptionGroup, OptionParser, make_option |
|
41 |
from xdg.BaseDirectory import xdg_data_home, xdg_config_home |
|
42 |
from urllib import quote |
|
43 |
||
44 |
from canonical.ubuntuone.oauthdesktop.logger import setupLogging |
|
45 |
setupLogging() |
|
46 |
import logging |
|
47 |
logger = logging.getLogger("UbuntuOne.Client.Applet") |
|
48 |
||
49 |
DBusGMainLoop(set_as_default=True) |
|
50 |
||
51 |
# Wait for 30 seconds to get a proper login request
|
|
52 |
LOGIN_TIMEOUT = 30 |
|
53 |
||
54 |
# Prepend tooltip labels with this label
|
|
55 |
TOOLTIP_TITLE = "Ubuntu One: " |
|
56 |
||
57 |
DBUS_IFACE_NAME = "com.ubuntuone.SyncDaemon" |
|
58 |
DBUS_IFACE_SYNC_NAME = "com.ubuntuone.SyncDaemon.SyncDaemon" |
|
59 |
DBUS_IFACE_STATUS_NAME = "com.ubuntuone.SyncDaemon.Status" |
|
60 |
||
61 |
class AppletMain(object): |
|
62 |
"""Main applet process class."""
|
|
63 |
||
64 |
def __init__(self, signup=False, *args, **kw): |
|
65 |
"""Initializes the child threads and dbus monitor."""
|
|
66 |
from twisted.internet import gtk2reactor |
|
67 |
gtk2reactor.install() |
|
68 |
login = Login(dbus.service.BusName("com.ubuntuone.Authentication", |
|
69 |
bus=dbus.SessionBus())) |
|
70 |
||
71 |
self.__signup = signup |
|
72 |
self.__icon = None |
|
73 |
self.__check_id = 0 |
|
74 |
||
75 |
self.__bus = dbus.SessionBus() |
|
76 |
self.__bus.add_signal_receiver( |
|
77 |
handler_function=self.__new_credentials, |
|
78 |
signal_name="NewCredentials", |
|
79 |
dbus_interface="com.ubuntuone.Authentication") |
|
80 |
self.__bus.add_signal_receiver( |
|
81 |
handler_function=self.__auth_denied, |
|
82 |
signal_name="AuthorizationDenied", |
|
83 |
dbus_interface="com.ubuntuone.Authentication") |
|
84 |
||
85 |
def __new_credentials(self, realm=None, consumer_key=None, sender=None): |
|
86 |
"""Signal callback for when we get new credentials."""
|
|
87 |
self.__start_storage_daemon() |
|
88 |
||
89 |
if not self.__icon: |
|
90 |
self.__icon = AppletIcon() |
|
91 |
if self.__check_id > 0: |
|
92 |
gobject.source_remove(self.__check_id) |
|
93 |
if self.__signup: |
|
94 |
self.add_to_autostart() |
|
95 |
||
96 |
def __auth_denied(self): |
|
97 |
"""Signal callback for when auth was denied by user."""
|
|
98 |
def timeout_exit(): |
|
99 |
"""Do the quit on a timeout"""
|
|
100 |
from twisted.internet import reactor |
|
101 |
reactor.stop() |
|
102 |
return False |
|
103 |
||
104 |
self.remove_from_autostart() |
|
105 |
if not self.__signup: |
|
106 |
self.__check_id = gobject.timeout_add_seconds(LOGIN_TIMEOUT, |
|
107 |
timeout_exit) |
|
108 |
||
109 |
def __check_for_token(self): |
|
110 |
"""Method to check for an existing token."""
|
|
111 |
try: |
|
112 |
client = self.__bus.get_object("com.ubuntuone.Authentication", |
|
113 |
"/") |
|
114 |
except DBusException: |
|
115 |
return False |
|
116 |
||
117 |
iface = dbus.Interface(client, "com.ubuntuone.Authentication") |
|
118 |
def handler(): |
|
119 |
"""Simple handler to make dbus do stuff async."""
|
|
120 |
pass
|
|
121 |
||
122 |
iface.maybe_login("https://ubuntuone.com", "ubuntuone", |
|
123 |
self.__signup, |
|
124 |
reply_handler=handler, error_handler=handler) |
|
125 |
return False |
|
126 |
||
127 |
def __start_storage_daemon_maybe(self): |
|
128 |
"""Start the storage daemon."""
|
|
129 |
try: |
|
130 |
client = self.__bus.get_object(DBUS_IFACE_NAME, "/") |
|
131 |
except DBusException: |
|
132 |
return False |
|
133 |
||
134 |
iface = dbus.Interface(client, DBUS_IFACE_SYNC_NAME) |
|
135 |
def handler(data): |
|
136 |
"""Simple handler to make dbus to stuff async."""
|
|
137 |
pass
|
|
138 |
||
139 |
iface.get_rootdir(reply_handler=handler, error_handler=handler) |
|
140 |
return False |
|
141 |
||
142 |
def __start_storage_daemon(self): |
|
143 |
"""Need to call dbus from a idle callback"""
|
|
144 |
gobject.idle_add(self.__start_storage_daemon_maybe) |
|
145 |
||
146 |
def add_to_autostart(self): |
|
147 |
"""Add ourself to the autostart config."""
|
|
148 |
autostart_entry = """[Desktop Entry] |
|
149 |
Name=Ubuntu One
|
|
150 |
Comment=Control applet for Ubuntu One
|
|
151 |
Exec=ubuntuone-client-applet
|
|
152 |
Icon=ubuntuone-client
|
|
153 |
Terminal=false
|
|
154 |
Type=Application
|
|
155 |
X-Ubuntu-Gettext-Domain=ubuntuone-client
|
|
156 |
X-KDE-autostart-after=panel
|
|
157 |
X-GNOME-Autostart-enabled=true
|
|
158 |
"""
|
|
159 |
with open(os.path.join(xdg_config_home, "autostart", |
|
160 |
"ubuntuone-client-applet.desktop"), |
|
161 |
"w+") as f: |
|
162 |
f.write(autostart_entry) |
|
163 |
||
164 |
def remove_from_autostart(self): |
|
165 |
"""Remove ourself from the autostart config."""
|
|
166 |
path = os.path.join(xdg_config_home, "autostart", |
|
167 |
"ubuntuone-client-applet.desktop") |
|
168 |
try: |
|
169 |
os.unlink(path) |
|
170 |
except OSError: |
|
171 |
pass
|
|
172 |
||
173 |
def main(self): |
|
174 |
"""Starts the gtk main loop."""
|
|
175 |
from twisted.internet import reactor |
|
176 |
gobject.idle_add(self.__check_for_token) |
|
177 |
||
178 |
reactor.run() |
|
179 |
||
180 |
||
181 |
def do_xdg_open(path_or_url): |
|
182 |
"""Utility method to run xdg-open with path_or_url."""
|
|
183 |
ret = subprocess.call(["xdg-open", path_or_url]) |
|
184 |
if ret != 0: |
|
185 |
logger.debug("Failed to run 'xdg-open %s'" % path_or_url) |
|
186 |
||
187 |
class AppletIcon(gtk.StatusIcon): |
|
188 |
"""
|
|
189 |
Custom StatusIcon derived from gtk.StatusIcon which supports
|
|
190 |
animated icons and a few other nice things.
|
|
191 |
"""
|
|
192 |
||
193 |
def __init__(self, *args, **kw): |
|
194 |
"""Initializes our custom StatusIcon based widget."""
|
|
195 |
super(AppletIcon, self).__init__(*args, **kw) |
|
196 |
||
197 |
self.__managed_dir = None |
|
198 |
||
199 |
self.__theme = gtk.icon_theme_get_default() |
|
200 |
iconpath = os.path.abspath(os.path.join( |
|
201 |
os.path.split(os.path.dirname(__file__))[0], |
|
202 |
"data")) |
|
203 |
self.__theme.append_search_path(iconpath) |
|
204 |
||
205 |
self.__theme.append_search_path(os.path.sep + os.path.join( |
|
206 |
"usr", "share", "ubuntuone-client", "icons")) |
|
207 |
self.__theme.append_search_path(os.path.sep + os.path.join( |
|
208 |
"usr", "local", "share", "ubuntuone-client", "icons")) |
|
209 |
||
210 |
self.set_from_icon_name('ubuntuone-client') |
|
211 |
self.connect("popup-menu", self.__popup_menu) |
|
212 |
self.connect("activate", self.__open_folder) |
|
213 |
||
214 |
self.__busy = False |
|
215 |
self.__busy_id = 0 |
|
216 |
||
217 |
self.__size = 24 |
|
218 |
self.__pixbuf = None |
|
219 |
||
220 |
self.__vframes = 0 |
|
221 |
self.__hframes = 0 |
|
222 |
self.__vpos = 0 |
|
223 |
self.__hpos = 0 |
|
224 |
||
225 |
self.__size_changed(self, self.__size) |
|
226 |
||
227 |
self.__items = {} |
|
228 |
self.__menu = self.__build_menus() |
|
229 |
||
230 |
self.__connected = False |
|
231 |
self.__need_update = False |
|
232 |
||
233 |
pynotify.init("Ubuntu One") |
|
234 |
||
235 |
self.__bus = dbus.SessionBus() |
|
236 |
||
237 |
self.__bus.add_signal_receiver( |
|
238 |
handler_function=self.__status_changed, |
|
239 |
signal_name="StatusChanged", |
|
240 |
dbus_interface=DBUS_IFACE_STATUS_NAME) |
|
241 |
||
242 |
gobject.idle_add(self.__get_root) |
|
243 |
||
244 |
def __status_changed(self, status): |
|
245 |
"""The sync daemon status changed."""
|
|
246 |
if self.__managed_dir is None: |
|
247 |
gobject.idle_add(self.__get_root) |
|
248 |
if str(status) == "OFFLINE" or str(status).startswith("INIT") or \ |
|
249 |
str(status).startswith("READY"): |
|
250 |
self.set_busy(False) |
|
251 |
self.set_from_icon_name("ubuntuone-client-offline") |
|
|
5.3.3
by Rodrigo Moya
* bin/ubuntuone-client-applet: fixed gettext import and marked missing strings |
252 |
self.set_tooltip(TOOLTIP_TITLE + _("Disconnected")) |
|
2
by Rodney Dawes
Import the code |
253 |
self.__connected = False |
254 |
elif str(status).startswith("IDLE"): |
|
255 |
self.set_busy(False) |
|
256 |
self.set_from_icon_name("ubuntuone-client") |
|
|
5.3.3
by Rodrigo Moya
* bin/ubuntuone-client-applet: fixed gettext import and marked missing strings |
257 |
self.set_tooltip(TOOLTIP_TITLE + _("Idle")) |
|
2
by Rodney Dawes
Import the code |
258 |
self.__connected = True |
259 |
elif str(status) == "BAD_VERSION": |
|
260 |
self.set_busy(False) |
|
261 |
self.set_from_icon_name("ubuntuone-client-offline") |
|
|
5.3.3
by Rodrigo Moya
* bin/ubuntuone-client-applet: fixed gettext import and marked missing strings |
262 |
self.set_tooltip(TOOLTIP_TITLE + _("Update Required")) |
|
2
by Rodney Dawes
Import the code |
263 |
self.__connected = False |
264 |
self.__need_update = True |
|
265 |
self.__items["connect"].set_sensitive(False) |
|
266 |
n = pynotify.Notification( |
|
267 |
"Ubuntu One", |
|
|
5.3.3
by Rodrigo Moya
* bin/ubuntuone-client-applet: fixed gettext import and marked missing strings |
268 |
_("A new client version is required to continue " + |
|
2
by Rodney Dawes
Import the code |
269 |
"using the service. Please click the Ubuntu One" + |
|
5.3.6
by Rodrigo Moya
Fixed misplaced paren |
270 |
"applet icon to upgrade."), |
271 |
"ubuntuone-client-offline") |
|
|
2
by Rodney Dawes
Import the code |
272 |
n.set_urgency(pynotify.URGENCY_CRITICAL) |
273 |
n.show() |
|
274 |
logger.debug("Invalid protocol version. Update needed.") |
|
275 |
elif str(status) == "AUTH_FAILED": |
|
276 |
self.set_busy(False) |
|
277 |
self.set_from_icon_name("ubuntuone-client-offline") |
|
278 |
self.set_tooltip(TOOLTIP_TITLE + "Authentication failed") |
|
279 |
self.__connected = False |
|
280 |
try: |
|
281 |
client = self.__bus.get_object( |
|
282 |
"com.ubuntuone.Authentication", |
|
283 |
"/") |
|
284 |
iface = dbus.Interface(client, |
|
285 |
"com.ubuntuone.Authentication") |
|
286 |
def handler(): |
|
287 |
"""Simple handler to make dbus do stuff async."""
|
|
288 |
return
|
|
289 |
||
290 |
iface.maybe_login("https://ubuntuone.com", |
|
291 |
"ubuntuone", |
|
292 |
True, |
|
293 |
reply_handler=handler, |
|
294 |
error_handler=handler) |
|
295 |
||
296 |
except DBusException, e: |
|
297 |
raise e |
|
298 |
||
299 |
else: |
|
300 |
self.set_busy() |
|
301 |
self.__connected = True |
|
302 |
if str(status).startswith("CONNECTING") or \ |
|
303 |
str(status).startswith("AUTHENTICATING") or \ |
|
304 |
str(status).startswith("CONNECTED"): |
|
|
5.3.3
by Rodrigo Moya
* bin/ubuntuone-client-applet: fixed gettext import and marked missing strings |
305 |
self.set_tooltip(TOOLTIP_TITLE + _("Connecting")) |
|
2
by Rodney Dawes
Import the code |
306 |
elif str(status).startswith("SCANNING") or \ |
307 |
str(status).startswith("READING"): |
|
|
5.3.3
by Rodrigo Moya
* bin/ubuntuone-client-applet: fixed gettext import and marked missing strings |
308 |
self.set_tooltip(TOOLTIP_TITLE + _("Scanning")) |
|
2
by Rodney Dawes
Import the code |
309 |
elif str(status).startswith("WORKING"): |
|
5.3.3
by Rodrigo Moya
* bin/ubuntuone-client-applet: fixed gettext import and marked missing strings |
310 |
self.set_tooltip(TOOLTIP_TITLE + _("Synchronizing")) |
|
2
by Rodney Dawes
Import the code |
311 |
elif str(status).startswith("UNKNOWN_ERROR"): |
312 |
pass
|
|
313 |
else: |
|
|
5.3.3
by Rodrigo Moya
* bin/ubuntuone-client-applet: fixed gettext import and marked missing strings |
314 |
self.set_tooltip(TOOLTIP_TITLE + _("Working")) |
|
2
by Rodney Dawes
Import the code |
315 |
|
316 |
if self.__connected: |
|
317 |
self.__items["connect"].hide() |
|
318 |
self.__items["disconnect"].show() |
|
319 |
else: |
|
320 |
self.__items["connect"].show() |
|
321 |
self.__items["disconnect"].hide() |
|
322 |
||
323 |
def __get_root(self): |
|
324 |
"""Method to get the rootdir from the sync daemon."""
|
|
325 |
# Get the managed root directory
|
|
326 |
try: |
|
327 |
client = self.__bus.get_object(DBUS_IFACE_NAME, "/") |
|
328 |
except DBusException: |
|
329 |
return False |
|
330 |
||
331 |
iface = dbus.Interface(client, DBUS_IFACE_SYNC_NAME) |
|
332 |
def got_root(root): |
|
333 |
"""We got the root dir."""
|
|
334 |
if self.__managed_dir: |
|
335 |
self.__remove_from_places(self.__managed_dir) |
|
336 |
self.__managed_dir = root |
|
337 |
if os.path.isdir(self.__managed_dir) and \ |
|
338 |
os.access(self.__managed_dir, |
|
339 |
os.F_OK | os.R_OK | os.W_OK): |
|
340 |
self.__items["open"].set_sensitive(True) |
|
341 |
self.__add_to_places() |
|
342 |
else: |
|
343 |
self.__items["open"].set_sensitive(False) |
|
344 |
||
345 |
def got_err(error): |
|
346 |
"""Handle error from the dbus callback."""
|
|
347 |
if self.__managed_dir: |
|
348 |
self.__remove_from_places(self.__managed_dir) |
|
349 |
self.__managed_dir = None |
|
350 |
self.__items["open"].set_sensitive(False) |
|
351 |
||
352 |
iface.get_rootdir(reply_handler=got_root, error_handler=got_err) |
|
353 |
||
354 |
# Now get the current status
|
|
355 |
try: |
|
356 |
client = self.__bus.get_object(DBUS_IFACE_NAME, "/status") |
|
357 |
except DBusException: |
|
358 |
return False |
|
359 |
||
360 |
iface = dbus.Interface(client, DBUS_IFACE_STATUS_NAME) |
|
361 |
def status_error(error): |
|
362 |
"""Handle status error."""
|
|
363 |
pass
|
|
364 |
||
365 |
iface.current_status(reply_handler=self.__status_changed, |
|
366 |
error_handler=status_error) |
|
367 |
||
368 |
return False |
|
369 |
||
370 |
def __build_menus(self): |
|
371 |
"""Create the pop-up menu items."""
|
|
372 |
menu = gtk.Menu() |
|
373 |
||
374 |
self.__items["connect"] = gtk.ImageMenuItem(stock_id=gtk.STOCK_CONNECT) |
|
375 |
menu.append(self.__items["connect"]) |
|
376 |
self.__items["connect"].connect("activate", self.__toggle_state) |
|
377 |
self.__items["connect"].show() |
|
378 |
||
379 |
self.__items["disconnect"] = gtk.ImageMenuItem(stock_id=gtk.STOCK_DISCONNECT) |
|
380 |
menu.append(self.__items["disconnect"]) |
|
381 |
self.__items["disconnect"].connect("activate", self.__toggle_state) |
|
382 |
||
383 |
sep = gtk.SeparatorMenuItem() |
|
384 |
menu.append(sep) |
|
385 |
sep.show() |
|
386 |
||
|
5.3.1
by Rodrigo Moya
Added initial support for translations in LP |
387 |
self.__items["bug"] = gtk.MenuItem(label=_("_Report a Problem")) |
|
2
by Rodney Dawes
Import the code |
388 |
menu.append(self.__items["bug"]) |
389 |
self.__items["bug"].connect("activate", self.__open_website, |
|
390 |
"https://bugs.launchpad.net/ubuntuone-client/+filebug") |
|
391 |
self.__items["bug"].show() |
|
392 |
||
|
5.3.1
by Rodrigo Moya
Added initial support for translations in LP |
393 |
self.__items["open"] = gtk.MenuItem(label=_("_Open Folder")) |
|
2
by Rodney Dawes
Import the code |
394 |
menu.append(self.__items["open"]) |
395 |
self.__items["open"].connect("activate", self.__open_folder) |
|
396 |
self.__items["open"].set_sensitive(False) |
|
397 |
self.__items["open"].show() |
|
398 |
||
|
5.3.1
by Rodrigo Moya
Added initial support for translations in LP |
399 |
self.__items["web"] = gtk.MenuItem(label=_("_Go to Web")) |
|
2
by Rodney Dawes
Import the code |
400 |
menu.append(self.__items["web"]) |
401 |
self.__items["web"].connect("activate", self.__open_website) |
|
402 |
self.__items["web"].show() |
|
403 |
||
404 |
sep = gtk.SeparatorMenuItem() |
|
405 |
menu.append(sep) |
|
406 |
sep.show() |
|
407 |
||
408 |
self.__items["quit"] = gtk.ImageMenuItem(stock_id=gtk.STOCK_QUIT) |
|
409 |
menu.append(self.__items["quit"]) |
|
410 |
self.__items["quit"].connect("activate", self.__quit_applet) |
|
411 |
self.__items["quit"].show() |
|
412 |
||
413 |
menu.show() |
|
414 |
||
415 |
return menu |
|
416 |
||
417 |
def __size_changed(self, icon, size, data=None): |
|
418 |
"""Callback for when the size changes."""
|
|
419 |
if size < 24: |
|
420 |
self.__size = 16 |
|
421 |
elif size >= 24 and size < 32: |
|
422 |
self.__size = 24 |
|
423 |
elif size >= 32 and size < 48: |
|
424 |
self.__size = 32 |
|
425 |
elif size >= 48 and size < 64: |
|
426 |
self.__size = 48 |
|
427 |
else: |
|
428 |
self.__size = size |
|
429 |
||
430 |
self.__pixbuf = self.__theme.load_icon( |
|
431 |
'ubuntuone-client-working', |
|
432 |
self.__size, |
|
433 |
gtk.ICON_LOOKUP_GENERIC_FALLBACK) |
|
434 |
||
435 |
self.__hframes = self.__pixbuf.get_width() / self.__size |
|
436 |
self.__vframes = self.__pixbuf.get_height() / self.__size |
|
437 |
||
438 |
return True |
|
439 |
||
440 |
||
441 |
def __spinner_timeout(self): |
|
442 |
"""Timeout callback that spins the spinner."""
|
|
443 |
# This is wrong
|
|
444 |
if not self.__busy: |
|
445 |
return False |
|
446 |
||
447 |
# Skip the first (resting) frame to avoid flicker
|
|
448 |
if self.__hpos == 0 and self.__vpos == 0: |
|
449 |
self.__hpos = 1 |
|
450 |
||
451 |
x = self.__size * self.__hpos |
|
452 |
y = self.__size * self.__vpos |
|
453 |
pixbuf = self.__pixbuf.subpixbuf(x, y, self.__size, self.__size) |
|
454 |
self.set_from_pixbuf(pixbuf) |
|
455 |
||
456 |
self.__hpos += 1 |
|
457 |
if self.__hpos == self.__hframes: |
|
458 |
self.__hpos = 0 |
|
459 |
self.__vpos += 1 |
|
460 |
if self.__vpos >= self.__vframes: |
|
461 |
self.__vpos = 0 |
|
462 |
||
463 |
return True |
|
464 |
||
465 |
def set_busy(self, busy=True): |
|
466 |
if self.__busy and busy: |
|
467 |
return
|
|
468 |
||
469 |
if not busy and self.__busy_id: |
|
470 |
gobject.source_remove(self.__busy_id) |
|
471 |
||
472 |
self.__busy = busy |
|
473 |
self.__busy_id = gobject.timeout_add(100, |
|
474 |
self.__spinner_timeout) |
|
475 |
||
476 |
def __popup_menu(self, icon, button, timestamp, data=None): |
|
477 |
"""Pops up the context menu for the tray icon."""
|
|
478 |
self.__menu.popup(None, None, gtk.status_icon_position_menu, |
|
479 |
button, timestamp, icon) |
|
480 |
||
481 |
def __quit_applet(self, menuitem, data=None): |
|
482 |
"""Disconnects the daemon and closes the applet."""
|
|
483 |
def handler(): |
|
484 |
"""Simple handler to make dbus do stuff async."""
|
|
485 |
pass
|
|
486 |
||
487 |
try: |
|
488 |
client = self.__bus.get_object(DBUS_IFACE_NAME, "/") |
|
489 |
iface = dbus.Interface(client, DBUS_IFACE_SYNC_NAME) |
|
490 |
iface.disconnect(reply_handler=handler, error_handler=handler) |
|
491 |
except DBusException: |
|
492 |
pass
|
|
493 |
||
494 |
from twisted.internet import reactor |
|
495 |
reactor.stop() |
|
496 |
||
497 |
def __toggle_state(self, menuitem, data=None): |
|
498 |
"""Connects or disconnects the storage sync process."""
|
|
499 |
def handler(): |
|
500 |
"""Simple handler to make dbus do stuff async."""
|
|
501 |
pass
|
|
502 |
||
503 |
try: |
|
504 |
client = self.__bus.get_object(DBUS_IFACE_NAME, "/") |
|
505 |
except DBusException: |
|
506 |
return
|
|
507 |
||
508 |
iface = dbus.Interface(client, DBUS_IFACE_SYNC_NAME) |
|
509 |
if self.__connected: |
|
510 |
iface.disconnect(reply_handler=handler, error_handler=handler) |
|
511 |
else: |
|
512 |
iface.connect(reply_handler=handler, error_handler=handler) |
|
513 |
||
514 |
def __open_folder(self, data=None): |
|
515 |
"""Opens the storage folder in the file manager."""
|
|
516 |
if self.__need_update: |
|
517 |
do_xdg_open("apt:ubuntuone-storage-protocol?refresh=yes") |
|
518 |
return
|
|
519 |
||
520 |
if not self.__managed_dir or not os.path.isdir(self.__managed_dir): |
|
521 |
return
|
|
522 |
||
523 |
folder = "file://%s" % quote(self.__managed_dir) |
|
524 |
do_xdg_open(folder) |
|
525 |
||
526 |
def __open_website(self, data=None, url=None): |
|
527 |
"""Opens the ubuntuone.com web site."""
|
|
528 |
if url: |
|
529 |
do_xdg_open(url) |
|
530 |
else: |
|
531 |
do_xdg_open("https://ubuntuone.com/") |
|
532 |
||
533 |
def __add_to_places(self): |
|
534 |
"""Add the managed directory to the .gtk-bookmarks file."""
|
|
535 |
path = os.path.join(os.path.expanduser("~"), ".gtk-bookmarks") |
|
536 |
with open(path, "a+") as f: |
|
537 |
bookmarks_entry = "file://%s %s\n" % ( |
|
538 |
quote(self.__managed_dir), |
|
539 |
os.path.basename(self.__managed_dir)) |
|
540 |
in_file = False |
|
541 |
for line in f: |
|
542 |
if line == bookmarks_entry: |
|
543 |
in_file = True |
|
544 |
if not in_file: |
|
545 |
f.write(bookmarks_entry) |
|
546 |
||
547 |
def __remove_from_places(self, dir): |
|
548 |
"""Remove the old path from the .gtk-bookmarks file."""
|
|
549 |
path = os.path.join(os.path.expanduser("~"), ".gtk-bookmarks") |
|
550 |
with open(path, "a+") as f: |
|
551 |
entry = "file://%s %s\n" % (quote(dir), os.path.basename(dir)) |
|
552 |
lines = [] |
|
553 |
for line in f: |
|
554 |
if line != entry: |
|
555 |
lines.append(line) |
|
556 |
f.truncate(0) |
|
557 |
f.seek(0) |
|
558 |
output = "".join(lines) |
|
559 |
f.write(output) |
|
560 |
||
561 |
||
562 |
if __name__ == "__main__": |
|
563 |
parser = OptionParser("", |
|
564 |
description="Ubuntu One status applet", |
|
565 |
option_list = [ |
|
566 |
make_option("--signup", "-s", |
|
567 |
action="store_true", |
|
568 |
dest="signup", |
|
|
5.3.3
by Rodrigo Moya
* bin/ubuntuone-client-applet: fixed gettext import and marked missing strings |
569 |
help=_("Log in or Sign Up for Ubuntu One")), |
|
2
by Rodney Dawes
Import the code |
570 |
])
|
571 |
options, args = parser.parse_args() |
|
572 |
||
573 |
# Register DBus service for making sure we run only one instance
|
|
574 |
bus = dbus.SessionBus() |
|
575 |
if bus.request_name("com.ubuntuone.ClientApplet", dbus.bus.NAME_FLAG_DO_NOT_QUEUE) == dbus.bus.REQUEST_NAME_REPLY_EXISTS: |
|
|
5.3.3
by Rodrigo Moya
* bin/ubuntuone-client-applet: fixed gettext import and marked missing strings |
576 |
print _("Ubuntu One client applet already running, quitting") |
|
2
by Rodney Dawes
Import the code |
577 |
sys.exit(-1) |
578 |
||
579 |
icon = AppletMain(signup=options.signup) |
|
580 |
icon.main() |