Merge lp:~dobey/ubuntuone-control-panel/remove-gtk into lp:ubuntuone-control-panel

Proposed by dobey
Status: Merged
Approved by: Natalia Bidart
Approved revision: 271
Merged at revision: 273
Proposed branch: lp:~dobey/ubuntuone-control-panel/remove-gtk
Merge into: lp:ubuntuone-control-panel
Diff against target: 7732 lines (+7/-7524)
26 files modified
bin/ubuntuone-control-panel-gtk (+0/-49)
com.ubuntuone.controlpanel.gui.service.in (+0/-3)
data/gtk/dashboard.ui (+0/-198)
data/gtk/device.ui (+0/-279)
data/gtk/devices.ui (+0/-44)
data/gtk/install.ui (+0/-57)
data/gtk/management.ui (+0/-334)
data/gtk/overview.ui (+0/-308)
data/gtk/services.ui (+0/-317)
data/gtk/volumes.ui (+0/-98)
docs/ubuntuone-control-panel-gtk.1 (+0/-15)
po/POTFILES.in (+0/-8)
run-tests (+2/-7)
run-tests.bat (+1/-1)
setup.py (+3/-5)
ubuntuone/controlpanel/dbustests/test_gui_service.py (+0/-104)
ubuntuone/controlpanel/gui/gtk/__init__.py (+0/-28)
ubuntuone/controlpanel/gui/gtk/gui.py (+0/-1667)
ubuntuone/controlpanel/gui/gtk/package_manager.py (+0/-62)
ubuntuone/controlpanel/gui/gtk/tests/__init__.py (+0/-232)
ubuntuone/controlpanel/gui/gtk/tests/test_gui.py (+0/-2179)
ubuntuone/controlpanel/gui/gtk/tests/test_gui_basic.py (+0/-780)
ubuntuone/controlpanel/gui/gtk/tests/test_package_manager.py (+0/-181)
ubuntuone/controlpanel/gui/gtk/tests/test_widgets.py (+0/-205)
ubuntuone/controlpanel/gui/gtk/widgets.py (+0/-362)
ubuntuone/controlpanel/gui/tests/__init__.py (+1/-1)
To merge this branch: bzr merge lp:~dobey/ubuntuone-control-panel/remove-gtk
Reviewer Review Type Date Requested Status
Natalia Bidart Approve
Roberto Alsina (community) Approve
Review via email: mp+95252@code.launchpad.net

Commit message

Remove the GTK+ 2.x control panel

To post a comment you must log in.
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Thanks for working on this!

I think you should also remove the contropanel backend dbus service, since that one was used only from the GTK+ UI.

review: Needs Fixing
Revision history for this message
dobey (dobey) wrote :

It looks like we can't remove the dbus backend service yet. Deja Dup is using it to query for amount of space the user has left on the account.

Revision history for this message
Roberto Alsina (ralsina) wrote :

+1 doesn't seem to remove anything it shouldn't

review: Approve
271. By dobey

