~nataliabidart/ubuntuone-control-panel/better-to-translate

1 by natalia.bidart at canonical
Initial directory structure for new project.
1
# -*- coding: utf-8 -*-
2
3
# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
116.1.6 by eric.casteleijn at canonical
working dbus
4
#          Eric Casteleijn <eric.casteleijn@canonical.com>
1 by natalia.bidart at canonical
Initial directory structure for new project.
5
#
6
# Copyright 2010 Canonical Ltd.
7
#
8
# This program is free software: you can redistribute it and/or modify it
9
# under the terms of the GNU General Public License version 3, as published
10
# by the Free Software Foundation.
11
#
12
# This program is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranties of
14
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15
# PURPOSE.  See the GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License along
18
# with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20
"""The user interface for the control panel for Ubuntu One."""
21
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
22
from __future__ import division
23
1.1.10 by natalia.bidart at canonical
Improved overview screen.
24
import gettext
31.2.3 by Natalia B. Bidart
User can now subcribe and unsubscribe from folders (LP: #689646).
25
import operator
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
26
import os
1.1.10 by natalia.bidart at canonical
Improved overview screen.
27
7.1.5 by natalia.bidart at canonical
app_name is filtered on SSO credentials callbacks.
28
from functools import wraps
29
1.1.10 by natalia.bidart at canonical
Improved overview screen.
30
import dbus
1 by natalia.bidart at canonical
Initial directory structure for new project.
31
import gtk
1.1.3 by natalia.bidart at canonical
Adding several glade files and some implementations. Still rough work.
32
import gobject
3.1.3 by natalia.bidart at canonical
So many improvements that I cna't list them all.
33
import ubuntu_sso
34
116.1.4 by eric.casteleijn at canonical
working though not async
35
from dbus.mainloop.glib import DBusGMainLoop
7.1.3 by natalia.bidart at canonical
Network state is asked at startup. If no connection, the UI gets disabled.
36
from ubuntu_sso import networkstate
3.1.3 by natalia.bidart at canonical
So many improvements that I cna't list them all.
37
from ubuntu_sso.credentials import (TC_URL_KEY, HELP_TEXT_KEY, WINDOW_ID_KEY,
38
    PING_URL_KEY)
39
# No name 'clientdefs' in module 'ubuntuone'
40
# pylint: disable=E0611,F0401
3.1.9 by natalia.bidart at canonical
Quota info is a Loading widget until ready.
41
from gi.repository import GLib
3.1.3 by natalia.bidart at canonical
So many improvements that I cna't list them all.
42
from ubuntuone.clientdefs import (APP_NAME as U1_APP_NAME, TC_URL as U1_TC_URL,
43
    PING_URL as U1_PING_URL, DESCRIPTION as U1_DESCRIPTION)
44
# pylint: enable=E0611,F0401
45
116.1.1 by eric.casteleijn at canonical
added dbus methods and test
46
from ubuntuone.controlpanel.gtk import (
47
    DBUS_IFACE_GUI, DBUS_BUS_NAME as DBUS_BUS_NAME_GUI,
48
    DBUS_PATH as DBUS_PATH_GUI)
70.2.1 by natalia.bidart at canonical
Commenting styling code out to allow UX people to create a proper .rc file
49
from ubuntuone.controlpanel.gtk.widgets import LabelLoading, PanelTitle
36.3.9 by Natalia B. Bidart
Less changes against trunk.
50
# Use ubiquity package when ready (LP: #673665)
51
from ubuntuone.controlpanel.gtk.widgets import GreyableBin
52
3.1.3 by natalia.bidart at canonical
So many improvements that I cna't list them all.
53
from ubuntuone.controlpanel import (DBUS_BUS_NAME, DBUS_PREFERENCES_PATH,
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
54
    DBUS_PREFERENCES_IFACE, backend)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
55
from ubuntuone.controlpanel.backend import (DEVICE_TYPE_PHONE,
35.1.6 by Natalia B. Bidart
After local device removal, show overview panel again.
56
    DEVICE_TYPE_COMPUTER, bool_str)
27.1.4 by Natalia B. Bidart
Made tests pass.
57
from ubuntuone.controlpanel.logger import setup_logging, log_call
121.1.1 by Natalia B. Bidart
Small improvement to show something else besides the generic "Value can not be
58
from ubuntuone.controlpanel.utils import (get_data_file,
59
    ERROR_TYPE, ERROR_MESSAGE)
1 by natalia.bidart at canonical
Initial directory structure for new project.
60
106.1.3 by Natalia B. Bidart
The gtk.Builder instance must set the translation domain as well.
61
from ubuntuone.controlpanel.gtk import package_manager, TRANSLATION_DOMAIN
1.1.2 by natalia.bidart at canonical
Initial setup for GUI.
62
17.1.2 by Natalia B. Bidart
Moved the gui code to a separated gtk module (LP: #673585).
63
logger = setup_logging('gtk.gui')
1.1.3 by natalia.bidart at canonical
Adding several glade files and some implementations. Still rough work.
64
_ = gettext.gettext
65
66
17.1.4 by Natalia B. Bidart
Replaced TODO's with bug reports. Fixed a few XXXs.
67
# To be replaced by values from the theme or Ubuntu One' specific (LP: #673663)
8.1.1 by natalia.bidart at canonical
Fixed a few TODOs (show warning on AccountInfoError, fix label wrapping and
68
ORANGE = '#c95724'
65.1.10 by natalia.bidart at canonical
Warning label is now red and more visible on overview screen.
69
ERROR_COLOR = 'red'
1.1.10 by natalia.bidart at canonical
Improved overview screen.
70
LOADING = _('Loading...')
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
71
VALUE_ERROR = _('Value could not be retrieved.')
121.1.1 by Natalia B. Bidart
Small improvement to show something else besides the generic "Value can not be
72
UNKNOWN_ERROR = _('Unknown error')
65.1.10 by natalia.bidart at canonical
Warning label is now red and more visible on overview screen.
73
WARNING_MARKUP = '<span foreground="%s"><b>%%s</b></span>' % ERROR_COLOR
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
74
KILOBYTES = 1024
41.1.9 by Natalia B. Bidart
Fixed lint issues.
75
NO_OP = lambda *a, **kw: None
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
76
FILE_URI_PREFIX = 'file://'
7.1.2 by natalia.bidart at canonical
The overview panel is gryed out when the SSO window is raised.
77
1 by natalia.bidart at canonical
Initial directory structure for new project.
78
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
79
def error_handler(*args, **kwargs):
80
    """Log errors when calling D-Bus methods in a async way."""
81
    logger.error('Error handler received: %r, %r', args, kwargs)
82
83
116.1.7 by eric.casteleijn at canonical
moved all implementation out of script, added first test, and removed awkward circular reference.
84
def register_service(bus):
85
    """Try to register DBus service for making sure we run only one instance.
86
87
    Return True if succesfully registered, False if already running.
88
    """
89
    name = bus.request_name(DBUS_BUS_NAME_GUI,
90
                                    dbus.bus.NAME_FLAG_DO_NOT_QUEUE)
91
    return name != dbus.bus.REQUEST_NAME_REPLY_EXISTS
92
93
116.1.8 by eric.casteleijn at canonical
some integration testing
94
def publish_service(window=None, switch_to='', alert=False):
95
    """Publish the service on DBus."""
96
    if window is None:
97
        window = ControlPanelWindow(switch_to=switch_to, alert=alert)
98
    return ControlPanelService(window)
99
100
116.1.7 by eric.casteleijn at canonical
moved all implementation out of script, added first test, and removed awkward circular reference.
101
def main(switch_to='', alert=False):
102
    """Hook the DBus listeners and start the main loop."""
103
    DBusGMainLoop(set_as_default=True)
104
    bus = dbus.SessionBus()
105
    if register_service(bus):
106
        publish_service(switch_to=switch_to, alert=alert)
107
    else:
108
        obj = bus.get_object(DBUS_BUS_NAME_GUI, DBUS_PATH_GUI)
109
        service = dbus.Interface(obj, dbus_interface=DBUS_IFACE_GUI)
110
111
        def gui_error_handler(*args, **kwargs):
112
            """Log errors when calling D-Bus methods in a async way."""
113
            logger.error('Error handler received: %r, %r', args, kwargs)
118.1.1 by eric.casteleijn at canonical
fixed issue with wrong main loop
114
            gtk.main_quit()
116.1.7 by eric.casteleijn at canonical
moved all implementation out of script, added first test, and removed awkward circular reference.
115
116
        def gui_reply_handler(*args, **kwargs):
117
            """Exit when done."""
118.1.1 by eric.casteleijn at canonical
fixed issue with wrong main loop
118
            gtk.main_quit()
116.1.7 by eric.casteleijn at canonical
moved all implementation out of script, added first test, and removed awkward circular reference.
119
120
        service.switch_to_alert(
121
            switch_to, alert, reply_handler=gui_reply_handler,
122
            error_handler=gui_error_handler)
123
118.1.1 by eric.casteleijn at canonical
fixed issue with wrong main loop
124
    gtk.main()
116.1.7 by eric.casteleijn at canonical
moved all implementation out of script, added first test, and removed awkward circular reference.
125
126
7.1.5 by natalia.bidart at canonical
app_name is filtered on SSO credentials callbacks.
127
def filter_by_app_name(f):
128
    """Excecute 'f' filtering by app_name."""
129
130
    @wraps(f)
131
    def filter_by_app_name_inner(instance, app_name, *args, **kwargs):
132
        """Execute 'f' only if 'app_name' matches 'U1_APP_NAME'."""
133
        if app_name == U1_APP_NAME:
134
            return f(instance, app_name, *args, **kwargs)
135
        else:
136
            logger.info('%s: ignoring call since received app_name '\
137
                        '"%s" (expected "%s")',
138
                        f.__name__, app_name, U1_APP_NAME)
139
    return filter_by_app_name_inner
140
141
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
142
def on_size_allocate(widget, allocation, label):
50.1.5 by natalia.bidart at canonical
Fised lint warnings.
143
    """Resize labels according to who 'widget' is being resized."""
144
    label.set_size_request(allocation.width - 2, -1)
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
145
146
53.1.2 by Natalia B. Bidart
- Strings tweaking in the UI.
147
@log_call(logger.debug)
46.1.13 by Natalia B. Bidart
URI hook for link buttons opens the browser when a real URL is passed (LP: #704895).
148
def uri_hook(button, uri, *args, **kwargs):
149
    """Open an URI or do nothing if URI is not an URL."""
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
150
    if uri.startswith('http') or uri.startswith(FILE_URI_PREFIX):
46.1.13 by Natalia B. Bidart
URI hook for link buttons opens the browser when a real URL is passed (LP: #704895).
151
        gtk.show_uri(None, uri, gtk.gdk.CURRENT_TIME)
152
153
1.1.2 by natalia.bidart at canonical
Initial setup for GUI.
154
class ControlPanelMixin(object):
1 by natalia.bidart at canonical
Initial directory structure for new project.
155
    """The main interface for the Ubuntu One control panel."""
156
7.1.4 by natalia.bidart at canonical
Started work on management notebook.
157
    def __init__(self, filename=None):
158
        bus = dbus.SessionBus()
159
        try:
160
            obj = bus.get_object(DBUS_BUS_NAME,
161
                                 DBUS_PREFERENCES_PATH,
162
                                 follow_name_owner_changes=True)
163
            iface = DBUS_PREFERENCES_IFACE
164
            self.backend = dbus.Interface(obj, dbus_interface=iface)
165
        except dbus.exceptions.DBusException:
166
            logger.exception('Can not connect to DBus at %r',
167
                             (DBUS_BUS_NAME, DBUS_PREFERENCES_PATH))
168
            raise
1.1.10 by natalia.bidart at canonical
Improved overview screen.
169
1.1.3 by natalia.bidart at canonical
Adding several glade files and some implementations. Still rough work.
170
        if filename is not None:
24.2.3 by Natalia B. Bidart
Draft of "Folders" tab in control panel (LP: #674455).
171
            builder = gtk.Builder()
106.1.3 by Natalia B. Bidart
The gtk.Builder instance must set the translation domain as well.
172
            builder.set_translation_domain(TRANSLATION_DOMAIN)
24.2.3 by Natalia B. Bidart
Draft of "Folders" tab in control panel (LP: #674455).
173
            builder.add_from_file(get_data_file(filename))
174
            builder.connect_signals(self)
1.1.3 by natalia.bidart at canonical
Adding several glade files and some implementations. Still rough work.
175
176
            # untested directly
24.2.3 by Natalia B. Bidart
Draft of "Folders" tab in control panel (LP: #674455).
177
            for obj in builder.get_objects():
1.1.3 by natalia.bidart at canonical
Adding several glade files and some implementations. Still rough work.
178
                name = getattr(obj, 'name', None)
179
                if name is None and isinstance(obj, gtk.Buildable):
180
                    # work around bug lp:507739
181
                    name = gtk.Buildable.get_name(obj)
182
                if name is None:
1.1.8 by natalia.bidart at canonical
Log setup is done using logger module.
183
                    logger.warning("%s has no name (??)", obj)
1.1.3 by natalia.bidart at canonical
Adding several glade files and some implementations. Still rough work.
184
                else:
185
                    setattr(self, name, obj)
186
3.1.3 by natalia.bidart at canonical
So many improvements that I cna't list them all.
187
        logger.debug('%s: started.', self.__class__.__name__)
188
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
189
    def humanize(self, int_bytes):
190
        """Return a human readble string of 'int_bytes'."""
3.1.9 by natalia.bidart at canonical
Quota info is a Loading widget until ready.
191
        return GLib.format_size_for_display(int_bytes)
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
192
8.1.1 by natalia.bidart at canonical
Fixed a few TODOs (show warning on AccountInfoError, fix label wrapping and
193
    def _set_warning(self, message, label):
194
        """Set 'message' as warning in 'label'."""
195
        label.set_markup(WARNING_MARKUP % message)
196
        label.show()
197
1.1.3 by natalia.bidart at canonical
Adding several glade files and some implementations. Still rough work.
198
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
199
class UbuntuOneBin(gtk.VBox):
200
    """A Ubuntu One bin."""
201
202
    TITLE = ''
203
204
    def __init__(self, title=None):
205
        gtk.VBox.__init__(self)
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
206
        self._is_processing = False
207
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
208
        if title is None:
209
            title = self.TITLE
210
50.1.5 by natalia.bidart at canonical
Fised lint warnings.
211
        title = '<span font_size="large">%s</span>' % title
212
        self.title = PanelTitle(markup=title)
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
213
        self.pack_start(self.title, expand=False)
214
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
215
        self.message = LabelLoading(LOADING)
216
        self.pack_start(self.message, expand=False)
217
97.3.1 by Alejandro J. Cura
simplify the PanelTitle; instead of a Label within an EventBox, it will just be a Label
218
        self.connect('size-allocate', on_size_allocate, self.title)
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
219
        self.show_all()
220
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
221
    def _get_is_processing(self):
222
        """Is this panel processing a request?"""
223
        return self._is_processing
224
225
    def _set_is_processing(self, new_value):
226
        """Set if this panel is processing a request."""
227
        if new_value:
228
            self.message.start()
229
            self.set_sensitive(False)
230
        else:
231
            self.message.stop()
232
            self.set_sensitive(True)
233
234
        self._is_processing = new_value
235
236
    is_processing = property(fget=_get_is_processing, fset=_set_is_processing)
237
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
238
    @log_call(logger.debug)
239
    def on_success(self, message=''):
240
        """Use this callback to stop the Loading and show 'message'."""
241
        self.message.stop()
242
        self.message.set_markup(message)
243
244
    @log_call(logger.error)
121.1.1 by Natalia B. Bidart
Small improvement to show something else besides the generic "Value can not be
245
    def on_error(self, message=None, error_dict=None):
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
246
        """Use this callback to stop the Loading and set a warning message."""
121.1.1 by Natalia B. Bidart
Small improvement to show something else besides the generic "Value can not be
247
        if message is None and error_dict is None:
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
248
            message = VALUE_ERROR
121.1.1 by Natalia B. Bidart
Small improvement to show something else besides the generic "Value can not be
249
        elif message is None and error_dict is not None:
250
            error_type = error_dict.get(ERROR_TYPE, UNKNOWN_ERROR)
251
            error_msg = error_dict.get(ERROR_MESSAGE)
252
            if error_msg:
253
                message = "%s (%s: %s)" % (VALUE_ERROR, error_type, error_msg)
254
            else:
255
                message = "%s (%s)" % (VALUE_ERROR, error_type)
256
257
        assert message is not None
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
258
259
        self.message.stop()
260
        self.message.set_markup(WARNING_MARKUP % message)
261
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
262
7.1.1 by natalia.bidart at canonical
Outter window and overview panel; are Greyable Bins.
263
class OverviewPanel(GreyableBin, ControlPanelMixin):
1.1.2 by natalia.bidart at canonical
Initial setup for GUI.
264
    """The overview panel. Introduces Ubuntu One to the not logged user."""
265
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
266
    __gsignals__ = {
267
        'credentials-found': (gobject.SIGNAL_RUN_FIRST,  gobject.TYPE_NONE,
268
                              (gobject.TYPE_BOOLEAN, gobject.TYPE_PYOBJECT)),
269
    }
270
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
271
    CREDENTIALS_ERROR = _('There was a problem while retrieving the '
7.1.3 by natalia.bidart at canonical
Network state is asked at startup. If no connection, the UI gets disabled.
272
        'credentials.')
273
    NETWORK_OFFLINE = _('An internet connection is required to join or sign '
274
        'in to %(app_name)s.')
46.1.13 by Natalia B. Bidart
URI hook for link buttons opens the browser when a real URL is passed (LP: #704895).
275
    CONNECT = _('Connect to Ubuntu One')
90.1.8 by Natalia B. Bidart
s/http/https
276
    LEARN_MORE_LINK = 'https://one.ubuntu.com/'
3.1.5 by natalia.bidart at canonical
Bullet for list is a lable now, instead an image.
277
65.1.2 by natalia.bidart at canonical
Removed all programatically added overview messages building.
278
    def __init__(self, main_window):
7.1.1 by natalia.bidart at canonical
Outter window and overview panel; are Greyable Bins.
279
        GreyableBin.__init__(self)
7.1.4 by natalia.bidart at canonical
Started work on management notebook.
280
        ControlPanelMixin.__init__(self, filename='overview.ui')
7.1.1 by natalia.bidart at canonical
Outter window and overview panel; are Greyable Bins.
281
        self.add(self.itself)
65.1.6 by natalia.bidart at canonical
Bringing back warnings.
282
        self.warning_label.set_text('')
283
        self.warning_label.set_property('xalign', 0.5)
65.1.7 by natalia.bidart at canonical
Overview screen looks better! It even adds a scrollbar if needed ;-)
284
46.1.13 by Natalia B. Bidart
URI hook for link buttons opens the browser when a real URL is passed (LP: #704895).
285
        self.connect_button.set_uri(self.CONNECT)
36.2.8 by Natalia B. Bidart
Link buttons now work, though the linkbutotn on the overview panel is
286
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
287
        self.main_window = main_window
32.1.2 by Natalia B. Bidart
After machine was added, Folders page is shown (LP: #674459).
288
        self._credentials_are_new = False
7.1.3 by natalia.bidart at canonical
Network state is asked at startup. If no connection, the UI gets disabled.
289
        self.show()
3.1.3 by natalia.bidart at canonical
So many improvements that I cna't list them all.
290
35.1.6 by Natalia B. Bidart
After local device removal, show overview panel again.
291
        bus = dbus.SessionBus()
292
        try:
293
            obj = bus.get_object(ubuntu_sso.DBUS_BUS_NAME,
294
                                 ubuntu_sso.DBUS_CREDENTIALS_PATH,
295
                                 follow_name_owner_changes=True)
296
            iface = ubuntu_sso.DBUS_CREDENTIALS_IFACE
297
            self.sso_backend = dbus.Interface(obj, dbus_interface=iface)
298
        except dbus.exceptions.DBusException:
299
            logger.exception('Can not connect to DBus at %r',
300
                             (ubuntu_sso.DBUS_BUS_NAME,
301
                              ubuntu_sso.DBUS_CREDENTIALS_PATH))
302
            raise
3.1.3 by natalia.bidart at canonical
So many improvements that I cna't list them all.
303
17.1.4 by Natalia B. Bidart
Replaced TODO's with bug reports. Fixed a few XXXs.
304
        # Disconnect signals!!! (LP: #673667)
3.1.3 by natalia.bidart at canonical
So many improvements that I cna't list them all.
305
        self.sso_backend.connect_to_signal('CredentialsFound',
306
                                           self.on_credentials_found)
307
        self.sso_backend.connect_to_signal('CredentialsNotFound',
308
                                           self.on_credentials_not_found)
309
        self.sso_backend.connect_to_signal('CredentialsError',
310
                                           self.on_credentials_error)
311
        self.sso_backend.connect_to_signal('AuthorizationDenied',
312
                                           self.on_authorization_denied)
7.1.3 by natalia.bidart at canonical
Network state is asked at startup. If no connection, the UI gets disabled.
313
        kw = dict(result_cb=self.on_network_state_changed)
314
        self.network_manager_state = networkstate.NetworkManagerState(**kw)
315
        self.network_manager_state.find_online_state()
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
316
65.1.6 by natalia.bidart at canonical
Bringing back warnings.
317
    def _set_warning(self, message, label=None):
318
        """Set 'message' as global warning."""
319
        ControlPanelMixin._set_warning(self, message,
320
                                       label=self.warning_label)
321
7.1.2 by natalia.bidart at canonical
The overview panel is gryed out when the SSO window is raised.
322
    def set_property(self, prop_name, new_value):
7.1.8 by natalia.bidart at canonical
More typos fixed.
323
        """Override 'set_property' to disable buttons if prop is 'greyed'."""
7.1.2 by natalia.bidart at canonical
The overview panel is gryed out when the SSO window is raised.
324
        if prop_name == 'greyed':
7.1.3 by natalia.bidart at canonical
Network state is asked at startup. If no connection, the UI gets disabled.
325
            self.set_sensitive(not new_value)
7.1.2 by natalia.bidart at canonical
The overview panel is gryed out when the SSO window is raised.
326
        GreyableBin.set_property(self, prop_name, new_value)
327
7.1.3 by natalia.bidart at canonical
Network state is asked at startup. If no connection, the UI gets disabled.
328
    def set_sensitive(self, value):
329
        """Set the sensitiveness as per 'value'."""
330
        self.join_now_button.set_sensitive(value)
331
        self.connect_button.set_sensitive(value)
332
333
    def get_sensitive(self):
334
        """Return the sensitiveness."""
335
        result = self.join_now_button.get_sensitive() and \
336
                 self.connect_button.get_sensitive()
337
        return result
338
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
339
    def on_join_now_button_clicked(self, *a, **kw):
340
        """User wants to join now."""
341
        settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION,
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
342
                    WINDOW_ID_KEY: str(self.main_window.window.xid),
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
343
                    PING_URL_KEY: U1_PING_URL}
41.1.9 by Natalia B. Bidart
Fixed lint issues.
344
        self.sso_backend.register(U1_APP_NAME, settings,
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
345
            reply_handler=NO_OP, error_handler=error_handler)
7.1.2 by natalia.bidart at canonical
The overview panel is gryed out when the SSO window is raised.
346
        self.set_property('greyed', True)
65.1.6 by natalia.bidart at canonical
Bringing back warnings.
347
        self.warning_label.set_text('')
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
348
349
    def on_connect_button_clicked(self, *a, **kw):
350
        """User wants to connect now."""
351
        settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION,
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
352
                    WINDOW_ID_KEY: str(self.main_window.window.xid),
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
353
                    PING_URL_KEY: U1_PING_URL}
41.1.9 by Natalia B. Bidart
Fixed lint issues.
354
        self.sso_backend.login(U1_APP_NAME, settings,
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
355
            reply_handler=NO_OP, error_handler=error_handler)
7.1.2 by natalia.bidart at canonical
The overview panel is gryed out when the SSO window is raised.
356
        self.set_property('greyed', True)
65.1.6 by natalia.bidart at canonical
Bringing back warnings.
357
        self.warning_label.set_text('')
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
358
90.1.1 by Natalia B. Bidart
Fixed typo on splash screen (LP: #725802).
359
    def on_learn_more_button_clicked(self, *a, **kw):
360
        """User wants to learn more."""
90.1.2 by Natalia B. Bidart
Added test for learn more button.
361
        uri_hook(self.learn_more_button, self.LEARN_MORE_LINK)
90.1.1 by Natalia B. Bidart
Fixed typo on splash screen (LP: #725802).
362
7.1.5 by natalia.bidart at canonical
app_name is filtered on SSO credentials callbacks.
363
    @filter_by_app_name
51.1.1 by Natalia B. Bidart
No more token info logged (LP: #706906).
364
    @log_call(logger.info, with_args=False)
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
365
    def on_credentials_found(self, app_name, credentials):
366
        """SSO backend notifies of credentials found."""
36.2.3 by Natalia B. Bidart
Made the ControlPanel to be a notebook to manage resizing more carefully.
367
        self.set_property('greyed', False)
32.1.2 by Natalia B. Bidart
After machine was added, Folders page is shown (LP: #674459).
368
        self.emit('credentials-found', self._credentials_are_new, credentials)
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
369
7.1.5 by natalia.bidart at canonical
app_name is filtered on SSO credentials callbacks.
370
    @filter_by_app_name
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
371
    @log_call(logger.info)
372
    def on_credentials_not_found(self, app_name):
373
        """SSO backend notifies of credentials not found."""
32.1.2 by Natalia B. Bidart
After machine was added, Folders page is shown (LP: #674459).
374
        self._credentials_are_new = True
7.1.2 by natalia.bidart at canonical
The overview panel is gryed out when the SSO window is raised.
375
        self.set_property('greyed', False)
1.1.3 by natalia.bidart at canonical
Adding several glade files and some implementations. Still rough work.
376
7.1.5 by natalia.bidart at canonical
app_name is filtered on SSO credentials callbacks.
377
    @filter_by_app_name
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
378
    @log_call(logger.error)
3.1.3 by natalia.bidart at canonical
So many improvements that I cna't list them all.
379
    def on_credentials_error(self, app_name, error_dict):
380
        """SSO backend notifies of an error when fetching credentials."""
7.1.2 by natalia.bidart at canonical
The overview panel is gryed out when the SSO window is raised.
381
        self.set_property('greyed', False)
382
        self._set_warning(self.CREDENTIALS_ERROR)
3.1.3 by natalia.bidart at canonical
So many improvements that I cna't list them all.
383
7.1.5 by natalia.bidart at canonical
app_name is filtered on SSO credentials callbacks.
384
    @filter_by_app_name
3.1.3 by natalia.bidart at canonical
So many improvements that I cna't list them all.
385
    @log_call(logger.info)
386
    def on_authorization_denied(self, app_name):
387
        """SSO backend notifies that user refused auth for 'app_name'."""
7.1.2 by natalia.bidart at canonical
The overview panel is gryed out when the SSO window is raised.
388
        self.set_property('greyed', False)
7.1.3 by natalia.bidart at canonical
Network state is asked at startup. If no connection, the UI gets disabled.
389
390
    @log_call(logger.info)
391
    def on_network_state_changed(self, state):
7.1.7 by natalia.bidart at canonical
Fixing a typo.
392
        """Network state is reported."""
89.1.1 by Natalia B. Bidart
If network connection is UNKNOWN, assume that there is an internet connection
393
        msg = ''
7.1.3 by natalia.bidart at canonical
Network state is asked at startup. If no connection, the UI gets disabled.
394
        if state is networkstate.OFFLINE:
395
            msg = self.NETWORK_OFFLINE % {'app_name': U1_APP_NAME}
396
            self.set_sensitive(False)
397
            self._set_warning(msg)
398
        else:
399
            self.set_sensitive(True)
89.1.1 by Natalia B. Bidart
If network connection is UNKNOWN, assume that there is an internet connection
400
            self.warning_label.set_text(msg)
41.1.9 by Natalia B. Bidart
Fixed lint issues.
401
            self.sso_backend.find_credentials(U1_APP_NAME, {},
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
402
                reply_handler=NO_OP, error_handler=error_handler)
1.1.3 by natalia.bidart at canonical
Adding several glade files and some implementations. Still rough work.
403
404
36.3.3 by Natalia B. Bidart
Basic renamings.
405
class DashboardPanel(UbuntuOneBin, ControlPanelMixin):
406
    """The dashboard panel. The user can manage the subscription."""
9.1.2 by natalia.bidart at canonical
Added account info.
407
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
408
    TITLE = _('Welcome to Ubuntu One!')
89.1.2 by Natalia B. Bidart
Minimal tweaks to offline experience.
409
    VALUE_ERROR = _('The information could not be retrieved. '
410
        'Maybe your internet connection is down?')
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
411
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
412
    def __init__(self, main_window=None):
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
413
        UbuntuOneBin.__init__(self)
36.3.3 by Natalia B. Bidart
Basic renamings.
414
        ControlPanelMixin.__init__(self, filename='dashboard.ui')
32.2.7 by Natalia B. Bidart
MAximun size is set using geometry hints.
415
        self.add(self.itself)
9.1.2 by natalia.bidart at canonical
Added account info.
416
        self.show()
417
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
418
        self.is_processing = True
419
9.1.2 by natalia.bidart at canonical
Added account info.
420
        self.backend.connect_to_signal('AccountInfoReady',
421
                                       self.on_account_info_ready)
422
        self.backend.connect_to_signal('AccountInfoError',
423
                                       self.on_account_info_error)
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
424
        self.account.hide()
9.1.2 by natalia.bidart at canonical
Added account info.
425
24.2.3 by Natalia B. Bidart
Draft of "Folders" tab in control panel (LP: #674455).
426
    @log_call(logger.debug)
9.1.2 by natalia.bidart at canonical
Added account info.
427
    def on_account_info_ready(self, info):
428
        """Backend notifies of account info."""
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
429
        self.on_success()
430
431
        for i in (u'name', u'type', u'email'):
9.1.2 by natalia.bidart at canonical
Added account info.
432
            label = getattr(self, '%s_label' % i)
36.2.6 by Natalia B. Bidart
Data within account section is now indented to the right.
433
            label.set_markup('%s' % (info[i]))
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
434
        self.account.show()
9.1.2 by natalia.bidart at canonical
Added account info.
435
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
436
        self.is_processing = False
437
9.1.2 by natalia.bidart at canonical
Added account info.
438
    @log_call(logger.error)
439
    def on_account_info_error(self, error_dict=None):
440
        """Backend notifies of an error when fetching account info."""
89.1.2 by Natalia B. Bidart
Minimal tweaks to offline experience.
441
        self.on_error(message=self.VALUE_ERROR)
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
442
        self.is_processing = False
9.1.2 by natalia.bidart at canonical
Added account info.
443
444
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
445
class VolumesPanel(UbuntuOneBin, ControlPanelMixin):
446
    """The volumes panel."""
24.2.3 by Natalia B. Bidart
Draft of "Folders" tab in control panel (LP: #674455).
447
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
448
    TITLE = _('Select which folders from your cloud you want to sync with '
449
              'this computer')
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
450
    MY_FOLDERS = _('My folders')
451
    ALWAYS_SUBSCRIBED = _('Always in sync!')
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
452
    FREE_SPACE = _('%(free_space)s available storage')
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
453
    NO_VOLUMES = _('No folders to show.')
454
    NAME_NOT_SET = _('[unknown user name]')
82.1.2 by Natalia B. Bidart
Fixed typo.
455
    CONFIRM_MERGE = _('The contents of your cloud folder will be merged with '
82.1.1 by Natalia B. Bidart
- Added warning messsage when user is about to subscribe to an UDF that already
456
                      'your local folder "%(folder_path)s" when subscribing.\n'
457
                      'Do you want to subscribe to this cloud folder?')
85.1.2 by Natalia B. Bidart
Cleanly show the specilal folder of purchased music (LP: #720650).
458
    MUSIC_DISPLAY_NAME = _('Purchased Music')
459
    MUSIC_REAL_PATH = '~/.ubuntuone/Purchased from Ubuntu One'
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
460
461
    MAX_COLS = 8
462
85.1.1 by Natalia B. Bidart
'User' icon for cloud folders list is now 'avatar-default' (LP: #706034).
463
    CONTACT_ICON_NAME = 'avatar-default'
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
464
    FOLDER_ICON_NAME = 'folder'
465
    SHARE_ICON_NAME = 'folder-remote'
85.1.2 by Natalia B. Bidart
Cleanly show the specilal folder of purchased music (LP: #720650).
466
    MUSIC_ICON_NAME = 'audio-x-generic'
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
467
    ROW_HEADER = '<span font_size="large"><b>%s</b></span> ' \
468
                 '<span foreground="grey">%s</span>'
469
    ROOT = '%s - <span foreground="%s" font_size="small">%s</span>'
65.1.1 by natalia.bidart at canonical
Fixing pep8 issue.
470
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
471
    def __init__(self, main_window=None):
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
472
        UbuntuOneBin.__init__(self)
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
473
        ControlPanelMixin.__init__(self, filename='volumes.ui')
32.2.7 by Natalia B. Bidart
MAximun size is set using geometry hints.
474
        self.add(self.itself)
24.2.3 by Natalia B. Bidart
Draft of "Folders" tab in control panel (LP: #674455).
475
        self.show_all()
476
82.1.1 by Natalia B. Bidart
- Added warning messsage when user is about to subscribe to an UDF that already
477
        kw = dict(parent=main_window,
478
                  flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
479
                  type=gtk.MESSAGE_WARNING,
480
                  buttons=gtk.BUTTONS_YES_NO)
481
        self.confirm_dialog = gtk.MessageDialog(**kw)
482
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
483
        # name, subscribed, icon name, show toggle, sensitive, icon size,
484
        # id, path
485
        self._empty_row = ('', False, '', False, False, gtk.ICON_SIZE_MENU,
486
                           None, None)
487
24.2.3 by Natalia B. Bidart
Draft of "Folders" tab in control panel (LP: #674455).
488
        self.backend.connect_to_signal('VolumesInfoReady',
489
                                       self.on_volumes_info_ready)
490
        self.backend.connect_to_signal('VolumesInfoError',
491
                                       self.on_volumes_info_error)
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
492
        self.backend.connect_to_signal('VolumeSettingsChanged',
493
                                       self.on_volume_settings_changed)
494
        self.backend.connect_to_signal('VolumeSettingsChangeError',
495
                                       self.on_volume_settings_change_error)
496
497
    def _process_path(self, path):
498
        """Trim 'path' so the '~' is removed."""
499
        home = os.path.expanduser('~')
85.1.2 by Natalia B. Bidart
Cleanly show the specilal folder of purchased music (LP: #720650).
500
        music_path = os.path.expanduser(self.MUSIC_REAL_PATH)
501
502
        if path == music_path:
503
            result = self.MUSIC_DISPLAY_NAME
504
        else:
505
            result = path.replace(os.path.join(home, ''), '')
506
507
        return result
24.2.3 by Natalia B. Bidart
Draft of "Folders" tab in control panel (LP: #674455).
508
509
    def on_volumes_info_ready(self, info):
510
        """Backend notifies of volumes info."""
50.1.4 by natalia.bidart at canonical
Less differences against trunk.
511
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
512
        self.volumes_store.clear()
31.2.1 by Natalia B. Bidart
Backend now provides change_volume_settings (LP: #689646).
513
        if not info:
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
514
            self.on_success(self.NO_VOLUMES)
31.2.1 by Natalia B. Bidart
Backend now provides change_volume_settings (LP: #689646).
515
            return
31.2.3 by Natalia B. Bidart
User can now subcribe and unsubscribe from folders (LP: #689646).
516
        else:
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
517
            self.on_success()
31.2.1 by Natalia B. Bidart
Backend now provides change_volume_settings (LP: #689646).
518
50.1.7 by natalia.bidart at canonical
Root folder is on top of others.
519
        for name, free_bytes, volumes in info:
61.1.2 by Natalia B. Bidart
Share names are now improved (LP: #716431).
520
            if backend.ControlBackend.NAME_NOT_SET in name:
521
                name = self.NAME_NOT_SET
522
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
523
            if name:
524
                name = name + "'s"
60.2.3 by Natalia B. Bidart
Shares info is now displayed and modifiable.
525
                # we already added user folders, let's add an empty row
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
526
                treeiter = self.volumes_store.append(None, self._empty_row)
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
527
            else:
528
                name = self.MY_FOLDERS
529
530
            free_bytes_args = {'free_space': self.humanize(int(free_bytes))}
531
            row = (self.ROW_HEADER % (name, self.FREE_SPACE % free_bytes_args),
532
                   True, self.CONTACT_ICON_NAME, False, False,
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
533
                   gtk.ICON_SIZE_LARGE_TOOLBAR, None, None)
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
534
            treeiter = self.volumes_store.append(None, row)
535
50.1.7 by natalia.bidart at canonical
Root folder is on top of others.
536
            volumes.sort(key=operator.itemgetter('path'))
537
            for volume in volumes:
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
538
                sensitive = True
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
539
                name = self._process_path(volume[u'path'])
85.1.2 by Natalia B. Bidart
Cleanly show the specilal folder of purchased music (LP: #720650).
540
                icon_name = self.FOLDER_ICON_NAME
61.1.2 by Natalia B. Bidart
Share names are now improved (LP: #716431).
541
542
                is_root = volume[u'type'] == backend.ControlBackend.ROOT_TYPE
543
                is_share = volume[u'type'] == backend.ControlBackend.SHARE_TYPE
60.2.3 by Natalia B. Bidart
Shares info is now displayed and modifiable.
544
545
                if is_root:
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
546
                    sensitive = False
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
547
                    name = self.ROOT % (name, ORANGE, self.ALWAYS_SUBSCRIBED)
61.1.2 by Natalia B. Bidart
Share names are now improved (LP: #716431).
548
                elif is_share:
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
549
                    name = volume[u'name']
85.1.2 by Natalia B. Bidart
Cleanly show the specilal folder of purchased music (LP: #720650).
550
                    icon_name = self.SHARE_ICON_NAME
551
                elif name == self.MUSIC_DISPLAY_NAME:
552
                    icon_name = self.MUSIC_ICON_NAME
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
553
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
554
                row = (name, bool(volume[u'subscribed']), icon_name, True,
555
                       sensitive, gtk.ICON_SIZE_MENU, volume['volume_id'],
556
                       volume[u'path'])
50.1.7 by natalia.bidart at canonical
Root folder is on top of others.
557
60.2.3 by Natalia B. Bidart
Shares info is now displayed and modifiable.
558
                if is_root:  # root should go first!
50.1.7 by natalia.bidart at canonical
Root folder is on top of others.
559
                    self.volumes_store.prepend(treeiter, row)
560
                else:
561
                    self.volumes_store.append(treeiter, row)
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
562
60.2.3 by Natalia B. Bidart
Shares info is now displayed and modifiable.
563
        self.volumes_view.expand_all()
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
564
        self.volumes_view.show_all()
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
565
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
566
        self.is_processing = False
24.2.3 by Natalia B. Bidart
Draft of "Folders" tab in control panel (LP: #674455).
567
568
    @log_call(logger.error)
569
    def on_volumes_info_error(self, error_dict=None):
570
        """Backend notifies of an error when fetching volumes info."""
121.1.1 by Natalia B. Bidart
Small improvement to show something else besides the generic "Value can not be
571
        self.on_error(error_dict=error_dict)
9.1.2 by natalia.bidart at canonical
Added account info.
572
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
573
    @log_call(logger.info)
574
    def on_volume_settings_changed(self, volume_id):
575
        """The settings for 'volume_id' were changed."""
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
576
        self.is_processing = False
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
577
578
    @log_call(logger.error)
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
579
    def on_volume_settings_change_error(self, volume_id, error_dict=None):
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
580
        """The settings for 'volume_id' were not changed."""
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
581
        self.load()
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
582
583
    def on_subscribed_toggled(self, widget, path, *args, **kwargs):
584
        """The user toggled 'widget'."""
585
        treeiter = self.volumes_store.get_iter(path)
586
        volume_id = self.volumes_store.get_value(treeiter, 6)
82.1.1 by Natalia B. Bidart
- Added warning messsage when user is about to subscribe to an UDF that already
587
        volume_path = self.volumes_store.get_value(treeiter, 7)
588
        subscribed = self.volumes_store.get_value(treeiter, 1)
589
590
        response = gtk.RESPONSE_YES
591
        if not subscribed and os.path.exists(volume_path):
592
            self.confirm_dialog.set_markup(self.CONFIRM_MERGE %
593
                                           {'folder_path': volume_path})
594
            response = self.confirm_dialog.run()
595
            self.confirm_dialog.hide()
596
597
        if response == gtk.RESPONSE_YES:
598
            subscribed = not subscribed
599
            self.volumes_store.set_value(treeiter, 1, subscribed)
600
            self.backend.change_volume_settings(volume_id,
601
                {'subscribed': bool_str(subscribed)},
602
                reply_handler=NO_OP, error_handler=error_handler)
603
604
            self.is_processing = True
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
605
61.2.3 by Natalia B. Bidart
Double-cliking on a folder opens the folder in a file manager.
606
    def on_volumes_view_row_activated(self, widget, path, *args, **kwargs):
607
        """The user double clicked on a row."""
608
        treeiter = self.volumes_store.get_iter(path)
609
        volume_path = self.volumes_store.get_value(treeiter, 7)
610
        uri_hook(None, FILE_URI_PREFIX + volume_path)
611
31.2.3 by Natalia B. Bidart
User can now subcribe and unsubscribe from folders (LP: #689646).
612
    def load(self):
613
        """Load the volume list."""
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
614
        self.backend.volumes_info(reply_handler=NO_OP,
615
                                  error_handler=error_handler)
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
616
        self.is_processing = True
50.1.1 by Natalia B. Bidart
Complete redesign of FOlders tab, now called Volumes.
617
618
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
619
class SharesPanel(UbuntuOneBin, ControlPanelMixin):
620
    """The shares panel - NOT IMPLEMENTED YET."""
621
622
    TITLE = _('Manage permissions for shares made to other users.')
623
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
624
    def __init__(self, main_window=None):
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
625
        UbuntuOneBin.__init__(self)
626
        ControlPanelMixin.__init__(self)
627
        self.show_all()
628
        self.on_success('Not implemented yet.')
629
630
631
class Device(gtk.EventBox, ControlPanelMixin):
35.1.6 by Natalia B. Bidart
After local device removal, show overview panel again.
632
    """The device widget."""
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
633
32.2.14 by natalia.bidart at canonical
UI is not disabled while changing setting for a device.
634
    DEVICE_CHANGE_ERROR = _('The settings could not be changed,\n'
635
                            'previous values were restored.')
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
636
    DEVICE_REMOVAL_ERROR = _('The device could not be removed.')
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
637
    REMOVABLE_PREFIX = 'Ubuntu One @ '
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
638
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
639
    def __init__(self, confirm_remove_dialog=None):
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
640
        gtk.EventBox.__init__(self)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
641
        ControlPanelMixin.__init__(self, filename='device.ui')
642
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
643
        self.confirm_dialog = confirm_remove_dialog
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
644
        self._updating = False
32.2.14 by natalia.bidart at canonical
UI is not disabled while changing setting for a device.
645
        self._last_settings = {}
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
646
        self.id = None
35.1.6 by Natalia B. Bidart
After local device removal, show overview panel again.
647
        self.is_local = False
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
648
        self.configurable = False
649
35.1.6 by Natalia B. Bidart
After local device removal, show overview panel again.
650
        self.update(device_id=None, device_name='',
651
                    is_local=False, configurable=False, limit_bandwidth=False,
70.1.3 by Alejandro J. Cura
ui for show_all_notifications
652
                    max_upload_speed=0, max_download_speed=0,
653
                    show_all_notifications=True)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
654
32.2.7 by Natalia B. Bidart
MAximun size is set using geometry hints.
655
        self.add(self.itself)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
656
        self.show()
657
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
658
        self.backend.connect_to_signal('DeviceSettingsChanged',
659
                                       self.on_device_settings_changed)
660
        self.backend.connect_to_signal('DeviceSettingsChangeError',
661
                                       self.on_device_settings_change_error)
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
662
        self.backend.connect_to_signal('DeviceRemoved',
663
                                       self.on_device_removed)
664
        self.backend.connect_to_signal('DeviceRemovalError',
665
                                       self.on_device_removal_error)
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
666
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
667
    def _change_device_settings(self, *args):
668
        """Update backend settings for this device."""
669
        if self._updating:
670
            return
671
32.2.14 by natalia.bidart at canonical
UI is not disabled while changing setting for a device.
672
        # Not disabling the GUI to avoid annyong twitchings
673
        #self.set_sensitive(False)
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
674
        self.warning_label.set_text('')
41.1.9 by Natalia B. Bidart
Fixed lint issues.
675
        self.backend.change_device_settings(self.id, self.__dict__,
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
676
            reply_handler=NO_OP, error_handler=error_handler)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
677
678
    def _block_signals(f):
679
        """Execute 'f' while having the _updating flag set."""
680
681
        # pylint: disable=E0213,W0212,E1102
682
683
        @wraps(f)
684
        def inner(self, *args, **kwargs):
685
            """Execute 'f' while having the _updating flag set."""
686
            old = self._updating
687
            self._updating = True
688
689
            result = f(self, *args, **kwargs)
690
691
            self._updating = old
692
            return result
693
694
        return inner
695
70.1.3 by Alejandro J. Cura
ui for show_all_notifications
696
    on_show_all_notifications_toggled = _change_device_settings
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
697
    on_max_upload_speed_value_changed = _change_device_settings
698
    on_max_download_speed_value_changed = _change_device_settings
699
84.1.1 by Natalia B. Bidart
- Throttling limits are disabled when limit bandwidth is disabled
700
    def on_limit_bandwidth_toggled(self, *args, **kwargs):
701
        """The limit bandwidth checkbox was toggled."""
702
        self.throttling_limits.set_sensitive(self.limit_bandwidth.get_active())
703
        self._change_device_settings()
704
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
705
    def on_remove_clicked(self, widget):
706
        """Remove button was clicked or activated."""
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
707
        response = gtk.RESPONSE_YES
708
        if self.confirm_dialog is not None:
709
            response = self.confirm_dialog.run()
710
            self.confirm_dialog.hide()
711
712
        if response == gtk.RESPONSE_YES:
713
            self.backend.remove_device(self.id,
714
                reply_handler=NO_OP, error_handler=error_handler)
715
            self.set_sensitive(False)
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
716
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
717
    @_block_signals
718
    def update(self, **kwargs):
719
        """Update according to named parameters.
720
721
        Possible settings are:
722
            * device_id (string, not shown to the user)
723
            * device_name (string)
724
            * type (either DEVICE_TYPE_PHONE or DEVICE_TYPE_COMPUTER)
35.1.6 by Natalia B. Bidart
After local device removal, show overview panel again.
725
            * is_local (True/False)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
726
            * configurable (True/False)
727
            * if configurable, the following can be set:
70.1.3 by Alejandro J. Cura
ui for show_all_notifications
728
                * show_all_notifications (True/False)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
729
                * limit_bandwidth (True/False)
730
                * max_upload_speed (bytes)
731
                * max_download_speed (bytes)
732
733
        """
734
        if 'device_id' in kwargs:
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
735
            self.id = kwargs['device_id']
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
736
737
        if 'device_name' in kwargs:
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
738
            name = kwargs['device_name'].replace(self.REMOVABLE_PREFIX, '')
739
            name = '<span font_size="large"><b>%s</b></span>' % name
740
            self.device_name.set_markup(name)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
741
742
        if 'device_type' in kwargs:
743
            dtype = kwargs['device_type']
744
            if dtype in (DEVICE_TYPE_COMPUTER, DEVICE_TYPE_PHONE):
745
                self.device_type.set_from_icon_name(dtype.lower(),
50.2.3 by natalia.bidart at canonical
Lint fix.
746
                    gtk.ICON_SIZE_LARGE_TOOLBAR)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
747
35.1.6 by Natalia B. Bidart
After local device removal, show overview panel again.
748
        if 'is_local' in kwargs:
749
            self.is_local = bool(kwargs['is_local'])
750
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
751
        if 'configurable' in kwargs:
752
            self.configurable = bool(kwargs['configurable'])
84.1.1 by Natalia B. Bidart
- Throttling limits are disabled when limit bandwidth is disabled
753
            self.config_settings.set_visible(self.configurable)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
754
70.1.3 by Alejandro J. Cura
ui for show_all_notifications
755
        if 'show_all_notifications' in kwargs:
756
            value = bool(kwargs['show_all_notifications'])
757
            self.show_all_notifications.set_active(value)
758
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
759
        if 'limit_bandwidth' in kwargs:
84.1.1 by Natalia B. Bidart
- Throttling limits are disabled when limit bandwidth is disabled
760
            enabled = bool(kwargs['limit_bandwidth'])
761
            self.limit_bandwidth.set_active(enabled)
762
            self.throttling_limits.set_sensitive(enabled)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
763
764
        for speed in ('max_upload_speed', 'max_download_speed'):
765
            if speed in kwargs:
766
                value = int(kwargs[speed]) // KILOBYTES
767
                getattr(self, speed).set_value(value)
768
32.2.14 by natalia.bidart at canonical
UI is not disabled while changing setting for a device.
769
        self._last_settings = self.__dict__
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
770
771
    @property
772
    def __dict__(self):
773
        result = {
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
774
            'device_id': self.id,
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
775
            'device_name': self.device_name.get_text(),
776
            'device_type': self.device_type.get_icon_name()[0].capitalize(),
35.1.6 by Natalia B. Bidart
After local device removal, show overview panel again.
777
            'is_local': bool_str(self.is_local),
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
778
            'configurable': bool_str(self.configurable),
70.1.3 by Alejandro J. Cura
ui for show_all_notifications
779
            'show_all_notifications': \
780
                bool_str(self.show_all_notifications.get_active()),
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
781
            'limit_bandwidth': bool_str(self.limit_bandwidth.get_active()),
782
            'max_upload_speed': \
783
                str(self.max_upload_speed.get_value_as_int() * KILOBYTES),
784
            'max_download_speed': \
785
                str(self.max_download_speed.get_value_as_int() * KILOBYTES),
786
        }
787
        return result
788
51.1.1 by Natalia B. Bidart
No more token info logged (LP: #706906).
789
    @log_call(logger.info, with_args=False)
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
790
    def on_device_settings_changed(self, device_id):
791
        """The change of this device settings succeded."""
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
792
        if device_id != self.id:
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
793
            return
794
        self.set_sensitive(True)
795
        self.warning_label.set_text('')
32.2.14 by natalia.bidart at canonical
UI is not disabled while changing setting for a device.
796
        self._last_settings = self.__dict__
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
797
798
    @log_call(logger.error)
799
    def on_device_settings_change_error(self, device_id, error_dict=None):
800
        """The change of this device settings failed."""
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
801
        if device_id != self.id:
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
802
            return
32.2.14 by natalia.bidart at canonical
UI is not disabled while changing setting for a device.
803
        self.update(**self._last_settings)
32.2.8 by Natalia B. Bidart
Change device errors are now handled.
804
        self._set_warning(self.DEVICE_CHANGE_ERROR, self.warning_label)
805
        self.set_sensitive(True)
806
51.1.1 by Natalia B. Bidart
No more token info logged (LP: #706906).
807
    # is safe to log the device_id since it was already removed
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
808
    @log_call(logger.warning)
809
    def on_device_removed(self, device_id):
810
        """The removal of this device succeded."""
811
        if device_id != self.id:
812
            return
813
        self.hide()
814
815
    @log_call(logger.error)
816
    def on_device_removal_error(self, device_id, error_dict=None):
817
        """The removal of this device failed."""
818
        if device_id != self.id:
819
            return
820
        self._set_warning(self.DEVICE_REMOVAL_ERROR, self.warning_label)
821
        self.set_sensitive(True)
822
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
823
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
824
class DevicesPanel(UbuntuOneBin, ControlPanelMixin):
9.1.2 by natalia.bidart at canonical
Added account info.
825
    """The devices panel."""
826
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
827
    __gsignals__ = {
828
        'local-device-removed': (gobject.SIGNAL_RUN_FIRST,
829
                                 gobject.TYPE_NONE, ()),
830
    }
831
66.1.2 by natalia.bidart at canonical
- 'your cloud' replcaed by 'your personal cloud' (LP: #715858).
832
    TITLE = _('The devices connected with your personal cloud are listed '
833
              'below.')
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
834
    NO_DEVICES = _('No devices to show.')
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
835
    CONFIRM_REMOVE = _('Are you sure you want to remove this device '
836
                       'from Ubuntu One?')
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
837
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
838
    def __init__(self, main_window=None):
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
839
        UbuntuOneBin.__init__(self)
9.1.2 by natalia.bidart at canonical
Added account info.
840
        ControlPanelMixin.__init__(self, filename='devices.ui')
32.2.7 by Natalia B. Bidart
MAximun size is set using geometry hints.
841
        self.add(self.itself)
9.1.2 by natalia.bidart at canonical
Added account info.
842
        self.show()
843
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
844
        self._devices = {}
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
845
        kw = dict(parent=main_window,
846
                  flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
847
                  type=gtk.MESSAGE_WARNING,
848
                  buttons=gtk.BUTTONS_YES_NO,
849
                  message_format=self.CONFIRM_REMOVE)
850
        self.confirm_remove_dialog = gtk.MessageDialog(**kw)
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
851
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
852
        self.backend.connect_to_signal('DevicesInfoReady',
853
                                       self.on_devices_info_ready)
854
        self.backend.connect_to_signal('DevicesInfoError',
855
                                       self.on_devices_info_error)
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
856
        self.backend.connect_to_signal('DeviceRemoved',
857
                                       self.on_device_removed)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
858
51.1.1 by Natalia B. Bidart
No more token info logged (LP: #706906).
859
    @log_call(logger.info, with_args=False)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
860
    def on_devices_info_ready(self, info):
861
        """Backend notifies of devices info."""
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
862
        for child in self.devices.get_children():
863
            self.devices.remove(child)
864
865
        if not info:
866
            self.on_success(self.NO_DEVICES)
867
        else:
868
            self.on_success()
869
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
870
        odd_row_color = self.message.style.bg[gtk.STATE_NORMAL]
871
        for i, device_info in enumerate(info):
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
872
            device = Device(confirm_remove_dialog=self.confirm_remove_dialog)
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
873
            device_info['device_name'] = device_info.pop('name', '')
874
            device_info['device_type'] = device_info.pop('type',
875
                                                         DEVICE_TYPE_COMPUTER)
876
            device.update(**device_info)
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
877
878
            if i % 2 == 1:
879
                device.modify_bg(gtk.STATE_NORMAL, odd_row_color)
880
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
881
            self.devices.pack_start(device)
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
882
            self._devices[device.id] = device
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
883
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
884
        self.is_processing = False
885
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
886
    @log_call(logger.error)
887
    def on_devices_info_error(self, error_dict=None):
888
        """Backend notifies of an error when fetching volumes info."""
121.1.1 by Natalia B. Bidart
Small improvement to show something else besides the generic "Value can not be
889
        self.on_error(error_dict=error_dict)
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
890
        self.is_processing = False
32.2.3 by Natalia B. Bidart
IMplementing devices tab.
891
35.1.2 by natalia.bidart at canonical
Devices can now be removed (LP: #691295).
892
    @log_call(logger.warning)
893
    def on_device_removed(self, device_id):
894
        """The removal of a device succeded."""
895
        if device_id in self._devices:
896
            child = self._devices.pop(device_id)
897
            self.devices.remove(child)
898
35.1.6 by Natalia B. Bidart
After local device removal, show overview panel again.
899
            if child.is_local:
900
                self.emit('local-device-removed')
901
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
902
    def load(self):
36.2.3 by Natalia B. Bidart
Made the ControlPanel to be a notebook to manage resizing more carefully.
903
        """Load the device list."""
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
904
        self.backend.devices_info(reply_handler=NO_OP,
905
                                  error_handler=error_handler)
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
906
        self.is_processing = True
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
907
9.1.2 by natalia.bidart at canonical
Added account info.
908
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
909
class InstallPackage(gtk.VBox, ControlPanelMixin):
910
    """A widget to process the install of a package."""
911
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
912
    __gsignals__ = {
913
        'finished': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()),
914
    }
915
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
916
    INSTALL_PACKAGE = _('You need to install the package <i>%(package_name)s'
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
917
                        '</i> in order to enable more sync services.')
102.2.1 by Natalia B. Bidart
- Changing the AspectFrame for a plain Frame to fix the different width issue
918
    INSTALLING = _('Installation of <i>%(package_name)s</i> in progress')
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
919
    FAILED_INSTALL = _('<i>%(package_name)s</i> could not be installed')
920
    SUCCESS_INSTALL = _('<i>%(package_name)s</i> was successfully installed')
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
921
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
922
    def __init__(self, package_name, message=None):
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
923
        gtk.VBox.__init__(self)
924
        ControlPanelMixin.__init__(self, filename='install.ui')
925
        self.add(self.itself)
926
927
        self.package_name = package_name
928
        self.package_manager = package_manager.PackageManager()
929
        self.args = {'package_name': self.package_name}
930
        self.transaction = None
931
932
        self.progress_bar = None
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
933
934
        self.message = message
935
        if self.message is None:
936
            self.message = self.INSTALL_PACKAGE % self.args
937
        self.reset()
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
938
939
        self.show()
940
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
941
    def reset(self):
942
        """Reset this interface."""
943
        children = self.itself.get_children()
944
        if self.progress_bar in children:
945
            self.itself.remove(self.progress_bar)
946
        if self.install_button_box not in children:
947
            self.itself.pack_start(self.install_button_box)
948
        self.install_label.set_markup(self.message)
949
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
950
    @package_manager.inline_callbacks
951
    def on_install_button_clicked(self, button):
952
        """The install button was clicked."""
953
        try:
954
            # create the install transaction
955
            self.transaction = yield self.package_manager.install(
956
                                    self.package_name)
957
76.1.1 by Natalia B. Bidart
Fixing desktopcouch dependencies management.
958
            logger.debug('on_install_button_clicked: transaction is %r',
959
                         self.transaction)
960
            success = package_manager.aptdaemon.enums.EXIT_SUCCESS
961
            if self.transaction == success:
962
                self.on_install_finished(None, self.transaction)
963
                return
964
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
965
            # create the progress bar and pack it to the box
966
            self.progress_bar = package_manager.PackageManagerProgressBar(
967
                                    self.transaction)
968
            self.progress_bar.show()
969
970
            self.itself.remove(self.install_button_box)
971
            self.itself.pack_start(self.progress_bar)
972
973
            self.transaction.connect('finished', self.on_install_finished)
974
            self.install_label.set_markup(self.INSTALLING % self.args)
975
            yield self.transaction.run()
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
976
        except package_manager.aptdaemon.errors.NotAuthorizedError:
977
            self.reset()
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
978
        except:  # pylint: disable=W0702
76.1.1 by Natalia B. Bidart
Fixing desktopcouch dependencies management.
979
            logger.exception('on_install_button_clicked')
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
980
            self._set_warning(self.FAILED_INSTALL % self.args,
981
                              self.install_label)
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
982
            if self.progress_bar is not None:
983
                self.progress_bar.hide()
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
984
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
985
    @log_call(logger.info)
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
986
    def on_install_finished(self, transaction, exit_code):
987
        """The installation finished."""
76.1.1 by Natalia B. Bidart
Fixing desktopcouch dependencies management.
988
        if self.progress_bar is not None:
989
            self.progress_bar.set_sensitive(False)
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
990
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
991
        logger.info('on_install_finished: installation of %r was %r',
992
                    self.package_name, exit_code)
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
993
        if exit_code != package_manager.aptdaemon.enums.EXIT_SUCCESS:
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
994
            if hasattr(transaction, 'error'):
995
                logger.error('transaction failed: %r', transaction.error)
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
996
            self._set_warning(self.FAILED_INSTALL % self.args,
997
                              self.install_label)
998
        else:
999
            self.install_label.set_markup(self.SUCCESS_INSTALL % self.args)
1000
            self.emit('finished')
1001
1002
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1003
class Service(gtk.VBox, ControlPanelMixin):
1004
    """A service."""
1005
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1006
    CHANGE_ERROR = _('The settings could not be changed,\n'
1007
                     'previous values were restored.')
1008
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1009
    def __init__(self, service_id, name,
1010
                 container=None, check_button=None, action_button=None,
1011
                 *args, **kwargs):
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1012
        gtk.VBox.__init__(self)
1013
        ControlPanelMixin.__init__(self)
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1014
        self.id = service_id
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1015
        self.container = container
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1016
        self.check_button = check_button
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1017
        self.action_button = action_button
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1018
1019
        self.warning_label = gtk.Label()
1020
        self.pack_start(self.warning_label, expand=False)
1021
1022
        self.button = gtk.CheckButton(label=name)
36.3.12 by Natalia B. Bidart
DesktopcouchService's now have dependency.
1023
        self.pack_start(self.button, expand=False)
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1024
1025
        self.show_all()
1026
1027
53.1.2 by Natalia B. Bidart
- Strings tweaking in the UI.
1028
class FileSyncService(Service):
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1029
    """The file sync service."""
1030
53.1.2 by Natalia B. Bidart
- Strings tweaking in the UI.
1031
    FILES_SERVICE_NAME = _('File Sync')
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1032
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1033
    def __init__(self, container, check_button, action_button):
53.1.2 by Natalia B. Bidart
- Strings tweaking in the UI.
1034
        Service.__init__(self, service_id='file-sync',
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1035
                         name=self.FILES_SERVICE_NAME,
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1036
                         container=container,
1037
                         check_button=check_button,
1038
                         action_button=action_button)
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1039
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1040
        self.container.set_sensitive(False)
41.1.9 by Natalia B. Bidart
Fixed lint issues.
1041
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1042
        self.backend.connect_to_signal('FileSyncStatusChanged',
1043
                                       self.on_file_sync_status_changed)
1044
        self.backend.connect_to_signal('FilesEnabled', self.on_files_enabled)
1045
        self.backend.connect_to_signal('FilesDisabled', self.on_files_disabled)
41.1.9 by Natalia B. Bidart
Fixed lint issues.
1046
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
1047
        self.backend.file_sync_status(reply_handler=NO_OP,
1048
                                      error_handler=error_handler)
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1049
1050
    @log_call(logger.debug)
1051
    def on_file_sync_status_changed(self, status):
53.1.2 by Natalia B. Bidart
- Strings tweaking in the UI.
1052
        """File Sync status changed."""
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1053
        enabled = status != backend.FILE_SYNC_DISABLED
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1054
        logger.info('FileSyncService: enabled? %r', enabled)
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1055
        self.check_button.set_active(enabled)
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1056
        # if service is disabled, disable the action_button
1057
        self.action_button.set_sensitive(enabled)
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1058
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1059
        if not self.container.is_sensitive():
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1060
            # first time we're getting this event
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1061
            self.check_button.connect('toggled', self.on_button_toggled)
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1062
            self.container.set_sensitive(True)
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1063
1064
    def on_files_enabled(self):
1065
        """Files service was enabled."""
1066
        self.on_file_sync_status_changed('enabled!')
1067
1068
    def on_files_disabled(self):
1069
        """Files service was disabled."""
1070
        self.on_file_sync_status_changed(backend.FILE_SYNC_DISABLED)
1071
1072
    @log_call(logger.debug)
1073
    def on_button_toggled(self, button):
1074
        """Button was toggled, exclude/replicate the service properly."""
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1075
        logger.info('File Sync enabled? %r', self.check_button.get_active())
1076
        if self.check_button.get_active():
41.1.9 by Natalia B. Bidart
Fixed lint issues.
1077
            self.backend.enable_files(reply_handler=NO_OP,
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
1078
                                      error_handler=error_handler)
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1079
        else:
41.1.9 by Natalia B. Bidart
Fixed lint issues.
1080
            self.backend.disable_files(reply_handler=NO_OP,
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
1081
                                       error_handler=error_handler)
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1082
1083
1084
class DesktopcouchService(Service):
36.3.6 by Natalia B. Bidart
Basic dc install works.
1085
    """A desktopcouch service."""
1086
102.2.4 by Natalia B. Bidart
Changed legend for plugin/extension installs.
1087
    INSTALL_PACKAGE = _('Install the %(plugin_name)s '
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1088
                        'for %(service_name)s sync')
1089
1090
    def __init__(self, service_id, name, enabled,
1091
                 container, check_button,
1092
                 dependency=None, dependency_name=None):
1093
        Service.__init__(self, service_id, name,
1094
                         container, check_button, action_button=None)
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1095
1096
        self.backend.connect_to_signal('ReplicationSettingsChanged',
41.1.8 by natalia.bidart at canonical
Tests pass. GUI code updated to user backend.
1097
            self.on_replication_settings_changed)
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1098
        self.backend.connect_to_signal('ReplicationSettingsChangeError',
41.1.8 by natalia.bidart at canonical
Tests pass. GUI code updated to user backend.
1099
            self.on_replication_settings_change_error)
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1100
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1101
        self.check_button.set_active(enabled)
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1102
36.3.12 by Natalia B. Bidart
DesktopcouchService's now have dependency.
1103
        self.dependency = None
1104
        if dependency is not None:
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1105
            if dependency_name is None:
1106
                dependency_name = dependency
1107
            args = {'plugin_name': dependency_name, 'service_name': service_id}
1108
            message = self.INSTALL_PACKAGE % args
1109
            self.dependency = InstallPackage(dependency, message)
36.3.12 by Natalia B. Bidart
DesktopcouchService's now have dependency.
1110
            self.dependency.connect('finished', self.on_depedency_finished)
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1111
1112
            self.container.pack_end(self.dependency, expand=False)
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1113
            self.check_button.set_sensitive(False)
36.3.12 by Natalia B. Bidart
DesktopcouchService's now have dependency.
1114
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1115
        self.check_button.connect('toggled', self.on_button_toggled)
36.3.6 by Natalia B. Bidart
Basic dc install works.
1116
36.3.12 by Natalia B. Bidart
DesktopcouchService's now have dependency.
1117
    def on_depedency_finished(self, widget):
1118
        """The dependency was installed."""
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1119
        self.check_button.set_sensitive(True)
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1120
        self.container.remove(self.dependency)
36.3.14 by Natalia B. Bidart
Install widget is removed once the dependency has been installed.
1121
        self.dependency = None
36.3.12 by Natalia B. Bidart
DesktopcouchService's now have dependency.
1122
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1123
    @log_call(logger.debug)
36.3.6 by Natalia B. Bidart
Basic dc install works.
1124
    def on_button_toggled(self, button):
1125
        """Button was toggled, exclude/replicate the service properly."""
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1126
        logger.info('Starting replication for %r? %r',
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1127
                    self.id, self.check_button.get_active())
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1128
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1129
        args = {'enabled': bool_str(self.check_button.get_active())}
41.1.9 by Natalia B. Bidart
Fixed lint issues.
1130
        self.backend.change_replication_settings(self.id, args,
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
1131
            reply_handler=NO_OP, error_handler=error_handler)
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1132
1133
    @log_call(logger.info)
1134
    def on_replication_settings_changed(self, replication_id):
1135
        """The change of settings for this replication succeded."""
1136
        if replication_id != self.id:
1137
            return
1138
        self.warning_label.set_text('')
1139
1140
    @log_call(logger.error)
1141
    def on_replication_settings_change_error(self, replication_id,
1142
                                             error_dict=None):
1143
        """The change of settings for this replication failed."""
1144
        if replication_id != self.id:
1145
            return
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1146
        self.check_button.set_active(not self.check_button.get_active())
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1147
        self._set_warning(self.CHANGE_ERROR, self.warning_label)
36.3.6 by Natalia B. Bidart
Basic dc install works.
1148
1149
36.3.3 by Natalia B. Bidart
Basic renamings.
1150
class ServicesPanel(UbuntuOneBin, ControlPanelMixin):
1151
    """The services panel."""
9.1.2 by natalia.bidart at canonical
Added account info.
1152
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1153
    TITLE = _('Enable the sync services for this computer.')
41.1.4 by Natalia B. Bidart
More on replications.
1154
    DESKTOPCOUCH_PKG = 'desktopcouch-ubuntuone'
102.2.4 by Natalia B. Bidart
Changed legend for plugin/extension installs.
1155
    BOOKMARKS = _('Firefox extension')
102.2.5 by Natalia B. Bidart
Spelled "plu-ing".
1156
    CONTACTS = _('Evolution plug-in')
36.3.16 by Natalia B. Bidart
Handling ValueError when creating the replicationExclusion instance.
1157
    NO_PAIRING_RECORD = _('There is no Ubuntu One pairing record.')
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1158
    CONTACTS_LINK = 'https://one.ubuntu.com/'
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
1159
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
1160
    def __init__(self, main_window=None):
24.2.6 by Natalia B. Bidart
Foreground colors for labels on status bar are not set to white.
1161
        UbuntuOneBin.__init__(self)
36.3.3 by Natalia B. Bidart
Basic renamings.
1162
        ControlPanelMixin.__init__(self, filename='services.ui')
32.2.7 by Natalia B. Bidart
MAximun size is set using geometry hints.
1163
        self.add(self.itself)
36.3.6 by Natalia B. Bidart
Basic dc install works.
1164
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1165
        self.plugin_names = {'contacts': self.CONTACTS,
88.1.3 by Natalia B. Bidart
Service names are mapping to translatable names when possible (LP: #728027).
1166
                              'bookmarks': self.BOOKMARKS}
1167
36.3.6 by Natalia B. Bidart
Basic dc install works.
1168
        self.package_manager = package_manager.PackageManager()
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
1169
        self.install_box = None
41.1.8 by natalia.bidart at canonical
Tests pass. GUI code updated to user backend.
1170
1171
        self.backend.connect_to_signal('ReplicationsInfoReady',
1172
                                       self.on_replications_info_ready)
1173
        self.backend.connect_to_signal('ReplicationsInfoError',
1174
                                       self.on_replications_info_error)
36.3.6 by Natalia B. Bidart
Basic dc install works.
1175
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1176
        self.file_sync_service = FileSyncService(container=self.files,
1177
            check_button=self.file_sync_check,
1178
            action_button=self.file_sync_button)
36.3.11 by Natalia B. Bidart
Moving stuff out of test_gui since lint complains of too many lines in module.
1179
9.1.2 by natalia.bidart at canonical
Added account info.
1180
        self.show()
1181
41.1.8 by natalia.bidart at canonical
Tests pass. GUI code updated to user backend.
1182
    @property
1183
    def has_desktopcouch(self):
1184
        """Is desktopcouch installed?"""
1185
        return self.package_manager.is_installed(self.DESKTOPCOUCH_PKG)
1186
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1187
    def on_file_sync_button_clicked(self, *args, **kwargs):
1188
        """The "Show me my U1 folder" button was clicked.
1189
1190
        XXX: this should be part of the FileSyncService widget.
1191
        XXX: the Ubuntu One folder should be the user's root.
1192
1193
        """
1194
        uri_hook(None, FILE_URI_PREFIX + os.path.expanduser('~/Ubuntu One'))
1195
1196
    def on_contacts_button_clicked(self, *args, **kwargs):
1197
        """The "Take me to the Ubuntu One website" button was clicked.
1198
1199
        XXX: this should be part of the DesktopcouchService widget.
1200
1201
        """
1202
        uri_hook(None, self.CONTACTS)
1203
1204
    def on_bookmarks_button_clicked(self, *args, **kwargs):
1205
        """The bookmarks button was clicked.
1206
1207
        XXX: this should be part of the DesktopcouchService widget.
1208
1209
        """
1210
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1211
    @log_call(logger.debug)
1212
    def load(self):
36.3.6 by Natalia B. Bidart
Basic dc install works.
1213
        """Load info."""
121.1.1 by Natalia B. Bidart
Small improvement to show something else besides the generic "Value can not be
1214
        self.replications.hide()
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
1215
        if self.install_box is not None:
1216
            self.itself.remove(self.install_box)
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1217
            self.install_box = None
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
1218
41.1.8 by natalia.bidart at canonical
Tests pass. GUI code updated to user backend.
1219
        logger.info('load: has_desktopcouch? %r', self.has_desktopcouch)
36.3.6 by Natalia B. Bidart
Basic dc install works.
1220
        if not self.has_desktopcouch:
1221
            self.message.set_text('')
36.3.7 by Natalia B. Bidart
Move install widget to a separated widget for further reuse.
1222
1223
            self.install_box = InstallPackage(self.DESKTOPCOUCH_PKG)
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1224
            self.install_box.connect('finished', self.load_replications)
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1225
            self.itself.pack_end(self.install_box, expand=False)
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1226
            self.itself.reorder_child(self.install_box, 0)
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1227
        else:
1228
            self.load_replications()
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1229
1230
        self.message.stop()
1231
1232
    @log_call(logger.debug)
1233
    def load_replications(self, *args):
1234
        """Load replications info."""
41.1.8 by natalia.bidart at canonical
Tests pass. GUI code updated to user backend.
1235
        # ask replications to the backend
1236
        self.message.start()
41.1.9 by Natalia B. Bidart
Fixed lint issues.
1237
        self.backend.replications_info(reply_handler=NO_OP,
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
1238
                                       error_handler=error_handler)
41.1.8 by natalia.bidart at canonical
Tests pass. GUI code updated to user backend.
1239
1240
    @log_call(logger.debug)
1241
    def on_replications_info_ready(self, info):
1242
        """The replication info is ready."""
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1243
        self.on_success()
41.1.8 by natalia.bidart at canonical
Tests pass. GUI code updated to user backend.
1244
36.3.8 by Natalia B. Bidart
Adding file sync enable/disable to teh backend.
1245
        self.replications.show()
1246
1247
        if self.install_box is not None:
1248
            self.itself.remove(self.install_box)
1249
            self.install_box = None
1250
41.1.8 by natalia.bidart at canonical
Tests pass. GUI code updated to user backend.
1251
        for item in info:
1252
            pkg = item['dependency']
76.1.1 by Natalia B. Bidart
Fixing desktopcouch dependencies management.
1253
            if not pkg or self.package_manager.is_installed(pkg):
1254
                pkg = None
88.1.3 by Natalia B. Bidart
Service names are mapping to translatable names when possible (LP: #728027).
1255
1256
            sid = item['replication_id']
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1257
            container = getattr(self, sid, None)
91.2.2 by Natalia B. Bidart
Main redesing of services tab, no functionality yet.
1258
            check_button = getattr(self, '%s_check' % sid, None)
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1259
            name = self.plugin_names.get(sid, None)
1260
            child = DesktopcouchService(service_id=sid, name=item['name'],
1261
                enabled=bool(item['enabled']), container=container,
1262
                check_button=check_button,
1263
                dependency=pkg, dependency_name=name)
1264
            setattr(self, '%s_service' % sid, child)
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1265
1266
    @log_call(logger.error)
41.1.8 by natalia.bidart at canonical
Tests pass. GUI code updated to user backend.
1267
    def on_replications_info_error(self, error_dict=None):
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1268
        """The replication info can not be retrieved."""
41.1.9 by Natalia B. Bidart
Fixed lint issues.
1269
        if error_dict is not None and \
1270
           error_dict.get('error_type', None) == 'NoPairingRecord':
1271
            self.on_error(self.NO_PAIRING_RECORD)
1272
        else:
121.1.1 by Natalia B. Bidart
Small improvement to show something else besides the generic "Value can not be
1273
            self.on_error(error_dict=error_dict)
41.1.7 by Natalia B. Bidart
Replication client is now implemented and handles ValueError.
1274
1275
46.1.4 by natalia.bidart at canonical
Remove not-related changes.
1276
class FileSyncStatus(gtk.HBox, ControlPanelMixin):
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1277
    """A file sync status widget."""
1278
53.1.2 by Natalia B. Bidart
- Strings tweaking in the UI.
1279
    FILE_SYNC_DISABLED = _('File Sync is disabled.')
1280
    FILE_SYNC_STARTING = _('File Sync starting...')
1281
    FILE_SYNC_STOPPED = _('File Sync is stopped.')
1282
    FILE_SYNC_DISCONNECTED = _('File Sync is disconnected.')
1283
    FILE_SYNC_SYNCING = _('File Sync in progress...')
1284
    FILE_SYNC_IDLE = _('File Sync is up-to-date.')
1285
    FILE_SYNC_ERROR = _('File Sync error.')
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1286
1287
    CONNECT = _('Connect')
1288
    DISCONNECT = _('Disconnect')
1289
    ENABLE = _('Enable')
1290
    RESTART = _('Restart')
1291
    START = _('Start')
1292
    STOP = _('Stop')
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
1293
71.1.2 by Chris McGinlay
Added tooltip strings for enable/disable/start/stop sync states along with testcases
1294
    CONNECT_TOOLTIP = _('Connect the file sync service '
1295
                        'with your personal cloud')
1296
    DISCONNECT_TOOLTIP = _('Disconnect the file sync service '
1297
                           'from your personal cloud')
1298
    ENABLE_TOOLTIP = _('Enable the file sync service')
1299
    RESTART_TOOLTIP = _('Restart the file sync service')
1300
    START_TOOLTIP = _('Start the file sync service')
1301
    STOP_TOOLTIP = _('Stop the file sync service')
71.1.1 by Chris McGinlay
modified:
1302
7.1.4 by natalia.bidart at canonical
Started work on management notebook.
1303
    def __init__(self):
46.1.4 by natalia.bidart at canonical
Remove not-related changes.
1304
        gtk.HBox.__init__(self)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1305
        ControlPanelMixin.__init__(self)
1306
70.2.1 by natalia.bidart at canonical
Commenting styling code out to allow UX people to create a proper .rc file
1307
        self.label = LabelLoading(LOADING)
82.2.1 by natalia.bidart at canonical
- Quota usage is now red when user is over quota (LP: #701729).
1308
        self.pack_start(self.label, expand=True)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1309
46.1.8 by Natalia B. Bidart
Added a button to file sync status manage the files service (LP: #693373).
1310
        self.button = gtk.LinkButton(uri='')
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1311
        self.button.connect('clicked', self._on_button_clicked)
1312
        self.pack_start(self.button, expand=False)
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
1313
27.1.1 by Natalia B. Bidart
Started work on file sync status retrieval and display.
1314
        self.backend.connect_to_signal('FileSyncStatusDisabled',
1315
                                       self.on_file_sync_status_disabled)
1316
        self.backend.connect_to_signal('FileSyncStatusStarting',
1317
                                       self.on_file_sync_status_starting)
46.1.10 by Natalia B. Bidart
Adding stop management.
1318
        self.backend.connect_to_signal('FileSyncStatusStopped',
1319
                                       self.on_file_sync_status_stopped)
27.1.4 by Natalia B. Bidart
Made tests pass.
1320
        self.backend.connect_to_signal('FileSyncStatusDisconnected',
1321
                                       self.on_file_sync_status_disconnected)
27.1.7 by Natalia B. Bidart
Cleaning up logging messages.
1322
        self.backend.connect_to_signal('FileSyncStatusSyncing',
1323
                                       self.on_file_sync_status_syncing)
27.1.1 by Natalia B. Bidart
Started work on file sync status retrieval and display.
1324
        self.backend.connect_to_signal('FileSyncStatusIdle',
1325
                                       self.on_file_sync_status_idle)
1326
        self.backend.connect_to_signal('FileSyncStatusError',
27.1.5 by Natalia B. Bidart
Code done! now some real testing.
1327
                                       self.on_file_sync_status_error)
46.1.10 by Natalia B. Bidart
Adding stop management.
1328
        self.backend.connect_to_signal('FilesStartError',
1329
                                       self.on_files_start_error)
27.1.1 by Natalia B. Bidart
Started work on file sync status retrieval and display.
1330
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1331
        self.backend.file_sync_status(reply_handler=NO_OP,
1332
                                      error_handler=error_handler)
1333
        self.show_all()
1334
71.1.1 by Chris McGinlay
modified:
1335
    def _update_status(self, msg, action, callback,
71.1.2 by Chris McGinlay
Added tooltip strings for enable/disable/start/stop sync states along with testcases
1336
                       icon=None, color=None, tooltip=None):
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1337
        """Update the status info."""
46.1.3 by natalia.bidart at canonical
Adding icons to file status label.
1338
        if icon is not None:
1339
            foreground = '' if color is None else 'foreground="%s"' % color
1340
            msg = '<span %s>%s</span> %s' % (foreground, icon, msg)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1341
        self.label.set_markup(msg)
1342
        self.label.stop()
1343
1344
        self.button.set_label(action)
46.1.13 by Natalia B. Bidart
URI hook for link buttons opens the browser when a real URL is passed (LP: #704895).
1345
        self.button.set_uri(action)
46.1.10 by Natalia B. Bidart
Adding stop management.
1346
        self.button.set_sensitive(True)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1347
        self.button.set_data('callback', callback)
71.1.1 by Chris McGinlay
modified:
1348
        if tooltip is not None:
1349
            self.button.set_tooltip_text(tooltip)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1350
1351
    def _on_button_clicked(self, button):
1352
        """Button was clicked, act accordingly the label."""
46.1.9 by Natalia B. Bidart
WAITING is not an unknown state but a starting state.
1353
        button.set_visited(False)
46.1.10 by Natalia B. Bidart
Adding stop management.
1354
        button.set_sensitive(False)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1355
        button.get_data('callback')(button)
1356
1357
    @log_call(logger.info)
1358
    def on_file_sync_status_disabled(self, msg):
1359
        """Backend notifies of file sync status being disabled."""
1360
        self._update_status(self.FILE_SYNC_DISABLED,
46.1.3 by natalia.bidart at canonical
Adding icons to file status label.
1361
                            self.ENABLE, self.on_enable_clicked,
71.1.2 by Chris McGinlay
Added tooltip strings for enable/disable/start/stop sync states along with testcases
1362
                            '✘', 'red', self.ENABLE_TOOLTIP)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1363
1364
    @log_call(logger.info)
1365
    def on_file_sync_status_starting(self, msg):
1366
        """Backend notifies of file sync status being starting."""
1367
        self._update_status(self.FILE_SYNC_STARTING,
46.1.3 by natalia.bidart at canonical
Adding icons to file status label.
1368
                            self.STOP, self.on_stop_clicked,
71.1.2 by Chris McGinlay
Added tooltip strings for enable/disable/start/stop sync states along with testcases
1369
                            '⇅', ORANGE, self.STOP_TOOLTIP)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1370
1371
    @log_call(logger.info)
46.1.10 by Natalia B. Bidart
Adding stop management.
1372
    def on_file_sync_status_stopped(self, msg):
1373
        """Backend notifies of file sync being stopped."""
1374
        self._update_status(self.FILE_SYNC_STOPPED,
1375
                            self.START, self.on_start_clicked,
71.1.2 by Chris McGinlay
Added tooltip strings for enable/disable/start/stop sync states along with testcases
1376
                            '✘', 'red', self.START_TOOLTIP)
46.1.10 by Natalia B. Bidart
Adding stop management.
1377
1378
    @log_call(logger.info)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1379
    def on_file_sync_status_disconnected(self, msg):
1380
        """Backend notifies of file sync status being ready."""
1381
        self._update_status(self.FILE_SYNC_DISCONNECTED,
46.1.3 by natalia.bidart at canonical
Adding icons to file status label.
1382
                            self.CONNECT, self.on_connect_clicked,
71.1.2 by Chris McGinlay
Added tooltip strings for enable/disable/start/stop sync states along with testcases
1383
                            '✘', 'red', self.CONNECT_TOOLTIP,)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1384
1385
    @log_call(logger.info)
1386
    def on_file_sync_status_syncing(self, msg):
1387
        """Backend notifies of file sync status being syncing."""
1388
        self._update_status(self.FILE_SYNC_SYNCING,
46.1.3 by natalia.bidart at canonical
Adding icons to file status label.
1389
                            self.DISCONNECT, self.on_disconnect_clicked,
71.1.2 by Chris McGinlay
Added tooltip strings for enable/disable/start/stop sync states along with testcases
1390
                            '⇅', ORANGE, self.DISCONNECT_TOOLTIP)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1391
1392
    @log_call(logger.info)
1393
    def on_file_sync_status_idle(self, msg):
1394
        """Backend notifies of file sync status being idle."""
1395
        self._update_status(self.FILE_SYNC_IDLE,
46.1.3 by natalia.bidart at canonical
Adding icons to file status label.
1396
                            self.DISCONNECT, self.on_disconnect_clicked,
71.1.2 by Chris McGinlay
Added tooltip strings for enable/disable/start/stop sync states along with testcases
1397
                            '✔', 'green', self.DISCONNECT_TOOLTIP)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1398
1399
    @log_call(logger.error)
1400
    def on_file_sync_status_error(self, error_dict=None):
1401
        """Backend notifies of an error when fetching file sync status."""
89.1.2 by Natalia B. Bidart
Minimal tweaks to offline experience.
1402
        msg = self.FILE_SYNC_ERROR
1403
        reason = error_dict.get('error_msg', '') if error_dict else ''
1404
        if reason:
1405
            msg += ' (' + reason + ')'
1406
        self._update_status(WARNING_MARKUP % msg,
71.1.2 by Chris McGinlay
Added tooltip strings for enable/disable/start/stop sync states along with testcases
1407
                            self.RESTART, self.on_restart_clicked,
1408
                            tooltip=self.RESTART_TOOLTIP)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1409
46.1.10 by Natalia B. Bidart
Adding stop management.
1410
    @log_call(logger.error)
1411
    def on_files_start_error(self, error_dict=None):
1412
        """Backend notifies of an error when starting the files service."""
1413
        # service is probably disabled, ask for status to backend
1414
        self.backend.file_sync_status(reply_handler=NO_OP,
1415
                                      error_handler=error_handler)
1416
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1417
    def on_connect_clicked(self, button=None):
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1418
        """User requested connection."""
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1419
        self.backend.connect_files(reply_handler=NO_OP,
1420
                                   error_handler=error_handler)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1421
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1422
    def on_disconnect_clicked(self, button=None):
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1423
        """User requested disconnection."""
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1424
        self.backend.disconnect_files(reply_handler=NO_OP,
1425
                                      error_handler=error_handler)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1426
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1427
    def on_enable_clicked(self, button=None):
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1428
        """User requested enable the service."""
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1429
        self.backend.enable_files(reply_handler=NO_OP,
1430
                                  error_handler=error_handler)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1431
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1432
    def on_restart_clicked(self, button=None):
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1433
        """User requested restart the service."""
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1434
        self.backend.restart_files(reply_handler=NO_OP,
1435
                                   error_handler=error_handler)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1436
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1437
    def on_start_clicked(self, button=None):
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1438
        """User requested start the service."""
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1439
        self.backend.start_files(reply_handler=NO_OP,
1440
                                 error_handler=error_handler)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1441
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1442
    def on_stop_clicked(self, button=None):
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1443
        """User requested stop the service."""
46.1.2 by natalia.bidart at canonical
Implemented file sync button callbacks.
1444
        self.backend.stop_files(reply_handler=NO_OP,
1445
                                error_handler=error_handler)
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1446
1447
1448
class ManagementPanel(gtk.VBox, ControlPanelMixin):
1449
    """The management panel.
1450
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
1451
    The user can manage dashboard, volumes, devices and services.
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1452
1453
    """
1454
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1455
    __gsignals__ = {
1456
        'local-device-removed': (gobject.SIGNAL_RUN_FIRST,
1457
                                 gobject.TYPE_NONE, ()),
1458
    }
1459
82.2.1 by natalia.bidart at canonical
- Quota usage is now red when user is over quota (LP: #701729).
1460
    QUOTA_LABEL = _('Using %(used)s of %(total)s (%(percentage).0f%%)')
82.2.3 by Natalia B. Bidart
Setting red quota label when usage reaches or exceeds QUOTA_THRESHOLD.
1461
    QUOTA_THRESHOLD = 0.95
102.1.1 by Natalia B. Bidart
- Name for notebook's tab-buttons have now a more realistic name, and also
1462
    DASHBOARD_BUTTON_NAME = 'ModeLeft'
1463
    SERVICES_BUTTON_NAME = 'ModeRight'
80.1.1 by Natalia B. Bidart
- General 'Account' tab cleanup (LP: #718629).
1464
1465
    DASHBOARD_BUTTON_TOOLTIP = _('View your personal details and service '
1466
                                 'summary')
1467
    VOLUMES_BUTTON_TOOLTIP = _('Manage your cloud folders')
1468
    SHARES_BUTTON_TOOLTIP = _('Manage the shares offered to others')
1469
    DEVICES_BUTTON_TOOLTIP = _('Manage devices registered with your personal '
1470
                               'cloud')
1471
    SERVICES_BUTTON_TOOLTIP = _('Manage the sync services')
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1472
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
1473
    def __init__(self, main_window=None):
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1474
        gtk.VBox.__init__(self)
1475
        ControlPanelMixin.__init__(self, filename='management.ui')
1476
        self.add(self.itself)
1477
        self.show()
1478
1479
        self.backend.connect_to_signal('AccountInfoReady',
1480
                                       self.on_account_info_ready)
1481
        self.backend.connect_to_signal('AccountInfoError',
1482
                                       self.on_account_info_error)
1483
46.1.3 by natalia.bidart at canonical
Adding icons to file status label.
1484
        self.quota_progressbar.set_sensitive(False)
70.2.1 by natalia.bidart at canonical
Commenting styling code out to allow UX people to create a proper .rc file
1485
1486
        self.quota_label = LabelLoading(LOADING)
36.2.5 by Natalia B. Bidart
UI fixes: progress bar is narrow now, less bold on Account tab, max size is
1487
        self.quota_box.pack_start(self.quota_label, expand=False)
63.1.4 by Natalia B. Bidart
Quota usage text is on top of progress bar (LP: #715713).
1488
        self.quota_box.reorder_child(self.quota_label, 0)
36.2.5 by Natalia B. Bidart
UI fixes: progress bar is narrow now, less bold on Account tab, max size is
1489
46.1.1 by natalia.bidart at canonical
Isolated File Sync status into its own widget.
1490
        self.status_label = FileSyncStatus()
82.2.1 by natalia.bidart at canonical
- Quota usage is now red when user is over quota (LP: #701729).
1491
        self.status_box.pack_end(self.status_label, expand=True)
9.1.2 by natalia.bidart at canonical
Added account info.
1492
51.2.2 by Natalia B. Bidart
When removing a device, a confirmation dialog is raised (LP: #706888).
1493
        self.dashboard = DashboardPanel(main_window=main_window)
1494
        self.volumes = VolumesPanel(main_window=main_window)
1495
        self.shares = SharesPanel(main_window=main_window)
1496
        self.devices = DevicesPanel(main_window=main_window)
1497
        self.services = ServicesPanel(main_window=main_window)
3.1.9 by natalia.bidart at canonical
Quota info is a Loading widget until ready.
1498
7.1.4 by natalia.bidart at canonical
Started work on management notebook.
1499
        cb = lambda button, page_num: self.notebook.set_current_page(page_num)
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
1500
        self.tabs = (u'dashboard', u'volumes', u'shares',
1501
                     u'devices', u'services')
7.1.4 by natalia.bidart at canonical
Started work on management notebook.
1502
        for page_num, tab in enumerate(self.tabs):
1503
            setattr(self, ('%s_page' % tab).upper(), page_num)
24.2.7 by Natalia B. Bidart
Default background color is set accordingly to spec.
1504
            button = getattr(self, '%s_button' % tab)
1505
            button.connect('clicked', cb, page_num)
9.1.2 by natalia.bidart at canonical
Added account info.
1506
            self.notebook.insert_page(getattr(self, tab), position=page_num)
1.1.3 by natalia.bidart at canonical
Adding several glade files and some implementations. Still rough work.
1507
63.1.2 by Natalia B. Bidart
Widgets have name now.
1508
        self.dashboard_button.set_name(self.DASHBOARD_BUTTON_NAME)
71.1.1 by Chris McGinlay
modified:
1509
        self.dashboard_button.set_tooltip_text(self.DASHBOARD_BUTTON_TOOLTIP)
63.1.2 by Natalia B. Bidart
Widgets have name now.
1510
80.1.1 by Natalia B. Bidart
- General 'Account' tab cleanup (LP: #718629).
1511
        self.volumes_button.set_tooltip_text(self.VOLUMES_BUTTON_TOOLTIP)
50.1.2 by natalia.bidart at canonical
Adding is_processing flag to UbuntuOneBin to be able to unify loading messages.
1512
        self.volumes_button.connect('clicked', lambda b: self.volumes.load())
80.1.1 by Natalia B. Bidart
- General 'Account' tab cleanup (LP: #718629).
1513
1514
        self.shares_button.set_tooltip_text(self.SHARES_BUTTON_TOOLTIP)
1515
71.1.1 by Chris McGinlay
modified:
1516
        self.devices_button.set_tooltip_text(self.DEVICES_BUTTON_TOOLTIP)
36.2.2 by Natalia B. Bidart
* Updated list of messages to be shown on the overview panel (LP: #690379).
1517
        self.devices_button.connect('clicked', lambda b: self.devices.load())
1518
        self.devices.connect('local-device-removed',
1519
                             lambda widget: self.emit('local-device-removed'))
31.2.3 by Natalia B. Bidart
User can now subcribe and unsubscribe from folders (LP: #689646).
1520
80.1.1 by Natalia B. Bidart
- General 'Account' tab cleanup (LP: #718629).
1521
        self.services_button.set_name(self.SERVICES_BUTTON_NAME)
1522
        self.services_button.set_tooltip_text(self.SERVICES_BUTTON_TOOLTIP)
91.2.4 by Natalia B. Bidart
- Services tab is re-designed (LP: #729361).
1523
        self.services.load()
80.1.1 by Natalia B. Bidart
- General 'Account' tab cleanup (LP: #718629).
1524
24.2.7 by Natalia B. Bidart
Default background color is set accordingly to spec.
1525
    def _update_quota(self, msg, data=None):
8.1.1 by natalia.bidart at canonical
Fixed a few TODOs (show warning on AccountInfoError, fix label wrapping and
1526
        """Update the quota info."""
24.2.7 by Natalia B. Bidart
Default background color is set accordingly to spec.
1527
        fraction = 0.0
1528
        if data is not None:
24.2.9 by Natalia B. Bidart
Removing unused code.
1529
            fraction = data.get('percentage', 0.0) / 100
50.2.2 by natalia.bidart at canonical
- Misc visual improvemnts (LP: #692772):
1530
            if fraction > 0 and fraction < 0.05:
1531
                fraction = 0.05
82.2.3 by Natalia B. Bidart
Setting red quota label when usage reaches or exceeds QUOTA_THRESHOLD.
1532
            else:
1533
                fraction = round(fraction, 2)
82.2.1 by natalia.bidart at canonical
- Quota usage is now red when user is over quota (LP: #701729).
1534
82.2.3 by Natalia B. Bidart
Setting red quota label when usage reaches or exceeds QUOTA_THRESHOLD.
1535
        logger.debug('ManagementPanel: updating quota to %r.', fraction)
1536
        if fraction >= self.QUOTA_THRESHOLD:
82.2.1 by natalia.bidart at canonical
- Quota usage is now red when user is over quota (LP: #701729).
1537
            self.quota_label.set_markup(WARNING_MARKUP % msg)
1538
        else:
1539
            self.quota_label.set_markup(msg)
1540
        self.quota_label.stop()
1541
89.1.2 by Natalia B. Bidart
Minimal tweaks to offline experience.
1542
        if fraction == 0.0:
1543
            self.quota_progressbar.set_sensitive(False)
1544
        else:
1545
            self.quota_progressbar.set_sensitive(True)
1546
82.2.1 by natalia.bidart at canonical
- Quota usage is now red when user is over quota (LP: #701729).
1547
        self.quota_progressbar.set_fraction(min(fraction, 1))
24.2.7 by Natalia B. Bidart
Default background color is set accordingly to spec.
1548
36.2.3 by Natalia B. Bidart
Made the ControlPanel to be a notebook to manage resizing more carefully.
1549
    def load(self):
1550
        """Load the account info and file sync status list."""
41.1.10 by Natalia B. Bidart
On dbus async errors, log properly.
1551
        self.backend.account_info(reply_handler=NO_OP,
1552
                                  error_handler=error_handler)
36.2.3 by Natalia B. Bidart
Made the ControlPanel to be a notebook to manage resizing more carefully.
1553
24.2.3 by Natalia B. Bidart
Draft of "Folders" tab in control panel (LP: #674455).
1554
    @log_call(logger.debug)
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
1555
    def on_account_info_ready(self, info):
1556
        """Backend notifies of account info."""
1557
        used = int(info['quota_used'])
1558
        total = int(info['quota_total'])
1559
        data = {'used': self.humanize(used), 'total': self.humanize(total),
1560
                'percentage': (used / total) * 100}
24.2.7 by Natalia B. Bidart
Default background color is set accordingly to spec.
1561
        self._update_quota(self.QUOTA_LABEL % data, data)
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
1562
1563
    @log_call(logger.error)
8.1.1 by natalia.bidart at canonical
Fixed a few TODOs (show warning on AccountInfoError, fix label wrapping and
1564
    def on_account_info_error(self, error_dict=None):
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
1565
        """Backend notifies of an error when fetching account info."""
89.1.2 by Natalia B. Bidart
Minimal tweaks to offline experience.
1566
        self._update_quota(msg='')
3.1.8 by natalia.bidart at canonical
Displaying quota usage.
1567
1.1.3 by natalia.bidart at canonical
Adding several glade files and some implementations. Still rough work.
1568
113.1.2 by Natalia B. Bidart
After initial computer adding, syncdameon is asked to connect (LP: #715873).
1569
class ControlPanel(gtk.Notebook, ControlPanelMixin):
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1570
    """The control panel per se, can be added into any other widget."""
1571
1572
    # should not be any larger than 736x525
1573
1574
    def __init__(self, main_window):
1575
        gtk.Notebook.__init__(self)
113.1.2 by Natalia B. Bidart
After initial computer adding, syncdameon is asked to connect (LP: #715873).
1576
        ControlPanelMixin.__init__(self)
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1577
        gtk.link_button_set_uri_hook(uri_hook)
113.2.3 by Natalia B. Bidart
Shutdown is working, still need to make a mocker test pass.
1578
        self.connect('destroy', self.shutdown)
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1579
1580
        self.main_window = main_window
1581
1582
        self.set_show_tabs(False)
1583
        self.set_show_border(False)
1584
1585
        self.overview = OverviewPanel(main_window=main_window)
1586
        self.insert_page(self.overview, position=0)
1587
1588
        self.management = ManagementPanel(main_window=main_window)
1589
        self.insert_page(self.management, position=1)
1590
1591
        self.overview.connect('credentials-found',
1592
                              self.on_show_management_panel)
1593
        self.management.connect('local-device-removed',
1594
                                self.on_show_overview_panel)
1595
1596
        self.show()
1597
        self.on_show_overview_panel()
1598
1599
        logger.debug('%s: started (window size %r).',
1600
                     self.__class__.__name__, self.get_size_request())
1601
113.2.3 by Natalia B. Bidart
Shutdown is working, still need to make a mocker test pass.
1602
    def shutdown(self, *args, **kwargs):
1603
        """Shutdown backend."""
116.1.1 by eric.casteleijn at canonical
added dbus methods and test
1604
        logger.info('Shutting down...')
113.2.3 by Natalia B. Bidart
Shutdown is working, still need to make a mocker test pass.
1605
        self.backend.shutdown(reply_handler=NO_OP,
1606
                              error_handler=error_handler)
1607
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1608
    def on_show_overview_panel(self, widget=None):
1609
        """Show the overview panel."""
1610
        self.set_current_page(0)
1611
1612
    def on_show_management_panel(self, widget=None,
1613
                                 credentials_are_new=False, token=None):
1614
        """Show the notebook (main panel)."""
1615
        if self.get_current_page() == 0:
1616
            self.management.load()
1617
            if credentials_are_new:
102.1.1 by Natalia B. Bidart
- Name for notebook's tab-buttons have now a more realistic name, and also
1618
                # redirect user to services page to start using Ubuntu One
1619
                self.management.services_button.clicked()
113.1.2 by Natalia B. Bidart
After initial computer adding, syncdameon is asked to connect (LP: #715873).
1620
                # instruct syncdaemon to connect
1621
                self.backend.connect_files(reply_handler=NO_OP,
1622
                                           error_handler=error_handler)
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1623
1624
            self.next_page()
1625
1626
116.1.1 by eric.casteleijn at canonical
added dbus methods and test
1627
class ControlPanelService(dbus.service.Object):
1628
    """DBUS service that exposes some of the window's methods."""
1629
1630
    def __init__(self, window):
116.1.4 by eric.casteleijn at canonical
working though not async
1631
        self.window = window
116.1.1 by eric.casteleijn at canonical
added dbus methods and test
1632
        bus_name = dbus.service.BusName(
1633
            DBUS_BUS_NAME_GUI, bus=dbus.SessionBus())
1634
        dbus.service.Object.__init__(
1635
            self, bus_name=bus_name, object_path=DBUS_PATH_GUI)
116.1.4 by eric.casteleijn at canonical
working though not async
1636
1637
    @log_call(logger.debug)
1638
    @dbus.service.method(dbus_interface=DBUS_IFACE_GUI, in_signature='sb')
1639
    def switch_to_alert(self, panel='', alert=False):
116.1.1 by eric.casteleijn at canonical
added dbus methods and test
1640
        """Switch to named panel."""
116.1.4 by eric.casteleijn at canonical
working though not async
1641
        if panel:
1642
            self.window.switch_to(panel)
1643
        if alert:
1644
            self.window.draw_attention()
116.1.1 by eric.casteleijn at canonical
added dbus methods and test
1645
1646
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1647
class ControlPanelWindow(gtk.Window):
1648
    """The main window for the Ubuntu One control panel."""
1649
65.1.9 by natalia.bidart at canonical
Better title name for the window.
1650
    TITLE = _('%(app_name)s Control Panel')
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1651
90.2.1 by eric.casteleijn at canonical
added attention seeking option
1652
    def __init__(self, switch_to=None, alert=False):
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1653
        super(ControlPanelWindow, self).__init__()
1654
        self.set_title(self.TITLE % {'app_name': U1_APP_NAME})
1655
        self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
1656
        self.set_icon_name('ubuntuone')
97.2.1 by Robert Roth
Set width request with height request (LP: #729530)
1657
        self.set_size_request(736, 525)  # bug #683164
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1658
1659
        self.connect('delete-event', lambda w, e: gtk.main_quit())
90.2.1 by eric.casteleijn at canonical
added attention seeking option
1660
        if alert:
116.1.1 by eric.casteleijn at canonical
added dbus methods and test
1661
            self.draw_attention()
90.2.2 by eric.casteleijn at canonical
present rather than show
1662
        else:
1663
            self.present()
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1664
1665
        self.control_panel = ControlPanel(main_window=self)
1666
        self.add(self.control_panel)
1667
1668
        logger.info('Starting %s pointing at panel: %r.',
1669
                     self.__class__.__name__, switch_to)
1670
        if switch_to is not None:
116.1.1 by eric.casteleijn at canonical
added dbus methods and test
1671
            self.switch_to(switch_to)
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1672
1673
        logger.debug('%s: started (window size %r).',
1674
                     self.__class__.__name__, self.get_size_request())
1675
116.1.1 by eric.casteleijn at canonical
added dbus methods and test
1676
    def draw_attention(self):
1677
        """Draw attention to the control panel."""
1678
        self.present_with_time(1)
1679
        self.set_urgency_hint(True)
1680
1681
    def switch_to(self, panel):
1682
        """Switch to named panel."""
1683
        button = getattr(
1684
            self.control_panel.management, '%s_button' % panel, None)
1685
        if button is not None:
1686
            button.clicked()
1687
        else:
1688
            logger.warning('Could not start at panel: %r.', panel)
1689
58.1.1 by natalia.bidart at canonical
Use proper mechanism to define object's signals (LP: #713271).
1690
    def main(self):
1691
        """Run the main loop of the widget toolkit."""
1692
        logger.debug('Starting GTK main loop.')
1693
        gtk.main()