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