Remove the man page for the gtk panel as well.

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'bin/ubuntuone-control-panel-gtk'
2--- bin/ubuntuone-control-panel-gtk 2012-02-22 12:09:28 +0000
3+++ bin/ubuntuone-control-panel-gtk 1970-01-01 00:00:00 +0000
4@@ -1,49 +0,0 @@
5-#!/usr/bin/python
6-# -*- coding: utf-8 -*-
7-
8-# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
9-# Eric Casteleijn <eric.casteleijn@canonical.com>
10-#
11-# Copyright 2010 Canonical Ltd.
12-#
13-# This program is free software: you can redistribute it and/or modify it
14-# under the terms of the GNU General Public License version 3, as published
15-# by the Free Software Foundation.
16-#
17-# This program is distributed in the hope that it will be useful, but
18-# WITHOUT ANY WARRANTY; without even the implied warranties of
19-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
20-# PURPOSE. See the GNU General Public License for more details.
21-#
22-# You should have received a copy of the GNU General Public License along
23-# with this program. If not, see <http://www.gnu.org/licenses/>.
24-"""Execute the graphical interface for the Ubuntu One control panel."""
25-
26-# Invalid name "ubuntuone-control-panel-gtk", pylint: disable=C0103
27-
28-import sys
29-
30-from optparse import OptionParser
31-
32-from ubuntuone.controlpanel.gui.gtk import main
33-
34-
35-def parser_options():
36- """Parse command line parameters."""
37- usage = "Usage: %prog [option]"
38- result = OptionParser(usage=usage)
39- result.add_option("", "--switch-to", dest="switch_to", type="string",
40- metavar="PANEL_NAME", default="",
41- help="Start Ubuntu One in the "
42- "PANEL_NAME tab. Possible values are: "
43- "dashboard, volumes, devices, applications")
44- result.add_option("-a", "--alert", dest="alert", action="store_true",
45- default=False, help="Start Ubuntu One "
46- "alerting the user to its presence.")
47- return result
48-
49-
50-if __name__ == "__main__":
51- parser = parser_options()
52- (options, args) = parser.parse_args(sys.argv)
53- main(switch_to=options.switch_to, alert=options.alert)
54
55=== removed file 'com.ubuntuone.controlpanel.gui.service.in'
56--- com.ubuntuone.controlpanel.gui.service.in 2011-03-22 13:04:38 +0000
57+++ com.ubuntuone.controlpanel.gui.service.in 1970-01-01 00:00:00 +0000
58@@ -1,3 +0,0 @@
59-[D-BUS Service]
60-Name=com.ubuntuone.controlpanel.gui
61-Exec=@prefix@/bin/ubuntuone-control-panel-gtk
62
63=== removed directory 'data/gtk'
64=== removed file 'data/gtk/dashboard.ui'
65--- data/gtk/dashboard.ui 2011-07-11 11:19:09 +0000
66+++ data/gtk/dashboard.ui 1970-01-01 00:00:00 +0000
67@@ -1,198 +0,0 @@
68-<?xml version="1.0" encoding="UTF-8"?>
69-<interface>
70- <requires lib="gtk+" version="2.22"/>
71- <!-- interface-naming-policy project-wide -->
72- <object class="GtkAlignment" id="itself">
73- <property name="visible">True</property>
74- <property name="can_focus">False</property>
75- <property name="yalign">0</property>
76- <property name="yscale">0</property>
77- <child>
78- <object class="GtkHBox" id="account">
79- <property name="visible">True</property>
80- <property name="can_focus">False</property>
81- <property name="border_width">12</property>
82- <property name="spacing">12</property>
83- <child>
84- <object class="GtkFrame" id="frame2">
85- <property name="visible">True</property>
86- <property name="can_focus">False</property>
87- <property name="label_xalign">0</property>
88- <property name="shadow_type">out</property>
89- <child>
90- <object class="GtkAlignment" id="alignment2">
91- <property name="visible">True</property>
92- <property name="can_focus">False</property>
93- <property name="top_padding">12</property>
94- <property name="bottom_padding">12</property>
95- <property name="left_padding">12</property>
96- <property name="right_padding">12</property>
97- <child>
98- <object class="GtkVBox" id="vbox5">
99- <property name="visible">True</property>
100- <property name="can_focus">False</property>
101- <property name="spacing">12</property>
102- <child>
103- <object class="GtkLabel" id="name_label">
104- <property name="visible">True</property>
105- <property name="can_focus">False</property>
106- <property name="xalign">0</property>
107- <property name="label">tester name</property>
108- <property name="use_markup">True</property>
109- </object>
110- <packing>
111- <property name="expand">False</property>
112- <property name="fill">True</property>
113- <property name="position">0</property>
114- </packing>
115- </child>
116- <child>
117- <object class="GtkLabel" id="email_label">
118- <property name="visible">True</property>
119- <property name="can_focus">False</property>
120- <property name="xalign">0</property>
121- <property name="label">a@example.com</property>
122- </object>
123- <packing>
124- <property name="expand">False</property>
125- <property name="fill">True</property>
126- <property name="position">1</property>
127- </packing>
128- </child>
129- <child>
130- <object class="GtkHButtonBox" id="hbuttonbox1">
131- <property name="visible">True</property>
132- <property name="can_focus">False</property>
133- <child>
134- <object class="GtkLinkButton" id="linkbutton3">
135- <property name="label" translatable="yes">Edit account details</property>
136- <property name="visible">True</property>
137- <property name="can_focus">True</property>
138- <property name="receives_default">True</property>
139- <property name="use_action_appearance">False</property>
140- <property name="relief">half</property>
141- <property name="uri">http://login.ubuntu.com</property>
142- </object>
143- <packing>
144- <property name="expand">False</property>
145- <property name="fill">False</property>
146- <property name="pack_type">end</property>
147- <property name="position">0</property>
148- </packing>
149- </child>
150- </object>
151- <packing>
152- <property name="expand">False</property>
153- <property name="fill">True</property>
154- <property name="pack_type">end</property>
155- <property name="position">2</property>
156- </packing>
157- </child>
158- </object>
159- </child>
160- </object>
161- </child>
162- <child type="label">
163- <object class="GtkLabel" id="label1">
164- <property name="visible">True</property>
165- <property name="can_focus">False</property>
166- <property name="label" translatable="yes">&lt;b&gt;Personal details&lt;/b&gt;</property>
167- <property name="use_markup">True</property>
168- </object>
169- </child>
170- </object>
171- <packing>
172- <property name="expand">True</property>
173- <property name="fill">True</property>
174- <property name="position">0</property>
175- </packing>
176- </child>
177- <child>
178- <object class="GtkFrame" id="frame1">
179- <property name="visible">True</property>
180- <property name="can_focus">False</property>
181- <property name="label_xalign">0</property>
182- <property name="shadow_type">out</property>
183- <child>
184- <object class="GtkAlignment" id="alignment3">
185- <property name="visible">True</property>
186- <property name="can_focus">False</property>
187- <property name="top_padding">12</property>
188- <property name="bottom_padding">12</property>
189- <property name="left_padding">12</property>
190- <property name="right_padding">12</property>
191- <child>
192- <object class="GtkVBox" id="vbox4">
193- <property name="visible">True</property>
194- <property name="can_focus">False</property>
195- <property name="spacing">12</property>
196- <child>
197- <object class="GtkLabel" id="type_label">
198- <property name="visible">True</property>
199- <property name="can_focus">False</property>
200- <property name="xalign">0</property>
201- <property name="label">Ubuntu One Basic (2 GB)
202-22GB of awesomeness
203-Total storage 22GB
204-You also have a mobile plan!
205-This is great!</property>
206- </object>
207- <packing>
208- <property name="expand">False</property>
209- <property name="fill">True</property>
210- <property name="position">0</property>
211- </packing>
212- </child>
213- <child>
214- <object class="GtkHButtonBox" id="hbuttonbox2">
215- <property name="visible">True</property>
216- <property name="can_focus">False</property>
217- <child>
218- <object class="GtkLinkButton" id="linkbutton1">
219- <property name="label" translatable="yes">Buy storage and plans</property>
220- <property name="visible">True</property>
221- <property name="can_focus">True</property>
222- <property name="receives_default">True</property>
223- <property name="use_action_appearance">False</property>
224- <property name="relief">half</property>
225- <property name="uri">https://one.ubuntu.com/plans/</property>
226- </object>
227- <packing>
228- <property name="expand">False</property>
229- <property name="fill">False</property>
230- <property name="pack_type">end</property>
231- <property name="position">0</property>
232- </packing>
233- </child>
234- </object>
235- <packing>
236- <property name="expand">False</property>
237- <property name="fill">True</property>
238- <property name="pack_type">end</property>
239- <property name="position">1</property>
240- </packing>
241- </child>
242- </object>
243- </child>
244- </object>
245- </child>
246- <child type="label">
247- <object class="GtkLabel" id="label3">
248- <property name="visible">True</property>
249- <property name="can_focus">False</property>
250- <property name="label" translatable="yes">&lt;b&gt;Your services&lt;/b&gt;</property>
251- <property name="use_markup">True</property>
252- </object>
253- </child>
254- </object>
255- <packing>
256- <property name="expand">True</property>
257- <property name="fill">True</property>
258- <property name="pack_type">end</property>
259- <property name="position">1</property>
260- </packing>
261- </child>
262- </object>
263- </child>
264- </object>
265-</interface>
266
267=== removed file 'data/gtk/device.ui'
268--- data/gtk/device.ui 2011-07-11 11:19:09 +0000
269+++ data/gtk/device.ui 1970-01-01 00:00:00 +0000
270@@ -1,279 +0,0 @@
271-<?xml version="1.0" encoding="UTF-8"?>
272-<interface>
273- <requires lib="gtk+" version="2.22"/>
274- <!-- interface-naming-policy project-wide -->
275- <object class="GtkAdjustment" id="adjustment1">
276- <property name="upper">10000</property>
277- <property name="step_increment">1</property>
278- </object>
279- <object class="GtkAdjustment" id="adjustment2">
280- <property name="upper">10000</property>
281- <property name="step_increment">1</property>
282- </object>
283- <object class="GtkVBox" id="itself">
284- <property name="visible">True</property>
285- <property name="can_focus">False</property>
286- <property name="border_width">10</property>
287- <property name="spacing">5</property>
288- <child>
289- <object class="GtkHBox" id="hbox1">
290- <property name="visible">True</property>
291- <property name="can_focus">False</property>
292- <property name="spacing">10</property>
293- <child>
294- <object class="GtkVBox" id="vbox1">
295- <property name="visible">True</property>
296- <property name="can_focus">False</property>
297- <property name="spacing">5</property>
298- <child>
299- <object class="GtkHBox" id="hbox2">
300- <property name="visible">True</property>
301- <property name="can_focus">False</property>
302- <child>
303- <object class="GtkImage" id="device_type">
304- <property name="visible">True</property>
305- <property name="can_focus">False</property>
306- <property name="icon_name">computer</property>
307- </object>
308- <packing>
309- <property name="expand">False</property>
310- <property name="fill">True</property>
311- <property name="position">0</property>
312- </packing>
313- </child>
314- <child>
315- <object class="GtkLabel" id="device_name">
316- <property name="visible">True</property>
317- <property name="can_focus">False</property>
318- <property name="xalign">0</property>
319- <property name="xpad">5</property>
320- <property name="label">My Laptop</property>
321- <property name="wrap">True</property>
322- </object>
323- <packing>
324- <property name="expand">True</property>
325- <property name="fill">True</property>
326- <property name="position">1</property>
327- </packing>
328- </child>
329- </object>
330- <packing>
331- <property name="expand">True</property>
332- <property name="fill">True</property>
333- <property name="position">0</property>
334- </packing>
335- </child>
336- <child>
337- <object class="GtkAlignment" id="alignment1">
338- <property name="visible">True</property>
339- <property name="can_focus">False</property>
340- <property name="left_padding">25</property>
341- <child>
342- <object class="GtkVBox" id="config_settings">
343- <property name="visible">True</property>
344- <property name="can_focus">False</property>
345- <child>
346- <object class="GtkCheckButton" id="show_all_notifications">
347- <property name="label" translatable="yes">Show activity notifications</property>
348- <property name="visible">True</property>
349- <property name="can_focus">True</property>
350- <property name="receives_default">False</property>
351- <property name="use_action_appearance">False</property>
352- <property name="draw_indicator">True</property>
353- <signal name="toggled" handler="on_show_all_notifications_toggled" swapped="no"/>
354- </object>
355- <packing>
356- <property name="expand">True</property>
357- <property name="fill">True</property>
358- <property name="position">0</property>
359- </packing>
360- </child>
361- <child>
362- <object class="GtkVBox" id="throttling">
363- <property name="visible">True</property>
364- <property name="can_focus">False</property>
365- <child>
366- <object class="GtkCheckButton" id="limit_bandwidth">
367- <property name="label" translatable="yes">Limit file sync bandwidth usage</property>
368- <property name="visible">True</property>
369- <property name="can_focus">True</property>
370- <property name="receives_default">False</property>
371- <property name="use_action_appearance">False</property>
372- <property name="draw_indicator">True</property>
373- <signal name="toggled" handler="on_limit_bandwidth_toggled" swapped="no"/>
374- </object>
375- <packing>
376- <property name="expand">True</property>
377- <property name="fill">True</property>
378- <property name="position">0</property>
379- </packing>
380- </child>
381- <child>
382- <object class="GtkTable" id="throttling_limits">
383- <property name="visible">True</property>
384- <property name="can_focus">False</property>
385- <property name="n_rows">2</property>
386- <property name="n_columns">3</property>
387- <property name="column_spacing">3</property>
388- <property name="row_spacing">3</property>
389- <child>
390- <object class="GtkLabel" id="max_upload_speed_label">
391- <property name="visible">True</property>
392- <property name="can_focus">False</property>
393- <property name="xalign">0</property>
394- <property name="xpad">22</property>
395- <property name="label" translatable="yes">Max upload speed:</property>
396- <property name="track_visited_links">False</property>
397- </object>
398- </child>
399- <child>
400- <object class="GtkLabel" id="max_download_speed_label">
401- <property name="visible">True</property>
402- <property name="can_focus">False</property>
403- <property name="xalign">0</property>
404- <property name="xpad">22</property>
405- <property name="label" translatable="yes">Max download speed:</property>
406- </object>
407- <packing>
408- <property name="top_attach">1</property>
409- <property name="bottom_attach">2</property>
410- </packing>
411- </child>
412- <child>
413- <object class="GtkSpinButton" id="max_upload_speed">
414- <property name="visible">True</property>
415- <property name="can_focus">True</property>
416- <property name="invisible_char">•</property>
417- <property name="activates_default">True</property>
418- <property name="invisible_char_set">True</property>
419- <property name="adjustment">adjustment1</property>
420- <signal name="value-changed" handler="on_max_upload_speed_value_changed" swapped="no"/>
421- </object>
422- <packing>
423- <property name="left_attach">1</property>
424- <property name="right_attach">2</property>
425- <property name="x_options">GTK_FILL</property>
426- <property name="y_options">GTK_FILL</property>
427- </packing>
428- </child>
429- <child>
430- <object class="GtkSpinButton" id="max_download_speed">
431- <property name="visible">True</property>
432- <property name="can_focus">True</property>
433- <property name="invisible_char">•</property>
434- <property name="activates_default">True</property>
435- <property name="invisible_char_set">True</property>
436- <property name="adjustment">adjustment2</property>
437- <signal name="value-changed" handler="on_max_download_speed_value_changed" swapped="no"/>
438- </object>
439- <packing>
440- <property name="left_attach">1</property>
441- <property name="right_attach">2</property>
442- <property name="top_attach">1</property>
443- <property name="bottom_attach">2</property>
444- </packing>
445- </child>
446- <child>
447- <object class="GtkLabel" id="label1">
448- <property name="visible">True</property>
449- <property name="can_focus">False</property>
450- <property name="label" translatable="yes">KiB/s</property>
451- </object>
452- <packing>
453- <property name="left_attach">2</property>
454- <property name="right_attach">3</property>
455- </packing>
456- </child>
457- <child>
458- <object class="GtkLabel" id="label2">
459- <property name="visible">True</property>
460- <property name="can_focus">False</property>
461- <property name="label" translatable="yes">KiB/s</property>
462- </object>
463- <packing>
464- <property name="left_attach">2</property>
465- <property name="right_attach">3</property>
466- <property name="top_attach">1</property>
467- <property name="bottom_attach">2</property>
468- </packing>
469- </child>
470- </object>
471- <packing>
472- <property name="expand">True</property>
473- <property name="fill">True</property>
474- <property name="position">1</property>
475- </packing>
476- </child>
477- </object>
478- <packing>
479- <property name="expand">True</property>
480- <property name="fill">True</property>
481- <property name="position">1</property>
482- </packing>
483- </child>
484- </object>
485- </child>
486- </object>
487- <packing>
488- <property name="expand">False</property>
489- <property name="fill">True</property>
490- <property name="position">1</property>
491- </packing>
492- </child>
493- </object>
494- <packing>
495- <property name="expand">False</property>
496- <property name="fill">True</property>
497- <property name="position">0</property>
498- </packing>
499- </child>
500- <child>
501- <object class="GtkVButtonBox" id="vbuttonbox1">
502- <property name="visible">True</property>
503- <property name="can_focus">False</property>
504- <property name="layout_style">start</property>
505- <child>
506- <object class="GtkButton" id="remove">
507- <property name="label">gtk-remove</property>
508- <property name="visible">True</property>
509- <property name="can_focus">True</property>
510- <property name="receives_default">True</property>
511- <property name="use_action_appearance">False</property>
512- <property name="use_stock">True</property>
513- <signal name="activate" handler="on_remove_clicked" swapped="no"/>
514- <signal name="clicked" handler="on_remove_clicked" swapped="no"/>
515- </object>
516- <packing>
517- <property name="expand">False</property>
518- <property name="fill">False</property>
519- <property name="position">0</property>
520- </packing>
521- </child>
522- </object>
523- <packing>
524- <property name="expand">False</property>
525- <property name="fill">True</property>
526- <property name="pack_type">end</property>
527- <property name="position">1</property>
528- </packing>
529- </child>
530- </object>
531- <packing>
532- <property name="expand">False</property>
533- <property name="fill">True</property>
534- <property name="position">0</property>
535- </packing>
536- </child>
537- <child>
538- <object class="GtkLabel" id="warning_label">
539- <property name="visible">True</property>
540- <property name="can_focus">False</property>
541- </object>
542- <packing>
543- <property name="expand">True</property>
544- <property name="fill">True</property>
545- <property name="position">1</property>
546- </packing>
547- </child>
548- </object>
549-</interface>
550
551=== removed file 'data/gtk/devices.ui'
552--- data/gtk/devices.ui 2011-07-11 11:19:09 +0000
553+++ data/gtk/devices.ui 1970-01-01 00:00:00 +0000
554@@ -1,44 +0,0 @@
555-<?xml version="1.0" encoding="UTF-8"?>
556-<interface>
557- <requires lib="gtk+" version="2.22"/>
558- <!-- interface-naming-policy project-wide -->
559- <object class="GtkVBox" id="itself">
560- <property name="visible">True</property>
561- <property name="can_focus">False</property>
562- <child>
563- <object class="GtkScrolledWindow" id="scrolledwindow1">
564- <property name="visible">True</property>
565- <property name="can_focus">True</property>
566- <property name="hscrollbar_policy">automatic</property>
567- <property name="vscrollbar_policy">automatic</property>
568- <child>
569- <object class="GtkViewport" id="viewport1">
570- <property name="visible">True</property>
571- <property name="can_focus">False</property>
572- <property name="resize_mode">queue</property>
573- <child>
574- <object class="GtkAlignment" id="alignment1">
575- <property name="visible">True</property>
576- <property name="can_focus">False</property>
577- <child>
578- <object class="GtkVBox" id="devices">
579- <property name="visible">True</property>
580- <property name="can_focus">False</property>
581- <child>
582- <placeholder/>
583- </child>
584- </object>
585- </child>
586- </object>
587- </child>
588- </object>
589- </child>
590- </object>
591- <packing>
592- <property name="expand">True</property>
593- <property name="fill">True</property>
594- <property name="position">0</property>
595- </packing>
596- </child>
597- </object>
598-</interface>
599
600=== removed file 'data/gtk/install.ui'
601--- data/gtk/install.ui 2011-07-11 11:19:09 +0000
602+++ data/gtk/install.ui 1970-01-01 00:00:00 +0000
603@@ -1,57 +0,0 @@
604-<?xml version="1.0" encoding="UTF-8"?>
605-<interface>
606- <requires lib="gtk+" version="2.22"/>
607- <!-- interface-naming-policy project-wide -->
608- <object class="GtkImage" id="image1">
609- <property name="visible">True</property>
610- <property name="can_focus">False</property>
611- <property name="stock">gtk-ok</property>
612- </object>
613- <object class="GtkVBox" id="itself">
614- <property name="visible">True</property>
615- <property name="can_focus">False</property>
616- <property name="border_width">10</property>
617- <property name="spacing">10</property>
618- <child>
619- <object class="GtkLabel" id="install_label">
620- <property name="visible">True</property>
621- <property name="can_focus">False</property>
622- <property name="label">label</property>
623- <property name="wrap">True</property>
624- </object>
625- <packing>
626- <property name="expand">True</property>
627- <property name="fill">True</property>
628- <property name="position">0</property>
629- </packing>
630- </child>
631- <child>
632- <object class="GtkHButtonBox" id="install_button_box">
633- <property name="visible">True</property>
634- <property name="can_focus">False</property>
635- <child>
636- <object class="GtkButton" id="install_button">
637- <property name="label" translatable="yes">_Install now</property>
638- <property name="visible">True</property>
639- <property name="can_focus">True</property>
640- <property name="receives_default">True</property>
641- <property name="use_action_appearance">False</property>
642- <property name="image">image1</property>
643- <property name="use_underline">True</property>
644- <signal name="clicked" handler="on_install_button_clicked" swapped="no"/>
645- </object>
646- <packing>
647- <property name="expand">False</property>
648- <property name="fill">False</property>
649- <property name="position">0</property>
650- </packing>
651- </child>
652- </object>
653- <packing>
654- <property name="expand">False</property>
655- <property name="fill">True</property>
656- <property name="position">1</property>
657- </packing>
658- </child>
659- </object>
660-</interface>
661
662=== removed file 'data/gtk/management.ui'
663--- data/gtk/management.ui 2011-07-11 11:19:09 +0000
664+++ data/gtk/management.ui 1970-01-01 00:00:00 +0000
665@@ -1,334 +0,0 @@
666-<?xml version="1.0" encoding="UTF-8"?>
667-<interface>
668- <requires lib="gtk+" version="2.22"/>
669- <!-- interface-naming-policy project-wide -->
670- <object class="GtkVBox" id="itself">
671- <property name="visible">True</property>
672- <property name="can_focus">False</property>
673- <child>
674- <object class="GtkEventBox" id="header">
675- <property name="visible">True</property>
676- <property name="can_focus">False</property>
677- <child>
678- <object class="GtkVBox" id="vbox2">
679- <property name="visible">True</property>
680- <property name="can_focus">False</property>
681- <child>
682- <object class="GtkHBox" id="status_box">
683- <property name="visible">True</property>
684- <property name="can_focus">False</property>
685- <property name="border_width">10</property>
686- <property name="spacing">10</property>
687- <child>
688- <object class="GtkVBox" id="quota_box">
689- <property name="visible">True</property>
690- <property name="can_focus">False</property>
691- <property name="spacing">5</property>
692- <child>
693- <object class="GtkProgressBar" id="quota_progressbar">
694- <property name="visible">True</property>
695- <property name="can_focus">False</property>
696- </object>
697- <packing>
698- <property name="expand">True</property>
699- <property name="fill">True</property>
700- <property name="position">0</property>
701- </packing>
702- </child>
703- </object>
704- <packing>
705- <property name="expand">False</property>
706- <property name="fill">True</property>
707- <property name="position">0</property>
708- </packing>
709- </child>
710- </object>
711- <packing>
712- <property name="expand">False</property>
713- <property name="fill">True</property>
714- <property name="position">0</property>
715- </packing>
716- </child>
717- <child>
718- <object class="GtkHBox" id="hbox2">
719- <property name="visible">True</property>
720- <property name="can_focus">False</property>
721- <child>
722- <object class="GtkHSeparator" id="hseparator1">
723- <property name="visible">True</property>
724- <property name="can_focus">False</property>
725- </object>
726- <packing>
727- <property name="expand">True</property>
728- <property name="fill">True</property>
729- <property name="position">0</property>
730- </packing>
731- </child>
732- <child>
733- <object class="GtkHButtonBox" id="hbuttonbox1">
734- <property name="visible">True</property>
735- <property name="can_focus">False</property>
736- <property name="layout_style">center</property>
737- <child>
738- <object class="GtkRadioButton" id="dashboard_button">
739- <property name="label" translatable="yes">Account</property>
740- <property name="visible">True</property>
741- <property name="can_focus">True</property>
742- <property name="receives_default">False</property>
743- <property name="use_action_appearance">False</property>
744- <property name="active">True</property>
745- <property name="draw_indicator">False</property>
746- </object>
747- <packing>
748- <property name="expand">False</property>
749- <property name="fill">False</property>
750- <property name="position">0</property>
751- </packing>
752- </child>
753- <child>
754- <object class="GtkRadioButton" id="volumes_button">
755- <property name="label" translatable="yes">Cloud Folders</property>
756- <property name="visible">True</property>
757- <property name="can_focus">True</property>
758- <property name="receives_default">False</property>
759- <property name="use_action_appearance">False</property>
760- <property name="draw_indicator">False</property>
761- <property name="group">dashboard_button</property>
762- </object>
763- <packing>
764- <property name="expand">False</property>
765- <property name="fill">False</property>
766- <property name="position">1</property>
767- </packing>
768- </child>
769- <child>
770- <object class="GtkRadioButton" id="shares_button">
771- <property name="label" translatable="yes">Shares</property>
772- <property name="can_focus">True</property>
773- <property name="receives_default">False</property>
774- <property name="use_action_appearance">False</property>
775- <property name="draw_indicator">False</property>
776- <property name="group">dashboard_button</property>
777- </object>
778- <packing>
779- <property name="expand">False</property>
780- <property name="fill">False</property>
781- <property name="position">2</property>
782- </packing>
783- </child>
784- <child>
785- <object class="GtkRadioButton" id="devices_button">
786- <property name="label" translatable="yes">Devices</property>
787- <property name="visible">True</property>
788- <property name="can_focus">True</property>
789- <property name="receives_default">False</property>
790- <property name="use_action_appearance">False</property>
791- <property name="draw_indicator">False</property>
792- <property name="group">dashboard_button</property>
793- </object>
794- <packing>
795- <property name="expand">False</property>
796- <property name="fill">False</property>
797- <property name="position">3</property>
798- </packing>
799- </child>
800- <child>
801- <object class="GtkRadioButton" id="services_button">
802- <property name="label" translatable="yes">Services</property>
803- <property name="visible">True</property>
804- <property name="can_focus">True</property>
805- <property name="receives_default">False</property>
806- <property name="use_action_appearance">False</property>
807- <property name="draw_indicator">False</property>
808- <property name="group">dashboard_button</property>
809- </object>
810- <packing>
811- <property name="expand">False</property>
812- <property name="fill">False</property>
813- <property name="position">4</property>
814- </packing>
815- </child>
816- </object>
817- <packing>
818- <property name="expand">False</property>
819- <property name="fill">True</property>
820- <property name="position">1</property>
821- </packing>
822- </child>
823- <child>
824- <object class="GtkHSeparator" id="hseparator2">
825- <property name="visible">True</property>
826- <property name="can_focus">False</property>
827- </object>
828- <packing>
829- <property name="expand">True</property>
830- <property name="fill">True</property>
831- <property name="position">2</property>
832- </packing>
833- </child>
834- </object>
835- <packing>
836- <property name="expand">False</property>
837- <property name="fill">True</property>
838- <property name="position">1</property>
839- </packing>
840- </child>
841- </object>
842- </child>
843- </object>
844- <packing>
845- <property name="expand">False</property>
846- <property name="fill">True</property>
847- <property name="position">0</property>
848- </packing>
849- </child>
850- <child>
851- <object class="GtkNotebook" id="notebook">
852- <property name="visible">True</property>
853- <property name="can_focus">False</property>
854- <property name="show_tabs">False</property>
855- <property name="show_border">False</property>
856- <property name="homogeneous">True</property>
857- </object>
858- <packing>
859- <property name="expand">True</property>
860- <property name="fill">True</property>
861- <property name="position">1</property>
862- </packing>
863- </child>
864- <child>
865- <object class="GtkHBox" id="hbox1">
866- <property name="visible">True</property>
867- <property name="can_focus">False</property>
868- <property name="border_width">12</property>
869- <child>
870- <object class="GtkAlignment" id="alignment3">
871- <property name="visible">True</property>
872- <property name="can_focus">False</property>
873- <property name="yalign">1</property>
874- <property name="yscale">0</property>
875- <child>
876- <object class="GtkHButtonBox" id="hbuttonbox3">
877- <property name="visible">True</property>
878- <property name="can_focus">False</property>
879- <property name="spacing">5</property>
880- <property name="layout_style">start</property>
881- <child>
882- <object class="GtkLinkButton" id="linkbutton2">
883- <property name="label" translatable="yes">Official Support</property>
884- <property name="visible">True</property>
885- <property name="can_focus">True</property>
886- <property name="receives_default">True</property>
887- <property name="use_action_appearance">False</property>
888- <property name="relief">half</property>
889- <property name="uri">https://one.ubuntu.com/support/</property>
890- </object>
891- <packing>
892- <property name="expand">False</property>
893- <property name="fill">False</property>
894- <property name="position">0</property>
895- </packing>
896- </child>
897- <child>
898- <object class="GtkLinkButton" id="linkbutton4">
899- <property name="label" translatable="yes">Community Support</property>
900- <property name="visible">True</property>
901- <property name="can_focus">True</property>
902- <property name="receives_default">True</property>
903- <property name="use_action_appearance">False</property>
904- <property name="relief">half</property>
905- <property name="uri">http://askubuntu.com/questions/tagged/ubuntu-one</property>
906- </object>
907- <packing>
908- <property name="expand">False</property>
909- <property name="fill">False</property>
910- <property name="position">1</property>
911- </packing>
912- </child>
913- </object>
914- </child>
915- </object>
916- <packing>
917- <property name="expand">False</property>
918- <property name="fill">True</property>
919- <property name="position">0</property>
920- </packing>
921- </child>
922- <child>
923- <object class="GtkHBox" id="hbox3">
924- <property name="visible">True</property>
925- <property name="can_focus">False</property>
926- <child>
927- <object class="GtkLabel" id="label4">
928- <property name="visible">True</property>
929- <property name="can_focus">False</property>
930- <property name="label" translatable="yes">Talk to us on:</property>
931- </object>
932- <packing>
933- <property name="expand">True</property>
934- <property name="fill">True</property>
935- <property name="position">0</property>
936- </packing>
937- </child>
938- <child>
939- <object class="GtkLinkButton" id="linkbutton5">
940- <property name="visible">True</property>
941- <property name="can_focus">True</property>
942- <property name="receives_default">True</property>
943- <property name="use_action_appearance">False</property>
944- <property name="relief">none</property>
945- <property name="uri">http://twitter.com/ubuntuone</property>
946- <child>
947- <object class="GtkImage" id="twitter_logo">
948- <property name="visible">True</property>
949- <property name="can_focus">False</property>
950- <property name="tooltip_text" translatable="yes">http://twitter.com/ubuntuone</property>
951- </object>
952- </child>
953- </object>
954- <packing>
955- <property name="expand">False</property>
956- <property name="fill">False</property>
957- <property name="position">1</property>
958- </packing>
959- </child>
960- <child>
961- <object class="GtkLinkButton" id="linkbutton6">
962- <property name="visible">True</property>
963- <property name="can_focus">True</property>
964- <property name="receives_default">True</property>
965- <property name="use_action_appearance">False</property>
966- <property name="relief">none</property>
967- <property name="uri">http://www.facebook.com/ubuntuone</property>
968- <child>
969- <object class="GtkImage" id="facebook_logo">
970- <property name="visible">True</property>
971- <property name="can_focus">False</property>
972- <property name="tooltip_text" translatable="yes">http://www.facebook.com/ubuntuone</property>
973- </object>
974- </child>
975- </object>
976- <packing>
977- <property name="expand">True</property>
978- <property name="fill">True</property>
979- <property name="position">2</property>
980- </packing>
981- </child>
982- </object>
983- <packing>
984- <property name="expand">False</property>
985- <property name="fill">True</property>
986- <property name="pack_type">end</property>
987- <property name="position">1</property>
988- </packing>
989- </child>
990- </object>
991- <packing>
992- <property name="expand">False</property>
993- <property name="fill">True</property>
994- <property name="pack_type">end</property>
995- <property name="position">1</property>
996- </packing>
997- </child>
998- </object>
999-</interface>
1000
1001=== removed file 'data/gtk/overview.ui'
1002--- data/gtk/overview.ui 2011-09-14 19:08:52 +0000
1003+++ data/gtk/overview.ui 1970-01-01 00:00:00 +0000
1004@@ -1,308 +0,0 @@
1005-<?xml version="1.0" encoding="UTF-8"?>
1006-<interface>
1007- <requires lib="gtk+" version="2.22"/>
1008- <!-- interface-naming-policy project-wide -->
1009- <object class="GtkVBox" id="itself">
1010- <property name="visible">True</property>
1011- <property name="can_focus">False</property>
1012- <child>
1013- <object class="GtkEventBox" id="eventbox1">
1014- <property name="visible">True</property>
1015- <property name="can_focus">False</property>
1016- <child>
1017- <object class="GtkImage" id="banner">
1018- <property name="visible">True</property>
1019- <property name="can_focus">False</property>
1020- <property name="xpad">12</property>
1021- <property name="ypad">12</property>
1022- </object>
1023- </child>
1024- </object>
1025- <packing>
1026- <property name="expand">True</property>
1027- <property name="fill">True</property>
1028- <property name="position">0</property>
1029- </packing>
1030- </child>
1031- <child>
1032- <object class="GtkLabel" id="label7">
1033- <property name="visible">True</property>
1034- <property name="can_focus">False</property>
1035- <property name="label" translatable="yes">&lt;span font="24" foreground="#4d4d4d"&gt;The Power of Your Personal Cloud&lt;/span&gt;</property>
1036- <property name="use_markup">True</property>
1037- </object>
1038- <packing>
1039- <property name="expand">True</property>
1040- <property name="fill">True</property>
1041- <property name="position">1</property>
1042- </packing>
1043- </child>
1044- <child>
1045- <object class="GtkHBox" id="hbox1">
1046- <property name="visible">True</property>
1047- <property name="can_focus">False</property>
1048- <property name="border_width">12</property>
1049- <child>
1050- <object class="GtkTable" id="table1">
1051- <property name="visible">True</property>
1052- <property name="can_focus">False</property>
1053- <property name="n_rows">4</property>
1054- <property name="n_columns">2</property>
1055- <property name="column_spacing">10</property>
1056- <child>
1057- <object class="GtkImage" id="files_icon">
1058- <property name="visible">True</property>
1059- <property name="can_focus">False</property>
1060- </object>
1061- <packing>
1062- <property name="x_options">GTK_FILL</property>
1063- <property name="y_options">GTK_FILL</property>
1064- </packing>
1065- </child>
1066- <child>
1067- <object class="GtkImage" id="music_stream_icon">
1068- <property name="visible">True</property>
1069- <property name="can_focus">False</property>
1070- </object>
1071- <packing>
1072- <property name="top_attach">1</property>
1073- <property name="bottom_attach">2</property>
1074- <property name="x_options">GTK_FILL</property>
1075- <property name="y_options">GTK_FILL</property>
1076- </packing>
1077- </child>
1078- <child>
1079- <object class="GtkImage" id="contacts_icon">
1080- <property name="visible">True</property>
1081- <property name="can_focus">False</property>
1082- </object>
1083- <packing>
1084- <property name="top_attach">2</property>
1085- <property name="bottom_attach">3</property>
1086- <property name="x_options">GTK_FILL</property>
1087- <property name="y_options">GTK_FILL</property>
1088- </packing>
1089- </child>
1090- <child>
1091- <object class="GtkImage" id="notes_icon">
1092- <property name="visible">True</property>
1093- <property name="can_focus">False</property>
1094- </object>
1095- <packing>
1096- <property name="top_attach">3</property>
1097- <property name="bottom_attach">4</property>
1098- <property name="x_options">GTK_FILL</property>
1099- <property name="y_options">GTK_FILL</property>
1100- </packing>
1101- </child>
1102- <child>
1103- <object class="GtkLabel" id="label3">
1104- <property name="visible">True</property>
1105- <property name="can_focus">False</property>
1106- <property name="xalign">0</property>
1107- <property name="label" translatable="yes">Files Anywhere
1108-&lt;span foreground="#909090"&gt;Back up and access your files from Ubuntu, Windows, Web or Mobile&lt;/span&gt;</property>
1109- <property name="use_markup">True</property>
1110- <property name="wrap">True</property>
1111- </object>
1112- <packing>
1113- <property name="left_attach">1</property>
1114- <property name="right_attach">2</property>
1115- </packing>
1116- </child>
1117- <child>
1118- <object class="GtkLabel" id="label4">
1119- <property name="visible">True</property>
1120- <property name="can_focus">False</property>
1121- <property name="xalign">0</property>
1122- <property name="label" translatable="yes">Keep Connected
1123-&lt;span foreground="#909090"&gt;Unify your contacts across Desktop, Mobile and Web&lt;/span&gt;</property>
1124- <property name="use_markup">True</property>
1125- <property name="wrap">True</property>
1126- </object>
1127- <packing>
1128- <property name="left_attach">1</property>
1129- <property name="right_attach">2</property>
1130- <property name="top_attach">2</property>
1131- <property name="bottom_attach">3</property>
1132- </packing>
1133- </child>
1134- <child>
1135- <object class="GtkLabel" id="label5">
1136- <property name="visible">True</property>
1137- <property name="can_focus">False</property>
1138- <property name="xalign">0</property>
1139- <property name="label" translatable="yes">Rock Out
1140-&lt;span foreground="#909090"&gt;Your entire collection follows you around with music streaming to Android and iPhone&lt;/span&gt;</property>
1141- <property name="use_markup">True</property>
1142- <property name="wrap">True</property>
1143- </object>
1144- <packing>
1145- <property name="left_attach">1</property>
1146- <property name="right_attach">2</property>
1147- <property name="top_attach">1</property>
1148- <property name="bottom_attach">2</property>
1149- </packing>
1150- </child>
1151- <child>
1152- <object class="GtkLabel" id="label6">
1153- <property name="visible">True</property>
1154- <property name="can_focus">False</property>
1155- <property name="xalign">0</property>
1156- <property name="label" translatable="yes">Stay Productive
1157-&lt;span foreground="#909090"&gt;Keep your Tomboy notes synced&lt;/span&gt;</property>
1158- <property name="use_markup">True</property>
1159- <property name="wrap">True</property>
1160- </object>
1161- <packing>
1162- <property name="left_attach">1</property>
1163- <property name="right_attach">2</property>
1164- <property name="top_attach">3</property>
1165- <property name="bottom_attach">4</property>
1166- </packing>
1167- </child>
1168- </object>
1169- <packing>
1170- <property name="expand">True</property>
1171- <property name="fill">True</property>
1172- <property name="position">0</property>
1173- </packing>
1174- </child>
1175- <child>
1176- <object class="GtkVBox" id="vbox2">
1177- <property name="visible">True</property>
1178- <property name="can_focus">False</property>
1179- <child>
1180- <object class="GtkLabel" id="warning_label">
1181- <property name="visible">True</property>
1182- <property name="can_focus">False</property>
1183- <property name="label">A warning label that can be long. Possible really long, let's see how it behaves.</property>
1184- <property name="wrap">True</property>
1185- </object>
1186- <packing>
1187- <property name="expand">False</property>
1188- <property name="fill">True</property>
1189- <property name="position">0</property>
1190- </packing>
1191- </child>
1192- <child>
1193- <object class="GtkAlignment" id="alignment2">
1194- <property name="visible">True</property>
1195- <property name="can_focus">False</property>
1196- <property name="xscale">0</property>
1197- <property name="yscale">0</property>
1198- <child>
1199- <object class="GtkVBox" id="vbox3">
1200- <property name="visible">True</property>
1201- <property name="can_focus">False</property>
1202- <property name="spacing">10</property>
1203- <child>
1204- <object class="GtkButton" id="learn_more_button">
1205- <property name="visible">True</property>
1206- <property name="can_focus">True</property>
1207- <property name="receives_default">True</property>
1208- <property name="use_action_appearance">False</property>
1209- <signal name="clicked" handler="on_learn_more_button_clicked" swapped="no"/>
1210- <child>
1211- <object class="GtkVBox" id="vbox5">
1212- <property name="visible">True</property>
1213- <property name="can_focus">False</property>
1214- <child>
1215- <object class="GtkImage" id="image5">
1216- <property name="visible">True</property>
1217- <property name="can_focus">False</property>
1218- <property name="pixel_size">55</property>
1219- <property name="icon_name">ubuntuone</property>
1220- </object>
1221- <packing>
1222- <property name="expand">True</property>
1223- <property name="fill">True</property>
1224- <property name="position">0</property>
1225- </packing>
1226- </child>
1227- <child>
1228- <object class="GtkLabel" id="label8">
1229- <property name="visible">True</property>
1230- <property name="can_focus">False</property>
1231- <property name="label" translatable="yes">&lt;span foreground="#909090"&gt;Learn More&lt;/span&gt;</property>
1232- <property name="use_markup">True</property>
1233- </object>
1234- <packing>
1235- <property name="expand">True</property>
1236- <property name="fill">True</property>
1237- <property name="position">1</property>
1238- </packing>
1239- </child>
1240- </object>
1241- </child>
1242- </object>
1243- <packing>
1244- <property name="expand">True</property>
1245- <property name="fill">True</property>
1246- <property name="position">0</property>
1247- </packing>
1248- </child>
1249- <child>
1250- <object class="GtkButton" id="join_now_button">
1251- <property name="visible">True</property>
1252- <property name="can_focus">True</property>
1253- <property name="can_default">True</property>
1254- <property name="receives_default">True</property>
1255- <property name="use_action_appearance">False</property>
1256- <signal name="clicked" handler="on_join_now_button_clicked" swapped="no"/>
1257- <child>
1258- <object class="GtkLabel" id="label1">
1259- <property name="visible">True</property>
1260- <property name="can_focus">False</property>
1261- <property name="label" translatable="yes">&lt;span font_size="xx-large" foreground="#4d4d4d"&gt;Join now&lt;/span&gt;</property>
1262- <property name="use_markup">True</property>
1263- </object>
1264- </child>
1265- </object>
1266- <packing>
1267- <property name="expand">False</property>
1268- <property name="fill">True</property>
1269- <property name="position">1</property>
1270- </packing>
1271- </child>
1272- <child>
1273- <object class="GtkLinkButton" id="connect_button">
1274- <property name="label" translatable="yes">I already have an account!</property>
1275- <property name="visible">True</property>
1276- <property name="can_focus">True</property>
1277- <property name="receives_default">True</property>
1278- <property name="use_action_appearance">False</property>
1279- <property name="relief">none</property>
1280- <signal name="clicked" handler="on_connect_button_clicked" swapped="no"/>
1281- </object>
1282- <packing>
1283- <property name="expand">False</property>
1284- <property name="fill">False</property>
1285- <property name="position">2</property>
1286- </packing>
1287- </child>
1288- </object>
1289- </child>
1290- </object>
1291- <packing>
1292- <property name="expand">True</property>
1293- <property name="fill">True</property>
1294- <property name="position">1</property>
1295- </packing>
1296- </child>
1297- </object>
1298- <packing>
1299- <property name="expand">True</property>
1300- <property name="fill">True</property>
1301- <property name="position">1</property>
1302- </packing>
1303- </child>
1304- </object>
1305- <packing>
1306- <property name="expand">True</property>
1307- <property name="fill">True</property>
1308- <property name="position">2</property>
1309- </packing>
1310- </child>
1311- </object>
1312-</interface>
1313
1314=== removed file 'data/gtk/services.ui'
1315--- data/gtk/services.ui 2011-09-14 19:08:52 +0000
1316+++ data/gtk/services.ui 1970-01-01 00:00:00 +0000
1317@@ -1,317 +0,0 @@
1318-<?xml version="1.0" encoding="UTF-8"?>
1319-<interface>
1320- <requires lib="gtk+" version="2.22"/>
1321- <!-- interface-naming-policy project-wide -->
1322- <object class="GtkVBox" id="itself">
1323- <property name="visible">True</property>
1324- <property name="can_focus">False</property>
1325- <child>
1326- <object class="GtkScrolledWindow" id="scrolledwindow1">
1327- <property name="visible">True</property>
1328- <property name="can_focus">True</property>
1329- <property name="hscrollbar_policy">automatic</property>
1330- <property name="vscrollbar_policy">automatic</property>
1331- <child>
1332- <object class="GtkViewport" id="viewport1">
1333- <property name="visible">True</property>
1334- <property name="can_focus">False</property>
1335- <property name="resize_mode">queue</property>
1336- <property name="shadow_type">none</property>
1337- <child>
1338- <object class="GtkAlignment" id="alignment1">
1339- <property name="visible">True</property>
1340- <property name="can_focus">False</property>
1341- <property name="left_padding">5</property>
1342- <property name="right_padding">5</property>
1343- <child>
1344- <object class="GtkVBox" id="vbox1">
1345- <property name="visible">True</property>
1346- <property name="can_focus">False</property>
1347- <property name="spacing">5</property>
1348- <child>
1349- <object class="GtkFrame" id="files">
1350- <property name="visible">True</property>
1351- <property name="can_focus">False</property>
1352- <property name="label_xalign">0</property>
1353- <property name="shadow_type">out</property>
1354- <child>
1355- <object class="GtkAlignment" id="alignment2">
1356- <property name="visible">True</property>
1357- <property name="can_focus">False</property>
1358- <child>
1359- <object class="GtkHBox" id="hbox2">
1360- <property name="visible">True</property>
1361- <property name="can_focus">False</property>
1362- <property name="border_width">5</property>
1363- <child>
1364- <object class="GtkTable" id="table1">
1365- <property name="visible">True</property>
1366- <property name="can_focus">False</property>
1367- <property name="n_rows">3</property>
1368- <property name="n_columns">3</property>
1369- <property name="column_spacing">5</property>
1370- <property name="row_spacing">5</property>
1371- <child>
1372- <object class="GtkCheckButton" id="file_sync_check">
1373- <property name="visible">True</property>
1374- <property name="can_focus">True</property>
1375- <property name="receives_default">False</property>
1376- <property name="use_action_appearance">False</property>
1377- <property name="draw_indicator">True</property>
1378- </object>
1379- <packing>
1380- <property name="x_options"></property>
1381- <property name="y_options"></property>
1382- </packing>
1383- </child>
1384- <child>
1385- <object class="GtkImage" id="files_icon">
1386- <property name="visible">True</property>
1387- <property name="can_focus">False</property>
1388- </object>
1389- <packing>
1390- <property name="left_attach">1</property>
1391- <property name="right_attach">2</property>
1392- <property name="x_options"></property>
1393- <property name="y_options"></property>
1394- </packing>
1395- </child>
1396- <child>
1397- <object class="GtkLabel" id="label1">
1398- <property name="visible">True</property>
1399- <property name="can_focus">False</property>
1400- <property name="xalign">0</property>
1401- <property name="label" translatable="yes">Enable File Sync</property>
1402- </object>
1403- <packing>
1404- <property name="left_attach">2</property>
1405- <property name="right_attach">3</property>
1406- </packing>
1407- </child>
1408- <child>
1409- <object class="GtkLabel" id="label2">
1410- <property name="visible">True</property>
1411- <property name="can_focus">False</property>
1412- <property name="xalign">0</property>
1413- <property name="yalign">0</property>
1414- <property name="label" translatable="yes">&lt;span font_size="small"&gt;Enable and then choose which folders you want to access from the Web or any device you connected to Ubuntu One
1415-
1416-Simply drag and drop any file or folder to your Ubuntu One folder on this computer&lt;/span&gt;</property>
1417- <property name="use_markup">True</property>
1418- <property name="wrap">True</property>
1419- <property name="width_chars">35</property>
1420- </object>
1421- <packing>
1422- <property name="left_attach">2</property>
1423- <property name="right_attach">3</property>
1424- <property name="top_attach">1</property>
1425- <property name="bottom_attach">2</property>
1426- </packing>
1427- </child>
1428- <child>
1429- <object class="GtkHButtonBox" id="hbuttonbox1">
1430- <property name="visible">True</property>
1431- <property name="can_focus">False</property>
1432- <child>
1433- <object class="GtkButton" id="file_sync_button">
1434- <property name="label" translatable="yes">_Show me my Ubuntu One folder</property>
1435- <property name="visible">True</property>
1436- <property name="can_focus">True</property>
1437- <property name="receives_default">True</property>
1438- <property name="use_action_appearance">False</property>
1439- <property name="use_underline">True</property>
1440- <signal name="clicked" handler="on_file_sync_button_clicked" swapped="no"/>
1441- </object>
1442- <packing>
1443- <property name="expand">False</property>
1444- <property name="fill">False</property>
1445- <property name="position">0</property>
1446- </packing>
1447- </child>
1448- </object>
1449- <packing>
1450- <property name="left_attach">2</property>
1451- <property name="right_attach">3</property>
1452- <property name="top_attach">2</property>
1453- <property name="bottom_attach">3</property>
1454- </packing>
1455- </child>
1456- <child>
1457- <placeholder/>
1458- </child>
1459- <child>
1460- <placeholder/>
1461- </child>
1462- <child>
1463- <placeholder/>
1464- </child>
1465- <child>
1466- <placeholder/>
1467- </child>
1468- </object>
1469- <packing>
1470- <property name="expand">False</property>
1471- <property name="fill">True</property>
1472- <property name="position">0</property>
1473- </packing>
1474- </child>
1475- <child>
1476- <object class="GtkImage" id="files_example">
1477- <property name="visible">True</property>
1478- <property name="can_focus">False</property>
1479- </object>
1480- <packing>
1481- <property name="expand">False</property>
1482- <property name="fill">True</property>
1483- <property name="pack_type">end</property>
1484- <property name="position">1</property>
1485- </packing>
1486- </child>
1487- </object>
1488- </child>
1489- </object>
1490- </child>
1491- <child type="label_item">
1492- <placeholder/>
1493- </child>
1494- </object>
1495- <packing>
1496- <property name="expand">False</property>
1497- <property name="fill">True</property>
1498- <property name="position">0</property>
1499- </packing>
1500- </child>
1501- <child>
1502- <object class="GtkFrame" id="replications">
1503- <property name="visible">True</property>
1504- <property name="can_focus">False</property>
1505- <property name="label_xalign">0</property>
1506- <property name="shadow_type">out</property>
1507- <child>
1508- <object class="GtkAlignment" id="alignment3">
1509- <property name="visible">True</property>
1510- <property name="can_focus">False</property>
1511- <property name="top_padding">6</property>
1512- <child>
1513- <object class="GtkHBox" id="hbox3">
1514- <property name="visible">True</property>
1515- <property name="can_focus">False</property>
1516- <property name="border_width">5</property>
1517- <child>
1518- <object class="GtkVBox" id="contacts">
1519- <property name="visible">True</property>
1520- <property name="can_focus">False</property>
1521- <child>
1522- <object class="GtkTable" id="contacts_sync">
1523- <property name="visible">True</property>
1524- <property name="can_focus">False</property>
1525- <property name="n_rows">2</property>
1526- <property name="n_columns">3</property>
1527- <property name="column_spacing">5</property>
1528- <property name="row_spacing">5</property>
1529- <child>
1530- <object class="GtkCheckButton" id="contacts_check">
1531- <property name="visible">True</property>
1532- <property name="can_focus">True</property>
1533- <property name="receives_default">False</property>
1534- <property name="use_action_appearance">False</property>
1535- <property name="draw_indicator">True</property>
1536- </object>
1537- <packing>
1538- <property name="x_options"></property>
1539- <property name="y_options"></property>
1540- </packing>
1541- </child>
1542- <child>
1543- <object class="GtkImage" id="contacts_icon">
1544- <property name="visible">True</property>
1545- <property name="can_focus">False</property>
1546- </object>
1547- <packing>
1548- <property name="left_attach">1</property>
1549- <property name="right_attach">2</property>
1550- <property name="x_options"></property>
1551- <property name="y_options"></property>
1552- </packing>
1553- </child>
1554- <child>
1555- <object class="GtkLabel" id="label4">
1556- <property name="visible">True</property>
1557- <property name="can_focus">False</property>
1558- <property name="xalign">0</property>
1559- <property name="label" translatable="yes">Enable Contacts Sync</property>
1560- </object>
1561- <packing>
1562- <property name="left_attach">2</property>
1563- <property name="right_attach">3</property>
1564- </packing>
1565- </child>
1566- <child>
1567- <object class="GtkLabel" id="label5">
1568- <property name="visible">True</property>
1569- <property name="can_focus">True</property>
1570- <property name="xalign">0</property>
1571- <property name="yalign">0</property>
1572- <property name="label" translatable="yes">&lt;span font_size="small"&gt;Once enabled, visit the &lt;a href="https://one.ubuntu.com"&gt;Ubuntu One website&lt;/a&gt; to manage your contacts, including Gmail and Facebook import&lt;/span&gt;</property>
1573- <property name="use_markup">True</property>
1574- <property name="wrap">True</property>
1575- </object>
1576- <packing>
1577- <property name="left_attach">2</property>
1578- <property name="right_attach">3</property>
1579- <property name="top_attach">1</property>
1580- <property name="bottom_attach">2</property>
1581- </packing>
1582- </child>
1583- <child>
1584- <placeholder/>
1585- </child>
1586- <child>
1587- <placeholder/>
1588- </child>
1589- </object>
1590- <packing>
1591- <property name="expand">False</property>
1592- <property name="fill">True</property>
1593- <property name="position">0</property>
1594- </packing>
1595- </child>
1596- </object>
1597- <packing>
1598- <property name="expand">True</property>
1599- <property name="fill">True</property>
1600- <property name="position">0</property>
1601- </packing>
1602- </child>
1603- <child>
1604- <placeholder/>
1605- </child>
1606- </object>
1607- </child>
1608- </object>
1609- </child>
1610- <child type="label_item">
1611- <placeholder/>
1612- </child>
1613- </object>
1614- <packing>
1615- <property name="expand">False</property>
1616- <property name="fill">True</property>
1617- <property name="position">1</property>
1618- </packing>
1619- </child>
1620- </object>
1621- </child>
1622- </object>
1623- </child>
1624- </object>
1625- </child>
1626- </object>
1627- <packing>
1628- <property name="expand">True</property>
1629- <property name="fill">True</property>
1630- <property name="position">0</property>
1631- </packing>
1632- </child>
1633- </object>
1634-</interface>
1635
1636=== removed file 'data/gtk/volumes.ui'
1637--- data/gtk/volumes.ui 2011-07-11 11:19:09 +0000
1638+++ data/gtk/volumes.ui 1970-01-01 00:00:00 +0000
1639@@ -1,98 +0,0 @@
1640-<?xml version="1.0" encoding="UTF-8"?>
1641-<interface>
1642- <requires lib="gtk+" version="2.22"/>
1643- <!-- interface-naming-policy project-wide -->
1644- <object class="GtkAlignment" id="itself">
1645- <property name="visible">True</property>
1646- <property name="can_focus">False</property>
1647- <child>
1648- <object class="GtkScrolledWindow" id="scrolledwindow1">
1649- <property name="visible">True</property>
1650- <property name="can_focus">True</property>
1651- <property name="hscrollbar_policy">automatic</property>
1652- <property name="vscrollbar_policy">automatic</property>
1653- <property name="shadow_type">in</property>
1654- <child>
1655- <object class="GtkTreeView" id="volumes_view">
1656- <property name="visible">True</property>
1657- <property name="can_focus">True</property>
1658- <property name="model">volumes_store</property>
1659- <property name="rules_hint">True</property>
1660- <property name="tooltip_column">0</property>
1661- <signal name="row-activated" handler="on_volumes_view_row_activated" swapped="no"/>
1662- <child>
1663- <object class="GtkTreeViewColumn" id="treeviewcolumn2">
1664- <property name="resizable">True</property>
1665- <property name="sizing">autosize</property>
1666- <property name="expand">True</property>
1667- <child>
1668- <object class="GtkCellRendererPixbuf" id="cellrendererpixbuf1"/>
1669- <attributes>
1670- <attribute name="sensitive">1</attribute>
1671- <attribute name="icon-name">2</attribute>
1672- <attribute name="stock-size">5</attribute>
1673- </attributes>
1674- </child>
1675- <child>
1676- <object class="GtkCellRendererText" id="text_renderer">
1677- <property name="ellipsize">end</property>
1678- <property name="width_chars">80</property>
1679- </object>
1680- <attributes>
1681- <attribute name="markup">0</attribute>
1682- <attribute name="text">0</attribute>
1683- </attributes>
1684- </child>
1685- </object>
1686- </child>
1687- <child>
1688- <object class="GtkTreeViewColumn" id="treeviewcolumn3">
1689- <property name="sizing">autosize</property>
1690- <property name="title" translatable="yes">Sync locally?</property>
1691- <child>
1692- <object class="GtkCellRendererToggle" id="cellrenderertoggle1">
1693- <property name="indicator_size">15</property>
1694- <signal name="toggled" handler="on_subscribed_toggled" swapped="no"/>
1695- </object>
1696- <attributes>
1697- <attribute name="sensitive">4</attribute>
1698- <attribute name="visible">3</attribute>
1699- <attribute name="active">1</attribute>
1700- </attributes>
1701- </child>
1702- <child>
1703- <object class="GtkCellRendererText" id="cellrenderertext1">
1704- <property name="visible">False</property>
1705- </object>
1706- <attributes>
1707- <attribute name="text">6</attribute>
1708- </attributes>
1709- </child>
1710- </object>
1711- </child>
1712- </object>
1713- </child>
1714- </object>
1715- </child>
1716- </object>
1717- <object class="GtkTreeStore" id="volumes_store">
1718- <columns>
1719- <!-- column-name description -->
1720- <column type="gchararray"/>
1721- <!-- column-name subscribed -->
1722- <column type="gboolean"/>
1723- <!-- column-name icon-name -->
1724- <column type="gchararray"/>
1725- <!-- column-name subscribed-visible -->
1726- <column type="gboolean"/>
1727- <!-- column-name subscribed-sensitive -->
1728- <column type="gboolean"/>
1729- <!-- column-name icon-size -->
1730- <column type="gint"/>
1731- <!-- column-name identifier -->
1732- <column type="gchararray"/>
1733- <!-- column-name path -->
1734- <column type="gchararray"/>
1735- </columns>
1736- </object>
1737-</interface>
1738
1739=== removed file 'docs/ubuntuone-control-panel-gtk.1'
1740--- docs/ubuntuone-control-panel-gtk.1 2011-09-07 13:50:37 +0000
1741+++ docs/ubuntuone-control-panel-gtk.1 1970-01-01 00:00:00 +0000
1742@@ -1,15 +0,0 @@
1743-.TH UBUNTUONE-CONTROL-PANEL-GTK 1
1744-
1745-.SH NAME
1746-ubuntuone-control-panel-gtk \- A GTK UI for managing an Ubuntu One account
1747-
1748-.SH SYNOPSYS
1749-.B ubutuone-control-panel-gtk
1750-
1751-.SH DESCRIPTION
1752-This manual page briefly documents the
1753-.BR ubuntuone-control-panel-gtk
1754-process, which provides a desktop application to manage an Ubuntu One account.
1755-
1756-.SH AUTHOR
1757-This manual page was written by Natalia Bidart <natalia.bidart@canonical.com>
1758
1759=== modified file 'po/POTFILES.in'
1760--- po/POTFILES.in 2011-09-16 14:37:20 +0000
1761+++ po/POTFILES.in 2012-03-02 19:03:20 +0000
1762@@ -1,9 +1,1 @@
1763 ubuntuone/controlpanel/gui/__init__.py
1764-[type: gettext/glade] data/gtk/dashboard.ui
1765-[type: gettext/glade] data/gtk/device.ui
1766-[type: gettext/glade] data/gtk/devices.ui
1767-[type: gettext/glade] data/gtk/install.ui
1768-[type: gettext/glade] data/gtk/management.ui
1769-[type: gettext/glade] data/gtk/overview.ui
1770-[type: gettext/glade] data/gtk/services.ui
1771-[type: gettext/glade] data/gtk/volumes.ui
1772
1773=== modified file 'run-tests'
1774--- run-tests 2012-02-24 21:00:56 +0000
1775+++ run-tests 2012-03-02 19:03:20 +0000
1776@@ -17,7 +17,6 @@
1777 # with this program. If not, see <http://www.gnu.org/licenses/>.
1778
1779 QT_TESTS_PATH="ubuntuone/controlpanel/gui/qt/tests, ubuntuone/controlpanel/gui/qt/main/tests"
1780-GTK_TESTS_PATH=ubuntuone/controlpanel/gui/gtk/tests
1781 DBUS_TESTS_PATH=ubuntuone/controlpanel/dbustests
1782 WINDOWS_TESTS=test_windows.py
1783
1784@@ -39,7 +38,6 @@
1785 echo "Please install the 'pep8' package."
1786 fi
1787 }
1788-unset GTK_MODULES
1789
1790 XVFB_CMDLINE=""
1791 XVFB=$(which xvfb-run)
1792@@ -48,17 +46,14 @@
1793 fi
1794
1795 echo "*** Running test suite for ""$MODULE"" ***"
1796-u1trial --reactor=gi -p "$DBUS_TESTS_PATH, $QT_TESTS_PATH, $GTK_TESTS_PATH" -i "$WINDOWS_TESTS" "$MODULE"
1797+u1trial --reactor=gi -p "$DBUS_TESTS_PATH, $QT_TESTS_PATH" -i "$WINDOWS_TESTS" "$MODULE"
1798
1799 echo "*** Running DBus test suite ***"
1800 u1trial --reactor=glib "$DBUS_TESTS_PATH"
1801
1802-echo "*** Running GTK test suite ***"
1803-$XVFB_CMDLINE u1trial --reactor=glib "$GTK_TESTS_PATH"
1804-
1805 echo "*** Running QT test suite for ""$MODULE"" ***"
1806 ./setup.py build
1807-$XVFB_CMDLINE u1trial -p "$GTK_TESTS_PATH" -i "$WINDOWS_TESTS" --reactor=qt4 --gui "$MODULE"
1808+$XVFB_CMDLINE u1trial -i "$WINDOWS_TESTS" --reactor=qt4 --gui "$MODULE"
1809 rm -rf _trial_temp
1810 rm -rf build
1811
1812
1813=== modified file 'run-tests.bat'
1814--- run-tests.bat 2012-01-31 16:55:33 +0000
1815+++ run-tests.bat 2012-03-02 19:03:20 +0000
1816@@ -18,7 +18,7 @@
1817
1818 SET MODULE="ubuntuone"
1819 SET PYTHONEXEPATH="C:\Python27"
1820-SET IGNORE_PATHS="ubuntuone\controlpanel\gui\gtk, ubuntuone\controlpanel\dbustests"
1821+SET IGNORE_PATHS="ubuntuone\controlpanel\dbustests"
1822 SET IGNORE_MODULES="test_linux.py, test_libsoup.py"
1823
1824 :: throw the first parameter away if is /skip-lint,
1825
1826=== modified file 'setup.py'
1827--- setup.py 2012-02-22 11:47:17 +0000
1828+++ setup.py 2012-03-02 19:03:20 +0000
1829@@ -39,12 +39,11 @@
1830
1831 POT_FILE = 'po/ubuntuone-control-panel.pot'
1832 SERVICE_FILE = 'com.ubuntuone.controlpanel.service'
1833-GUI_SERVICE_FILE = 'com.ubuntuone.controlpanel.gui.service'
1834 MESSAGE_ENTRY = 'ubuntuone-control-panel'
1835 CONSTANTS = 'ubuntuone/controlpanel/constants.py'
1836
1837 CLEANFILES = [
1838- SERVICE_FILE, GUI_SERVICE_FILE, MESSAGE_ENTRY, CONSTANTS, POT_FILE,
1839+ SERVICE_FILE, MESSAGE_ENTRY, CONSTANTS, POT_FILE,
1840 'MANIFEST']
1841 QT_UI_DIR = os.path.join('ubuntuone', 'controlpanel', 'gui', 'qt', 'ui')
1842
1843@@ -52,7 +51,7 @@
1844 def replace_prefix(prefix):
1845 """Replace every '@prefix@' with prefix within 'filename' content."""
1846 # replace .service file, DATA_DIR constant
1847- for filename in (SERVICE_FILE, GUI_SERVICE_FILE, MESSAGE_ENTRY, CONSTANTS):
1848+ for filename in (SERVICE_FILE, MESSAGE_ENTRY, CONSTANTS):
1849 with open(filename + '.in') as in_file:
1850 content = in_file.read()
1851 with open(filename, 'w') as out_file:
1852@@ -206,7 +205,6 @@
1853 'ubuntuone',
1854 'ubuntuone.controlpanel',
1855 'ubuntuone.controlpanel.gui',
1856- 'ubuntuone.controlpanel.gui.gtk',
1857 'ubuntuone.controlpanel.gui.qt',
1858 'ubuntuone.controlpanel.gui.qt.main',
1859 'ubuntuone.controlpanel.gui.qt.ui',
1860@@ -218,7 +216,7 @@
1861 data_files=[
1862 ('lib/ubuntuone-control-panel',
1863 ['bin/ubuntuone-control-panel-backend']),
1864- ('share/dbus-1/services/', [SERVICE_FILE, GUI_SERVICE_FILE]),
1865+ ('share/dbus-1/services/', [SERVICE_FILE]),
1866 ('share/indicators/messages/applications/', [MESSAGE_ENTRY]),
1867 ('share/apport/package-hooks/',
1868 ['data/source_ubuntuone-control-panel.py']),
1869
1870=== removed file 'ubuntuone/controlpanel/dbustests/test_gui_service.py'
1871--- ubuntuone/controlpanel/dbustests/test_gui_service.py 2011-11-21 13:37:07 +0000
1872+++ ubuntuone/controlpanel/dbustests/test_gui_service.py 1970-01-01 00:00:00 +0000
1873@@ -1,104 +0,0 @@
1874-# -*- coding: utf-8 -*-
1875-
1876-# Authors: Alejandro J. Cura <alecu@canonical.com>
1877-# Natalia B. Bidart <nataliabidart@canonical.com>
1878-# Eric Casteleijn <eric.casteleijn@canonical.com>
1879-#
1880-# Copyright 2011 Canonical Ltd.
1881-#
1882-# This program is free software: you can redistribute it and/or modify it
1883-# under the terms of the GNU General Public License version 3, as published
1884-# by the Free Software Foundation.
1885-#
1886-# This program is distributed in the hope that it will be useful, but
1887-# WITHOUT ANY WARRANTY; without even the implied warranties of
1888-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1889-# PURPOSE. See the GNU General Public License for more details.
1890-#
1891-# You should have received a copy of the GNU General Public License along
1892-# with this program. If not, see <http://www.gnu.org/licenses/>.
1893-
1894-"""Tests for the control panel backend DBus service."""
1895-
1896-import dbus
1897-import mocker
1898-
1899-from dbus.mainloop.glib import DBusGMainLoop
1900-from twisted.internet import defer
1901-
1902-from ubuntuone.controlpanel.gui.gtk import gui
1903-from ubuntuone.devtools.testcases.dbus import DBusTestCase
1904-from twisted.trial.unittest import TestCase
1905-
1906-
1907-class MockWindow(object):
1908- """A mock backend."""
1909-
1910- exception = None
1911-
1912- def __init__(self, switch_to=None, alert=False):
1913- self.called = []
1914-
1915- def draw_attention(self):
1916- """Draw attention to the control panel."""
1917- self.called.append('draw_attention')
1918-
1919- def switch_to(self, panel):
1920- """Switch to named panel."""
1921- self.called.append(('switch_to', panel))
1922-
1923-
1924-class DBusServiceMockTestCase(TestCase):
1925- """Tests for the main function."""
1926-
1927- @defer.inlineCallbacks
1928- def setUp(self):
1929- yield super(DBusServiceMockTestCase, self).setUp()
1930- self.mocker = mocker.Mocker()
1931-
1932- @defer.inlineCallbacks
1933- def tearDown(self):
1934- yield super(DBusServiceMockTestCase, self).tearDown()
1935- self.mocker.restore()
1936- self.mocker.verify()
1937-
1938- def test_dbus_service_main(self):
1939- """The main method starts the loop and hooks up to DBus."""
1940- self.patch(gui, 'ControlPanelWindow', MockWindow)
1941- dbus_gmain_loop = self.mocker.replace(
1942- "dbus.mainloop.glib.DBusGMainLoop")
1943- register_service = self.mocker.replace(
1944- "ubuntuone.controlpanel.gui.gtk.gui.register_service")
1945- publish_service = self.mocker.replace(
1946- "ubuntuone.controlpanel.gui.gtk.gui.publish_service")
1947- main = self.mocker.replace("gtk.main")
1948- dbus_gmain_loop(set_as_default=True)
1949- loop = self.mocker.mock()
1950- self.mocker.result(loop)
1951- register_service(mocker.ANY)
1952- self.mocker.result(True)
1953- publish_service(switch_to='', alert=False)
1954- main()
1955- self.mocker.replay()
1956- gui.main()
1957-
1958-
1959-class DBusServiceTestCase(DBusTestCase):
1960- """Test for the DBus service."""
1961-
1962- def _set_called(self, *args, **kwargs):
1963- """Keep track of function calls, useful for monkeypatching."""
1964- self._called = (args, kwargs)
1965-
1966- @defer.inlineCallbacks
1967- def setUp(self):
1968- """Initialize each test run."""
1969- yield super(DBusServiceTestCase, self).setUp()
1970- DBusGMainLoop(set_as_default=True)
1971- self._called = False
1972-
1973- def test_register_service(self):
1974- """The DBus service is successfully registered."""
1975- bus = dbus.SessionBus()
1976- ret = gui.register_service(bus)
1977- self.assertTrue(ret)
1978
1979=== removed directory 'ubuntuone/controlpanel/gui/gtk'
1980=== removed file 'ubuntuone/controlpanel/gui/gtk/__init__.py'
1981--- ubuntuone/controlpanel/gui/gtk/__init__.py 2011-05-24 14:20:18 +0000
1982+++ ubuntuone/controlpanel/gui/gtk/__init__.py 1970-01-01 00:00:00 +0000
1983@@ -1,28 +0,0 @@
1984-# -*- coding: utf-8 -*-
1985-
1986-# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
1987-#
1988-# Copyright 2010 Canonical Ltd.
1989-#
1990-# This program is free software: you can redistribute it and/or modify it
1991-# under the terms of the GNU General Public License version 3, as published
1992-# by the Free Software Foundation.
1993-#
1994-# This program is distributed in the hope that it will be useful, but
1995-# WITHOUT ANY WARRANTY; without even the implied warranties of
1996-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1997-# PURPOSE. See the GNU General Public License for more details.
1998-#
1999-# You should have received a copy of the GNU General Public License along
2000-# with this program. If not, see <http://www.gnu.org/licenses/>.
2001-
2002-"""The GTK graphical interface for the control panel for Ubuntu One."""
2003-
2004-DBUS_BUS_NAME = 'com.ubuntuone.controlpanel.gui'
2005-DBUS_PATH = '/gui'
2006-DBUS_IFACE_GUI = 'com.ubuntuone.controlpanel.gui'
2007-
2008-# Unused import main
2009-# pylint: disable=W0611
2010-
2011-from ubuntuone.controlpanel.gui.gtk.gui import main
2012
2013=== removed file 'ubuntuone/controlpanel/gui/gtk/gui.py'
2014--- ubuntuone/controlpanel/gui/gtk/gui.py 2012-02-06 21:02:54 +0000
2015+++ ubuntuone/controlpanel/gui/gtk/gui.py 1970-01-01 00:00:00 +0000
2016@@ -1,1667 +0,0 @@
2017-# -*- coding: utf-8 -*-
2018-
2019-# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
2020-# Eric Casteleijn <eric.casteleijn@canonical.com>
2021-#
2022-# Copyright 2010 Canonical Ltd.
2023-#
2024-# This program is free software: you can redistribute it and/or modify it
2025-# under the terms of the GNU General Public License version 3, as published
2026-# by the Free Software Foundation.
2027-#
2028-# This program is distributed in the hope that it will be useful, but
2029-# WITHOUT ANY WARRANTY; without even the implied warranties of
2030-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2031-# PURPOSE. See the GNU General Public License for more details.
2032-#
2033-# You should have received a copy of the GNU General Public License along
2034-# with this program. If not, see <http://www.gnu.org/licenses/>.
2035-
2036-"""The user interface for the control panel for Ubuntu One."""
2037-
2038-from __future__ import division
2039-
2040-import os
2041-
2042-from functools import wraps
2043-
2044-import dbus
2045-import gtk
2046-import gobject
2047-
2048-from dbus.mainloop.glib import DBusGMainLoop
2049-from ubuntu_sso import networkstate
2050-# pylint: disable=E0611,F0401
2051-from ubuntuone.platform.credentials import (
2052- APP_NAME as U1_APP_NAME,
2053- CredentialsManagementTool,
2054-)
2055-# pylint: enable=E0611,F0401
2056-
2057-# Wildcard import ubuntuone.controlpanel.gui
2058-# pylint: disable=W0401, W0614
2059-from ubuntuone.controlpanel.gui import *
2060-# pylint: enable=W0401, W0614
2061-from ubuntuone.controlpanel.gui.gtk import (
2062- DBUS_IFACE_GUI, DBUS_BUS_NAME as DBUS_BUS_NAME_GUI,
2063- DBUS_PATH as DBUS_PATH_GUI, package_manager)
2064-from ubuntuone.controlpanel.gui.gtk.widgets import LabelLoading, PanelTitle
2065-# Use ubiquity package when ready (LP: #673665)
2066-from ubuntuone.controlpanel.gui.gtk.widgets import GreyableBin
2067-
2068-from ubuntuone.controlpanel import (DBUS_BUS_NAME, DBUS_PREFERENCES_PATH,
2069- DBUS_PREFERENCES_IFACE, TRANSLATION_DOMAIN, backend)
2070-from ubuntuone.controlpanel.backend import (DEVICE_TYPE_PHONE,
2071- DEVICE_TYPE_COMPUTER)
2072-from ubuntuone.controlpanel.dbus_service import bool_str
2073-from ubuntuone.controlpanel.logger import setup_logging, log_call
2074-from ubuntuone.controlpanel.utils import (get_data_file,
2075- ERROR_TYPE, ERROR_MESSAGE)
2076-
2077-
2078-try:
2079- from gi.repository import Unity # pylint: disable=E0611
2080- USE_LIBUNITY = True
2081- U1_DOTDESKTOP = "ubuntuone-installer.desktop"
2082-except ImportError:
2083- USE_LIBUNITY = False
2084-
2085-logger = setup_logging('gtk.gui')
2086-
2087-
2088-WARNING_MARKUP = '<span foreground="%s"><b>%%s</b></span>' % ERROR_COLOR
2089-
2090-CP_WMCLASS_NAME = 'ubuntuone-control-panel-gtk'
2091-CP_WMCLASS_CLASS = 'ubuntuone-installer'
2092-
2093-
2094-def error_handler(*args, **kwargs):
2095- """Log errors when calling D-Bus methods in a async way."""
2096- logger.error('Error handler received: %r, %r', args, kwargs)
2097-
2098-
2099-def register_service(bus):
2100- """Try to register DBus service for making sure we run only one instance.
2101-
2102- Return True if succesfully registered, False if already running.
2103- """
2104- name = bus.request_name(DBUS_BUS_NAME_GUI,
2105- dbus.bus.NAME_FLAG_DO_NOT_QUEUE)
2106- return name != dbus.bus.REQUEST_NAME_REPLY_EXISTS
2107-
2108-
2109-def publish_service(window=None, switch_to='', alert=False):
2110- """Publish the service on DBus."""
2111- if window is None:
2112- window = ControlPanelWindow(switch_to=switch_to, alert=alert)
2113- return ControlPanelService(window)
2114-
2115-
2116-def main(switch_to='', alert=False):
2117- """Hook the DBus listeners and start the main loop."""
2118- DBusGMainLoop(set_as_default=True)
2119- bus = dbus.SessionBus()
2120- if register_service(bus):
2121- publish_service(switch_to=switch_to, alert=alert)
2122- else:
2123- obj = bus.get_object(DBUS_BUS_NAME_GUI, DBUS_PATH_GUI)
2124- service = dbus.Interface(obj, dbus_interface=DBUS_IFACE_GUI)
2125-
2126- def gui_error_handler(*args, **kwargs):
2127- """Log errors when calling D-Bus methods in a async way."""
2128- logger.error('Error handler received: %r, %r', args, kwargs)
2129- gtk.main_quit()
2130-
2131- def gui_reply_handler(*args, **kwargs):
2132- """Exit when done."""
2133- gtk.main_quit()
2134-
2135- service.switch_to_alert(
2136- switch_to, alert, reply_handler=gui_reply_handler,
2137- error_handler=gui_error_handler)
2138-
2139- gtk.main()
2140-
2141-
2142-def on_size_allocate(widget, allocation, label):
2143- """Resize labels according to who 'widget' is being resized."""
2144- label.set_size_request(allocation.width - 2, -1)
2145-
2146-
2147-@log_call(logger.debug)
2148-def uri_hook(button, uri, *args, **kwargs):
2149- """Open an URI or do nothing if URI is not an URL."""
2150- if uri.startswith('http') or uri.startswith(FILE_URI_PREFIX):
2151- gtk.show_uri(None, uri, gtk.gdk.CURRENT_TIME)
2152-
2153-
2154-class ControlPanelMixin(object):
2155- """A basic mixin class to provide common functionality to widgets."""
2156-
2157- def __init__(self, filename=None, backend_instance=None):
2158- if backend_instance is not None:
2159- self.backend = backend_instance
2160- else:
2161- bus = dbus.SessionBus()
2162- try:
2163- obj = bus.get_object(DBUS_BUS_NAME,
2164- DBUS_PREFERENCES_PATH,
2165- follow_name_owner_changes=True)
2166- iface = DBUS_PREFERENCES_IFACE
2167- self.backend = dbus.Interface(obj, dbus_interface=iface)
2168- except dbus.exceptions.DBusException:
2169- logger.exception('Can not connect to DBus at %r',
2170- (DBUS_BUS_NAME, DBUS_PREFERENCES_PATH))
2171- raise
2172-
2173- if filename is not None:
2174- builder = gtk.Builder()
2175- builder.set_translation_domain(TRANSLATION_DOMAIN)
2176- builder.add_from_file(get_data_file(os.path.join('gtk', filename)))
2177- builder.connect_signals(self)
2178-
2179- # untested directly
2180- for obj in builder.get_objects():
2181- name = getattr(obj, 'name', None)
2182- if name is None and isinstance(obj, gtk.Buildable):
2183- # work around bug lp:507739
2184- name = gtk.Buildable.get_name(obj)
2185- if name is None:
2186- logger.warning("%s has no name (??)", obj)
2187- else:
2188- setattr(self, name, obj)
2189-
2190- logger.debug('%s: started.', self.__class__.__name__)
2191-
2192- def _set_warning(self, message, label):
2193- """Set 'message' as warning in 'label'."""
2194- label.set_markup(WARNING_MARKUP % message)
2195- label.show()
2196-
2197- def destroy(self):
2198- """Cleanup."""
2199-
2200-
2201-class UbuntuOneBin(gtk.VBox):
2202- """A Ubuntu One bin."""
2203-
2204- TITLE = ''
2205-
2206- def __init__(self, title=None):
2207- gtk.VBox.__init__(self)
2208- self._is_processing = False
2209-
2210- if title is None:
2211- title = self.TITLE
2212-
2213- title = '<span font_size="large">%s</span>' % title
2214- self.title = PanelTitle(markup=title)
2215- self.pack_start(self.title, expand=False)
2216-
2217- self.message = LabelLoading(LOADING)
2218- self.pack_start(self.message, expand=False)
2219-
2220- self.connect('size-allocate', on_size_allocate, self.title)
2221- self.show_all()
2222-
2223- def _get_is_processing(self):
2224- """Is this panel processing a request?"""
2225- return self._is_processing
2226-
2227- def _set_is_processing(self, new_value):
2228- """Set if this panel is processing a request."""
2229- if new_value:
2230- self.message.start()
2231- self.set_sensitive(False)
2232- else:
2233- self.message.stop()
2234- self.set_sensitive(True)
2235-
2236- self._is_processing = new_value
2237-
2238- is_processing = property(fget=_get_is_processing, fset=_set_is_processing)
2239-
2240- @log_call(logger.debug)
2241- def on_success(self, message=''):
2242- """Use this callback to stop the Loading and show 'message'."""
2243- self.message.stop()
2244- self.message.set_markup(message)
2245-
2246- @log_call(logger.error)
2247- def on_error(self, message=None, error_dict=None):
2248- """Use this callback to stop the Loading and set a warning message."""
2249- if message is None and error_dict is None:
2250- message = VALUE_ERROR
2251- elif message is None and error_dict is not None:
2252- error_type = error_dict.get(ERROR_TYPE, UNKNOWN_ERROR)
2253- error_msg = error_dict.get(ERROR_MESSAGE)
2254- if error_msg:
2255- message = "%s (%s: %s)" % (VALUE_ERROR, error_type, error_msg)
2256- else:
2257- message = "%s (%s)" % (VALUE_ERROR, error_type)
2258-
2259- assert message is not None
2260-
2261- self.message.stop()
2262- self.message.set_markup(WARNING_MARKUP % message)
2263-
2264-
2265-class OverviewPanel(GreyableBin, ControlPanelMixin):
2266- """The overview panel. Introduces Ubuntu One to the not logged user."""
2267-
2268- __gsignals__ = {
2269- 'credentials-found': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
2270- (gobject.TYPE_BOOLEAN,)),
2271- }
2272-
2273- def __init__(self, main_window):
2274- GreyableBin.__init__(self)
2275- creds_backend = CredentialsManagementTool()
2276- ControlPanelMixin.__init__(self, filename='overview.ui',
2277- backend_instance=creds_backend)
2278- self.add(self.itself)
2279- self.banner.set_from_file(get_data_file(OVERVIEW_BANNER))
2280- self.files_icon.set_from_file(get_data_file(FILES_ICON))
2281- self.music_stream_icon.set_from_file(get_data_file(MUSIC_STREAM_ICON))
2282- self.contacts_icon.set_from_file(get_data_file(CONTACTS_ICON))
2283- self.notes_icon.set_from_file(get_data_file(NOTES_ICON))
2284-
2285- self.warning_label.set_text('')
2286- self.warning_label.set_property('xalign', 0.5)
2287-
2288- self.connect_button.set_uri(CONNECT_BUTTON_LABEL)
2289-
2290- self.main_window = main_window
2291- self._credentials_are_new = False
2292- self.show()
2293-
2294- kw = dict(result_cb=self.on_network_state_changed)
2295- self.network_manager_state = networkstate.NetworkManagerState(**kw)
2296- self.network_manager_state.find_online_state()
2297-
2298- def _set_warning(self, message, label=None):
2299- """Set 'message' as global warning."""
2300- ControlPanelMixin._set_warning(self, message,
2301- label=self.warning_label)
2302-
2303- def _window_xid(self):
2304- """Return settings for credentials backend."""
2305- if self.main_window.window is not None:
2306- settings = {'window_id': str(self.main_window.window.xid)}
2307- else:
2308- settings = {}
2309- return settings
2310-
2311- def set_property(self, prop_name, new_value):
2312- """Override 'set_property' to disable buttons if prop is 'greyed'."""
2313- if prop_name == 'greyed':
2314- self.set_sensitive(not new_value)
2315- GreyableBin.set_property(self, prop_name, new_value)
2316-
2317- def set_sensitive(self, value):
2318- """Set the sensitiveness as per 'value'."""
2319- self.join_now_button.set_sensitive(value)
2320- self.connect_button.set_sensitive(value)
2321-
2322- def get_sensitive(self):
2323- """Return the sensitiveness."""
2324- result = self.join_now_button.get_sensitive() and \
2325- self.connect_button.get_sensitive()
2326- return result
2327-
2328- def on_join_now_button_clicked(self, *a, **kw):
2329- """User wants to join now."""
2330- d = self.backend.register(**self._window_xid())
2331- d.addCallback(self.on_credentials_result)
2332- d.addErrback(self.on_credentials_error)
2333- self.set_property('greyed', True)
2334- self.warning_label.set_text('')
2335-
2336- def on_connect_button_clicked(self, *a, **kw):
2337- """User wants to connect now."""
2338- d = self.backend.login(**self._window_xid())
2339- d.addCallback(self.on_credentials_result)
2340- d.addErrback(self.on_credentials_error)
2341- self.set_property('greyed', True)
2342- self.warning_label.set_text('')
2343-
2344- def on_learn_more_button_clicked(self, *a, **kw):
2345- """User wants to learn more."""
2346- uri_hook(self.learn_more_button, LEARN_MORE_LINK)
2347-
2348- def on_credentials_result(self, result):
2349- """Process the credentials response.
2350-
2351- If 'result' is a non empty dict, they were found.
2352- If 'result' is an empty dict, they were not found.
2353- If 'result' is None, the user cancelled the process.
2354-
2355- """
2356- if result is None:
2357- self.on_authorization_denied()
2358- elif result == {}:
2359- self.on_credentials_not_found()
2360- else:
2361- self.on_credentials_found(result)
2362-
2363- @log_call(logger.info, with_args=False)
2364- def on_credentials_found(self, credentials):
2365- """Credentials backend notifies of credentials found."""
2366- self.set_property('greyed', False)
2367- self.emit('credentials-found', self._credentials_are_new)
2368-
2369- @log_call(logger.info)
2370- def on_credentials_not_found(self):
2371- """Creds backend notifies of credentials not found."""
2372- self._credentials_are_new = True
2373- self.set_property('greyed', False)
2374-
2375- @log_call(logger.error)
2376- def on_credentials_error(self, error_dict):
2377- """Creds backend notifies of an error when fetching credentials."""
2378- self.set_property('greyed', False)
2379- self._set_warning(CREDENTIALS_ERROR)
2380-
2381- @log_call(logger.info)
2382- def on_authorization_denied(self):
2383- """Creds backend notifies that user refused auth for 'app_name'."""
2384- self.set_property('greyed', False)
2385-
2386- @log_call(logger.info)
2387- def on_network_state_changed(self, state):
2388- """Network state is reported."""
2389- msg = ''
2390- if state is networkstate.OFFLINE:
2391- msg = NETWORK_OFFLINE % {'app_name': U1_APP_NAME}
2392- self.set_sensitive(False)
2393- self._set_warning(msg)
2394- else:
2395- self.set_sensitive(True)
2396- self.warning_label.set_text(msg)
2397- d = self.backend.find_credentials()
2398- d.addCallback(self.on_credentials_result)
2399- d.addErrback(self.on_credentials_error)
2400-
2401-
2402-class DashboardPanel(UbuntuOneBin, ControlPanelMixin):
2403- """The dashboard panel. The user can manage the subscription."""
2404-
2405- TITLE = DASHBOARD_TITLE
2406- VALUE_ERROR = DASHBOARD_VALUE_ERROR
2407-
2408- def __init__(self, main_window=None):
2409- UbuntuOneBin.__init__(self)
2410- ControlPanelMixin.__init__(self, filename='dashboard.ui')
2411- self.add(self.itself)
2412- self.show()
2413-
2414- self.is_processing = True
2415-
2416- self.backend.connect_to_signal('AccountInfoReady',
2417- self.on_account_info_ready)
2418- self.backend.connect_to_signal('AccountInfoError',
2419- self.on_account_info_error)
2420- self.account.hide()
2421-
2422- @log_call(logger.debug)
2423- def on_account_info_ready(self, info):
2424- """Backend notifies of account info."""
2425- self.on_success()
2426-
2427- for i in (u'name', u'type', u'email'):
2428- label = getattr(self, '%s_label' % i)
2429- label.set_markup('%s' % (info[i]))
2430- self.account.show()
2431-
2432- self.is_processing = False
2433-
2434- @log_call(logger.error)
2435- def on_account_info_error(self, error_dict=None):
2436- """Backend notifies of an error when fetching account info."""
2437- self.on_error(message=self.VALUE_ERROR)
2438- self.is_processing = False
2439-
2440-
2441-class VolumesPanel(UbuntuOneBin, ControlPanelMixin):
2442- """The volumes panel."""
2443-
2444- TITLE = FOLDERS_TITLE
2445- MAX_COLS = 8
2446- FREE_SPACE = '<span foreground="grey">%s</span>' % FREE_SPACE_TEXT
2447- NO_FREE_SPACE = '<span foreground="red"><b>%s</b></span>' % FREE_SPACE_TEXT
2448- ROW_HEADER = '<span font_size="large"><b>%s</b></span> %s'
2449- ROOT = '%s - <span foreground="%s" font_size="small">%s</span>'
2450-
2451- def __init__(self, main_window=None):
2452- UbuntuOneBin.__init__(self)
2453- ControlPanelMixin.__init__(self, filename='volumes.ui')
2454- self.add(self.itself)
2455- self.show_all()
2456-
2457- kw = dict(parent=main_window,
2458- flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
2459- type=gtk.MESSAGE_WARNING,
2460- buttons=gtk.BUTTONS_YES_NO)
2461- self.confirm_dialog = gtk.MessageDialog(**kw)
2462-
2463- # name, subscribed, icon name, show toggle, sensitive, icon size,
2464- # id, path
2465- self._empty_row = ('', False, '', False, False, gtk.ICON_SIZE_MENU,
2466- None, None)
2467-
2468- self.backend.connect_to_signal('VolumesInfoReady',
2469- self.on_volumes_info_ready)
2470- self.backend.connect_to_signal('VolumesInfoError',
2471- self.on_volumes_info_error)
2472- self.backend.connect_to_signal('VolumeSettingsChanged',
2473- self.on_volume_settings_changed)
2474- self.backend.connect_to_signal('VolumeSettingsChangeError',
2475- self.on_volume_settings_change_error)
2476-
2477- def _process_name(self, name):
2478- """Tweak 'name' with a translatable music folder name."""
2479- if name == MUSIC_REAL_PATH:
2480- result = MUSIC_DISPLAY_NAME
2481- else:
2482- result = name
2483- return result
2484-
2485- def on_volumes_info_ready(self, info):
2486- """Backend notifies of volumes info."""
2487-
2488- self.volumes_store.clear()
2489- if not info:
2490- self.on_success(NO_FOLDERS)
2491- return
2492- else:
2493- self.on_success()
2494-
2495- for name, free_bytes, volumes in info:
2496- if backend.ControlBackend.NAME_NOT_SET in name:
2497- name = NAME_NOT_SET
2498-
2499- if name:
2500- name = name + "'s"
2501- # we already added user folders, let's add an empty row
2502- treeiter = self.volumes_store.append(None, self._empty_row)
2503- else:
2504- name = MY_FOLDERS
2505-
2506- scroll_to_cell = False
2507- if free_bytes == backend.ControlBackend.FREE_BYTES_NOT_AVAILABLE:
2508- free_bytes = ''
2509- else:
2510- free_bytes = int(free_bytes)
2511- if free_bytes < SHARES_MIN_SIZE_FULL:
2512- free_bytes_str = self.NO_FREE_SPACE
2513- scroll_to_cell = True
2514- else:
2515- free_bytes_str = self.FREE_SPACE
2516- free_bytes_args = {'free_space': humanize(free_bytes)}
2517- free_bytes = free_bytes_str % free_bytes_args
2518-
2519- row = (self.ROW_HEADER % (name, free_bytes),
2520- True, CONTACT_ICON_NAME, False, False,
2521- gtk.ICON_SIZE_LARGE_TOOLBAR, None, None)
2522- treeiter = self.volumes_store.append(None, row)
2523-
2524- if scroll_to_cell:
2525- path = self.volumes_store.get_string_from_iter(treeiter)
2526- self.volumes_view.scroll_to_cell(path)
2527-
2528- for volume in volumes:
2529- sensitive = True
2530- name = self._process_name(volume[u'display_name'])
2531- icon_name = FOLDER_ICON_NAME
2532-
2533- is_root = volume[u'type'] == backend.ControlBackend.ROOT_TYPE
2534- is_share = volume[u'type'] == backend.ControlBackend.SHARE_TYPE
2535-
2536- if is_root:
2537- sensitive = False
2538- name = self.ROOT % (name, ORANGE, ALWAYS_SUBSCRIBED)
2539- elif is_share:
2540- icon_name = SHARE_ICON_NAME
2541- elif name == MUSIC_DISPLAY_NAME:
2542- icon_name = MUSIC_ICON_NAME
2543-
2544- if volume[u'path'] is None:
2545- logger.warning('on_volumes_info_ready: about to store a '
2546- 'volume with None path: %r', volume)
2547-
2548- row = (name, bool(volume[u'subscribed']), icon_name, True,
2549- sensitive, gtk.ICON_SIZE_MENU, volume['volume_id'],
2550- volume[u'path'])
2551-
2552- if is_root: # root should go first!
2553- self.volumes_store.prepend(treeiter, row)
2554- else:
2555- self.volumes_store.append(treeiter, row)
2556-
2557- self.volumes_view.expand_all()
2558- self.volumes_view.show_all()
2559-
2560- self.is_processing = False
2561-
2562- @log_call(logger.error)
2563- def on_volumes_info_error(self, error_dict=None):
2564- """Backend notifies of an error when fetching volumes info."""
2565- self.on_error(error_dict=error_dict)
2566-
2567- @log_call(logger.info)
2568- def on_volume_settings_changed(self, volume_id):
2569- """The settings for 'volume_id' were changed."""
2570- self.is_processing = False
2571-
2572- @log_call(logger.error)
2573- def on_volume_settings_change_error(self, volume_id, error_dict=None):
2574- """The settings for 'volume_id' were not changed."""
2575- self.load()
2576-
2577- def on_subscribed_toggled(self, widget, path, *args, **kwargs):
2578- """The user toggled 'widget'."""
2579- treeiter = self.volumes_store.get_iter(path)
2580- volume_id = self.volumes_store.get_value(treeiter, 6)
2581- volume_path = self.volumes_store.get_value(treeiter, 7)
2582- subscribed = self.volumes_store.get_value(treeiter, 1)
2583-
2584- response = gtk.RESPONSE_YES
2585- if not subscribed and os.path.exists(volume_path):
2586- self.confirm_dialog.set_markup(FOLDERS_CONFIRM_MERGE %
2587- {'folder_path': volume_path})
2588- response = self.confirm_dialog.run()
2589- self.confirm_dialog.hide()
2590-
2591- if response == gtk.RESPONSE_YES:
2592- subscribed = not subscribed
2593- self.volumes_store.set_value(treeiter, 1, subscribed)
2594- self.backend.change_volume_settings(volume_id,
2595- {'subscribed': bool_str(subscribed)},
2596- reply_handler=NO_OP, error_handler=error_handler)
2597-
2598- self.is_processing = True
2599-
2600- def on_volumes_view_row_activated(self, widget, path, *args, **kwargs):
2601- """The user double clicked on a row."""
2602- treeiter = self.volumes_store.get_iter(path)
2603- volume_path = self.volumes_store.get_value(treeiter, 7)
2604- if volume_path is None:
2605- logger.warning('on_volumes_view_row_activated: volume_path for '
2606- 'tree_path %r is None', path)
2607- elif not os.path.exists(volume_path):
2608- logger.warning('on_volumes_view_row_activated: path %r '
2609- 'does not exist', volume_path)
2610- else:
2611- uri_hook(None, FILE_URI_PREFIX + volume_path)
2612-
2613- def load(self):
2614- """Load the volume list."""
2615- self.backend.volumes_info(reply_handler=NO_OP,
2616- error_handler=error_handler)
2617- self.is_processing = True
2618-
2619-
2620-class SharesPanel(UbuntuOneBin, ControlPanelMixin):
2621- """The shares panel - NOT IMPLEMENTED YET."""
2622-
2623- TITLE = SHARES_TITLE
2624-
2625- def __init__(self, main_window=None):
2626- UbuntuOneBin.__init__(self)
2627- ControlPanelMixin.__init__(self)
2628- self.show_all()
2629- self.on_success('Not implemented yet.')
2630-
2631-
2632-class Device(gtk.EventBox, ControlPanelMixin):
2633- """The device widget."""
2634-
2635- def __init__(self, confirm_remove_dialog=None):
2636- gtk.EventBox.__init__(self)
2637- ControlPanelMixin.__init__(self, filename='device.ui')
2638-
2639- self.confirm_dialog = confirm_remove_dialog
2640- self._updating = False
2641- self._last_settings = {}
2642- self.id = None
2643- self.is_local = False
2644- self.configurable = False
2645-
2646- self.update(device_id=None, device_name='',
2647- is_local=False, configurable=False, limit_bandwidth=False,
2648- max_upload_speed=0, max_download_speed=0,
2649- show_all_notifications=True)
2650-
2651- self.add(self.itself)
2652- self.show()
2653-
2654- self.backend.connect_to_signal('DeviceSettingsChanged',
2655- self.on_device_settings_changed)
2656- self.backend.connect_to_signal('DeviceSettingsChangeError',
2657- self.on_device_settings_change_error)
2658- self.backend.connect_to_signal('DeviceRemoved',
2659- self.on_device_removed)
2660- self.backend.connect_to_signal('DeviceRemovalError',
2661- self.on_device_removal_error)
2662-
2663- def _change_device_settings(self, *args):
2664- """Update backend settings for this device."""
2665- if self._updating:
2666- return
2667-
2668- # Not disabling the GUI to avoid annyong twitchings
2669- #self.set_sensitive(False)
2670- self.warning_label.set_text('')
2671- self.backend.change_device_settings(self.id, self.__dict__,
2672- reply_handler=NO_OP, error_handler=error_handler)
2673-
2674- def _block_signals(f):
2675- """Execute 'f' while having the _updating flag set."""
2676-
2677- # pylint: disable=E0213,W0212,E1102
2678-
2679- @wraps(f)
2680- def inner(self, *args, **kwargs):
2681- """Execute 'f' while having the _updating flag set."""
2682- old = self._updating
2683- self._updating = True
2684-
2685- result = f(self, *args, **kwargs)
2686-
2687- self._updating = old
2688- return result
2689-
2690- return inner
2691-
2692- on_show_all_notifications_toggled = _change_device_settings
2693- on_max_upload_speed_value_changed = _change_device_settings
2694- on_max_download_speed_value_changed = _change_device_settings
2695-
2696- def on_limit_bandwidth_toggled(self, *args, **kwargs):
2697- """The limit bandwidth checkbox was toggled."""
2698- self.throttling_limits.set_sensitive(self.limit_bandwidth.get_active())
2699- self._change_device_settings()
2700-
2701- def on_remove_clicked(self, widget):
2702- """Remove button was clicked or activated."""
2703- response = gtk.RESPONSE_YES
2704- if self.confirm_dialog is not None:
2705- response = self.confirm_dialog.run()
2706- self.confirm_dialog.hide()
2707-
2708- if response == gtk.RESPONSE_YES:
2709- self.backend.remove_device(self.id,
2710- reply_handler=NO_OP, error_handler=error_handler)
2711- self.set_sensitive(False)
2712-
2713- @_block_signals
2714- def update(self, **kwargs):
2715- """Update according to named parameters.
2716-
2717- Possible settings are:
2718- * device_id (string, not shown to the user)
2719- * device_name (string)
2720- * type (either DEVICE_TYPE_PHONE or DEVICE_TYPE_COMPUTER)
2721- * is_local (True/False)
2722- * configurable (True/False)
2723- * if configurable, the following can be set:
2724- * show_all_notifications (True/False)
2725- * limit_bandwidth (True/False)
2726- * max_upload_speed (bytes)
2727- * max_download_speed (bytes)
2728-
2729- """
2730- if 'device_id' in kwargs:
2731- self.id = kwargs['device_id']
2732-
2733- if 'device_name' in kwargs:
2734- name = kwargs['device_name'].replace(DEVICE_REMOVABLE_PREFIX, '')
2735- name = '<span font_size="large"><b>%s</b></span>' % name
2736- self.device_name.set_markup(name)
2737-
2738- if 'device_type' in kwargs:
2739- dtype = kwargs['device_type']
2740- if dtype in (DEVICE_TYPE_COMPUTER, DEVICE_TYPE_PHONE):
2741- self.device_type.set_from_icon_name(dtype.lower(),
2742- gtk.ICON_SIZE_LARGE_TOOLBAR)
2743-
2744- if 'is_local' in kwargs:
2745- self.is_local = bool(kwargs['is_local'])
2746-
2747- if 'configurable' in kwargs:
2748- self.configurable = bool(kwargs['configurable'])
2749- self.config_settings.set_visible(self.configurable)
2750-
2751- if 'show_all_notifications' in kwargs:
2752- value = bool(kwargs['show_all_notifications'])
2753- self.show_all_notifications.set_active(value)
2754-
2755- if 'limit_bandwidth' in kwargs:
2756- enabled = bool(kwargs['limit_bandwidth'])
2757- self.limit_bandwidth.set_active(enabled)
2758- self.throttling_limits.set_sensitive(enabled)
2759-
2760- for speed in ('max_upload_speed', 'max_download_speed'):
2761- if speed in kwargs:
2762- value = int(kwargs[speed]) // KILOBYTES
2763- getattr(self, speed).set_value(value)
2764-
2765- self._last_settings = self.__dict__
2766-
2767- @property
2768- def __dict__(self):
2769- result = {
2770- 'device_id': self.id,
2771- 'device_name': self.device_name.get_text(),
2772- 'device_type': self.device_type.get_icon_name()[0].capitalize(),
2773- 'is_local': bool_str(self.is_local),
2774- 'configurable': bool_str(self.configurable),
2775- 'show_all_notifications': \
2776- bool_str(self.show_all_notifications.get_active()),
2777- 'limit_bandwidth': bool_str(self.limit_bandwidth.get_active()),
2778- 'max_upload_speed': \
2779- str(self.max_upload_speed.get_value_as_int() * KILOBYTES),
2780- 'max_download_speed': \
2781- str(self.max_download_speed.get_value_as_int() * KILOBYTES),
2782- }
2783- return result
2784-
2785- @log_call(logger.info, with_args=False)
2786- def on_device_settings_changed(self, device_id):
2787- """The change of this device settings succeded."""
2788- if device_id != self.id:
2789- return
2790- self.set_sensitive(True)
2791- self.warning_label.set_text('')
2792- self._last_settings = self.__dict__
2793-
2794- @log_call(logger.error)
2795- def on_device_settings_change_error(self, device_id, error_dict=None):
2796- """The change of this device settings failed."""
2797- if device_id != self.id:
2798- return
2799- self.update(**self._last_settings)
2800- self._set_warning(DEVICE_CHANGE_ERROR, self.warning_label)
2801- self.set_sensitive(True)
2802-
2803- # is safe to log the device_id since it was already removed
2804- @log_call(logger.warning)
2805- def on_device_removed(self, device_id):
2806- """The removal of this device succeded."""
2807- if device_id != self.id:
2808- return
2809- self.hide()
2810-
2811- @log_call(logger.error)
2812- def on_device_removal_error(self, device_id, error_dict=None):
2813- """The removal of this device failed."""
2814- if device_id != self.id:
2815- return
2816- self._set_warning(DEVICE_REMOVAL_ERROR, self.warning_label)
2817- self.set_sensitive(True)
2818-
2819-
2820-class DevicesPanel(UbuntuOneBin, ControlPanelMixin):
2821- """The devices panel."""
2822-
2823- __gsignals__ = {
2824- 'local-device-removed': (gobject.SIGNAL_RUN_FIRST,
2825- gobject.TYPE_NONE, ()),
2826- }
2827-
2828- TITLE = DEVICES_TITLE
2829-
2830- def __init__(self, main_window=None):
2831- UbuntuOneBin.__init__(self)
2832- ControlPanelMixin.__init__(self, filename='devices.ui')
2833- self.add(self.itself)
2834- self.show()
2835-
2836- self._devices = {}
2837- kw = dict(parent=main_window,
2838- flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
2839- type=gtk.MESSAGE_WARNING,
2840- buttons=gtk.BUTTONS_YES_NO,
2841- message_format=DEVICE_CONFIRM_REMOVE)
2842- self.confirm_remove_dialog = gtk.MessageDialog(**kw)
2843-
2844- self.backend.connect_to_signal('DevicesInfoReady',
2845- self.on_devices_info_ready)
2846- self.backend.connect_to_signal('DevicesInfoError',
2847- self.on_devices_info_error)
2848- self.backend.connect_to_signal('DeviceRemoved',
2849- self.on_device_removed)
2850-
2851- @log_call(logger.info, with_args=False)
2852- def on_devices_info_ready(self, info):
2853- """Backend notifies of devices info."""
2854- for child in self.devices.get_children():
2855- self.devices.remove(child)
2856-
2857- if not info:
2858- self.on_success(NO_DEVICES)
2859- else:
2860- self.on_success()
2861-
2862- # Class 'style' has no 'bg' member
2863- # pylint: disable=E1101
2864- odd_row_color = self.message.style.bg[gtk.STATE_NORMAL]
2865- for i, device_info in enumerate(info):
2866- device = Device(confirm_remove_dialog=self.confirm_remove_dialog)
2867- device_info['device_name'] = device_info.pop('name', '')
2868- device_info['device_type'] = device_info.pop('type',
2869- DEVICE_TYPE_COMPUTER)
2870- device.update(**device_info)
2871-
2872- if i % 2 == 1:
2873- device.modify_bg(gtk.STATE_NORMAL, odd_row_color)
2874-
2875- self.devices.pack_start(device)
2876- self._devices[device.id] = device
2877-
2878- self.is_processing = False
2879-
2880- @log_call(logger.error)
2881- def on_devices_info_error(self, error_dict=None):
2882- """Backend notifies of an error when fetching volumes info."""
2883- self.on_error(error_dict=error_dict)
2884- self.is_processing = False
2885-
2886- @log_call(logger.warning)
2887- def on_device_removed(self, device_id):
2888- """The removal of a device succeded."""
2889- if device_id in self._devices:
2890- child = self._devices.pop(device_id)
2891- self.devices.remove(child)
2892-
2893- if child.is_local:
2894- self.emit('local-device-removed')
2895-
2896- def load(self):
2897- """Load the device list."""
2898- self.backend.devices_info(reply_handler=NO_OP,
2899- error_handler=error_handler)
2900- self.is_processing = True
2901-
2902-
2903-class InstallPackage(gtk.VBox, ControlPanelMixin):
2904- """A widget to process the install of a package."""
2905-
2906- __gsignals__ = {
2907- 'finished': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()),
2908- }
2909-
2910- def __init__(self, package_name, message=None):
2911- gtk.VBox.__init__(self)
2912- ControlPanelMixin.__init__(self, filename='install.ui')
2913- self.add(self.itself)
2914-
2915- self.package_name = package_name
2916- self.package_manager = package_manager.PackageManager()
2917- self.args = {'package_name': self.package_name}
2918- self.transaction = None
2919-
2920- self.progress_bar = None
2921-
2922- self.message = message
2923- if self.message is None:
2924- self.message = INSTALL_PACKAGE % self.args
2925- self.reset()
2926-
2927- self.show()
2928-
2929- def reset(self):
2930- """Reset this interface."""
2931- children = self.itself.get_children()
2932- if self.progress_bar in children:
2933- self.itself.remove(self.progress_bar)
2934- if self.install_button_box not in children:
2935- self.itself.pack_start(self.install_button_box)
2936- self.install_label.set_markup(self.message)
2937-
2938- @package_manager.inline_callbacks
2939- def on_install_button_clicked(self, button):
2940- """The install button was clicked."""
2941- try:
2942- # create the install transaction
2943- self.transaction = yield self.package_manager.install(
2944- self.package_name)
2945-
2946- logger.debug('on_install_button_clicked: transaction is %r',
2947- self.transaction)
2948- success = package_manager.aptdaemon.enums.EXIT_SUCCESS
2949- if self.transaction == success:
2950- self.on_install_finished(None, self.transaction)
2951- return
2952-
2953- # create the progress bar and pack it to the box
2954- self.progress_bar = package_manager.PackageManagerProgressBar(
2955- self.transaction)
2956- self.progress_bar.show()
2957-
2958- self.itself.remove(self.install_button_box)
2959- self.itself.pack_start(self.progress_bar)
2960-
2961- self.transaction.connect('finished', self.on_install_finished)
2962- self.install_label.set_markup(INSTALLING % self.args)
2963- yield self.transaction.run()
2964- except package_manager.aptdaemon.errors.NotAuthorizedError:
2965- self.reset()
2966- except: # pylint: disable=W0702
2967- logger.exception('on_install_button_clicked')
2968- self._set_warning(FAILED_INSTALL % self.args,
2969- self.install_label)
2970- if self.progress_bar is not None:
2971- self.progress_bar.hide()
2972-
2973- @log_call(logger.info)
2974- def on_install_finished(self, transaction, exit_code):
2975- """The installation finished."""
2976- if self.progress_bar is not None:
2977- self.progress_bar.set_sensitive(False)
2978-
2979- logger.info('on_install_finished: installation of %r was %r',
2980- self.package_name, exit_code)
2981- if exit_code != package_manager.aptdaemon.enums.EXIT_SUCCESS:
2982- if hasattr(transaction, 'error'):
2983- logger.error('transaction failed: %r', transaction.error)
2984- self._set_warning(FAILED_INSTALL % self.args,
2985- self.install_label)
2986- else:
2987- self.install_label.set_markup(SUCCESS_INSTALL % self.args)
2988- self.emit('finished')
2989-
2990-
2991-class Service(gtk.VBox, ControlPanelMixin):
2992- """A service."""
2993-
2994- def __init__(self, service_id, name,
2995- container=None, check_button=None, action_button=None,
2996- *args, **kwargs):
2997- gtk.VBox.__init__(self)
2998- ControlPanelMixin.__init__(self)
2999- self.id = service_id
3000- self.container = container
3001- self.check_button = check_button
3002- self.action_button = action_button
3003-
3004- self.warning_label = gtk.Label()
3005- self.pack_start(self.warning_label, expand=False)
3006-
3007- self.button = gtk.CheckButton(label=name)
3008- self.pack_start(self.button, expand=False)
3009-
3010- self.show_all()
3011-
3012-
3013-class FileSyncService(Service):
3014- """The file sync service."""
3015-
3016- def __init__(self, container, check_button, action_button):
3017- Service.__init__(self, service_id='file-sync',
3018- name=FILE_SYNC_SERVICE_NAME,
3019- container=container,
3020- check_button=check_button,
3021- action_button=action_button)
3022-
3023- self.container.set_sensitive(False)
3024-
3025- self.backend.connect_to_signal('FileSyncStatusChanged',
3026- self.on_file_sync_status_changed)
3027- self.backend.connect_to_signal('FilesEnabled', self.on_files_enabled)
3028- self.backend.connect_to_signal('FilesDisabled', self.on_files_disabled)
3029-
3030- @log_call(logger.debug)
3031- def on_file_sync_status_changed(self, status):
3032- """File Sync status changed."""
3033- enabled = status != backend.FILE_SYNC_DISABLED
3034- logger.info('FileSyncService: on_file_sync_status_changed: '
3035- 'status %r, enabled? %r', status, enabled)
3036- self.check_button.set_active(enabled)
3037- # if service is disabled, disable the action_button
3038- self.action_button.set_sensitive(enabled)
3039-
3040- if not self.container.is_sensitive():
3041- # first time we're getting this event
3042- self.check_button.connect('toggled', self.on_button_toggled)
3043- self.container.set_sensitive(True)
3044-
3045- def on_files_enabled(self):
3046- """Files service was enabled."""
3047- self.on_file_sync_status_changed('enabled!')
3048-
3049- def on_files_disabled(self):
3050- """Files service was disabled."""
3051- self.on_file_sync_status_changed(backend.FILE_SYNC_DISABLED)
3052-
3053- @log_call(logger.debug)
3054- def on_button_toggled(self, button):
3055- """Button was toggled, exclude/replicate the service properly."""
3056- logger.info('File Sync enabled? %r', self.check_button.get_active())
3057- if self.check_button.get_active():
3058- self.backend.enable_files(reply_handler=NO_OP,
3059- error_handler=error_handler)
3060- else:
3061- self.backend.disable_files(reply_handler=NO_OP,
3062- error_handler=error_handler)
3063-
3064- def load(self):
3065- """Load the information."""
3066- self.backend.file_sync_status(reply_handler=NO_OP,
3067- error_handler=error_handler)
3068-
3069-
3070-class DesktopcouchService(Service):
3071- """A desktopcouch service."""
3072-
3073- def __init__(self, service_id, name, enabled,
3074- container, check_button,
3075- dependency=None, dependency_name=None):
3076- Service.__init__(self, service_id, name,
3077- container, check_button, action_button=None)
3078-
3079- self.backend.connect_to_signal('ReplicationSettingsChanged',
3080- self.on_replication_settings_changed)
3081- self.backend.connect_to_signal('ReplicationSettingsChangeError',
3082- self.on_replication_settings_change_error)
3083-
3084- self.check_button.set_active(enabled)
3085-
3086- self.dependency = None
3087- if dependency is not None:
3088- if dependency_name is None:
3089- dependency_name = dependency
3090- args = {'plugin_name': dependency_name, 'service_name': service_id}
3091- message = INSTALL_PLUGIN % args
3092- self.dependency = InstallPackage(dependency, message)
3093- self.dependency.connect('finished', self.on_depedency_finished)
3094-
3095- self.container.pack_end(self.dependency, expand=False)
3096- self.check_button.set_sensitive(False)
3097-
3098- self.check_button.connect('toggled', self.on_button_toggled)
3099-
3100- def on_depedency_finished(self, widget):
3101- """The dependency was installed."""
3102- self.check_button.set_sensitive(True)
3103- self.container.remove(self.dependency)
3104- self.dependency = None
3105-
3106- @log_call(logger.debug)
3107- def on_button_toggled(self, button):
3108- """Button was toggled, exclude/replicate the service properly."""
3109- logger.info('Starting replication for %r? %r',
3110- self.id, self.check_button.get_active())
3111-
3112- args = {'enabled': bool_str(self.check_button.get_active())}
3113- self.backend.change_replication_settings(self.id, args,
3114- reply_handler=NO_OP, error_handler=error_handler)
3115-
3116- @log_call(logger.info)
3117- def on_replication_settings_changed(self, replication_id):
3118- """The change of settings for this replication succeded."""
3119- if replication_id != self.id:
3120- return
3121- self.warning_label.set_text('')
3122-
3123- @log_call(logger.error)
3124- def on_replication_settings_change_error(self, replication_id,
3125- error_dict=None):
3126- """The change of settings for this replication failed."""
3127- if replication_id != self.id:
3128- return
3129- self.check_button.set_active(not self.check_button.get_active())
3130- self._set_warning(SETTINGS_CHANGE_ERROR, self.warning_label)
3131-
3132-
3133-class ServicesPanel(UbuntuOneBin, ControlPanelMixin):
3134- """The services panel."""
3135-
3136- TITLE = SERVICES_TITLE
3137-
3138- def __init__(self, main_window=None):
3139- UbuntuOneBin.__init__(self)
3140- ControlPanelMixin.__init__(self, filename='services.ui')
3141- self.add(self.itself)
3142- self.files_icon.set_from_file(get_data_file(SERVICES_FILES_ICON))
3143- self.files_example.set_from_file(get_data_file(SERVICES_FILES_EXAMPLE))
3144- self.contacts_icon.set_from_file(get_data_file(SERVICES_CONTACTS_ICON))
3145-
3146- self.plugin_names = {'contacts': CONTACTS}
3147-
3148- self.package_manager = package_manager.PackageManager()
3149- self.install_box = None
3150-
3151- self._replications_ready = False # hack to solve LP: #750309
3152- self.backend.connect_to_signal('ReplicationsInfoReady',
3153- self.on_replications_info_ready)
3154- self.backend.connect_to_signal('ReplicationsInfoError',
3155- self.on_replications_info_error)
3156-
3157- self.file_sync_service = FileSyncService(container=self.files,
3158- check_button=self.file_sync_check,
3159- action_button=self.file_sync_button)
3160-
3161- self.show()
3162-
3163- @property
3164- def has_desktopcouch(self):
3165- """Is desktopcouch installed?"""
3166- return self.package_manager.is_installed(DESKTOPCOUCH_PKG)
3167-
3168- def on_file_sync_button_clicked(self, *args, **kwargs):
3169- """The "Show me my U1 folder" button was clicked.
3170-
3171- XXX: this should be part of the FileSyncService widget.
3172- XXX: the Ubuntu One folder should be the user's root.
3173-
3174- """
3175- uri_hook(None, FILE_URI_PREFIX + os.path.expanduser('~/Ubuntu One'))
3176-
3177- def on_contacts_button_clicked(self, *args, **kwargs):
3178- """The "Take me to the Ubuntu One website" button was clicked.
3179-
3180- XXX: this should be part of the DesktopcouchService widget.
3181-
3182- """
3183- uri_hook(None, CONTACTS)
3184-
3185- @log_call(logger.debug)
3186- def load(self):
3187- """Load info."""
3188- self.file_sync_service.load()
3189- self.replications.hide()
3190- if self.install_box is not None:
3191- self.itself.remove(self.install_box)
3192- self.install_box = None
3193-
3194- logger.info('load: has_desktopcouch? %r', self.has_desktopcouch)
3195- if not self.has_desktopcouch:
3196- self.message.set_text('')
3197-
3198- self.install_box = InstallPackage(DESKTOPCOUCH_PKG)
3199- self.install_box.connect('finished', self.load_replications)
3200- self.itself.pack_end(self.install_box, expand=False)
3201- self.itself.reorder_child(self.install_box, 0)
3202- else:
3203- self.load_replications()
3204-
3205- self.message.stop()
3206-
3207- @log_call(logger.debug)
3208- def load_replications(self, *args):
3209- """Load replications info."""
3210- self._replications_ready = False # hack to solve LP: #750309
3211- # ask replications to the backend
3212- self.message.start()
3213- self.backend.replications_info(reply_handler=NO_OP,
3214- error_handler=error_handler)
3215-
3216- @log_call(logger.debug)
3217- def on_replications_info_ready(self, info):
3218- """The replication info is ready."""
3219- self.on_success()
3220-
3221- self.replications.show()
3222-
3223- if self.install_box is not None:
3224- self.itself.remove(self.install_box)
3225- self.install_box = None
3226-
3227- for item in info:
3228- pkg = item['dependency']
3229- if not pkg or self.package_manager.is_installed(pkg):
3230- pkg = None
3231-
3232- sid = item['replication_id']
3233- container = getattr(self, sid, None)
3234- check_button = getattr(self, '%s_check' % sid, None)
3235- name = self.plugin_names.get(sid, None)
3236- child = DesktopcouchService(service_id=sid, name=item['name'],
3237- enabled=bool(item['enabled']), container=container,
3238- check_button=check_button,
3239- dependency=pkg, dependency_name=name)
3240- setattr(self, '%s_service' % sid, child)
3241- self._replications_ready = True # hack to solve LP: #750309
3242-
3243- @log_call(logger.error)
3244- def on_replications_info_error(self, error_dict=None):
3245- """The replication info can not be retrieved."""
3246- if error_dict is not None and \
3247- error_dict.get('error_type', None) == 'NoPairingRecord':
3248- self.on_error(NO_PAIRING_RECORD)
3249- else:
3250- self.on_error(error_dict=error_dict)
3251-
3252- def refresh(self):
3253- """If replication list has been loaded, hide and show them."""
3254- if self._replications_ready: # hack to solve LP: #750309
3255- self.replications.hide()
3256- self.replications.show()
3257-
3258-
3259-class FileSyncStatus(gtk.HBox, ControlPanelMixin):
3260- """A file sync status widget."""
3261-
3262- def __init__(self):
3263- gtk.HBox.__init__(self)
3264- ControlPanelMixin.__init__(self)
3265-
3266- self.label = LabelLoading(LOADING)
3267- self.pack_start(self.label, expand=True)
3268-
3269- self.button = gtk.LinkButton(uri='')
3270- self.button.connect('clicked', self._on_button_clicked)
3271- self.pack_start(self.button, expand=False)
3272-
3273- self.show_all()
3274-
3275- self.backend.connect_to_signal('FileSyncStatusDisabled',
3276- self.on_file_sync_status_disabled)
3277- self.backend.connect_to_signal('FileSyncStatusStarting',
3278- self.on_file_sync_status_starting)
3279- self.backend.connect_to_signal('FileSyncStatusStopped',
3280- self.on_file_sync_status_stopped)
3281- self.backend.connect_to_signal('FileSyncStatusDisconnected',
3282- self.on_file_sync_status_disconnected)
3283- self.backend.connect_to_signal('FileSyncStatusSyncing',
3284- self.on_file_sync_status_syncing)
3285- self.backend.connect_to_signal('FileSyncStatusIdle',
3286- self.on_file_sync_status_idle)
3287- self.backend.connect_to_signal('FileSyncStatusError',
3288- self.on_file_sync_status_error)
3289- self.backend.connect_to_signal('FilesStartError',
3290- self.on_files_start_error)
3291- self.backend.connect_to_signal('FilesEnabled',
3292- self.on_file_sync_status_starting)
3293- self.backend.connect_to_signal('FilesDisabled',
3294- self.on_file_sync_status_disabled)
3295-
3296- def _update_status(self, msg, action, callback,
3297- icon=None, color=None, tooltip=None):
3298- """Update the status info."""
3299- if icon is not None:
3300- foreground = '' if color is None else 'foreground="%s"' % color
3301- msg = '<span %s>%s</span> %s' % (foreground, icon, msg)
3302- self.label.set_markup(msg)
3303- self.label.stop()
3304-
3305- self.button.set_label(action)
3306- self.button.set_uri(action)
3307- self.button.set_sensitive(True)
3308- self.button.set_data('callback', callback)
3309- if tooltip is not None:
3310- self.button.set_tooltip_text(tooltip)
3311-
3312- def _on_button_clicked(self, button):
3313- """Button was clicked, act accordingly the label."""
3314- button.set_visited(False)
3315- button.set_sensitive(False)
3316- button.get_data('callback')(button)
3317-
3318- @log_call(logger.info)
3319- def on_file_sync_status_disabled(self, msg=None):
3320- """Backend notifies of file sync status being disabled."""
3321- self._update_status(FILE_SYNC_DISABLED,
3322- FILE_SYNC_ENABLE, self.on_enable_clicked,
3323- ERROR_ICON, ERROR_COLOR, FILE_SYNC_ENABLE_TOOLTIP)
3324-
3325- @log_call(logger.info)
3326- def on_file_sync_status_starting(self, msg=None):
3327- """Backend notifies of file sync status being starting."""
3328- self._update_status(FILE_SYNC_STARTING,
3329- FILE_SYNC_STOP, self.on_stop_clicked,
3330- SYNCING_ICON, ORANGE, FILE_SYNC_STOP_TOOLTIP)
3331-
3332- @log_call(logger.info)
3333- def on_file_sync_status_stopped(self, msg=None):
3334- """Backend notifies of file sync being stopped."""
3335- self._update_status(FILE_SYNC_STOPPED,
3336- FILE_SYNC_START, self.on_start_clicked,
3337- ERROR_ICON, ERROR_COLOR, FILE_SYNC_START_TOOLTIP)
3338-
3339- @log_call(logger.info)
3340- def on_file_sync_status_disconnected(self, msg=None):
3341- """Backend notifies of file sync status being ready."""
3342- self._update_status(FILE_SYNC_DISCONNECTED,
3343- FILE_SYNC_CONNECT, self.on_connect_clicked,
3344- ERROR_ICON, ERROR_COLOR,
3345- FILE_SYNC_CONNECT_TOOLTIP,)
3346-
3347- @log_call(logger.info)
3348- def on_file_sync_status_syncing(self, msg=None):
3349- """Backend notifies of file sync status being syncing."""
3350- self._update_status(FILE_SYNC_SYNCING,
3351- FILE_SYNC_DISCONNECT, self.on_disconnect_clicked,
3352- SYNCING_ICON, ORANGE, FILE_SYNC_DISCONNECT_TOOLTIP)
3353-
3354- @log_call(logger.info)
3355- def on_file_sync_status_idle(self, msg=None):
3356- """Backend notifies of file sync status being idle."""
3357- self._update_status(FILE_SYNC_IDLE,
3358- FILE_SYNC_DISCONNECT, self.on_disconnect_clicked,
3359- IDLE_ICON, SUCCESS_COLOR,
3360- FILE_SYNC_DISCONNECT_TOOLTIP)
3361-
3362- @log_call(logger.error)
3363- def on_file_sync_status_error(self, error_dict=None):
3364- """Backend notifies of an error when fetching file sync status."""
3365- msg = FILE_SYNC_ERROR
3366- reason = error_dict.get('error_msg', '') if error_dict else ''
3367- if reason:
3368- msg += ' (' + reason + ')'
3369- self._update_status(WARNING_MARKUP % msg,
3370- FILE_SYNC_RESTART, self.on_restart_clicked,
3371- tooltip=FILE_SYNC_RESTART_TOOLTIP)
3372-
3373- @log_call(logger.error)
3374- def on_files_start_error(self, error_dict=None):
3375- """Backend notifies of an error when starting the files service."""
3376- # service is probably disabled, ask for status to backend
3377- self.backend.file_sync_status(reply_handler=NO_OP,
3378- error_handler=error_handler)
3379-
3380- def on_connect_clicked(self, button=None):
3381- """User requested connection."""
3382- self.backend.connect_files(reply_handler=NO_OP,
3383- error_handler=error_handler)
3384-
3385- def on_disconnect_clicked(self, button=None):
3386- """User requested disconnection."""
3387- self.backend.disconnect_files(reply_handler=NO_OP,
3388- error_handler=error_handler)
3389-
3390- def on_enable_clicked(self, button=None):
3391- """User requested enable the service."""
3392- self.backend.enable_files(reply_handler=NO_OP,
3393- error_handler=error_handler)
3394-
3395- def on_restart_clicked(self, button=None):
3396- """User requested restart the service."""
3397- self.backend.restart_files(reply_handler=NO_OP,
3398- error_handler=error_handler)
3399-
3400- def on_start_clicked(self, button=None):
3401- """User requested start the service."""
3402- self.backend.start_files(reply_handler=NO_OP,
3403- error_handler=error_handler)
3404-
3405- def on_stop_clicked(self, button=None):
3406- """User requested stop the service."""
3407- self.backend.stop_files(reply_handler=NO_OP,
3408- error_handler=error_handler)
3409-
3410- def load(self):
3411- """Load the information."""
3412- self.backend.file_sync_status(reply_handler=NO_OP,
3413- error_handler=error_handler)
3414-
3415-
3416-class ManagementPanel(gtk.VBox, ControlPanelMixin):
3417- """The management panel.
3418-
3419- The user can manage dashboard, volumes, devices and services.
3420-
3421- """
3422-
3423- __gsignals__ = {
3424- 'local-device-removed': (gobject.SIGNAL_RUN_FIRST,
3425- gobject.TYPE_NONE, ()),
3426- 'unauthorized': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()),
3427- }
3428-
3429- DASHBOARD_BUTTON_NAME = 'ModeLeft'
3430- SERVICES_BUTTON_NAME = 'ModeRight'
3431-
3432- def __init__(self, main_window=None):
3433- gtk.VBox.__init__(self)
3434- ControlPanelMixin.__init__(self, filename='management.ui')
3435- self.add(self.itself)
3436- self.facebook_logo.set_from_file(get_data_file(FACEBOOK_LOGO))
3437- self.twitter_logo.set_from_file(get_data_file(TWITTER_LOGO))
3438- self.show()
3439-
3440- self.backend.connect_to_signal('AccountInfoReady',
3441- self.on_account_info_ready)
3442- self.backend.connect_to_signal('AccountInfoError',
3443- self.on_account_info_error)
3444- self.backend.connect_to_signal('UnauthorizedError',
3445- self.on_unauthorized_error)
3446-
3447- self.quota_progressbar.set_sensitive(False)
3448-
3449- self.quota_label = LabelLoading(LOADING)
3450- self.quota_box.pack_start(self.quota_label, expand=False)
3451- self.quota_box.reorder_child(self.quota_label, 0)
3452-
3453- self.status_label = FileSyncStatus()
3454- self.status_box.pack_end(self.status_label, expand=True)
3455-
3456- self.dashboard = DashboardPanel(main_window=main_window)
3457- self.volumes = VolumesPanel(main_window=main_window)
3458- self.shares = SharesPanel(main_window=main_window)
3459- self.devices = DevicesPanel(main_window=main_window)
3460- self.services = ServicesPanel(main_window=main_window)
3461-
3462- cb = lambda button, page_num: self.notebook.set_current_page(page_num)
3463- self.tabs = (u'dashboard', u'volumes', u'shares',
3464- u'devices', u'services')
3465- for page_num, tab in enumerate(self.tabs):
3466- setattr(self, ('%s_page' % tab).upper(), page_num)
3467- button = getattr(self, '%s_button' % tab)
3468- button.connect('clicked', cb, page_num)
3469- self.notebook.insert_page(getattr(self, tab), position=page_num)
3470-
3471- self.dashboard_button.set_name(self.DASHBOARD_BUTTON_NAME)
3472- self.dashboard_button.set_tooltip_text(DASHBOARD_BUTTON_TOOLTIP)
3473-
3474- self.volumes_button.set_tooltip_text(FOLDERS_BUTTON_TOOLTIP)
3475- self.volumes_button.connect('clicked', lambda b: self.volumes.load())
3476-
3477- self.shares_button.set_tooltip_text(SHARES_BUTTON_TOOLTIP)
3478-
3479- self.devices_button.set_tooltip_text(DEVICES_BUTTON_TOOLTIP)
3480- self.devices_button.connect('clicked', lambda b: self.devices.load())
3481- self.devices.connect('local-device-removed',
3482- lambda widget: self.emit('local-device-removed'))
3483-
3484- self.services_button.set_name(self.SERVICES_BUTTON_NAME)
3485- self.services_button.set_tooltip_text(SERVICES_BUTTON_TOOLTIP)
3486- self.services_button.connect('clicked',
3487- lambda b: self.services.refresh())
3488-
3489- self.enable_volumes = lambda: self.volumes_button.set_sensitive(True)
3490- self.disable_volumes = lambda: self.volumes_button.set_sensitive(False)
3491- self.backend.connect_to_signal('FilesEnabled', self.enable_volumes)
3492- self.backend.connect_to_signal('FilesDisabled', self.disable_volumes)
3493-
3494- def _update_quota(self, msg, data=None):
3495- """Update the quota info."""
3496- fraction = 0.0
3497- if data is not None:
3498- fraction = data.get('percentage', 0.0) / 100
3499- if fraction > 0 and fraction < 0.05:
3500- fraction = 0.05
3501- else:
3502- fraction = round(fraction, 2)
3503-
3504- logger.debug('ManagementPanel: updating quota to %r.', fraction)
3505- if fraction >= QUOTA_THRESHOLD:
3506- self.quota_label.set_markup(WARNING_MARKUP % msg)
3507- else:
3508- self.quota_label.set_markup(msg)
3509- self.quota_label.stop()
3510-
3511- if fraction == 0.0:
3512- self.quota_progressbar.set_sensitive(False)
3513- else:
3514- self.quota_progressbar.set_sensitive(True)
3515-
3516- self.quota_progressbar.set_fraction(min(fraction, 1))
3517-
3518- def load(self):
3519- """Load the account info and file sync status list."""
3520- self.backend.account_info(reply_handler=NO_OP,
3521- error_handler=error_handler)
3522- self.status_label.load()
3523- self.services.load()
3524-
3525- @log_call(logger.debug)
3526- def on_account_info_ready(self, info):
3527- """Backend notifies of account info."""
3528- used = int(info['quota_used'])
3529- total = int(info['quota_total'])
3530- data = {'used': humanize(used), 'total': humanize(total),
3531- 'percentage': (used / total) * 100}
3532- self._update_quota(QUOTA_LABEL % data, data)
3533-
3534- @log_call(logger.error)
3535- def on_account_info_error(self, error_dict=None):
3536- """Backend notifies of an error when fetching account info."""
3537- self._update_quota(msg='')
3538-
3539- @log_call(logger.error)
3540- def on_unauthorized_error(self, error_dict=None):
3541- """Backend notifies that credentials are not valid."""
3542- self.emit('unauthorized')
3543-
3544-
3545-class ControlPanel(gtk.Notebook, ControlPanelMixin):
3546- """The control panel per se, can be added into any other widget."""
3547-
3548- # should not be any larger than 736x525
3549-
3550- def __init__(self, main_window):
3551- gtk.Notebook.__init__(self)
3552- ControlPanelMixin.__init__(self)
3553- gtk.link_button_set_uri_hook(uri_hook)
3554- self.connect('destroy', self.shutdown)
3555-
3556- self.main_window = main_window
3557-
3558- self.set_show_tabs(False)
3559- self.set_show_border(False)
3560-
3561- self.overview = OverviewPanel(main_window=main_window)
3562- self.insert_page(self.overview, position=0)
3563-
3564- self.management = ManagementPanel(main_window=main_window)
3565- self.insert_page(self.management, position=1)
3566-
3567- self.overview.connect('credentials-found',
3568- self.on_show_management_panel)
3569- self.management.connect('local-device-removed',
3570- self.on_show_overview_panel)
3571- self.management.connect('unauthorized',
3572- self.on_show_overview_panel)
3573-
3574- self.show()
3575- self.on_show_overview_panel()
3576-
3577- logger.debug('%s: started (window size %r).',
3578- self.__class__.__name__, self.get_size_request())
3579-
3580- def shutdown(self, *args, **kwargs):
3581- """Shutdown backend."""
3582- logger.info('Shutting down...')
3583- self.backend.shutdown(reply_handler=NO_OP,
3584- error_handler=error_handler)
3585-
3586- def on_show_overview_panel(self, widget=None):
3587- """Show the overview panel."""
3588- self.set_current_page(0)
3589-
3590- def on_show_management_panel(self, widget=None, credentials_are_new=False):
3591- """Show the notebook (main panel)."""
3592- if self.get_current_page() == 0:
3593- self.management.load()
3594- if credentials_are_new:
3595- # redirect user to services page to start using Ubuntu One
3596- self.management.services_button.clicked()
3597- # instruct syncdaemon to connect
3598- self.backend.connect_files(reply_handler=NO_OP,
3599- error_handler=error_handler)
3600-
3601- self.next_page()
3602-
3603-
3604-class ControlPanelService(dbus.service.Object):
3605- """DBUS service that exposes some of the window's methods."""
3606-
3607- def __init__(self, window):
3608- self.window = window
3609- bus_name = dbus.service.BusName(
3610- DBUS_BUS_NAME_GUI, bus=dbus.SessionBus())
3611- dbus.service.Object.__init__(
3612- self, bus_name=bus_name, object_path=DBUS_PATH_GUI)
3613-
3614- @log_call(logger.debug)
3615- @dbus.service.method(dbus_interface=DBUS_IFACE_GUI, in_signature='sb')
3616- def switch_to_alert(self, panel='', alert=False):
3617- """Switch to named panel."""
3618- if panel:
3619- self.window.switch_to(panel)
3620- if alert:
3621- self.window.draw_attention()
3622-
3623-
3624-class ControlPanelWindow(gtk.Window):
3625- """The main window for the Ubuntu One control panel."""
3626-
3627- def __init__(self, switch_to='', alert=False):
3628- super(ControlPanelWindow, self).__init__()
3629-
3630- # We need to set WMCLASS so Unity falls back and we only get one
3631- # launcher on the launcher panel
3632- self.set_wmclass(CP_WMCLASS_NAME, CP_WMCLASS_CLASS)
3633-
3634- self.connect('focus-in-event', self.remove_urgency)
3635- self.set_title(MAIN_WINDOW_TITLE % {'app_name': U1_APP_NAME})
3636- self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
3637- self.set_icon_name('ubuntuone')
3638- self.set_size_request(736, 525) # bug #683164
3639-
3640- self.connect('delete-event', lambda w, e: gtk.main_quit())
3641- if alert:
3642- self.draw_attention()
3643- else:
3644- self.present()
3645-
3646- self.control_panel = ControlPanel(main_window=self)
3647- self.add(self.control_panel)
3648-
3649- logger.info('Starting %s pointing at panel: %r.',
3650- self.__class__.__name__, switch_to)
3651- if switch_to:
3652- self.switch_to(switch_to)
3653-
3654- logger.debug('%s: started (window size %r).',
3655- self.__class__.__name__, self.get_size_request())
3656-
3657- def remove_urgency(self, *args, **kwargs):
3658- """Remove urgency from the launcher entry."""
3659- if not USE_LIBUNITY:
3660- return
3661- entry = Unity.LauncherEntry.get_for_desktop_id(U1_DOTDESKTOP)
3662- if getattr(entry.props, 'urgent', False):
3663- self.switch_to('volumes')
3664- entry.props.urgent = False
3665-
3666- def draw_attention(self):
3667- """Draw attention to the control panel."""
3668- self.present_with_time(1)
3669- self.set_urgency_hint(True)
3670-
3671- def switch_to(self, panel):
3672- """Switch to named panel."""
3673- button = getattr(
3674- self.control_panel.management, '%s_button' % panel, None)
3675- if button is not None:
3676- button.clicked()
3677- else:
3678- logger.warning('Could not start at panel: %r.', panel)
3679-
3680- def main(self):
3681- """Run the main loop of the widget toolkit."""
3682- logger.debug('Starting GTK main loop.')
3683- gtk.main()
3684
3685=== removed file 'ubuntuone/controlpanel/gui/gtk/package_manager.py'
3686--- ubuntuone/controlpanel/gui/gtk/package_manager.py 2011-04-05 18:04:56 +0000
3687+++ ubuntuone/controlpanel/gui/gtk/package_manager.py 1970-01-01 00:00:00 +0000
3688@@ -1,62 +0,0 @@
3689-# -*- coding: utf-8 -*-
3690-
3691-# Authors: Natalia B. Bidart <nataliabidart@canonical.com>
3692-#
3693-# Copyright 2010 Canonical Ltd.
3694-#
3695-# This program is free software: you can redistribute it and/or modify it
3696-# under the terms of the GNU General Public License version 3, as published
3697-# by the Free Software Foundation.
3698-#
3699-# This program is distributed in the hope that it will be useful, but
3700-# WITHOUT ANY WARRANTY; without even the implied warranties of
3701-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3702-# PURPOSE. See the GNU General Public License for more details.
3703-#
3704-# You should have received a copy of the GNU General Public License along
3705-# with this program. If not, see <http://www.gnu.org/licenses/>.
3706-
3707-"""Client to manage packages."""
3708-
3709-import apt
3710-import aptdaemon.client
3711-# pylint: disable=W0404
3712-import aptdaemon.enums
3713-
3714-try:
3715- # Unable to import 'defer', pylint: disable=F0401,E0611,W0404
3716- from aptdaemon.defer import inline_callbacks, return_value
3717-except ImportError:
3718- # Unable to import 'defer', pylint: disable=F0401,E0611,W0404
3719- from defer import inline_callbacks, return_value
3720-from aptdaemon.gtkwidgets import AptProgressBar
3721-
3722-from ubuntuone.controlpanel.logger import setup_logging
3723-
3724-
3725-logger = setup_logging('package_manager')
3726-
3727-
3728-class PackageManagerProgressBar(AptProgressBar):
3729- """A progress bar for a transaction."""
3730-
3731-
3732-class PackageManager(object):
3733- """Manage packages (check if is installed, install)."""
3734-
3735- def is_installed(self, package_name):
3736- """Return whether 'package_name' is installed in this system."""
3737- cache = apt.Cache()
3738- result = package_name in cache and cache[package_name].is_installed
3739- logger.debug('is %r installed? %r', package_name, result)
3740- return result
3741-
3742- @inline_callbacks
3743- def install(self, package_name):
3744- """Install 'package_name' if is not installed in this system."""
3745- if self.is_installed(package_name):
3746- return_value(aptdaemon.enums.EXIT_SUCCESS)
3747-
3748- client = aptdaemon.client.AptClient()
3749- transaction = yield client.install_packages([package_name])
3750- return_value(transaction)
3751
3752=== removed directory 'ubuntuone/controlpanel/gui/gtk/tests'
3753=== removed file 'ubuntuone/controlpanel/gui/gtk/tests/__init__.py'
3754--- ubuntuone/controlpanel/gui/gtk/tests/__init__.py 2012-02-06 21:02:54 +0000
3755+++ ubuntuone/controlpanel/gui/gtk/tests/__init__.py 1970-01-01 00:00:00 +0000
3756@@ -1,232 +0,0 @@
3757-# -*- coding: utf-8 -*-
3758-
3759-# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
3760-#
3761-# Copyright 2010 Canonical Ltd.
3762-#
3763-# This program is free software: you can redistribute it and/or modify it
3764-# under the terms of the GNU General Public License version 3, as published
3765-# by the Free Software Foundation.
3766-#
3767-# This program is distributed in the hope that it will be useful, but
3768-# WITHOUT ANY WARRANTY; without even the implied warranties of
3769-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3770-# PURPOSE. See the GNU General Public License for more details.
3771-#
3772-# You should have received a copy of the GNU General Public License along
3773-# with this program. If not, see <http://www.gnu.org/licenses/>.
3774-
3775-"""The test suite for the GTK UI for the control panel for Ubuntu One."""
3776-
3777-import logging
3778-
3779-from collections import defaultdict
3780-
3781-from twisted.internet import defer
3782-from ubuntuone.devtools.handlers import MementoHandler
3783-
3784-from ubuntuone.controlpanel.gui.gtk import gui
3785-from ubuntuone.controlpanel.gui.gtk.tests.test_package_manager import (
3786- FakedTransaction)
3787-# Unused imports, they are here to maintain old module API
3788-# pylint: disable=W0611
3789-from ubuntuone.controlpanel.gui.tests import (FakedObject,
3790- FAKE_ACCOUNT_INFO,
3791- FAKE_DEVICE_INFO,
3792- FAKE_DEVICES_INFO,
3793- FAKE_FOLDERS_INFO,
3794- FAKE_SHARES_INFO,
3795- FAKE_VOLUMES_INFO,
3796- FAKE_VOLUMES_NO_FREE_SPACE_INFO,
3797- MUSIC_FOLDER,
3798- ROOT,
3799- USER_HOME,
3800-)
3801-# pylint: enable=W0611
3802-from ubuntuone.controlpanel.tests import TestCase
3803-
3804-
3805-# Attribute 'yyy' defined outside __init__, access to a protected member
3806-# pylint: disable=W0201, W0212
3807-
3808-
3809-FAKE_REPLICATIONS_INFO = [
3810- {'replication_id': 'foo', 'name': 'Bar',
3811- 'enabled': 'True', 'dependency': ''},
3812- {'replication_id': 'yadda', 'name': 'Foo',
3813- 'enabled': '', 'dependency': 'a very weird one'},
3814- {'replication_id': 'yoda', 'name': 'Figthers',
3815- 'enabled': 'True', 'dependency': 'other dep'},
3816-]
3817-
3818-
3819-class FakedNMState(FakedObject):
3820- """Fake a NetworkManagerState."""
3821-
3822- exposed_methods = ['find_online_state']
3823-
3824-
3825-class FakedDBusBackend(FakedObject):
3826- """Fake a DBus Backend."""
3827-
3828- bus_name = None
3829- object_path = None
3830- iface = None
3831-
3832- def __init__(self, obj, dbus_interface, *args, **kwargs):
3833- if dbus_interface != self.iface:
3834- raise TypeError()
3835- self._signals = defaultdict(list)
3836- super(FakedDBusBackend, self).__init__(*args, **kwargs)
3837-
3838- def connect_to_signal(self, signal, handler):
3839- """Bind 'handler' to be callback'd when 'signal' is fired."""
3840- self._signals[signal].append(handler)
3841-
3842-
3843-class FakedCredentialsBackend(FakedObject):
3844- """Fake a credentials backend."""
3845-
3846- exposed_methods = ['find_credentials', 'clear_credentials',
3847- 'login', 'register']
3848- next_result = defer.succeed(None)
3849-
3850-
3851-class FakedControlPanelBackend(FakedDBusBackend):
3852- """Fake a Control Panel Backend, act as a dbus.Interface."""
3853-
3854- bus_name = gui.DBUS_BUS_NAME
3855- object_path = gui.DBUS_PREFERENCES_PATH
3856- iface = gui.DBUS_PREFERENCES_IFACE
3857- exposed_methods = [
3858- 'account_info', # account
3859- 'devices_info', 'change_device_settings', 'remove_device', # devices
3860- 'volumes_info', 'change_volume_settings', # volumes
3861- 'replications_info', 'change_replication_settings', # replications
3862- 'file_sync_status', 'enable_files', 'disable_files', # files
3863- 'connect_files', 'disconnect_files',
3864- 'restart_files', 'start_files', 'stop_files', 'shutdown',
3865- ]
3866-
3867-
3868-class FakedGUIBackend(FakedDBusBackend):
3869- """Fake a Control Panel GUI Service, act as a dbus.Interface."""
3870-
3871- bus_name = gui.DBUS_BUS_NAME_GUI
3872- object_path = gui.DBUS_PATH_GUI
3873- iface = gui.DBUS_IFACE_GUI
3874- exposed_methods = ['draw_attention', 'switch_to']
3875-
3876-
3877-class FakedSessionBus(object):
3878- """Fake a session bus."""
3879-
3880- def get_object(self, bus_name, object_path, introspect=True,
3881- follow_name_owner_changes=False, **kwargs):
3882- """Return a faked proxy for the given remote object."""
3883- return None
3884-
3885-
3886-class FakedInterface(object):
3887- """Fake a dbus interface."""
3888-
3889- def __new__(cls, obj, dbus_interface, *args, **kwargs):
3890- if dbus_interface == gui.DBUS_PREFERENCES_IFACE:
3891- return FakedControlPanelBackend(obj, dbus_interface,
3892- *args, **kwargs)
3893- if dbus_interface == gui.DBUS_IFACE_GUI:
3894- return FakedGUIBackend(
3895- obj, dbus_interface, *args, **kwargs)
3896-
3897-
3898-class FakedPackageManager(object):
3899- """Faked a package manager."""
3900-
3901- def __init__(self):
3902- self._installed = {}
3903- self.is_installed = lambda package_name: \
3904- self._installed.setdefault(package_name, False)
3905-
3906- @gui.package_manager.inline_callbacks
3907- def install(self, package_name):
3908- """Install 'package_name' if is not installed in this system."""
3909- yield
3910- self._installed[package_name] = True
3911- gui.package_manager.return_value(FakedTransaction([package_name]))
3912-
3913-
3914-class FakedConfirmDialog(object):
3915- """Fake a confirmation dialog."""
3916-
3917- def __init__(self, *args, **kwargs):
3918- self._args = args
3919- self._kwargs = kwargs
3920- self.was_run = False
3921- self.is_visible = False
3922- self.markup = kwargs.get('message_format', None)
3923- self.show = lambda: setattr(self, 'is_visible', True)
3924- self.hide = lambda: setattr(self, 'is_visible', False)
3925- self.response_code = None
3926-
3927- def run(self):
3928- """Set flag and return 'self.response_code'."""
3929- self.was_run = True
3930- return self.response_code
3931-
3932- def set_markup(self, msg):
3933- """Set the markup."""
3934- self.markup = msg
3935-
3936-
3937-class BaseTestCase(TestCase):
3938- """Basics for testing."""
3939-
3940- # self.klass is not callable
3941- # pylint: disable=E1102
3942- klass = None
3943- kwargs = {}
3944- backend_is_dbus = True
3945-
3946- @defer.inlineCallbacks
3947- def setUp(self):
3948- yield super(BaseTestCase, self).setUp()
3949- self.patch(gui, 'CredentialsManagementTool', FakedCredentialsBackend)
3950- self.patch(gui.os.path, 'expanduser',
3951- lambda path: path.replace('~', USER_HOME))
3952- self.patch(gui.gtk, 'main', lambda: None)
3953- self.patch(gui.gtk, 'MessageDialog', FakedConfirmDialog)
3954- self.patch(gui.dbus, 'SessionBus', FakedSessionBus)
3955- self.patch(gui.dbus, 'Interface', FakedInterface)
3956- self.patch(gui.networkstate, 'NetworkManagerState', FakedNMState)
3957- self.patch(gui.package_manager, 'PackageManager', FakedPackageManager)
3958-
3959- if self.klass is not None:
3960- self.ui = self.klass(**self.kwargs)
3961- self.addCleanup(self.ui.destroy)
3962-
3963- self.memento = MementoHandler()
3964- self.memento.setLevel(logging.DEBUG)
3965- gui.logger.addHandler(self.memento)
3966-
3967- def assert_image_equal(self, image, filename):
3968- """Check that expected and actual represent the same image."""
3969- pb = gui.gtk.gdk.pixbuf_new_from_file(gui.get_data_file(filename))
3970- self.assertEqual(image.get_pixbuf().get_pixels(), pb.get_pixels())
3971-
3972- def assert_backend_called(self, method_name, *args, **kwargs):
3973- """Check that the control panel backend 'method_name' was called."""
3974- if self.backend_is_dbus:
3975- kwargs = {'reply_handler': gui.NO_OP,
3976- 'error_handler': gui.error_handler}
3977- self.assertIn(method_name, self.ui.backend._called)
3978- self.assertEqual(self.ui.backend._called[method_name], (args, kwargs))
3979-
3980- def assert_warning_correct(self, warning, text):
3981- """Check that 'warning' is visible, showing 'text'."""
3982- self.assertTrue(warning.get_visible(), 'Must be visible.')
3983- self.assertEqual(warning.get_label(), gui.WARNING_MARKUP % text)
3984-
3985- def assert_function_decorated(self, decorator, func):
3986- """Check that 'func' is decorated with 'decorator'."""
3987- expected = decorator(lambda: None)
3988- self.assertEqual(expected.func_code, func.im_func.func_code)
3989
3990=== removed file 'ubuntuone/controlpanel/gui/gtk/tests/test_gui.py'
3991--- ubuntuone/controlpanel/gui/gtk/tests/test_gui.py 2011-10-24 21:48:27 +0000
3992+++ ubuntuone/controlpanel/gui/gtk/tests/test_gui.py 1970-01-01 00:00:00 +0000
3993@@ -1,2179 +0,0 @@
3994-# -*- coding: utf-8 -*-
3995-
3996-# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
3997-#
3998-# Copyright 2010 Canonical Ltd.
3999-#
4000-# This program is free software: you can redistribute it and/or modify it
4001-# under the terms of the GNU General Public License version 3, as published
4002-# by the Free Software Foundation.
4003-#
4004-# This program is distributed in the hope that it will be useful, but
4005-# WITHOUT ANY WARRANTY; without even the implied warranties of
4006-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4007-# PURPOSE. See the GNU General Public License for more details.
4008-#
4009-# You should have received a copy of the GNU General Public License along
4010-# with this program. If not, see <http://www.gnu.org/licenses/>.
4011-
4012-"""The test suite for the control panel user interface."""
4013-
4014-from __future__ import division
4015-
4016-import operator
4017-
4018-from twisted.internet import defer
4019-
4020-from ubuntuone.controlpanel.gui.gtk import gui
4021-from ubuntuone.controlpanel.gui.gtk.tests import (
4022- FakedConfirmDialog,
4023- FAKE_REPLICATIONS_INFO,
4024-)
4025-from ubuntuone.controlpanel.gui.tests import (
4026- FAKE_ACCOUNT_INFO,
4027- FAKE_DEVICE_INFO,
4028- FAKE_DEVICES_INFO,
4029- FAKE_FOLDERS_INFO,
4030- FAKE_VOLUMES_INFO,
4031- FAKE_VOLUMES_MINIMAL_INFO,
4032- FAKE_VOLUMES_NO_FREE_SPACE_INFO,
4033- MUSIC_FOLDER, ROOT, USER_HOME,
4034-)
4035-from ubuntuone.controlpanel.gui.gtk.tests.test_gui_basic import (
4036- ControlPanelMixinTestCase,
4037-)
4038-from ubuntuone.controlpanel.gui.gtk.tests.test_package_manager import (
4039- SUCCESS, FAILURE)
4040-from ubuntuone.controlpanel.gui import humanize
4041-
4042-
4043-# Attribute 'yyy' defined outside __init__, access to a protected member
4044-# pylint: disable=W0201, W0212
4045-
4046-# Unused variable 'skip'
4047-#pylint: disable=W0612
4048-
4049-
4050-class DashboardTestCase(ControlPanelMixinTestCase):
4051- """The test suite for the dashboard panel."""
4052-
4053- klass = gui.DashboardPanel
4054- ui_filename = 'dashboard.ui'
4055-
4056- def assert_account_info_correct(self, info):
4057- """Check that the displayed account info matches 'info'."""
4058- self.assertEqual(self.ui.name_label.get_label(),
4059- FAKE_ACCOUNT_INFO['name'])
4060- self.assertEqual(self.ui.type_label.get_label(),
4061- FAKE_ACCOUNT_INFO['type'])
4062- self.assertEqual(self.ui.email_label.get_label(),
4063- FAKE_ACCOUNT_INFO['email'])
4064-
4065- def test_is_an_ubuntuone_bin(self):
4066- """Inherits from UbuntuOneBin."""
4067- self.assertIsInstance(self.ui, gui.UbuntuOneBin)
4068-
4069- def test_inner_widget_is_packed(self):
4070- """The 'itself' vbox is packed into the widget."""
4071- self.assertIn(self.ui.itself, self.ui.get_children())
4072-
4073- def test_is_visible(self):
4074- """Is visible."""
4075- self.assertTrue(self.ui.get_visible())
4076-
4077- def test_account_info_is_not_visible(self):
4078- """Account info is not visible."""
4079- self.assertFalse(self.ui.account.get_visible())
4080-
4081- def test_backend_signals(self):
4082- """The proper signals are connected to the backend."""
4083- self.assertEqual(self.ui.backend._signals['AccountInfoReady'],
4084- [self.ui.on_account_info_ready])
4085- self.assertEqual(self.ui.backend._signals['AccountInfoError'],
4086- [self.ui.on_account_info_error])
4087-
4088- def test_is_processing_at_startup(self):
4089- """The ui is processing when info is being loaded."""
4090- self.assertTrue(self.ui.is_processing)
4091-
4092- def test_is_not_processing_on_info_ready(self):
4093- """The ui is not processing when info is ready."""
4094- self.ui.on_account_info_ready(FAKE_ACCOUNT_INFO)
4095-
4096- self.assertFalse(self.ui.is_processing)
4097-
4098- def test_on_account_info_ready(self):
4099- """The account info is processed when ready."""
4100- self.ui.on_account_info_ready(FAKE_ACCOUNT_INFO)
4101-
4102- self.assert_account_info_correct(FAKE_ACCOUNT_INFO)
4103- self.assertTrue(self.ui.account.get_visible())
4104-
4105- def test_is_not_processing_on_info_error(self):
4106- """The ui is not processing when info is ready."""
4107- self.ui.on_account_info_error()
4108-
4109- self.assertFalse(self.ui.is_processing)
4110-
4111- def test_on_account_info_error(self):
4112- """The account info couldn't be retrieved."""
4113- self.ui.on_account_info_error()
4114-
4115- self.assertFalse(self.ui.account.get_visible())
4116- self.assert_warning_correct(self.ui.message, self.ui.VALUE_ERROR)
4117-
4118-
4119-class VolumesTestCase(ControlPanelMixinTestCase):
4120- """The test suite for the volumes panel."""
4121-
4122- klass = gui.VolumesPanel
4123- ui_filename = 'volumes.ui'
4124-
4125- @defer.inlineCallbacks
4126- def setUp(self):
4127- yield super(VolumesTestCase, self).setUp()
4128- self.ui.load()
4129-
4130- def test_is_an_ubuntuone_bin(self):
4131- """Inherits from UbuntuOneBin."""
4132- self.assertIsInstance(self.ui, gui.UbuntuOneBin)
4133-
4134- def test_inner_widget_is_packed(self):
4135- """The 'itself' vbox is packed into the widget."""
4136- self.assertIn(self.ui.itself, self.ui.get_children())
4137-
4138- def test_is_visible(self):
4139- """Is visible."""
4140- self.assertTrue(self.ui.get_visible())
4141-
4142- def test_backend_signals(self):
4143- """The proper signals are connected to the backend."""
4144- self.assertEqual(self.ui.backend._signals['VolumesInfoReady'],
4145- [self.ui.on_volumes_info_ready])
4146- self.assertEqual(self.ui.backend._signals['VolumesInfoError'],
4147- [self.ui.on_volumes_info_error])
4148- self.assertEqual(self.ui.backend._signals['VolumeSettingsChanged'],
4149- [self.ui.on_volume_settings_changed])
4150- self.assertEqual(self.ui.backend._signals['VolumeSettingsChangeError'],
4151- [self.ui.on_volume_settings_change_error])
4152-
4153- def test_volumes_info_is_requested_on_load(self):
4154- """The volumes info is requested to the backend."""
4155- # clean backend calls
4156- self.ui.backend._called.pop('volumes_info', None)
4157- self.ui.load()
4158-
4159- self.assert_backend_called('volumes_info')
4160-
4161- def test_is_processing_after_load(self):
4162- """The ui is processing when contents are load."""
4163- self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
4164- self.ui.load()
4165-
4166- self.assertTrue(self.ui.is_processing)
4167-
4168- def test_is_not_processing_after_volumes_info_ready(self):
4169- """The ui is processing when contents are load."""
4170- self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
4171-
4172- self.assertFalse(self.ui.is_processing)
4173-
4174- def test_message_after_non_empty_volumes_info_ready(self):
4175- """The volumes label is a LabelLoading."""
4176- self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
4177-
4178- self.assertFalse(self.ui.message.active)
4179-
4180- def test_message_after_empty_volumes_info_ready(self):
4181- """When there are no volumes, a notification is shown."""
4182- self.ui.on_volumes_info_ready([])
4183-
4184- self.assertFalse(self.ui.message.active)
4185- self.assertEqual(self.ui.message.get_text(), gui.NO_FOLDERS)
4186-
4187- def test_on_volumes_info_ready(self):
4188- """The volumes info is processed when ready."""
4189- self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
4190-
4191- self.assertEqual(len(FAKE_VOLUMES_INFO) + 1, # count the empty row
4192- len(self.ui.volumes_store))
4193- treeiter = self.ui.volumes_store.get_iter_root()
4194- for name, free_bytes, volumes in FAKE_VOLUMES_INFO:
4195- name = "%s's" % name if name else gui.MY_FOLDERS
4196- free_bytes = humanize(int(free_bytes))
4197- header = (name, self.ui.FREE_SPACE % {'free_space': free_bytes})
4198-
4199- # check parent row
4200- row = self.ui.volumes_store.get(treeiter,
4201- *xrange(self.ui.MAX_COLS))
4202-
4203- self.assertEqual(row[0], self.ui.ROW_HEADER % header)
4204- self.assertTrue(row[1], 'parent will always be subscribed')
4205- self.assertEqual(row[2], gui.CONTACT_ICON_NAME)
4206- self.assertFalse(row[3], 'no toggle should be shown on parent!')
4207- self.assertFalse(row[4], 'toggle should be non sensitive.')
4208- self.assertEqual(row[5], gui.gtk.ICON_SIZE_LARGE_TOOLBAR)
4209- self.assertEqual(row[6], None)
4210- self.assertEqual(row[7], None)
4211-
4212- # check children
4213- self.assertEqual(len(volumes),
4214- self.ui.volumes_store.iter_n_children(treeiter))
4215- childiter = self.ui.volumes_store.iter_children(treeiter)
4216-
4217- sorted_vols = sorted(volumes, key=operator.itemgetter('path'))
4218- for volume in sorted_vols:
4219- row = self.ui.volumes_store.get(childiter,
4220- *xrange(self.ui.MAX_COLS))
4221-
4222- sensitive = True
4223- path = volume['path'].replace(USER_HOME + '/', '')
4224- if volume['type'] == 'ROOT':
4225- sensitive = False
4226- path = self.ui.ROOT % (path, gui.ORANGE,
4227- gui.ALWAYS_SUBSCRIBED)
4228- elif volume['type'] == 'SHARE':
4229- path = volume['name']
4230-
4231- self.assertEqual(row[0], path)
4232- self.assertEqual(row[1], bool(volume['subscribed']))
4233- if volume['type'] != 'SHARE':
4234- self.assertEqual(row[2], gui.FOLDER_ICON_NAME)
4235- else:
4236- self.assertEqual(row[2], gui.SHARE_ICON_NAME)
4237- self.assertTrue(row[3], 'toggle should be shown on child!')
4238- self.assertEqual(row[4], sensitive)
4239- self.assertEqual(row[5], gui.gtk.ICON_SIZE_MENU)
4240- self.assertEqual(row[6], volume['volume_id'])
4241- self.assertEqual(row[7], volume['path'])
4242-
4243- childiter = self.ui.volumes_store.iter_next(childiter)
4244-
4245- treeiter = self.ui.volumes_store.iter_next(treeiter)
4246-
4247- if treeiter is not None:
4248- # skip the empty row
4249- row = self.ui.volumes_store.get(treeiter,
4250- *xrange(self.ui.MAX_COLS))
4251- self.assertEqual(row, self.ui._empty_row)
4252-
4253- # grab next non-empty row
4254- treeiter = self.ui.volumes_store.iter_next(treeiter)
4255-
4256- def test_on_volumes_info_ready_clears_the_list(self):
4257- """The old volumes info is cleared before updated."""
4258- self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
4259- self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
4260-
4261- self.assertEqual(len(FAKE_VOLUMES_INFO) + 1,
4262- len(self.ui.volumes_store))
4263-
4264- def test_on_volumes_info_ready_with_no_volumes(self):
4265- """When there are no volumes, a notification is shown."""
4266- self.ui.on_volumes_info_ready([])
4267-
4268- self.assertEqual(len(self.ui.volumes_store), 0)
4269-
4270- def test_on_volumes_info_ready_highlights_little_free_space(self):
4271- """The free space is red if is zero (or close to 0)."""
4272- self.ui.on_volumes_info_ready(FAKE_VOLUMES_NO_FREE_SPACE_INFO)
4273-
4274- treeiter = self.ui.volumes_store.get_iter_root()
4275- for name, free_bytes, volumes in FAKE_VOLUMES_NO_FREE_SPACE_INFO:
4276- name = "%s's" % name if name else gui.MY_FOLDERS
4277- free_bytes = humanize(int(free_bytes))
4278- free_bytes = self.ui.NO_FREE_SPACE % {'free_space': free_bytes}
4279-
4280- # check parent row
4281- row = self.ui.volumes_store.get(treeiter,
4282- *xrange(self.ui.MAX_COLS))
4283-
4284- self.assertEqual(row[0], self.ui.ROW_HEADER % (name, free_bytes))
4285-
4286- treeiter = self.ui.volumes_store.iter_next(treeiter)
4287-
4288- if treeiter is not None:
4289- # skip the empty row
4290- row = self.ui.volumes_store.get(treeiter,
4291- *xrange(self.ui.MAX_COLS))
4292- self.assertEqual(row, self.ui._empty_row)
4293-
4294- # grab next non-empty row
4295- treeiter = self.ui.volumes_store.iter_next(treeiter)
4296-
4297- def test_on_volumes_info_ready_handles_no_quota_info(self):
4298- """The lack of free space is handled."""
4299- info = [
4300- (u'', gui.backend.ControlBackend.FREE_BYTES_NOT_AVAILABLE, [ROOT]),
4301- (u'No free space available',
4302- gui.backend.ControlBackend.FREE_BYTES_NOT_AVAILABLE,
4303- [{u'volume_id': u'0', u'name': u'full', u'display_name': u'test',
4304- u'path': u'full-share', u'subscribed': u'',
4305- u'type': gui.backend.ControlBackend.SHARE_TYPE}]),
4306- ]
4307- self.ui.on_volumes_info_ready(info)
4308-
4309- treeiter = self.ui.volumes_store.get_iter_root()
4310- for name, free_bytes, volumes in info:
4311- name = "%s's" % name if name else gui.MY_FOLDERS
4312-
4313- # check parent row
4314- row = self.ui.volumes_store.get(treeiter,
4315- *xrange(self.ui.MAX_COLS))
4316-
4317- self.assertEqual(row[0], self.ui.ROW_HEADER % (name, ''))
4318-
4319- treeiter = self.ui.volumes_store.iter_next(treeiter)
4320-
4321- if treeiter is not None:
4322- # skip the empty row
4323- row = self.ui.volumes_store.get(treeiter,
4324- *xrange(self.ui.MAX_COLS))
4325- self.assertEqual(row, self.ui._empty_row)
4326-
4327- # grab next non-empty row
4328- treeiter = self.ui.volumes_store.iter_next(treeiter)
4329-
4330- def test_on_volumes_info_error(self):
4331- """The volumes info couldn't be retrieved."""
4332- self.ui.on_volumes_info_error()
4333- self.assert_warning_correct(warning=self.ui.message,
4334- text=gui.VALUE_ERROR)
4335- self.assertFalse(self.ui.message.active)
4336-
4337- def test_on_volumes_info_error_after_success(self):
4338- """The volumes info couldn't be retrieved after a prior success."""
4339- self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
4340-
4341- self.ui.on_volumes_info_error()
4342-
4343- self.test_on_volumes_info_error()
4344- self.test_on_volumes_info_ready_with_no_volumes()
4345-
4346- def test_clicking_on_row_opens_folder(self):
4347- """The folder activated is opened."""
4348- self.patch(gui.os.path, 'exists', lambda *a: True)
4349- self.patch(gui, 'uri_hook', self._set_called)
4350- self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
4351-
4352- self.ui.volumes_view.row_activated('0:0',
4353- self.ui.volumes_view.get_column(0))
4354-
4355- self.assertEqual(self._called,
4356- ((None, gui.FILE_URI_PREFIX + ROOT['path']), {}))
4357-
4358- def test_clicking_on_row_handles_path_none(self):
4359- """None paths are properly handled."""
4360- self.patch(gui, 'uri_hook', self._set_called)
4361- self.patch(self.ui.volumes_store, 'get_value', lambda *a: None)
4362- self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
4363-
4364- self.ui.volumes_view.row_activated('0:0',
4365- self.ui.volumes_view.get_column(0))
4366-
4367- self.assertTrue(self.memento.check_warning('tree_path (0, 0)',
4368- 'volume_path', 'is None'))
4369- self.assertEqual(self._called, False)
4370-
4371- def test_clicking_on_row_handles_path_non_existent(self):
4372- """Not-existent paths are properly handled."""
4373- self.patch(gui.os.path, 'exists', lambda *a: False)
4374- self.patch(gui, 'uri_hook', self._set_called)
4375- path = 'not-in-disk'
4376- self.patch(self.ui.volumes_store, 'get_value', lambda *a: path)
4377- self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
4378-
4379- self.ui.volumes_view.row_activated('0:0',
4380- self.ui.volumes_view.get_column(0))
4381-
4382- self.assertTrue(self.memento.check_warning(path, 'does not exist'))
4383- self.assertEqual(self._called, False)
4384-
4385- def test_on_volumes_info_ready_with_music_folder(self):
4386- """The volumes info is processed when ready."""
4387- self.ui.on_volumes_info_ready(FAKE_VOLUMES_MINIMAL_INFO)
4388-
4389- treeiter = self.ui.volumes_store.get_iter_root()
4390- row = self.ui.volumes_store.get(treeiter, *xrange(self.ui.MAX_COLS))
4391-
4392- # walk 'Mine' folders children
4393- treeiter = self.ui.volumes_store.iter_children(treeiter)
4394-
4395- # grab next row since first one is root
4396- treeiter = self.ui.volumes_store.iter_next(treeiter)
4397- row = self.ui.volumes_store.get(treeiter, *xrange(self.ui.MAX_COLS))
4398-
4399- volume = MUSIC_FOLDER
4400- self.assertEqual(row[0], gui.MUSIC_DISPLAY_NAME)
4401- self.assertEqual(row[1], bool(volume['subscribed']))
4402- self.assertEqual(row[2], gui.MUSIC_ICON_NAME)
4403- self.assertTrue(row[3], 'toggle should be shown on child!')
4404- self.assertTrue(row[4], 'toggle should be sensitive')
4405- self.assertEqual(row[5], gui.gtk.ICON_SIZE_MENU)
4406- self.assertEqual(row[6], volume['volume_id'])
4407- self.assertEqual(row[7], volume['path'])
4408-
4409-
4410-class VolumesSubscriptionTestCase(VolumesTestCase):
4411- """The test suite for the volumes panel."""
4412-
4413- kwargs = {'main_window': object()}
4414- tree_path = '0:3' # this is the /home/tester/foo folder, not subscribed
4415-
4416- @defer.inlineCallbacks
4417- def setUp(self):
4418- yield super(VolumesSubscriptionTestCase, self).setUp()
4419- self.patch(gui.os.path, 'exists', lambda path: True)
4420- self.ui.confirm_dialog.response_code = gui.gtk.RESPONSE_YES
4421- self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
4422-
4423- def test_on_subscribed_toggled(self):
4424- """Clicking on 'subscribed' updates the folder subscription."""
4425- real_rows = len(FAKE_VOLUMES_INFO)
4426- data = zip(range(real_rows)[::2], FAKE_VOLUMES_INFO) # skip emtpy rows
4427- for parent, (_, _, volumes) in data:
4428-
4429- sorted_vols = sorted(volumes, key=operator.itemgetter('path'))
4430- for child, volume in enumerate(sorted_vols):
4431- if volume['type'] == 'ROOT':
4432- continue # not editable
4433-
4434- path = '%s:%s' % (parent, child)
4435- self.ui.on_subscribed_toggled(widget=None, path=path)
4436-
4437- fid = volume['volume_id']
4438- subscribed = gui.bool_str(not bool(volume['subscribed']))
4439- # backend was called
4440- self.assert_backend_called('change_volume_settings',
4441- fid, {'subscribed': subscribed})
4442- # store was updated
4443- it = self.ui.volumes_store.get_iter(path)
4444- value = self.ui.volumes_store.get_value(it, 1)
4445- self.assertEqual(value, bool(subscribed))
4446-
4447- # the ui is processing
4448- self.assertTrue(self.ui.is_processing, 'ui must be processing')
4449-
4450- # simulate success for setting change
4451- self.ui.on_volume_settings_changed(volume_id=fid)
4452-
4453- def test_on_volume_setting_changed(self):
4454- """The setting for a volume was successfully changed."""
4455- self.ui.on_subscribed_toggled(None, self.tree_path)
4456-
4457- self.ui.on_volume_settings_changed(volume_id=None) # id not used
4458-
4459- # the ui is no longer processing
4460- self.assertFalse(self.ui.is_processing, 'ui must not be processing')
4461-
4462- def test_on_volume_setting_change_error(self):
4463- """The setting for a volume was not successfully changed."""
4464- self.ui.on_subscribed_toggled(None, self.tree_path)
4465-
4466- self.patch(self.ui, 'load', self._set_called)
4467- self.ui.on_volume_settings_change_error(volume_id=None,
4468- error_dict=None) # id not used
4469- # reload folders list to sanitize the info in volumes_store
4470- self.assertTrue(self._called, ((), {}))
4471-
4472- def test_confirm_dialog(self):
4473- """The confirmation dialog is correct."""
4474- dialog = self.ui.confirm_dialog
4475-
4476- self.assertEqual(dialog._args, ())
4477- flags = gui.gtk.DIALOG_MODAL | gui.gtk.DIALOG_DESTROY_WITH_PARENT
4478- kwargs = dict(parent=self.kwargs['main_window'],
4479- flags=flags, type=gui.gtk.MESSAGE_WARNING,
4480- buttons=gui.gtk.BUTTONS_YES_NO)
4481- self.assertEqual(dialog._kwargs, kwargs)
4482-
4483- def test_subscribe_shows_confirmation_dialog(self):
4484- """Clicking on subscribe displays a confirmation dialog."""
4485- self.ui.on_subscribed_toggled(None, self.tree_path)
4486-
4487- path = FAKE_FOLDERS_INFO[-1]['path']
4488- self.assertTrue(self.ui.confirm_dialog.was_run, 'dialog was run')
4489- self.assertEqual(self.ui.confirm_dialog.markup,
4490- gui.FOLDERS_CONFIRM_MERGE % {'folder_path': path})
4491- self.assertFalse(self.ui.confirm_dialog.is_visible, 'dialog was hid')
4492-
4493- def test_subscribe_does_not_call_backend_if_dialog_closed(self):
4494- """Backend is not called if users closes the confirmation dialog."""
4495- self.ui.confirm_dialog.response_code = gui.gtk.RESPONSE_DELETE_EVENT
4496- self.ui.on_subscribed_toggled(None, self.tree_path)
4497-
4498- self.assertNotIn('change_volume_settings', self.ui.backend._called)
4499- self.assertFalse(self.ui.is_processing)
4500-
4501- def test_subscribe_does_not_call_backend_if_answer_is_no(self):
4502- """Backend is not called if users clicks on 'No'."""
4503- self.ui.confirm_dialog.response_code = gui.gtk.RESPONSE_NO
4504- self.ui.on_subscribed_toggled(None, self.tree_path)
4505-
4506- self.assertNotIn('change_volume_settings', self.ui.backend._called)
4507- self.assertFalse(self.ui.is_processing)
4508-
4509- def test_no_confirmation_if_no_local_folder(self):
4510- """The confirmation dialog is not shown if local folder not present."""
4511- self.patch(gui.os.path, 'exists', lambda path: False)
4512- self.ui.on_subscribed_toggled(None, self.tree_path)
4513-
4514- self.assertFalse(self.ui.confirm_dialog.was_run, 'dialog was not run')
4515- self.assertFalse(self.ui.confirm_dialog.is_visible, 'dialog was hid')
4516-
4517- def test_no_confirmation_if_unsubscribing(self):
4518- """The confirmation dialog is not shown if unsubscribing."""
4519- self.ui.on_subscribed_toggled(None, self.tree_path)
4520-
4521- treeiter = self.ui.volumes_store.get_iter(self.tree_path)
4522- assert self.ui.volumes_store.get_value(treeiter, 1)
4523-
4524- # reset flags
4525- self.ui.confirm_dialog.was_run = False
4526- self.ui.confirm_dialog.is_visible = False
4527-
4528- self.ui.on_subscribed_toggled(None, self.tree_path)
4529-
4530- self.assertFalse(self.ui.confirm_dialog.was_run, 'dialog was not run')
4531- self.assertFalse(self.ui.confirm_dialog.is_visible, 'dialog was hid')
4532-
4533-
4534-class DeviceTestCase(ControlPanelMixinTestCase):
4535- """The test suite for the device widget."""
4536-
4537- klass = gui.Device
4538- ui_filename = 'device.ui'
4539-
4540- def assert_device_equal(self, device, expected):
4541- """Assert that the device has the values from expected."""
4542- self.assertEqual(device.id,
4543- expected['device_id'])
4544- value = expected['device_name'].replace(gui.DEVICE_REMOVABLE_PREFIX,
4545- '')
4546- self.assertEqual(device.device_name.get_text(), value)
4547- self.assertEqual(device.device_type.get_icon_name()[0],
4548- expected['device_type'].lower())
4549- self.assertEqual(device.is_local,
4550- bool(expected['is_local']))
4551- self.assertEqual(device.configurable,
4552- bool(expected['configurable']))
4553- self.assertEqual(device.show_all_notifications.get_active(),
4554- bool(expected['show_all_notifications']))
4555- self.assertEqual(device.limit_bandwidth.get_active(),
4556- bool(expected['limit_bandwidth']))
4557-
4558- config_enabled = self.ui.config_settings.get_sensitive()
4559- self.assertEqual(device.configurable, config_enabled)
4560-
4561- limit_enabled = self.ui.throttling_limits.get_sensitive()
4562- self.assertEqual(device.limit_bandwidth.get_active(), limit_enabled)
4563-
4564- value = int(expected['max_upload_speed']) // gui.KILOBYTES
4565- self.assertEqual(device.max_upload_speed.get_value_as_int(), value)
4566- value = int(expected['max_download_speed']) // gui.KILOBYTES
4567- self.assertEqual(device.max_download_speed.get_value_as_int(), value)
4568-
4569- def assert_device_settings_changed(self):
4570- """Changing throttling settings updates the backend properly."""
4571- expected = self.ui.__dict__
4572- self.assert_backend_called('change_device_settings',
4573- self.ui.id, expected)
4574- self.assertEqual(self.ui.warning_label.get_text(), '')
4575-
4576- limit_enabled = self.ui.throttling_limits.get_sensitive()
4577- self.assertEqual(self.ui.limit_bandwidth.get_active(), limit_enabled)
4578-
4579- def modify_settings(self):
4580- """Modify settings so values actually change."""
4581- new_val = not self.ui.show_all_notifications.get_active()
4582- self.ui.show_all_notifications.set_active(new_val)
4583-
4584- new_val = not self.ui.limit_bandwidth.get_active()
4585- self.ui.limit_bandwidth.set_active(new_val)
4586-
4587- new_val = self.ui.max_upload_speed.get_value_as_int() + 1
4588- self.ui.max_upload_speed.set_value(new_val)
4589-
4590- new_val = self.ui.max_download_speed.get_value_as_int() + 1
4591- self.ui.max_download_speed.set_value(new_val)
4592-
4593- def test_is_a_container(self):
4594- """Inherits from a container class."""
4595- self.assertIsInstance(self.ui, gui.gtk.Bin)
4596-
4597- def test_inner_widget_is_packed(self):
4598- """The 'itself' vbox is packed into the widget."""
4599- self.assertIn(self.ui.itself, self.ui.get_children())
4600-
4601- def test_is_visible(self):
4602- """Is visible."""
4603- self.assertTrue(self.ui.get_visible())
4604-
4605- def test_is_sensitive(self):
4606- """Is sensitive."""
4607- self.assertTrue(self.ui.get_sensitive())
4608-
4609- def test_warning_label_is_cleared(self):
4610- """The warning label is cleared."""
4611- self.assertEqual(self.ui.warning_label.get_text(), '')
4612-
4613- def test_default_values(self):
4614- """Default values are correct."""
4615- self.assertEqual(self.ui.id, None)
4616- self.assertEqual(self.ui.device_name.get_text(), '')
4617- self.assertEqual(self.ui.device_type.get_icon_name()[0],
4618- gui.DEVICE_TYPE_COMPUTER.lower())
4619- self.assertEqual(self.ui.is_local, False)
4620- self.assertEqual(self.ui.configurable, False)
4621- self.assertEqual(self.ui.show_all_notifications.get_active(), True)
4622- self.assertEqual(self.ui.limit_bandwidth.get_active(), False)
4623- self.assertEqual(self.ui.max_upload_speed.get_value_as_int(), 0)
4624- self.assertEqual(self.ui.max_download_speed.get_value_as_int(), 0)
4625-
4626- def test_init_does_not_call_backend(self):
4627- """When updating, the backend is not called."""
4628- self.assertEqual(self.ui.backend._called, {})
4629-
4630- def test_update_device_name(self):
4631- """A device can be updated from a dict."""
4632- value = 'The death star'
4633- self.ui.update(device_name=gui.DEVICE_REMOVABLE_PREFIX + value)
4634- self.assertEqual(value, self.ui.device_name.get_text())
4635-
4636- def test_update_unicode_device_name(self):
4637- """A device can be updated from a dict."""
4638- value = u'Ñoño Ñandú'
4639- self.ui.update(device_name=gui.DEVICE_REMOVABLE_PREFIX + value)
4640- self.assertEqual(value, self.ui.device_name.get_text())
4641-
4642- def test_update_device_type_computer(self):
4643- """A device can be updated from a dict."""
4644- dtype = gui.DEVICE_TYPE_COMPUTER
4645- self.ui.update(device_type=dtype)
4646- self.assertEqual((dtype.lower(), gui.gtk.ICON_SIZE_LARGE_TOOLBAR),
4647- self.ui.device_type.get_icon_name())
4648-
4649- def test_update_device_type_phone(self):
4650- """A device can be updated from a dict."""
4651- dtype = gui.DEVICE_TYPE_PHONE
4652- self.ui.update(device_type=dtype)
4653- self.assertEqual((dtype.lower(), gui.gtk.ICON_SIZE_LARGE_TOOLBAR),
4654- self.ui.device_type.get_icon_name())
4655-
4656- def test_update_is_not_local(self):
4657- """A device can be updated from a dict."""
4658- self.ui.update(is_local='')
4659- self.assertFalse(self.ui.is_local)
4660-
4661- def test_update_is_local(self):
4662- """A device can be updated from a dict."""
4663- self.ui.update(is_local='True')
4664- self.assertTrue(self.ui.is_local)
4665-
4666- def test_update_non_configurable(self):
4667- """A device can be updated from a dict."""
4668- self.ui.update(configurable='')
4669- self.assertFalse(self.ui.configurable)
4670- self.assertFalse(self.ui.config_settings.get_visible())
4671-
4672- def test_update_configurable(self):
4673- """A device can be updated from a dict."""
4674- self.ui.update(configurable='True')
4675- self.assertTrue(self.ui.configurable)
4676- self.assertTrue(self.ui.config_settings.get_visible())
4677-
4678- def test_update_show_all_notifications(self):
4679- """A device can be updated from a dict."""
4680- self.ui.update(show_all_notifications='')
4681- self.assertFalse(self.ui.show_all_notifications.get_active())
4682-
4683- self.ui.update(show_all_notifications='True')
4684- self.assertTrue(self.ui.show_all_notifications.get_active())
4685-
4686- def test_update_limit_bandwidth(self):
4687- """A device can be updated from a dict."""
4688- self.ui.update(limit_bandwidth='')
4689- self.assertFalse(self.ui.limit_bandwidth.get_active())
4690- self.assertFalse(self.ui.throttling_limits.get_sensitive())
4691-
4692- self.ui.update(limit_bandwidth='True')
4693- self.assertTrue(self.ui.limit_bandwidth.get_active())
4694- self.assertTrue(self.ui.throttling_limits.get_sensitive())
4695-
4696- def test_update_upload_speed(self):
4697- """A device can be updated from a dict."""
4698- value = '12345'
4699- self.ui.update(max_upload_speed=value)
4700- self.assertEqual(int(value) // gui.KILOBYTES,
4701- self.ui.max_upload_speed.get_value_as_int())
4702-
4703- def test_update_download_speed(self):
4704- """A device can be updated from a dict."""
4705- value = '987654'
4706- self.ui.update(max_download_speed=value)
4707- self.assertEqual(int(value) // gui.KILOBYTES,
4708- self.ui.max_download_speed.get_value_as_int())
4709-
4710- def test_update_does_not_call_backend(self):
4711- """When updating, the backend is not called."""
4712- self.ui.update(**FAKE_DEVICE_INFO)
4713- self.assertEqual(self.ui.backend._called, {})
4714- self.assert_device_equal(self.ui, FAKE_DEVICE_INFO)
4715-
4716- def test_on_show_all_notifications_toggled(self):
4717- """When toggling show_all_notifications, backend is updated."""
4718- value = not self.ui.show_all_notifications.get_active()
4719- self.ui.show_all_notifications.set_active(value)
4720- self.assert_device_settings_changed()
4721-
4722- def test_on_limit_bandwidth_toggled(self):
4723- """When toggling limit_bandwidth, backend is updated."""
4724- value = not self.ui.limit_bandwidth.get_active()
4725- self.ui.limit_bandwidth.set_active(value)
4726- self.assert_device_settings_changed()
4727-
4728- def test_on_max_upload_speed_value_changed(self):
4729- """When setting max_upload_speed, backend is updated."""
4730- self.ui.max_upload_speed.set_value(25)
4731- self.assert_device_settings_changed()
4732-
4733- def test_on_max_download_speed_value_changed(self):
4734- """When setting max_download_speed, backend is updated."""
4735- self.ui.max_download_speed.set_value(52)
4736- self.assert_device_settings_changed()
4737-
4738- def test_backend_signals(self):
4739- """The proper signals are connected to the backend."""
4740- self.assertEqual(self.ui.backend._signals['DeviceSettingsChanged'],
4741- [self.ui.on_device_settings_changed])
4742- self.assertEqual(self.ui.backend._signals['DeviceSettingsChangeError'],
4743- [self.ui.on_device_settings_change_error])
4744- self.assertEqual(self.ui.backend._signals['DeviceRemoved'],
4745- [self.ui.on_device_removed])
4746- self.assertEqual(self.ui.backend._signals['DeviceRemovalError'],
4747- [self.ui.on_device_removal_error])
4748-
4749- def test_on_device_settings_changed(self):
4750- """When settings were changed for this device, enable it."""
4751- self.modify_settings()
4752- self.ui.on_device_settings_changed(device_id=self.ui.id)
4753-
4754- self.assertTrue(self.ui.get_sensitive())
4755- self.assertEqual(self.ui.warning_label.get_text(), '')
4756- self.assertEqual(self.ui.__dict__, self.ui._last_settings)
4757-
4758- def test_on_device_settings_change_after_error(self):
4759- """Change success after error."""
4760- self.modify_settings()
4761- self.ui.on_device_settings_change_error(device_id=self.ui.id) # error
4762-
4763- self.test_on_device_settings_changed()
4764-
4765- def test_on_device_settings_changed_different_id(self):
4766- """When settings were changed for other device, nothing changes."""
4767- self.modify_settings()
4768- self.ui.on_device_settings_changed(device_id='yadda')
4769-
4770- self.assertEqual(self.ui.warning_label.get_text(), '')
4771-
4772- def test_on_device_settings_change_error(self):
4773- """When settings were not changed for this device, notify the user.
4774-
4775- Also, confirm that old values were restored.
4776-
4777- """
4778- self.ui.update(**FAKE_DEVICE_INFO) # use known values
4779-
4780- self.modify_settings()
4781-
4782- self.ui.on_device_settings_change_error(device_id=self.ui.id) # error
4783-
4784- self.assertTrue(self.ui.get_sensitive())
4785- self.assert_warning_correct(self.ui.warning_label,
4786- gui.DEVICE_CHANGE_ERROR)
4787- self.assert_device_equal(self.ui, FAKE_DEVICE_INFO) # restored info
4788-
4789- def test_on_device_settings_change_error_after_success(self):
4790- """Change error after success."""
4791- self.modify_settings()
4792- self.ui.on_device_settings_changed(device_id=self.ui.id)
4793-
4794- self.test_on_device_settings_change_error()
4795-
4796- def test_on_device_settings_change_error_different_id(self):
4797- """When settings were not changed for other device, do nothing."""
4798- self.modify_settings()
4799- self.ui.on_device_settings_change_error(device_id='yudo')
4800- self.assertEqual(self.ui.warning_label.get_text(), '')
4801-
4802- def test_remove(self):
4803- """Clicking on remove calls the backend properly."""
4804- self.ui.is_local = False
4805- self.ui.remove.clicked()
4806-
4807- self.assert_backend_called('remove_device', self.ui.id)
4808- self.assertFalse(self.ui.get_sensitive(),
4809- 'Must be disabled while removing.')
4810-
4811- def test_on_device_removed(self):
4812- """On this device removed, hide and destroy."""
4813- self.ui.remove.clicked()
4814- self.ui.on_device_removed(device_id=self.ui.id)
4815-
4816- self.assertFalse(self.ui.get_visible(),
4817- 'Must not be visible after removed.')
4818-
4819- def test_on_device_removed_other_id(self):
4820- """On other device removed, do nothing."""
4821- self.ui.remove.clicked()
4822- self.ui.on_device_removed(device_id='foo')
4823-
4824- self.assertTrue(self.ui.get_visible(),
4825- 'Must be visible after other device was removed.')
4826-
4827- def test_on_device_removal_error(self):
4828- """On this device removal error, re-enable and show error."""
4829- self.ui.remove.clicked()
4830- self.ui.on_device_removal_error(device_id=self.ui.id)
4831-
4832- self.assertTrue(self.ui.get_sensitive(),
4833- 'Must be enabled after removal error.')
4834- self.assert_warning_correct(self.ui.warning_label,
4835- gui.DEVICE_REMOVAL_ERROR)
4836-
4837- def test_on_device_removal_error_other_id(self):
4838- """On other device removal error, do nothing."""
4839- self.ui.remove.clicked()
4840- self.ui.on_device_removal_error(device_id='foo')
4841-
4842- self.assertFalse(self.ui.get_sensitive(),
4843- 'Must be disabled after other device removal error.')
4844-
4845-
4846-class RemoveDeviceTestCase(DeviceTestCase):
4847- """The test suite for the device widget when prompting for removal."""
4848-
4849- confirm_dialog = FakedConfirmDialog()
4850- kwargs = {'confirm_remove_dialog': confirm_dialog}
4851-
4852- def test_remove(self):
4853- """Clicking on remove calls the backend properly."""
4854- self.confirm_dialog.response_code = gui.gtk.RESPONSE_YES
4855- super(RemoveDeviceTestCase, self).test_remove()
4856-
4857- def test_on_device_removal_error_other_id(self):
4858- """On other device removal error, do nothing."""
4859- self.confirm_dialog.response_code = gui.gtk.RESPONSE_YES
4860- parent_test = super(RemoveDeviceTestCase, self)
4861- parent_test.test_on_device_removal_error_other_id()
4862-
4863- def test_remove_shows_confirmation_dialog(self):
4864- """Clicking on remove displays a confirmation dialog."""
4865- self.ui.remove.clicked()
4866-
4867- self.assertTrue(self.confirm_dialog.was_run, 'dialog was run')
4868- self.assertFalse(self.confirm_dialog.is_visible, 'dialog was hid')
4869-
4870- def test_remove_does_not_call_backend_if_dialog_closed(self):
4871- """Backend is not called if users closes the confirmation dialog."""
4872- self.confirm_dialog.response_code = gui.gtk.RESPONSE_DELETE_EVENT
4873- self.ui.remove.clicked()
4874-
4875- self.assertNotIn('remove_device', self.ui.backend._called)
4876- self.assertTrue(self.ui.is_sensitive())
4877-
4878- def test_remove_does_not_call_backend_if_answer_is_no(self):
4879- """Backend is not called if users clicks on 'No'."""
4880- self.confirm_dialog.response_code = gui.gtk.RESPONSE_NO
4881- self.ui.remove.clicked()
4882-
4883- self.assertNotIn('remove_device', self.ui.backend._called)
4884- self.assertTrue(self.ui.is_sensitive())
4885-
4886-
4887-class DevicesTestCase(ControlPanelMixinTestCase):
4888- """The test suite for the devices panel."""
4889-
4890- klass = gui.DevicesPanel
4891- ui_filename = 'devices.ui'
4892- kwargs = {'main_window': object()}
4893-
4894- @defer.inlineCallbacks
4895- def setUp(self):
4896- yield super(DevicesTestCase, self).setUp()
4897- self.ui.load()
4898-
4899- def test_is_an_ubuntuone_bin(self):
4900- """Inherits from UbuntuOneBin."""
4901- self.assertIsInstance(self.ui, gui.UbuntuOneBin)
4902-
4903- def test_inner_widget_is_packed(self):
4904- """The 'itself' vbox is packed into the widget."""
4905- self.assertIn(self.ui.itself, self.ui.get_children())
4906-
4907- def test_is_visible(self):
4908- """Is visible."""
4909- self.assertTrue(self.ui.get_visible())
4910-
4911- def test_confirm_remove_dialog(self):
4912- """The confirmation dialog is correct."""
4913- dialog = self.ui.confirm_remove_dialog
4914-
4915- self.assertEqual(dialog._args, ())
4916- flags = gui.gtk.DIALOG_MODAL | gui.gtk.DIALOG_DESTROY_WITH_PARENT
4917- kwargs = dict(parent=self.kwargs['main_window'],
4918- flags=flags, type=gui.gtk.MESSAGE_WARNING,
4919- buttons=gui.gtk.BUTTONS_YES_NO,
4920- message_format=gui.DEVICE_CONFIRM_REMOVE)
4921- self.assertEqual(dialog._kwargs, kwargs)
4922-
4923- def test_backend_signals(self):
4924- """The proper signals are connected to the backend."""
4925- self.assertEqual(self.ui.backend._signals['DevicesInfoReady'],
4926- [self.ui.on_devices_info_ready])
4927- self.assertEqual(self.ui.backend._signals['DevicesInfoError'],
4928- [self.ui.on_devices_info_error])
4929- self.assertEqual(self.ui.backend._signals['DeviceRemoved'],
4930- [self.ui.on_device_removed])
4931-
4932- def test_devices_info_is_requested_on_load(self):
4933- """The devices info is requested to the backend."""
4934- # clean backend calls
4935- self.ui.backend._called.pop('devices_info', None)
4936- self.ui.load()
4937-
4938- self.assert_backend_called('devices_info')
4939-
4940- def test_is_processing_after_load(self):
4941- """The ui is processing when contents are load."""
4942- self.ui.on_devices_info_ready(FAKE_DEVICES_INFO)
4943- self.ui.load()
4944-
4945- self.assertTrue(self.ui.is_processing)
4946-
4947- def test_is_not_processing_after_non_empty_devices_info_ready(self):
4948- """The ui is no longer processing after a non empty device list."""
4949- self.ui.on_devices_info_ready(FAKE_DEVICES_INFO)
4950-
4951- self.assertFalse(self.ui.is_processing)
4952-
4953- def test_is_not_processing_after_empty_devices_info_ready(self):
4954- """The ui is no longer processing after a empty device list."""
4955- self.ui.on_devices_info_ready([])
4956-
4957- self.assertFalse(self.ui.is_processing)
4958-
4959- def test_show_message_after_empty_devices_info_ready(self):
4960- """When there are no devices, a notification is shown."""
4961- self.ui.on_devices_info_ready([])
4962-
4963- self.assertEqual(self.ui.message.get_text(), gui.NO_DEVICES)
4964-
4965- def test_on_devices_info_ready(self):
4966- """The devices info is processed when ready."""
4967- self.ui.on_devices_info_ready(FAKE_DEVICES_INFO)
4968-
4969- children = self.ui.devices.get_children()
4970- self.assertEqual(len(children), len(FAKE_DEVICES_INFO))
4971-
4972- for child, device in zip(children, FAKE_DEVICES_INFO):
4973- self.assertIsInstance(child, gui.Device)
4974-
4975- self.assertEqual(device['device_id'], child.id)
4976- value = device['device_name'].replace(gui.DEVICE_REMOVABLE_PREFIX,
4977- '')
4978- self.assertEqual(value, child.device_name.get_text())
4979- self.assertEqual(device['device_type'].lower(),
4980- child.device_type.get_icon_name()[0])
4981- self.assertEqual(bool(device['is_local']),
4982- child.is_local)
4983- self.assertEqual(bool(device['configurable']),
4984- child.configurable)
4985-
4986- if bool(device['configurable']):
4987- self.assertEqual(bool(device['show_all_notifications']),
4988- child.show_all_notifications.get_active())
4989- self.assertEqual(bool(device['limit_bandwidth']),
4990- child.limit_bandwidth.get_active())
4991- value = int(device['max_upload_speed']) // gui.KILOBYTES
4992- self.assertEqual(value,
4993- child.max_upload_speed.get_value_as_int())
4994- value = int(device['max_download_speed']) // gui.KILOBYTES
4995- self.assertEqual(value,
4996- child.max_download_speed.get_value_as_int())
4997-
4998- self.assertIs(child.confirm_dialog, self.ui.confirm_remove_dialog)
4999-
5000- def test_on_devices_info_ready_have_devices_cached(self):
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: