Merge lp:~dobey/ubuntu/natty/ubuntuone-control-panel/release-0-9-1 into lp:ubuntu/natty/ubuntuone-control-panel

Proposed by dobey
Status: Merged
Merged at revision: 15
Proposed branch: lp:~dobey/ubuntu/natty/ubuntuone-control-panel/release-0-9-1
Merge into: lp:ubuntu/natty/ubuntuone-control-panel
Diff against target: 4681 lines (+2189/-1405)
20 files modified
PKG-INFO (+1/-1)
bin/ubuntuone-control-panel-gtk (+4/-2)
data/dashboard.ui (+5/-138)
data/device.ui (+160/-122)
data/management.ui (+214/-101)
data/overview.ui (+292/-223)
data/services.ui (+309/-14)
data/volumes.ui (+20/-20)
debian/changelog (+24/-0)
debian/control (+4/-4)
pylintrc (+1/-1)
setup.py (+1/-1)
ubuntuone/__init__.py (+0/-1)
ubuntuone/controlpanel/backend.py (+5/-1)
ubuntuone/controlpanel/gtk/gui.py (+215/-90)
ubuntuone/controlpanel/gtk/tests/__init__.py (+92/-7)
ubuntuone/controlpanel/gtk/tests/test_gui.py (+235/-670)
ubuntuone/controlpanel/gtk/tests/test_gui_basic.py (+595/-0)
ubuntuone/controlpanel/tests/__init__.py (+11/-8)
ubuntuone/controlpanel/tests/test_backend.py (+1/-1)
To merge this branch: bzr merge lp:~dobey/ubuntu/natty/ubuntuone-control-panel/release-0-9-1
Reviewer Review Type Date Requested Status
Daniel Holbach (community) Approve
Review via email: mp+52795@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Daniel Holbach (dholbach) wrote :

Good work!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'PKG-INFO'
--- PKG-INFO 2011-02-28 15:38:15 +0000
+++ PKG-INFO 2011-03-10 03:11:54 +0000
@@ -1,6 +1,6 @@
1Metadata-Version: 1.11Metadata-Version: 1.1
2Name: ubuntuone-control-panel2Name: ubuntuone-control-panel
3Version: 0.9.03Version: 0.9.1
4Summary: Ubuntu One Control Panel4Summary: Ubuntu One Control Panel
5Home-page: https://launchpad.net/ubuntuone-control-panel5Home-page: https://launchpad.net/ubuntuone-control-panel
6Author: Natalia Bidart6Author: Natalia Bidart
77
=== modified file 'bin/ubuntuone-control-panel-gtk'
--- bin/ubuntuone-control-panel-gtk 2011-01-25 19:08:59 +0000
+++ bin/ubuntuone-control-panel-gtk 2011-03-10 03:11:54 +0000
@@ -40,12 +40,14 @@
40 help="Start the Ubuntu One Control Panel (GTK) in the "40 help="Start the Ubuntu One Control Panel (GTK) in the "
41 "PANEL_NAME tab. Possible values are: "41 "PANEL_NAME tab. Possible values are: "
42 "dashboard, volumes, devices, applications")42 "dashboard, volumes, devices, applications")
43 result.add_option("-a", "--alert", dest="alert", action="store_true",
44 help="Start the Ubuntu One Control Panel (GTK) alerting "
45 "the user to its presence.")
43 return result46 return result
4447
4548
46if __name__ == "__main__":49if __name__ == "__main__":
47 parser = parser_options()50 parser = parser_options()
48 (options, args) = parser.parse_args(sys.argv)51 (options, args) = parser.parse_args(sys.argv)
4952 gui = ControlPanelWindow(switch_to=options.switch_to, alert=options.alert)
50 gui = ControlPanelWindow(switch_to=options.switch_to)
51 gui.main()53 gui.main()
5254
=== removed file 'data/banner.png'
53Binary files data/banner.png 2011-02-28 15:38:15 +0000 and data/banner.png 1970-01-01 00:00:00 +0000 differ55Binary files data/banner.png 2011-02-28 15:38:15 +0000 and data/banner.png 1970-01-01 00:00:00 +0000 differ
=== modified file 'data/contacts.png'
54Binary files data/contacts.png 2011-02-12 03:07:22 +0000 and data/contacts.png 2011-03-10 03:11:54 +0000 differ56Binary files data/contacts.png 2011-02-12 03:07:22 +0000 and data/contacts.png 2011-03-10 03:11:54 +0000 differ
=== modified file 'data/dashboard.ui'
--- data/dashboard.ui 2011-02-28 15:38:15 +0000
+++ data/dashboard.ui 2011-03-10 03:11:54 +0000
@@ -5,8 +5,6 @@
5 <object class="GtkVBox" id="itself">5 <object class="GtkVBox" id="itself">
6 <property name="visible">True</property>6 <property name="visible">True</property>
7 <property name="can_focus">False</property>7 <property name="can_focus">False</property>
8 <property name="border_width">10</property>
9 <property name="spacing">10</property>
10 <child>8 <child>
11 <object class="GtkHBox" id="account">9 <object class="GtkHBox" id="account">
12 <property name="visible">True</property>10 <property name="visible">True</property>
@@ -59,12 +57,13 @@
59 </child>57 </child>
60 <child>58 <child>
61 <object class="GtkLinkButton" id="linkbutton3">59 <object class="GtkLinkButton" id="linkbutton3">
62 <property name="label" translatable="yes">Edit</property>60 <property name="label" translatable="yes">Edit account details</property>
63 <property name="visible">True</property>61 <property name="visible">True</property>
64 <property name="can_focus">True</property>62 <property name="can_focus">True</property>
65 <property name="receives_default">True</property>63 <property name="receives_default">True</property>
64 <property name="tooltip_text" translatable="yes">Edit your account details</property>
66 <property name="use_action_appearance">False</property>65 <property name="use_action_appearance">False</property>
67 <property name="relief">none</property>66 <property name="relief">half</property>
68 <property name="uri">http://login.ubuntu.com</property>67 <property name="uri">http://login.ubuntu.com</property>
69 </object>68 </object>
70 <packing>69 <packing>
@@ -131,8 +130,9 @@
131 <property name="visible">True</property>130 <property name="visible">True</property>
132 <property name="can_focus">True</property>131 <property name="can_focus">True</property>
133 <property name="receives_default">True</property>132 <property name="receives_default">True</property>
133 <property name="tooltip_text" translatable="yes">Upgrade the storage space on your account</property>
134 <property name="use_action_appearance">False</property>134 <property name="use_action_appearance">False</property>
135 <property name="relief">none</property>135 <property name="relief">half</property>
136 <property name="uri">https://one.ubuntu.com/plans/</property>136 <property name="uri">https://one.ubuntu.com/plans/</property>
137 </object>137 </object>
138 <packing>138 <packing>
@@ -169,138 +169,5 @@
169 <property name="position">0</property>169 <property name="position">0</property>
170 </packing>170 </packing>
171 </child>171 </child>
172 <child>
173 <object class="GtkAlignment" id="alignment5">
174 <property name="visible">True</property>
175 <property name="can_focus">False</property>
176 <child>
177 <object class="GtkHBox" id="hbox1">
178 <property name="visible">True</property>
179 <property name="can_focus">False</property>
180 <property name="spacing">20</property>
181 <child>
182 <object class="GtkHButtonBox" id="hbuttonbox3">
183 <property name="visible">True</property>
184 <property name="can_focus">False</property>
185 <property name="spacing">5</property>
186 <child>
187 <object class="GtkLinkButton" id="linkbutton2">
188 <property name="label" translatable="yes">Official Support</property>
189 <property name="visible">True</property>
190 <property name="can_focus">True</property>
191 <property name="receives_default">True</property>
192 <property name="tooltip_text" translatable="yes">Get official Ubuntu One support online</property>
193 <property name="use_action_appearance">False</property>
194 <property name="uri">https://one.ubuntu.com/support/</property>
195 </object>
196 <packing>
197 <property name="expand">False</property>
198 <property name="fill">False</property>
199 <property name="position">0</property>
200 </packing>
201 </child>
202 <child>
203 <object class="GtkLinkButton" id="linkbutton4">
204 <property name="label" translatable="yes">Community Support</property>
205 <property name="visible">True</property>
206 <property name="can_focus">True</property>
207 <property name="receives_default">True</property>
208 <property name="tooltip_text" translatable="yes">View and ask Ubuntu One related questions at AskUbuntu.com</property>
209 <property name="use_action_appearance">False</property>
210 <property name="uri">http://askubuntu.com/questions/tagged/ubuntu-one</property>
211 </object>
212 <packing>
213 <property name="expand">False</property>
214 <property name="fill">False</property>
215 <property name="position">1</property>
216 </packing>
217 </child>
218 </object>
219 <packing>
220 <property name="expand">False</property>
221 <property name="fill">True</property>
222 <property name="position">0</property>
223 </packing>
224 </child>
225 <child>
226 <object class="GtkHBox" id="hbox2">
227 <property name="visible">True</property>
228 <property name="can_focus">False</property>
229 <child>
230 <object class="GtkLabel" id="label4">
231 <property name="visible">True</property>
232 <property name="can_focus">False</property>
233 <property name="label" translatable="yes">Talk to us on:</property>
234 </object>
235 <packing>
236 <property name="expand">True</property>
237 <property name="fill">True</property>
238 <property name="position">0</property>
239 </packing>
240 </child>
241 <child>
242 <object class="GtkLinkButton" id="linkbutton5">
243 <property name="visible">True</property>
244 <property name="can_focus">True</property>
245 <property name="receives_default">True</property>
246 <property name="use_action_appearance">False</property>
247 <property name="relief">none</property>
248 <property name="uri">http://twitter.com/ubuntuone</property>
249 <child>
250 <object class="GtkImage" id="twitter">
251 <property name="visible">True</property>
252 <property name="can_focus">False</property>
253 <property name="tooltip_text" translatable="yes">http://twitter.com/ubuntuone</property>
254 <property name="pixbuf">twitter.png</property>
255 </object>
256 </child>
257 </object>
258 <packing>
259 <property name="expand">False</property>
260 <property name="fill">False</property>
261 <property name="position">1</property>
262 </packing>
263 </child>
264 <child>
265 <object class="GtkLinkButton" id="linkbutton6">
266 <property name="visible">True</property>
267 <property name="can_focus">True</property>
268 <property name="receives_default">True</property>
269 <property name="use_action_appearance">False</property>
270 <property name="relief">none</property>
271 <property name="uri">http://www.facebook.com/ubuntuone</property>
272 <child>
273 <object class="GtkImage" id="facebook">
274 <property name="visible">True</property>
275 <property name="can_focus">False</property>
276 <property name="tooltip_text" translatable="yes">http://www.facebook.com/ubuntuone</property>
277 <property name="pixbuf">facebook.png</property>
278 </object>
279 </child>
280 </object>
281 <packing>
282 <property name="expand">True</property>
283 <property name="fill">True</property>
284 <property name="position">2</property>
285 </packing>
286 </child>
287 </object>
288 <packing>
289 <property name="expand">False</property>
290 <property name="fill">True</property>
291 <property name="pack_type">end</property>
292 <property name="position">1</property>
293 </packing>
294 </child>
295 </object>
296 </child>
297 </object>
298 <packing>
299 <property name="expand">False</property>
300 <property name="fill">True</property>
301 <property name="pack_type">end</property>
302 <property name="position">1</property>
303 </packing>
304 </child>
305 </object>172 </object>
306</interface>173</interface>
307174
=== modified file 'data/device.ui'
--- data/device.ui 2011-02-23 13:57:42 +0000
+++ data/device.ui 2011-03-10 03:11:54 +0000
@@ -12,174 +12,203 @@
12 </object>12 </object>
13 <object class="GtkVBox" id="itself">13 <object class="GtkVBox" id="itself">
14 <property name="visible">True</property>14 <property name="visible">True</property>
15 <property name="can_focus">False</property>
15 <property name="border_width">10</property>16 <property name="border_width">10</property>
16 <property name="spacing">5</property>17 <property name="spacing">5</property>
17 <child>18 <child>
18 <object class="GtkHBox" id="hbox1">19 <object class="GtkHBox" id="hbox1">
19 <property name="visible">True</property>20 <property name="visible">True</property>
21 <property name="can_focus">False</property>
20 <property name="spacing">10</property>22 <property name="spacing">10</property>
21 <child>23 <child>
22 <object class="GtkVBox" id="vbox1">24 <object class="GtkVBox" id="vbox1">
23 <property name="visible">True</property>25 <property name="visible">True</property>
26 <property name="can_focus">False</property>
24 <property name="spacing">5</property>27 <property name="spacing">5</property>
25 <child>28 <child>
26 <object class="GtkHBox" id="hbox2">29 <object class="GtkHBox" id="hbox2">
27 <property name="visible">True</property>30 <property name="visible">True</property>
31 <property name="can_focus">False</property>
28 <child>32 <child>
29 <object class="GtkImage" id="device_type">33 <object class="GtkImage" id="device_type">
30 <property name="visible">True</property>34 <property name="visible">True</property>
35 <property name="can_focus">False</property>
31 <property name="icon_name">computer</property>36 <property name="icon_name">computer</property>
32 </object>37 </object>
33 <packing>38 <packing>
34 <property name="expand">False</property>39 <property name="expand">False</property>
40 <property name="fill">True</property>
35 <property name="position">0</property>41 <property name="position">0</property>
36 </packing>42 </packing>
37 </child>43 </child>
38 <child>44 <child>
39 <object class="GtkLabel" id="device_name">45 <object class="GtkLabel" id="device_name">
40 <property name="visible">True</property>46 <property name="visible">True</property>
47 <property name="can_focus">False</property>
41 <property name="xalign">0</property>48 <property name="xalign">0</property>
42 <property name="xpad">5</property>49 <property name="xpad">5</property>
43 <property name="label">My Laptop</property>50 <property name="label">My Laptop</property>
44 <property name="wrap">True</property>51 <property name="wrap">True</property>
45 </object>52 </object>
46 <packing>53 <packing>
54 <property name="expand">True</property>
55 <property name="fill">True</property>
47 <property name="position">1</property>56 <property name="position">1</property>
48 </packing>57 </packing>
49 </child>58 </child>
50 </object>59 </object>
51 <packing>60 <packing>
61 <property name="expand">True</property>
62 <property name="fill">True</property>
52 <property name="position">0</property>63 <property name="position">0</property>
53 </packing>64 </packing>
54 </child>65 </child>
55 <child>66 <child>
56 <object class="GtkAlignment" id="alignment1">67 <object class="GtkAlignment" id="alignment1">
57 <property name="visible">True</property>68 <property name="visible">True</property>
69 <property name="can_focus">False</property>
58 <property name="left_padding">25</property>70 <property name="left_padding">25</property>
59 <child>71 <child>
60 <object class="GtkTable" id="throttling">72 <object class="GtkVBox" id="config_settings">
61 <property name="visible">True</property>73 <property name="visible">True</property>
62 <property name="n_rows">4</property>74 <property name="can_focus">False</property>
63 <property name="n_columns">3</property>
64 <property name="column_spacing">3</property>
65 <property name="row_spacing">3</property>
66 <child>75 <child>
67 <object class="GtkCheckButton" id="show_all_notifications">76 <object class="GtkCheckButton" id="show_all_notifications">
68 <property name="label" translatable="yes">Show notifications</property>77 <property name="label" translatable="yes">Show activity notifications</property>
69 <property name="visible">True</property>78 <property name="visible">True</property>
70 <property name="can_focus">True</property>79 <property name="can_focus">True</property>
71 <property name="receives_default">False</property>80 <property name="receives_default">False</property>
72 <property name="draw_indicator">True</property>81 <property name="use_action_appearance">False</property>
73 <signal name="toggled" handler="on_show_all_notifications_toggled"/>82 <property name="draw_indicator">True</property>
74 </object>83 <signal name="toggled" handler="on_show_all_notifications_toggled" swapped="no"/>
75 </child>84 </object>
76 <child>85 <packing>
77 <object class="GtkCheckButton" id="limit_bandwidth">86 <property name="expand">True</property>
78 <property name="label" translatable="yes">Limit bandwidth usage</property>87 <property name="fill">True</property>
79 <property name="visible">True</property>88 <property name="position">0</property>
80 <property name="can_focus">True</property>89 </packing>
81 <property name="receives_default">False</property>90 </child>
82 <property name="draw_indicator">True</property>91 <child>
83 <signal name="toggled" handler="on_limit_bandwidth_toggled"/>92 <object class="GtkVBox" id="throttling">
84 </object>93 <property name="visible">True</property>
85 <packing>94 <property name="can_focus">False</property>
86 <property name="top_attach">1</property>95 <child>
87 <property name="bottom_attach">2</property>96 <object class="GtkCheckButton" id="limit_bandwidth">
88 </packing>97 <property name="label" translatable="yes">Limit file sync bandwidth usage</property>
89 </child>98 <property name="visible">True</property>
90 <child>99 <property name="can_focus">True</property>
91 <object class="GtkLabel" id="max_upload_speed_label">100 <property name="receives_default">False</property>
92 <property name="visible">True</property>101 <property name="use_action_appearance">False</property>
93 <property name="xalign">0</property>102 <property name="draw_indicator">True</property>
94 <property name="label" translatable="yes">Max upload speed:</property>103 <signal name="toggled" handler="on_limit_bandwidth_toggled" swapped="no"/>
95 <property name="track_visited_links">False</property>104 </object>
96 </object>105 <packing>
97 <packing>106 <property name="expand">True</property>
98 <property name="top_attach">2</property>107 <property name="fill">True</property>
99 <property name="bottom_attach">3</property>108 <property name="position">0</property>
100 </packing>109 </packing>
101 </child>110 </child>
102 <child>111 <child>
103 <object class="GtkLabel" id="max_download_speed_label">112 <object class="GtkTable" id="throttling_limits">
104 <property name="visible">True</property>113 <property name="visible">True</property>
105 <property name="xalign">0</property>114 <property name="can_focus">False</property>
106 <property name="label" translatable="yes">Max download speed:</property>115 <property name="n_rows">2</property>
107 </object>116 <property name="n_columns">3</property>
108 <packing>117 <property name="column_spacing">3</property>
109 <property name="top_attach">3</property>118 <property name="row_spacing">3</property>
110 <property name="bottom_attach">4</property>119 <child>
111 </packing>120 <object class="GtkLabel" id="max_upload_speed_label">
112 </child>121 <property name="visible">True</property>
113 <child>122 <property name="can_focus">False</property>
114 <object class="GtkSpinButton" id="max_upload_speed">123 <property name="xalign">0</property>
115 <property name="visible">True</property>124 <property name="xpad">22</property>
116 <property name="can_focus">True</property>125 <property name="label" translatable="yes">Max upload speed:</property>
117 <property name="invisible_char">•</property>126 <property name="track_visited_links">False</property>
118 <property name="activates_default">True</property>127 </object>
119 <property name="invisible_char_set">True</property>128 </child>
120 <property name="adjustment">adjustment1</property>129 <child>
121 <signal name="value_changed" handler="on_max_upload_speed_value_changed"/>130 <object class="GtkLabel" id="max_download_speed_label">
122 </object>131 <property name="visible">True</property>
123 <packing>132 <property name="can_focus">False</property>
124 <property name="left_attach">1</property>133 <property name="xalign">0</property>
125 <property name="right_attach">2</property>134 <property name="xpad">22</property>
126 <property name="top_attach">2</property>135 <property name="label" translatable="yes">Max download speed:</property>
127 <property name="bottom_attach">3</property>136 </object>
128 <property name="x_options">GTK_FILL</property>137 <packing>
129 <property name="y_options">GTK_FILL</property>138 <property name="top_attach">1</property>
130 </packing>139 <property name="bottom_attach">2</property>
131 </child>140 </packing>
132 <child>141 </child>
133 <object class="GtkSpinButton" id="max_download_speed">142 <child>
134 <property name="visible">True</property>143 <object class="GtkSpinButton" id="max_upload_speed">
135 <property name="can_focus">True</property>144 <property name="visible">True</property>
136 <property name="invisible_char">•</property>145 <property name="can_focus">True</property>
137 <property name="activates_default">True</property>146 <property name="invisible_char">•</property>
138 <property name="invisible_char_set">True</property>147 <property name="activates_default">True</property>
139 <property name="adjustment">adjustment2</property>148 <property name="invisible_char_set">True</property>
140 <signal name="value_changed" handler="on_max_download_speed_value_changed"/>149 <property name="adjustment">adjustment1</property>
141 </object>150 <signal name="value-changed" handler="on_max_upload_speed_value_changed" swapped="no"/>
142 <packing>151 </object>
143 <property name="left_attach">1</property>152 <packing>
144 <property name="right_attach">2</property>153 <property name="left_attach">1</property>
145 <property name="top_attach">3</property>154 <property name="right_attach">2</property>
146 <property name="bottom_attach">4</property>155 <property name="x_options">GTK_FILL</property>
147 </packing>156 <property name="y_options">GTK_FILL</property>
148 </child>157 </packing>
149 <child>158 </child>
150 <placeholder/>159 <child>
151 </child>160 <object class="GtkSpinButton" id="max_download_speed">
152 <child>161 <property name="visible">True</property>
153 <placeholder/>162 <property name="can_focus">True</property>
154 </child>163 <property name="invisible_char">•</property>
155 <child>164 <property name="activates_default">True</property>
156 <placeholder/>165 <property name="invisible_char_set">True</property>
157 </child>166 <property name="adjustment">adjustment2</property>
158 <child>167 <signal name="value-changed" handler="on_max_download_speed_value_changed" swapped="no"/>
159 <placeholder/>168 </object>
160 </child>169 <packing>
161 <child>170 <property name="left_attach">1</property>
162 <object class="GtkLabel" id="label1">171 <property name="right_attach">2</property>
163 <property name="visible">True</property>172 <property name="top_attach">1</property>
164 <property name="label" translatable="yes">KiB/s</property>173 <property name="bottom_attach">2</property>
165 </object>174 </packing>
166 <packing>175 </child>
167 <property name="left_attach">2</property>176 <child>
168 <property name="right_attach">3</property>177 <object class="GtkLabel" id="label1">
169 <property name="top_attach">2</property>178 <property name="visible">True</property>
170 <property name="bottom_attach">3</property>179 <property name="can_focus">False</property>
171 </packing>180 <property name="label" translatable="yes">KiB/s</property>
172 </child>181 </object>
173 <child>182 <packing>
174 <object class="GtkLabel" id="label2">183 <property name="left_attach">2</property>
175 <property name="visible">True</property>184 <property name="right_attach">3</property>
176 <property name="label" translatable="yes">KiB/s</property>185 </packing>
177 </object>186 </child>
178 <packing>187 <child>
179 <property name="left_attach">2</property>188 <object class="GtkLabel" id="label2">
180 <property name="right_attach">3</property>189 <property name="visible">True</property>
181 <property name="top_attach">3</property>190 <property name="can_focus">False</property>
182 <property name="bottom_attach">4</property>191 <property name="label" translatable="yes">KiB/s</property>
192 </object>
193 <packing>
194 <property name="left_attach">2</property>
195 <property name="right_attach">3</property>
196 <property name="top_attach">1</property>
197 <property name="bottom_attach">2</property>
198 </packing>
199 </child>
200 </object>
201 <packing>
202 <property name="expand">True</property>
203 <property name="fill">True</property>
204 <property name="position">1</property>
205 </packing>
206 </child>
207 </object>
208 <packing>
209 <property name="expand">True</property>
210 <property name="fill">True</property>
211 <property name="position">1</property>
183 </packing>212 </packing>
184 </child>213 </child>
185 </object>214 </object>
@@ -187,18 +216,21 @@
187 </object>216 </object>
188 <packing>217 <packing>
189 <property name="expand">False</property>218 <property name="expand">False</property>
219 <property name="fill">True</property>
190 <property name="position">1</property>220 <property name="position">1</property>
191 </packing>221 </packing>
192 </child>222 </child>
193 </object>223 </object>
194 <packing>224 <packing>
195 <property name="expand">False</property>225 <property name="expand">False</property>
226 <property name="fill">True</property>
196 <property name="position">0</property>227 <property name="position">0</property>
197 </packing>228 </packing>
198 </child>229 </child>
199 <child>230 <child>
200 <object class="GtkVButtonBox" id="vbuttonbox1">231 <object class="GtkVButtonBox" id="vbuttonbox1">
201 <property name="visible">True</property>232 <property name="visible">True</property>
233 <property name="can_focus">False</property>
202 <property name="layout_style">start</property>234 <property name="layout_style">start</property>
203 <child>235 <child>
204 <object class="GtkButton" id="remove">236 <object class="GtkButton" id="remove">
@@ -206,9 +238,10 @@
206 <property name="visible">True</property>238 <property name="visible">True</property>
207 <property name="can_focus">True</property>239 <property name="can_focus">True</property>
208 <property name="receives_default">True</property>240 <property name="receives_default">True</property>
241 <property name="use_action_appearance">False</property>
209 <property name="use_stock">True</property>242 <property name="use_stock">True</property>
210 <signal name="clicked" handler="on_remove_clicked"/>243 <signal name="activate" handler="on_remove_clicked" swapped="no"/>
211 <signal name="activate" handler="on_remove_clicked"/>244 <signal name="clicked" handler="on_remove_clicked" swapped="no"/>
212 </object>245 </object>
213 <packing>246 <packing>
214 <property name="expand">False</property>247 <property name="expand">False</property>
@@ -219,6 +252,7 @@
219 </object>252 </object>
220 <packing>253 <packing>
221 <property name="expand">False</property>254 <property name="expand">False</property>
255 <property name="fill">True</property>
222 <property name="pack_type">end</property>256 <property name="pack_type">end</property>
223 <property name="position">1</property>257 <property name="position">1</property>
224 </packing>258 </packing>
@@ -226,14 +260,18 @@
226 </object>260 </object>
227 <packing>261 <packing>
228 <property name="expand">False</property>262 <property name="expand">False</property>
263 <property name="fill">True</property>
229 <property name="position">0</property>264 <property name="position">0</property>
230 </packing>265 </packing>
231 </child>266 </child>
232 <child>267 <child>
233 <object class="GtkLabel" id="warning_label">268 <object class="GtkLabel" id="warning_label">
234 <property name="visible">True</property>269 <property name="visible">True</property>
270 <property name="can_focus">False</property>
235 </object>271 </object>
236 <packing>272 <packing>
273 <property name="expand">True</property>
274 <property name="fill">True</property>
237 <property name="position">1</property>275 <property name="position">1</property>
238 </packing>276 </packing>
239 </child>277 </child>
240278
=== modified file 'data/files.png'
241Binary files data/files.png 2011-02-12 03:07:22 +0000 and data/files.png 2011-03-10 03:11:54 +0000 differ279Binary files data/files.png 2011-02-12 03:07:22 +0000 and data/files.png 2011-03-10 03:11:54 +0000 differ
=== modified file 'data/management.ui'
--- data/management.ui 2011-02-23 13:57:42 +0000
+++ data/management.ui 2011-03-10 03:11:54 +0000
@@ -50,143 +50,120 @@
50 </packing>50 </packing>
51 </child>51 </child>
52 <child>52 <child>
53 <object class="GtkVBox" id="vbox1">53 <object class="GtkHBox" id="hbox2">
54 <property name="visible">True</property>54 <property name="visible">True</property>
55 <property name="can_focus">False</property>55 <property name="can_focus">False</property>
56 <child>56 <child>
57 <object class="GtkHBox" id="hbox2">57 <object class="GtkHSeparator" id="hseparator1">
58 <property name="visible">True</property>58 <property name="visible">True</property>
59 <property name="can_focus">False</property>59 <property name="can_focus">False</property>
60 </object>
61 <packing>
62 <property name="expand">True</property>
63 <property name="fill">True</property>
64 <property name="position">0</property>
65 </packing>
66 </child>
67 <child>
68 <object class="GtkHButtonBox" id="hbuttonbox1">
69 <property name="visible">True</property>
70 <property name="can_focus">False</property>
71 <property name="layout_style">center</property>
60 <child>72 <child>
61 <object class="GtkHSeparator" id="hseparator1">73 <object class="GtkRadioButton" id="dashboard_button">
74 <property name="label" translatable="yes">Account</property>
62 <property name="visible">True</property>75 <property name="visible">True</property>
63 <property name="can_focus">False</property>76 <property name="can_focus">True</property>
77 <property name="receives_default">False</property>
78 <property name="use_action_appearance">False</property>
79 <property name="active">True</property>
80 <property name="draw_indicator">False</property>
64 </object>81 </object>
65 <packing>82 <packing>
66 <property name="expand">True</property>83 <property name="expand">False</property>
67 <property name="fill">True</property>84 <property name="fill">False</property>
68 <property name="position">0</property>85 <property name="position">0</property>
69 </packing>86 </packing>
70 </child>87 </child>
71 <child>88 <child>
72 <object class="GtkHButtonBox" id="hbuttonbox1">89 <object class="GtkRadioButton" id="volumes_button">
90 <property name="label" translatable="yes">Cloud Folders</property>
73 <property name="visible">True</property>91 <property name="visible">True</property>
74 <property name="can_focus">False</property>92 <property name="can_focus">True</property>
75 <property name="layout_style">center</property>93 <property name="receives_default">False</property>
76 <child>94 <property name="use_action_appearance">False</property>
77 <object class="GtkRadioButton" id="dashboard_button">95 <property name="draw_indicator">False</property>
78 <property name="label" translatable="yes">Account</property>96 <property name="group">dashboard_button</property>
79 <property name="visible">True</property>
80 <property name="can_focus">True</property>
81 <property name="receives_default">False</property>
82 <property name="use_action_appearance">False</property>
83 <property name="active">True</property>
84 <property name="draw_indicator">False</property>
85 </object>
86 <packing>
87 <property name="expand">False</property>
88 <property name="fill">False</property>
89 <property name="position">0</property>
90 </packing>
91 </child>
92 <child>
93 <object class="GtkRadioButton" id="volumes_button">
94 <property name="label" translatable="yes">Cloud Folders</property>
95 <property name="visible">True</property>
96 <property name="can_focus">True</property>
97 <property name="receives_default">False</property>
98 <property name="use_action_appearance">False</property>
99 <property name="draw_indicator">False</property>
100 <property name="group">dashboard_button</property>
101 </object>
102 <packing>
103 <property name="expand">False</property>
104 <property name="fill">False</property>
105 <property name="position">1</property>
106 </packing>
107 </child>
108 <child>
109 <object class="GtkRadioButton" id="shares_button">
110 <property name="label" translatable="yes">Shares</property>
111 <property name="can_focus">True</property>
112 <property name="receives_default">False</property>
113 <property name="use_action_appearance">False</property>
114 <property name="draw_indicator">False</property>
115 <property name="group">dashboard_button</property>
116 </object>
117 <packing>
118 <property name="expand">False</property>
119 <property name="fill">False</property>
120 <property name="position">2</property>
121 </packing>
122 </child>
123 <child>
124 <object class="GtkRadioButton" id="devices_button">
125 <property name="label" translatable="yes">Devices</property>
126 <property name="visible">True</property>
127 <property name="can_focus">True</property>
128 <property name="receives_default">False</property>
129 <property name="use_action_appearance">False</property>
130 <property name="draw_indicator">False</property>
131 <property name="group">dashboard_button</property>
132 </object>
133 <packing>
134 <property name="expand">False</property>
135 <property name="fill">False</property>
136 <property name="position">3</property>
137 </packing>
138 </child>
139 <child>
140 <object class="GtkRadioButton" id="services_button">
141 <property name="label" translatable="yes">Services</property>
142 <property name="visible">True</property>
143 <property name="can_focus">True</property>
144 <property name="receives_default">False</property>
145 <property name="use_action_appearance">False</property>
146 <property name="draw_indicator">False</property>
147 <property name="group">dashboard_button</property>
148 </object>
149 <packing>
150 <property name="expand">False</property>
151 <property name="fill">False</property>
152 <property name="position">4</property>
153 </packing>
154 </child>
155 </object>97 </object>
156 <packing>98 <packing>
157 <property name="expand">False</property>99 <property name="expand">False</property>
158 <property name="fill">True</property>100 <property name="fill">False</property>
159 <property name="position">1</property>101 <property name="position">1</property>
160 </packing>102 </packing>
161 </child>103 </child>
162 <child>104 <child>
163 <object class="GtkHSeparator" id="hseparator2">105 <object class="GtkRadioButton" id="shares_button">
164 <property name="visible">True</property>106 <property name="label" translatable="yes">Shares</property>
165 <property name="can_focus">False</property>107 <property name="can_focus">True</property>
108 <property name="receives_default">False</property>
109 <property name="use_action_appearance">False</property>
110 <property name="draw_indicator">False</property>
111 <property name="group">dashboard_button</property>
166 </object>112 </object>
167 <packing>113 <packing>
168 <property name="expand">True</property>114 <property name="expand">False</property>
169 <property name="fill">True</property>115 <property name="fill">False</property>
170 <property name="position">2</property>116 <property name="position">2</property>
171 </packing>117 </packing>
172 </child>118 </child>
119 <child>
120 <object class="GtkRadioButton" id="devices_button">
121 <property name="label" translatable="yes">Devices</property>
122 <property name="visible">True</property>
123 <property name="can_focus">True</property>
124 <property name="receives_default">False</property>
125 <property name="use_action_appearance">False</property>
126 <property name="draw_indicator">False</property>
127 <property name="group">dashboard_button</property>
128 </object>
129 <packing>
130 <property name="expand">False</property>
131 <property name="fill">False</property>
132 <property name="position">3</property>
133 </packing>
134 </child>
135 <child>
136 <object class="GtkRadioButton" id="services_button">
137 <property name="label" translatable="yes">Services</property>
138 <property name="visible">True</property>
139 <property name="can_focus">True</property>
140 <property name="receives_default">False</property>
141 <property name="use_action_appearance">False</property>
142 <property name="draw_indicator">False</property>
143 <property name="group">dashboard_button</property>
144 </object>
145 <packing>
146 <property name="expand">False</property>
147 <property name="fill">False</property>
148 <property name="position">4</property>
149 </packing>
150 </child>
173 </object>151 </object>
174 <packing>152 <packing>
175 <property name="expand">False</property>153 <property name="expand">False</property>
176 <property name="fill">True</property>154 <property name="fill">True</property>
177 <property name="position">0</property>155 <property name="position">1</property>
178 </packing>156 </packing>
179 </child>157 </child>
180 <child>158 <child>
181 <object class="GtkImage" id="image1">159 <object class="GtkHSeparator" id="hseparator2">
182 <property name="visible">True</property>160 <property name="visible">True</property>
183 <property name="can_focus">False</property>161 <property name="can_focus">False</property>
184 <property name="pixbuf">banner.png</property>
185 </object>162 </object>
186 <packing>163 <packing>
187 <property name="expand">False</property>164 <property name="expand">True</property>
188 <property name="fill">True</property>165 <property name="fill">True</property>
189 <property name="position">1</property>166 <property name="position">2</property>
190 </packing>167 </packing>
191 </child>168 </child>
192 </object>169 </object>
@@ -219,5 +196,141 @@
219 <property name="position">1</property>196 <property name="position">1</property>
220 </packing>197 </packing>
221 </child>198 </child>
199 <child>
200 <object class="GtkHBox" id="hbox1">
201 <property name="visible">True</property>
202 <property name="can_focus">False</property>
203 <property name="border_width">12</property>
204 <child>
205 <object class="GtkAlignment" id="alignment3">
206 <property name="visible">True</property>
207 <property name="can_focus">False</property>
208 <property name="yalign">1</property>
209 <property name="yscale">0</property>
210 <child>
211 <object class="GtkHButtonBox" id="hbuttonbox3">
212 <property name="visible">True</property>
213 <property name="can_focus">False</property>
214 <property name="spacing">5</property>
215 <property name="layout_style">start</property>
216 <child>
217 <object class="GtkLinkButton" id="linkbutton2">
218 <property name="label" translatable="yes">Official Support</property>
219 <property name="visible">True</property>
220 <property name="can_focus">True</property>
221 <property name="receives_default">True</property>
222 <property name="use_action_appearance">False</property>
223 <property name="relief">half</property>
224 <property name="uri">https://one.ubuntu.com/support/</property>
225 </object>
226 <packing>
227 <property name="expand">False</property>
228 <property name="fill">False</property>
229 <property name="position">0</property>
230 </packing>
231 </child>
232 <child>
233 <object class="GtkLinkButton" id="linkbutton4">
234 <property name="label" translatable="yes">Community Support</property>
235 <property name="visible">True</property>
236 <property name="can_focus">True</property>
237 <property name="receives_default">True</property>
238 <property name="use_action_appearance">False</property>
239 <property name="relief">half</property>
240 <property name="uri">http://askubuntu.com/questions/tagged/ubuntu-one</property>
241 </object>
242 <packing>
243 <property name="expand">False</property>
244 <property name="fill">False</property>
245 <property name="position">1</property>
246 </packing>
247 </child>
248 </object>
249 </child>
250 </object>
251 <packing>
252 <property name="expand">False</property>
253 <property name="fill">True</property>
254 <property name="position">0</property>
255 </packing>
256 </child>
257 <child>
258 <object class="GtkHBox" id="hbox3">
259 <property name="visible">True</property>
260 <property name="can_focus">False</property>
261 <child>
262 <object class="GtkLabel" id="label4">
263 <property name="visible">True</property>
264 <property name="can_focus">False</property>
265 <property name="label" translatable="yes">Talk to us on:</property>
266 </object>
267 <packing>
268 <property name="expand">True</property>
269 <property name="fill">True</property>
270 <property name="position">0</property>
271 </packing>
272 </child>
273 <child>
274 <object class="GtkLinkButton" id="linkbutton5">
275 <property name="visible">True</property>
276 <property name="can_focus">True</property>
277 <property name="receives_default">True</property>
278 <property name="use_action_appearance">False</property>
279 <property name="relief">none</property>
280 <property name="uri">http://twitter.com/ubuntuone</property>
281 <child>
282 <object class="GtkImage" id="twitter">
283 <property name="visible">True</property>
284 <property name="can_focus">False</property>
285 <property name="tooltip_text" translatable="yes">http://twitter.com/ubuntuone</property>
286 <property name="pixbuf">twitter.png</property>
287 </object>
288 </child>
289 </object>
290 <packing>
291 <property name="expand">False</property>
292 <property name="fill">False</property>
293 <property name="position">1</property>
294 </packing>
295 </child>
296 <child>
297 <object class="GtkLinkButton" id="linkbutton6">
298 <property name="visible">True</property>
299 <property name="can_focus">True</property>
300 <property name="receives_default">True</property>
301 <property name="use_action_appearance">False</property>
302 <property name="relief">none</property>
303 <property name="uri">http://www.facebook.com/ubuntuone</property>
304 <child>
305 <object class="GtkImage" id="facebook">
306 <property name="visible">True</property>
307 <property name="can_focus">False</property>
308 <property name="tooltip_text" translatable="yes">http://www.facebook.com/ubuntuone</property>
309 <property name="pixbuf">facebook.png</property>
310 </object>
311 </child>
312 </object>
313 <packing>
314 <property name="expand">True</property>
315 <property name="fill">True</property>
316 <property name="position">2</property>
317 </packing>
318 </child>
319 </object>
320 <packing>
321 <property name="expand">False</property>
322 <property name="fill">True</property>
323 <property name="pack_type">end</property>
324 <property name="position">1</property>
325 </packing>
326 </child>
327 </object>
328 <packing>
329 <property name="expand">False</property>
330 <property name="fill">True</property>
331 <property name="pack_type">end</property>
332 <property name="position">1</property>
333 </packing>
334 </child>
222 </object>335 </object>
223</interface>336</interface>
224337
=== added file 'data/music-store.png'
225Binary files data/music-store.png 1970-01-01 00:00:00 +0000 and data/music-store.png 2011-03-10 03:11:54 +0000 differ338Binary files data/music-store.png 1970-01-01 00:00:00 +0000 and data/music-store.png 2011-03-10 03:11:54 +0000 differ
=== added file 'data/music-stream.png'
226Binary files data/music-stream.png 1970-01-01 00:00:00 +0000 and data/music-stream.png 2011-03-10 03:11:54 +0000 differ339Binary files data/music-stream.png 1970-01-01 00:00:00 +0000 and data/music-stream.png 2011-03-10 03:11:54 +0000 differ
=== removed file 'data/music.png'
227Binary files data/music.png 2011-02-12 03:07:22 +0000 and data/music.png 1970-01-01 00:00:00 +0000 differ340Binary files data/music.png 2011-02-12 03:07:22 +0000 and data/music.png 1970-01-01 00:00:00 +0000 differ
=== modified file 'data/notes.png'
228Binary files data/notes.png 2011-02-12 03:07:22 +0000 and data/notes.png 2011-03-10 03:11:54 +0000 differ341Binary files data/notes.png 2011-02-12 03:07:22 +0000 and data/notes.png 2011-03-10 03:11:54 +0000 differ
=== modified file 'data/overview.png'
229Binary files data/overview.png 2010-12-06 12:27:11 +0000 and data/overview.png 2011-03-10 03:11:54 +0000 differ342Binary files data/overview.png 2010-12-06 12:27:11 +0000 and data/overview.png 2011-03-10 03:11:54 +0000 differ
=== modified file 'data/overview.ui'
--- data/overview.ui 2011-02-12 03:07:22 +0000
+++ data/overview.ui 2011-03-10 03:11:54 +0000
@@ -6,7 +6,7 @@
6 <property name="visible">True</property>6 <property name="visible">True</property>
7 <property name="can_focus">False</property>7 <property name="can_focus">False</property>
8 <child>8 <child>
9 <object class="GtkEventBox" id="header">9 <object class="GtkEventBox" id="banner">
10 <property name="visible">True</property>10 <property name="visible">True</property>
11 <property name="can_focus">False</property>11 <property name="can_focus">False</property>
12 <child>12 <child>
@@ -35,247 +35,316 @@
35 <property name="can_focus">False</property>35 <property name="can_focus">False</property>
36 <property name="shadow_type">none</property>36 <property name="shadow_type">none</property>
37 <child>37 <child>
38 <object class="GtkHBox" id="hbox1">38 <object class="GtkVBox" id="vbox1">
39 <property name="visible">True</property>39 <property name="visible">True</property>
40 <property name="can_focus">False</property>40 <property name="can_focus">False</property>
41 <property name="border_width">20</property>41 <child>
42 <property name="spacing">5</property>42 <object class="GtkLabel" id="label7">
43 <child>43 <property name="visible">True</property>
44 <object class="GtkTable" id="table1">44 <property name="can_focus">False</property>
45 <property name="visible">True</property>45 <property name="label" translatable="yes">&lt;span font_size="xx-large" foreground="#4d4d4d"&gt;The Power of Your Personal Cloud&lt;/span&gt;</property>
46 <property name="can_focus">False</property>46 <property name="use_markup">True</property>
47 <property name="n_rows">4</property>47 </object>
48 <property name="n_columns">2</property>48 <packing>
49 <property name="column_spacing">10</property>49 <property name="expand">False</property>
50 <property name="row_spacing">10</property>50 <property name="fill">True</property>
51 <child>51 <property name="padding">12</property>
52 <object class="GtkImage" id="image1">52 <property name="position">0</property>
53 <property name="visible">True</property>53 </packing>
54 <property name="can_focus">False</property>54 </child>
55 <property name="pixbuf">files.png</property>55 <child>
56 </object>56 <object class="GtkHBox" id="hbox1">
57 <packing>57 <property name="visible">True</property>
58 <property name="x_options">GTK_FILL</property>58 <property name="can_focus">False</property>
59 <property name="y_options">GTK_FILL</property>59 <property name="border_width">20</property>
60 </packing>60 <property name="spacing">5</property>
61 </child>61 <child>
62 <child>62 <object class="GtkTable" id="table1">
63 <object class="GtkImage" id="image2">63 <property name="visible">True</property>
64 <property name="visible">True</property>64 <property name="can_focus">False</property>
65 <property name="can_focus">False</property>65 <property name="n_rows">4</property>
66 <property name="pixbuf">contacts.png</property>66 <property name="n_columns">2</property>
67 </object>67 <property name="column_spacing">10</property>
68 <packing>68 <child>
69 <property name="top_attach">1</property>69 <object class="GtkImage" id="image1">
70 <property name="bottom_attach">2</property>70 <property name="visible">True</property>
71 <property name="x_options">GTK_FILL</property>71 <property name="can_focus">False</property>
72 <property name="y_options">GTK_FILL</property>72 <property name="pixbuf">files.png</property>
73 </packing>73 </object>
74 </child>74 <packing>
75 <child>75 <property name="x_options">GTK_FILL</property>
76 <object class="GtkImage" id="image3">76 <property name="y_options">GTK_FILL</property>
77 <property name="visible">True</property>77 </packing>
78 <property name="can_focus">False</property>78 </child>
79 <property name="pixbuf">music.png</property>79 <child>
80 </object>80 <object class="GtkImage" id="image2">
81 <packing>81 <property name="visible">True</property>
82 <property name="top_attach">2</property>82 <property name="can_focus">False</property>
83 <property name="bottom_attach">3</property>83 <property name="pixbuf">music-stream.png</property>
84 <property name="x_options">GTK_FILL</property>84 </object>
85 <property name="y_options">GTK_FILL</property>85 <packing>
86 </packing>86 <property name="top_attach">1</property>
87 </child>87 <property name="bottom_attach">2</property>
88 <child>88 <property name="x_options">GTK_FILL</property>
89 <object class="GtkImage" id="image4">89 <property name="y_options">GTK_FILL</property>
90 <property name="visible">True</property>90 </packing>
91 <property name="can_focus">False</property>91 </child>
92 <property name="pixbuf">notes.png</property>92 <child>
93 </object>93 <object class="GtkImage" id="image3">
94 <packing>94 <property name="visible">True</property>
95 <property name="top_attach">3</property>95 <property name="can_focus">False</property>
96 <property name="bottom_attach">4</property>96 <property name="pixbuf">contacts.png</property>
97 <property name="x_options">GTK_FILL</property>97 </object>
98 <property name="y_options">GTK_FILL</property>98 <packing>
99 </packing>99 <property name="top_attach">2</property>
100 </child>100 <property name="bottom_attach">3</property>
101 <child>101 <property name="x_options">GTK_FILL</property>
102 <object class="GtkLabel" id="label3">102 <property name="y_options">GTK_FILL</property>
103 <property name="visible">True</property>103 </packing>
104 <property name="can_focus">False</property>104 </child>
105 <property name="xalign">0</property>105 <child>
106 <property name="label" translatable="yes">Files Anywhere106 <object class="GtkImage" id="image4">
107&lt;span foreground="#909090"&gt;Backup and access your files from Windows, Ubuntu, or Mobile&lt;/span&gt;</property>107 <property name="visible">True</property>
108 <property name="use_markup">True</property>108 <property name="can_focus">False</property>
109 <property name="wrap">True</property>109 <property name="pixbuf">notes.png</property>
110 </object>110 </object>
111 <packing>111 <packing>
112 <property name="left_attach">1</property>112 <property name="top_attach">3</property>
113 <property name="right_attach">2</property>113 <property name="bottom_attach">4</property>
114 </packing>114 <property name="x_options">GTK_FILL</property>
115 </child>115 <property name="y_options">GTK_FILL</property>
116 <child>116 </packing>
117 <object class="GtkLabel" id="label4">117 </child>
118 <property name="visible">True</property>118 <child>
119 <property name="can_focus">False</property>119 <object class="GtkLabel" id="label3">
120 <property name="xalign">0</property>120 <property name="visible">True</property>
121 <property name="label" translatable="yes">Keep connected121 <property name="can_focus">False</property>
122&lt;span foreground="#909090"&gt;Unify your contacts accress Desktop, Mobile and Web&lt;/span&gt;</property>122 <property name="xalign">0</property>
123 <property name="use_markup">True</property>123 <property name="label" translatable="yes">Files Anywhere
124 <property name="wrap">True</property>124&lt;span foreground="#909090"&gt;Backup and access your files from Ubuntu, Windows or Mobile&lt;/span&gt;</property>
125 </object>125 <property name="use_markup">True</property>
126 <packing>126 <property name="wrap">True</property>
127 <property name="left_attach">1</property>127 </object>
128 <property name="right_attach">2</property>128 <packing>
129 <property name="top_attach">1</property>129 <property name="left_attach">1</property>
130 <property name="bottom_attach">2</property>130 <property name="right_attach">2</property>
131 </packing>131 </packing>
132 </child>132 </child>
133 <child>133 <child>
134 <object class="GtkLabel" id="label5">134 <object class="GtkLabel" id="label4">
135 <property name="visible">True</property>135 <property name="visible">True</property>
136 <property name="can_focus">False</property>136 <property name="can_focus">False</property>
137 <property name="xalign">0</property>137 <property name="xalign">0</property>
138 <property name="label" translatable="yes">Rock Out138 <property name="label" translatable="yes">Keep Connected
139&lt;span foreground="#909090"&gt;Your library at your fingertips with Android, iPhone, and AirPlay139&lt;span foreground="#909090"&gt;Unify your contacts across Desktop, Mobile and Web&lt;/span&gt;</property>
140Plus the Ubuntu One Music store to grow your collection&lt;/span&gt;</property>140 <property name="use_markup">True</property>
141 <property name="use_markup">True</property>141 <property name="wrap">True</property>
142 <property name="wrap">True</property>142 </object>
143 </object>143 <packing>
144 <packing>144 <property name="left_attach">1</property>
145 <property name="left_attach">1</property>145 <property name="right_attach">2</property>
146 <property name="right_attach">2</property>146 <property name="top_attach">2</property>
147 <property name="top_attach">2</property>147 <property name="bottom_attach">3</property>
148 <property name="bottom_attach">3</property>148 </packing>
149 </packing>149 </child>
150 </child>150 <child>
151 <child>151 <object class="GtkLabel" id="label5">
152 <object class="GtkLabel" id="label6">152 <property name="visible">True</property>
153 <property name="visible">True</property>153 <property name="can_focus">False</property>
154 <property name="can_focus">False</property>154 <property name="xalign">0</property>
155 <property name="xalign">0</property>155 <property name="label" translatable="yes">Rock Out
156 <property name="label" translatable="yes">Stay Productive156&lt;span foreground="#909090"&gt;Your entire collection follows you around with music streaming to Android and iPhone&lt;/span&gt;</property>
157 <property name="use_markup">True</property>
158 <property name="wrap">True</property>
159 </object>
160 <packing>
161 <property name="left_attach">1</property>
162 <property name="right_attach">2</property>
163 <property name="top_attach">1</property>
164 <property name="bottom_attach">2</property>
165 </packing>
166 </child>
167 <child>
168 <object class="GtkLabel" id="label6">
169 <property name="visible">True</property>
170 <property name="can_focus">False</property>
171 <property name="xalign">0</property>
172 <property name="label" translatable="yes">Stay Productive
157&lt;span foreground="#909090"&gt;Keep your Firefox bookmarks and Tomboy notes synced&lt;/span&gt;</property>173&lt;span foreground="#909090"&gt;Keep your Firefox bookmarks and Tomboy notes synced&lt;/span&gt;</property>
158 <property name="use_markup">True</property>174 <property name="use_markup">True</property>
159 <property name="wrap">True</property>175 <property name="wrap">True</property>
176 </object>
177 <packing>
178 <property name="left_attach">1</property>
179 <property name="right_attach">2</property>
180 <property name="top_attach">3</property>
181 <property name="bottom_attach">4</property>
182 </packing>
183 </child>
160 </object>184 </object>
161 <packing>185 <packing>
162 <property name="left_attach">1</property>186 <property name="expand">True</property>
163 <property name="right_attach">2</property>187 <property name="fill">True</property>
164 <property name="top_attach">3</property>188 <property name="position">0</property>
165 <property name="bottom_attach">4</property>
166 </packing>189 </packing>
167 </child>190 </child>
168 </object>
169 <packing>
170 <property name="expand">True</property>
171 <property name="fill">True</property>
172 <property name="position">0</property>
173 </packing>
174 </child>
175 <child>
176 <object class="GtkVBox" id="vbox1">
177 <property name="visible">True</property>
178 <property name="can_focus">False</property>
179 <child>191 <child>
180 <object class="GtkLabel" id="warning_label">192 <object class="GtkVBox" id="vbox2">
181 <property name="visible">True</property>193 <property name="visible">True</property>
182 <property name="can_focus">False</property>194 <property name="can_focus">False</property>
183 <property name="label">A warning label that can be long. Possible really long, let's see how it behaves.</property>195 <child>
184 <property name="wrap">True</property>196 <object class="GtkLabel" id="warning_label">
197 <property name="visible">True</property>
198 <property name="can_focus">False</property>
199 <property name="label">A warning label that can be long. Possible really long, let's see how it behaves.</property>
200 <property name="wrap">True</property>
201 </object>
202 <packing>
203 <property name="expand">False</property>
204 <property name="fill">True</property>
205 <property name="position">0</property>
206 </packing>
207 </child>
208 <child>
209 <object class="GtkAlignment" id="alignment2">
210 <property name="visible">True</property>
211 <property name="can_focus">False</property>
212 <property name="xscale">0</property>
213 <property name="yscale">0</property>
214 <child>
215 <object class="GtkVBox" id="vbox3">
216 <property name="visible">True</property>
217 <property name="can_focus">False</property>
218 <property name="spacing">10</property>
219 <child>
220 <object class="GtkButton" id="learn_more_button">
221 <property name="visible">True</property>
222 <property name="can_focus">True</property>
223 <property name="receives_default">True</property>
224 <property name="use_action_appearance">False</property>
225 <signal name="clicked" handler="on_learn_more_button_clicked" swapped="no"/>
226 <child>
227 <object class="GtkVBox" id="vbox5">
228 <property name="visible">True</property>
229 <property name="can_focus">False</property>
230 <child>
231 <object class="GtkImage" id="image5">
232 <property name="visible">True</property>
233 <property name="can_focus">False</property>
234 <property name="pixel_size">45</property>
235 <property name="icon_name">ubuntuone</property>
236 </object>
237 <packing>
238 <property name="expand">True</property>
239 <property name="fill">True</property>
240 <property name="position">0</property>
241 </packing>
242 </child>
243 <child>
244 <object class="GtkLabel" id="label8">
245 <property name="visible">True</property>
246 <property name="can_focus">False</property>
247 <property name="label" translatable="yes">&lt;span foreground="#909090"&gt;Learn More&lt;/span&gt;</property>
248 <property name="use_markup">True</property>
249 </object>
250 <packing>
251 <property name="expand">True</property>
252 <property name="fill">True</property>
253 <property name="position">1</property>
254 </packing>
255 </child>
256 </object>
257 </child>
258 </object>
259 <packing>
260 <property name="expand">True</property>
261 <property name="fill">True</property>
262 <property name="position">0</property>
263 </packing>
264 </child>
265 <child>
266 <object class="GtkButton" id="join_now_button">
267 <property name="visible">True</property>
268 <property name="can_focus">True</property>
269 <property name="can_default">True</property>
270 <property name="receives_default">True</property>
271 <property name="use_action_appearance">False</property>
272 <signal name="clicked" handler="on_join_now_button_clicked" swapped="no"/>
273 <child>
274 <object class="GtkVBox" id="vbox4">
275 <property name="visible">True</property>
276 <property name="can_focus">False</property>
277 <property name="spacing">5</property>
278 <child>
279 <object class="GtkLabel" id="label1">
280 <property name="visible">True</property>
281 <property name="can_focus">False</property>
282 <property name="label" translatable="yes">&lt;span font_size="xx-large" foreground="#4d4d4d"&gt;Join now&lt;/span&gt;</property>
283 <property name="use_markup">True</property>
284 </object>
285 <packing>
286 <property name="expand">True</property>
287 <property name="fill">True</property>
288 <property name="position">0</property>
289 </packing>
290 </child>
291 <child>
292 <object class="GtkLabel" id="label2">
293 <property name="visible">True</property>
294 <property name="can_focus">False</property>
295 <property name="label" translatable="yes">&lt;span foreground="#909090"&gt;2GB of free storage&lt;/span&gt;</property>
296 <property name="use_markup">True</property>
297 </object>
298 <packing>
299 <property name="expand">True</property>
300 <property name="fill">True</property>
301 <property name="position">1</property>
302 </packing>
303 </child>
304 </object>
305 </child>
306 </object>
307 <packing>
308 <property name="expand">False</property>
309 <property name="fill">True</property>
310 <property name="position">1</property>
311 </packing>
312 </child>
313 <child>
314 <object class="GtkLinkButton" id="connect_button">
315 <property name="label" translatable="yes">I already have an account!</property>
316 <property name="visible">True</property>
317 <property name="can_focus">True</property>
318 <property name="receives_default">True</property>
319 <property name="use_action_appearance">False</property>
320 <property name="relief">none</property>
321 <signal name="clicked" handler="on_connect_button_clicked" swapped="no"/>
322 </object>
323 <packing>
324 <property name="expand">False</property>
325 <property name="fill">False</property>
326 <property name="position">2</property>
327 </packing>
328 </child>
329 </object>
330 </child>
331 </object>
332 <packing>
333 <property name="expand">True</property>
334 <property name="fill">True</property>
335 <property name="position">1</property>
336 </packing>
337 </child>
185 </object>338 </object>
186 <packing>339 <packing>
187 <property name="expand">False</property>340 <property name="expand">False</property>
188 <property name="fill">True</property>341 <property name="fill">True</property>
189 <property name="position">0</property>
190 </packing>
191 </child>
192 <child>
193 <object class="GtkAlignment" id="alignment2">
194 <property name="visible">True</property>
195 <property name="can_focus">False</property>
196 <property name="xscale">0</property>
197 <property name="yscale">0</property>
198 <child>
199 <object class="GtkVBox" id="vbox2">
200 <property name="visible">True</property>
201 <property name="can_focus">False</property>
202 <property name="spacing">10</property>
203 <child>
204 <object class="GtkButton" id="join_now_button">
205 <property name="visible">True</property>
206 <property name="can_focus">True</property>
207 <property name="can_default">True</property>
208 <property name="receives_default">True</property>
209 <property name="use_action_appearance">False</property>
210 <signal name="clicked" handler="on_join_now_button_clicked" swapped="no"/>
211 <child>
212 <object class="GtkVBox" id="vbox3">
213 <property name="visible">True</property>
214 <property name="can_focus">False</property>
215 <property name="spacing">5</property>
216 <child>
217 <object class="GtkLabel" id="label1">
218 <property name="visible">True</property>
219 <property name="can_focus">False</property>
220 <property name="label" translatable="yes">&lt;span font_size="xx-large"&gt;Join now&lt;/span&gt;</property>
221 <property name="use_markup">True</property>
222 </object>
223 <packing>
224 <property name="expand">True</property>
225 <property name="fill">True</property>
226 <property name="position">0</property>
227 </packing>
228 </child>
229 <child>
230 <object class="GtkLabel" id="label2">
231 <property name="visible">True</property>
232 <property name="can_focus">False</property>
233 <property name="label" translatable="yes">&lt;span foreground="#909090"&gt;2GB of free storage&lt;/span&gt;</property>
234 <property name="use_markup">True</property>
235 </object>
236 <packing>
237 <property name="expand">True</property>
238 <property name="fill">True</property>
239 <property name="position">1</property>
240 </packing>
241 </child>
242 </object>
243 </child>
244 </object>
245 <packing>
246 <property name="expand">False</property>
247 <property name="fill">True</property>
248 <property name="position">0</property>
249 </packing>
250 </child>
251 <child>
252 <object class="GtkLinkButton" id="connect_button">
253 <property name="label" translatable="yes">I already have an account!</property>
254 <property name="visible">True</property>
255 <property name="can_focus">True</property>
256 <property name="receives_default">True</property>
257 <property name="use_action_appearance">False</property>
258 <property name="relief">none</property>
259 <signal name="clicked" handler="on_connect_button_clicked" swapped="no"/>
260 </object>
261 <packing>
262 <property name="expand">False</property>
263 <property name="fill">False</property>
264 <property name="position">1</property>
265 </packing>
266 </child>
267 </object>
268 </child>
269 </object>
270 <packing>
271 <property name="expand">True</property>
272 <property name="fill">True</property>
273 <property name="position">1</property>342 <property name="position">1</property>
274 </packing>343 </packing>
275 </child>344 </child>
276 </object>345 </object>
277 <packing>346 <packing>
278 <property name="expand">False</property>347 <property name="expand">True</property>
279 <property name="fill">True</property>348 <property name="fill">True</property>
280 <property name="position">1</property>349 <property name="position">1</property>
281 </packing>350 </packing>
282351
=== added file 'data/services-bookmarks.png'
283Binary files data/services-bookmarks.png 1970-01-01 00:00:00 +0000 and data/services-bookmarks.png 2011-03-10 03:11:54 +0000 differ352Binary files data/services-bookmarks.png 1970-01-01 00:00:00 +0000 and data/services-bookmarks.png 2011-03-10 03:11:54 +0000 differ
=== added file 'data/services-contacts.png'
284Binary files data/services-contacts.png 1970-01-01 00:00:00 +0000 and data/services-contacts.png 2011-03-10 03:11:54 +0000 differ353Binary files data/services-contacts.png 1970-01-01 00:00:00 +0000 and data/services-contacts.png 2011-03-10 03:11:54 +0000 differ
=== added file 'data/services-files-example.png'
285Binary files data/services-files-example.png 1970-01-01 00:00:00 +0000 and data/services-files-example.png 2011-03-10 03:11:54 +0000 differ354Binary files data/services-files-example.png 1970-01-01 00:00:00 +0000 and data/services-files-example.png 2011-03-10 03:11:54 +0000 differ
=== added file 'data/services-files.png'
286Binary files data/services-files.png 1970-01-01 00:00:00 +0000 and data/services-files.png 2011-03-10 03:11:54 +0000 differ355Binary files data/services-files.png 1970-01-01 00:00:00 +0000 and data/services-files.png 2011-03-10 03:11:54 +0000 differ
=== modified file 'data/services.ui'
--- data/services.ui 2011-01-25 19:08:59 +0000
+++ data/services.ui 2011-03-10 03:11:54 +0000
@@ -4,8 +4,7 @@
4 <!-- interface-naming-policy project-wide -->4 <!-- interface-naming-policy project-wide -->
5 <object class="GtkVBox" id="itself">5 <object class="GtkVBox" id="itself">
6 <property name="visible">True</property>6 <property name="visible">True</property>
7 <property name="border_width">10</property>7 <property name="can_focus">False</property>
8 <property name="spacing">10</property>
9 <child>8 <child>
10 <object class="GtkScrolledWindow" id="scrolledwindow1">9 <object class="GtkScrolledWindow" id="scrolledwindow1">
11 <property name="visible">True</property>10 <property name="visible">True</property>
@@ -15,44 +14,338 @@
15 <child>14 <child>
16 <object class="GtkViewport" id="viewport1">15 <object class="GtkViewport" id="viewport1">
17 <property name="visible">True</property>16 <property name="visible">True</property>
17 <property name="can_focus">False</property>
18 <property name="resize_mode">queue</property>18 <property name="resize_mode">queue</property>
19 <property name="shadow_type">none</property>19 <property name="shadow_type">none</property>
20 <child>20 <child>
21 <object class="GtkVBox" id="vbox1">21 <object class="GtkVBox" id="vbox1">
22 <property name="visible">True</property>22 <property name="visible">True</property>
23 <property name="can_focus">False</property>
24 <property name="spacing">5</property>
23 <child>25 <child>
24 <object class="GtkAlignment" id="alignment1">26 <object class="GtkAspectFrame" id="files">
25 <property name="visible">True</property>27 <property name="visible">True</property>
28 <property name="can_focus">False</property>
29 <property name="label_xalign">0</property>
30 <property name="shadow_type">out</property>
26 <child>31 <child>
27 <object class="GtkVBox" id="replications">32 <object class="GtkHBox" id="hbox2">
28 <property name="visible">True</property>33 <property name="visible">True</property>
29 <property name="spacing">5</property>34 <property name="can_focus">False</property>
30 <child>35 <property name="border_width">5</property>
31 <placeholder/>36 <child>
37 <object class="GtkTable" id="table1">
38 <property name="visible">True</property>
39 <property name="can_focus">False</property>
40 <property name="n_rows">3</property>
41 <property name="n_columns">3</property>
42 <property name="row_spacing">5</property>
43 <child>
44 <object class="GtkCheckButton" id="file_sync_check">
45 <property name="visible">True</property>
46 <property name="can_focus">True</property>
47 <property name="receives_default">False</property>
48 <property name="use_action_appearance">False</property>
49 <property name="draw_indicator">True</property>
50 </object>
51 </child>
52 <child>
53 <object class="GtkImage" id="image2">
54 <property name="visible">True</property>
55 <property name="can_focus">False</property>
56 <property name="xpad">5</property>
57 <property name="pixbuf">services-files.png</property>
58 </object>
59 <packing>
60 <property name="left_attach">1</property>
61 <property name="right_attach">2</property>
62 </packing>
63 </child>
64 <child>
65 <object class="GtkLabel" id="label1">
66 <property name="visible">True</property>
67 <property name="can_focus">False</property>
68 <property name="xalign">0</property>
69 <property name="label" translatable="yes">Enable File Sync</property>
70 </object>
71 <packing>
72 <property name="left_attach">2</property>
73 <property name="right_attach">3</property>
74 </packing>
75 </child>
76 <child>
77 <object class="GtkLabel" id="label2">
78 <property name="visible">True</property>
79 <property name="can_focus">False</property>
80 <property name="xalign">0</property>
81 <property name="yalign">0</property>
82 <property name="label" translatable="yes">&lt;span font_size="small"&gt;Enable and then choose which folders you want to access from the Web or any device you connected to Ubuntu One
83
84Simply drag and drop any file or folder to your Ubuntu One folder on this computer&lt;/span&gt;</property>
85 <property name="use_markup">True</property>
86 <property name="wrap">True</property>
87 <property name="width_chars">30</property>
88 </object>
89 <packing>
90 <property name="left_attach">2</property>
91 <property name="right_attach">3</property>
92 <property name="top_attach">1</property>
93 <property name="bottom_attach">2</property>
94 </packing>
95 </child>
96 <child>
97 <object class="GtkHButtonBox" id="hbuttonbox1">
98 <property name="visible">True</property>
99 <property name="can_focus">False</property>
100 <child>
101 <object class="GtkButton" id="file_sync_button">
102 <property name="label" translatable="yes">_Show me my Ubuntu One folder</property>
103 <property name="visible">True</property>
104 <property name="can_focus">True</property>
105 <property name="receives_default">True</property>
106 <property name="use_action_appearance">False</property>
107 <property name="use_underline">True</property>
108 <signal name="clicked" handler="on_file_sync_button_clicked" swapped="no"/>
109 </object>
110 <packing>
111 <property name="expand">False</property>
112 <property name="fill">False</property>
113 <property name="position">0</property>
114 </packing>
115 </child>
116 </object>
117 <packing>
118 <property name="left_attach">2</property>
119 <property name="right_attach">3</property>
120 <property name="top_attach">2</property>
121 <property name="bottom_attach">3</property>
122 </packing>
123 </child>
124 <child>
125 <placeholder/>
126 </child>
127 <child>
128 <placeholder/>
129 </child>
130 <child>
131 <placeholder/>
132 </child>
133 <child>
134 <placeholder/>
135 </child>
136 </object>
137 <packing>
138 <property name="expand">False</property>
139 <property name="fill">True</property>
140 <property name="position">0</property>
141 </packing>
142 </child>
143 <child>
144 <object class="GtkImage" id="image1">
145 <property name="visible">True</property>
146 <property name="can_focus">False</property>
147 <property name="xpad">5</property>
148 <property name="ypad">5</property>
149 <property name="pixbuf">services-files-example.png</property>
150 </object>
151 <packing>
152 <property name="expand">False</property>
153 <property name="fill">True</property>
154 <property name="pack_type">end</property>
155 <property name="position">1</property>
156 </packing>
32 </child>157 </child>
33 </object>158 </object>
34 </child>159 </child>
35 </object>160 </object>
36 <packing>161 <packing>
37 <property name="expand">False</property>162 <property name="expand">True</property>
163 <property name="fill">True</property>
38 <property name="position">0</property>164 <property name="position">0</property>
39 </packing>165 </packing>
40 </child>166 </child>
41 <child>167 <child>
42 <object class="GtkAlignment" id="alignment2">168 <object class="GtkAspectFrame" id="replications">
43 <property name="visible">True</property>169 <property name="visible">True</property>
170 <property name="can_focus">False</property>
171 <property name="label_xalign">0</property>
172 <property name="shadow_type">out</property>
44 <child>173 <child>
45 <object class="GtkVBox" id="files">174 <object class="GtkHBox" id="hbox3">
46 <property name="visible">True</property>175 <property name="visible">True</property>
47 <property name="spacing">5</property>176 <property name="can_focus">False</property>
48 <child>177 <property name="border_width">5</property>
49 <placeholder/>178 <child>
179 <object class="GtkVBox" id="contacts">
180 <property name="visible">True</property>
181 <property name="can_focus">False</property>
182 <child>
183 <object class="GtkTable" id="contacts_sync">
184 <property name="visible">True</property>
185 <property name="can_focus">False</property>
186 <property name="n_rows">2</property>
187 <property name="n_columns">3</property>
188 <property name="row_spacing">5</property>
189 <child>
190 <object class="GtkCheckButton" id="contacts_check">
191 <property name="visible">True</property>
192 <property name="can_focus">True</property>
193 <property name="receives_default">False</property>
194 <property name="use_action_appearance">False</property>
195 <property name="draw_indicator">True</property>
196 </object>
197 </child>
198 <child>
199 <object class="GtkImage" id="image3">
200 <property name="visible">True</property>
201 <property name="can_focus">False</property>
202 <property name="xpad">5</property>
203 <property name="pixbuf">services-contacts.png</property>
204 </object>
205 <packing>
206 <property name="left_attach">1</property>
207 <property name="right_attach">2</property>
208 </packing>
209 </child>
210 <child>
211 <object class="GtkLabel" id="label4">
212 <property name="visible">True</property>
213 <property name="can_focus">False</property>
214 <property name="xalign">0</property>
215 <property name="label" translatable="yes">Enable Contacts Sync</property>
216 </object>
217 <packing>
218 <property name="left_attach">2</property>
219 <property name="right_attach">3</property>
220 </packing>
221 </child>
222 <child>
223 <object class="GtkLabel" id="label5">
224 <property name="visible">True</property>
225 <property name="can_focus">True</property>
226 <property name="xalign">0</property>
227 <property name="yalign">0</property>
228 <property name="label" translatable="yes">&lt;span font_size="small"&gt;Once enabled, visit the &lt;a href="https://one.ubuntu.com"&gt;Ubuntu One website&lt;/a&gt; to manage your contacts, including Gmail and Facebook import&lt;/span&gt;</property>
229 <property name="use_markup">True</property>
230 <property name="wrap">True</property>
231 <property name="width_chars">30</property>
232 </object>
233 <packing>
234 <property name="left_attach">2</property>
235 <property name="right_attach">3</property>
236 <property name="top_attach">1</property>
237 <property name="bottom_attach">2</property>
238 </packing>
239 </child>
240 <child>
241 <placeholder/>
242 </child>
243 <child>
244 <placeholder/>
245 </child>
246 </object>
247 <packing>
248 <property name="expand">False</property>
249 <property name="fill">True</property>
250 <property name="position">0</property>
251 </packing>
252 </child>
253 </object>
254 <packing>
255 <property name="expand">False</property>
256 <property name="fill">True</property>
257 <property name="position">0</property>
258 </packing>
259 </child>
260 <child>
261 <object class="GtkVBox" id="bookmarks">
262 <property name="visible">True</property>
263 <property name="can_focus">False</property>
264 <child>
265 <object class="GtkTable" id="bookmarks_sync">
266 <property name="visible">True</property>
267 <property name="can_focus">False</property>
268 <property name="n_rows">2</property>
269 <property name="n_columns">3</property>
270 <property name="row_spacing">5</property>
271 <child>
272 <object class="GtkCheckButton" id="bookmarks_check">
273 <property name="visible">True</property>
274 <property name="can_focus">True</property>
275 <property name="receives_default">False</property>
276 <property name="use_action_appearance">False</property>
277 <property name="draw_indicator">True</property>
278 </object>
279 </child>
280 <child>
281 <object class="GtkImage" id="image4">
282 <property name="visible">True</property>
283 <property name="can_focus">False</property>
284 <property name="xpad">5</property>
285 <property name="pixbuf">services-bookmarks.png</property>
286 </object>
287 <packing>
288 <property name="left_attach">1</property>
289 <property name="right_attach">2</property>
290 </packing>
291 </child>
292 <child>
293 <object class="GtkLabel" id="label6">
294 <property name="visible">True</property>
295 <property name="can_focus">False</property>
296 <property name="xalign">0</property>
297 <property name="label" translatable="yes">Enable Bookmarks Sync</property>
298 </object>
299 <packing>
300 <property name="left_attach">2</property>
301 <property name="right_attach">3</property>
302 </packing>
303 </child>
304 <child>
305 <object class="GtkLabel" id="label7">
306 <property name="visible">True</property>
307 <property name="can_focus">False</property>
308 <property name="xalign">0</property>
309 <property name="yalign">0</property>
310 <property name="label" translatable="yes">&lt;span font_size="small"&gt;Bookmarks sync works with Firefox. Once enabled, you will need to install a plugin&lt;/span&gt;</property>
311 <property name="use_markup">True</property>
312 <property name="wrap">True</property>
313 <property name="width_chars">30</property>
314 </object>
315 <packing>
316 <property name="left_attach">2</property>
317 <property name="right_attach">3</property>
318 <property name="top_attach">1</property>
319 <property name="bottom_attach">2</property>
320 </packing>
321 </child>
322 <child>
323 <placeholder/>
324 </child>
325 <child>
326 <placeholder/>
327 </child>
328 </object>
329 <packing>
330 <property name="expand">False</property>
331 <property name="fill">True</property>
332 <property name="position">0</property>
333 </packing>
334 </child>
335 </object>
336 <packing>
337 <property name="expand">False</property>
338 <property name="fill">True</property>
339 <property name="pack_type">end</property>
340 <property name="position">1</property>
341 </packing>
50 </child>342 </child>
51 </object>343 </object>
52 </child>344 </child>
53 </object>345 </object>
54 <packing>346 <packing>
55 <property name="expand">False</property>347 <property name="expand">True</property>
348 <property name="fill">True</property>
56 <property name="position">1</property>349 <property name="position">1</property>
57 </packing>350 </packing>
58 </child>351 </child>
@@ -62,6 +355,8 @@
62 </child>355 </child>
63 </object>356 </object>
64 <packing>357 <packing>
358 <property name="expand">True</property>
359 <property name="fill">True</property>
65 <property name="position">0</property>360 <property name="position">0</property>
66 </packing>361 </packing>
67 </child>362 </child>
68363
=== modified file 'data/volumes.ui'
--- data/volumes.ui 2011-02-12 03:07:22 +0000
+++ data/volumes.ui 2011-03-10 03:11:54 +0000
@@ -2,26 +2,6 @@
2<interface>2<interface>
3 <requires lib="gtk+" version="2.22"/>3 <requires lib="gtk+" version="2.22"/>
4 <!-- interface-naming-policy project-wide -->4 <!-- interface-naming-policy project-wide -->
5 <object class="GtkTreeStore" id="volumes_store">
6 <columns>
7 <!-- column-name description -->
8 <column type="gchararray"/>
9 <!-- column-name subscribed -->
10 <column type="gboolean"/>
11 <!-- column-name icon-name -->
12 <column type="gchararray"/>
13 <!-- column-name subscribed-visible -->
14 <column type="gboolean"/>
15 <!-- column-name subscribed-sensitive -->
16 <column type="gboolean"/>
17 <!-- column-name icon-size -->
18 <column type="gint"/>
19 <!-- column-name identifier -->
20 <column type="gchararray"/>
21 <!-- column-name path -->
22 <column type="gchararray"/>
23 </columns>
24 </object>
25 <object class="GtkAlignment" id="itself">5 <object class="GtkAlignment" id="itself">
26 <property name="visible">True</property>6 <property name="visible">True</property>
27 <property name="can_focus">False</property>7 <property name="can_focus">False</property>
@@ -94,4 +74,24 @@
94 </object>74 </object>
95 </child>75 </child>
96 </object>76 </object>
77 <object class="GtkTreeStore" id="volumes_store">
78 <columns>
79 <!-- column-name description -->
80 <column type="gchararray"/>
81 <!-- column-name subscribed -->
82 <column type="gboolean"/>
83 <!-- column-name icon-name -->
84 <column type="gchararray"/>
85 <!-- column-name subscribed-visible -->
86 <column type="gboolean"/>
87 <!-- column-name subscribed-sensitive -->
88 <column type="gboolean"/>
89 <!-- column-name icon-size -->
90 <column type="gint"/>
91 <!-- column-name identifier -->
92 <column type="gchararray"/>
93 <!-- column-name path -->
94 <column type="gchararray"/>
95 </columns>
96 </object>
97</interface>97</interface>
9898
=== modified file 'debian/changelog'
--- debian/changelog 2011-02-28 15:38:15 +0000
+++ debian/changelog 2011-03-10 03:11:54 +0000
@@ -1,3 +1,27 @@
1ubuntuone-control-panel (0.9.1-0ubuntu1) natty; urgency=low
2
3 * New upstream release.
4 - Display notice when merging volumes (LP: #674462)
5 - Show visible message when out of space (LP: #701729)
6 - Move 'get support' button (LP: #706661)
7 - Purchased Music folder not clearly shown (LP: #720650)
8 - More UI tweaks (LP: #728663)
9 - Redesign Services tab (LP: #729361)
10 - Better icon for folder owner (LP: #706034)
11 - Center status messages on toolbar (LP: #715715)
12 - Alter bandwidth throttling layout (LP: #715812)
13 - Tooltip for 'Edit' is unhelpful (LP: #715822)
14 - Tooltip for 'Buy more storage' not helpful (LP: #715875)
15 - Improve off-line experience (LP: #720990)
16 - Make link buttons in Account tab regular buttons (LP: #725143)
17 - Typo: 'accress' (LP: #725802)
18 - Show local device first in devices list (LP: #727996)
19 - Misc. improvements to GTK+ UI (LP: #727998)
20 - Service names should use title format (LP: #728027)
21 * Require new version of ubuntuone-client
22
23 -- Rodney Dawes <rodney.dawes@ubuntu.com> Wed, 09 Mar 2011 21:59:45 -0500
24
1ubuntuone-control-panel (0.9.0-0ubuntu1) natty; urgency=low25ubuntuone-control-panel (0.9.0-0ubuntu1) natty; urgency=low
226
3 * New upstream release:27 * New upstream release:
428
=== modified file 'debian/control'
--- debian/control 2011-02-28 15:38:15 +0000
+++ debian/control 2011-03-10 03:11:54 +0000
@@ -17,7 +17,7 @@
17 ${python:Depends},17 ${python:Depends},
18 python,18 python,
19 python-ubuntuone-control-panel (= ${binary:Version}),19 python-ubuntuone-control-panel (= ${binary:Version}),
20 ubuntuone-client (>= 1.5.4),20 ubuntuone-client (>= 1.5.6),
21Recommends: ubuntuone-control-panel-gui21Recommends: ubuntuone-control-panel-gui
22Description: Ubuntu One Control Panel22Description: Ubuntu One Control Panel
23 Desktop application to manage a Ubuntu One account.23 Desktop application to manage a Ubuntu One account.
@@ -37,7 +37,7 @@
37 python-simplejson,37 python-simplejson,
38 python-twisted-core,38 python-twisted-core,
39 python-twisted-web,39 python-twisted-web,
40 python-ubuntuone-client (>= 1.5.4),40 python-ubuntuone-client (>= 1.5.6),
41 ubuntu-sso-client (>= 1.1.11),41 ubuntu-sso-client (>= 1.1.11),
42Description: Ubuntu One Control Panel Python Libraries42Description: Ubuntu One Control Panel Python Libraries
43 Ubuntu One Control Panel provides a Python library to manage an Ubuntu One43 Ubuntu One Control Panel provides a Python library to manage an Ubuntu One
@@ -54,9 +54,9 @@
54 python-defer,54 python-defer,
55 python-gobject,55 python-gobject,
56 python-gtk2,56 python-gtk2,
57 python-ubuntuone-client (>= 1.5.4),57 python-ubuntuone-client (>= 1.5.6),
58 ubuntu-sso-client (>= 1.1.11),58 ubuntu-sso-client (>= 1.1.11),
59 ubuntuone-client (>= 1.5.4),59 ubuntuone-client (>= 1.5.6),
60 ubuntuone-control-panel (= ${binary:Version}),60 ubuntuone-control-panel (= ${binary:Version}),
61Provides: ubuntuone-control-panel-gui61Provides: ubuntuone-control-panel-gui
62Description: Ubuntu One Control Panel62Description: Ubuntu One Control Panel
6363
=== modified file 'pylintrc'
--- pylintrc 2011-01-07 20:07:39 +0000
+++ pylintrc 2011-03-10 03:11:54 +0000
@@ -49,7 +49,7 @@
49# Disable the message(s) with the given id(s) or categories49# Disable the message(s) with the given id(s) or categories
50# W0142: Used * or ** magic50# W0142: Used * or ** magic
51# W0613: Unused argument 'yyy'51# W0613: Unused argument 'yyy'
52disable=R,I,W0142,W061352disable=R,I,W0142,W0613,W0511
5353
5454
55[REPORTS]55[REPORTS]
5656
=== modified file 'setup.py'
--- setup.py 2011-02-28 15:38:15 +0000
+++ setup.py 2011-03-10 03:11:54 +0000
@@ -76,7 +76,7 @@
7676
77DistUtilsExtra.auto.setup(77DistUtilsExtra.auto.setup(
78 name='ubuntuone-control-panel',78 name='ubuntuone-control-panel',
79 version='0.9.0',79 version='0.9.1',
80 license='GPL v3',80 license='GPL v3',
81 author='Natalia Bidart',81 author='Natalia Bidart',
82 author_email='natalia.bidart@canonical.com',82 author_email='natalia.bidart@canonical.com',
8383
=== modified file 'ubuntuone/__init__.py'
--- ubuntuone/__init__.py 2010-12-06 12:27:11 +0000
+++ ubuntuone/__init__.py 2011-03-10 03:11:54 +0000
@@ -17,5 +17,4 @@
17# with this program. If not, see <http://www.gnu.org/licenses/>.17# with this program. If not, see <http://www.gnu.org/licenses/>.
1818
19"""Ubuntuone package."""19"""Ubuntuone package."""
20
21__import__('pkg_resources').declare_namespace(__name__)20__import__('pkg_resources').declare_namespace(__name__)
2221
=== modified file 'ubuntuone/controlpanel/backend.py'
--- ubuntuone/controlpanel/backend.py 2011-02-23 13:57:42 +0000
+++ ubuntuone/controlpanel/backend.py 2011-03-10 03:11:54 +0000
@@ -195,7 +195,6 @@
195 devices = yield self.wc.call_api(DEVICES_API)195 devices = yield self.wc.call_api(DEVICES_API)
196 for d in devices:196 for d in devices:
197 di = {}197 di = {}
198 result.append(di)
199 di["type"] = d["kind"]198 di["type"] = d["kind"]
200 di["name"] = d["description"]199 di["name"] = d["description"]
201 di["configurable"] = ''200 di["configurable"] = ''
@@ -225,6 +224,11 @@
225 # di["available_services"] = ""224 # di["available_services"] = ""
226 # di["enabled_services"] = ""225 # di["enabled_services"] = ""
227226
227 if is_local: # prepend the local device!
228 result.insert(0, di)
229 else:
230 result.append(di)
231
228 returnValue(result)232 returnValue(result)
229233
230 def type_n_id(self, device_id):234 def type_n_id(self, device_id):
231235
=== modified file 'ubuntuone/controlpanel/gtk/gui.py'
--- ubuntuone/controlpanel/gtk/gui.py 2011-02-28 15:38:15 +0000
+++ ubuntuone/controlpanel/gtk/gui.py 2011-03-10 03:11:54 +0000
@@ -210,13 +210,10 @@
210210
211 CREDENTIALS_ERROR = _('There was a problem while retrieving the '211 CREDENTIALS_ERROR = _('There was a problem while retrieving the '
212 'credentials.')212 'credentials.')
213 AUTHORIZATION_DENIED = _('The authentication was cancelled.')
214 NETWORK_OFFLINE = _('An internet connection is required to join or sign '213 NETWORK_OFFLINE = _('An internet connection is required to join or sign '
215 'in to %(app_name)s.')214 'in to %(app_name)s.')
216 NETWORK_UNKNOWN = _('The internet connection state couldn\'t be '
217 'discovered. Maybe NetworkManager is not running?')
218
219 CONNECT = _('Connect to Ubuntu One')215 CONNECT = _('Connect to Ubuntu One')
216 LEARN_MORE_LINK = 'https://one.ubuntu.com/'
220217
221 def __init__(self, main_window):218 def __init__(self, main_window):
222 GreyableBin.__init__(self)219 GreyableBin.__init__(self)
@@ -299,6 +296,10 @@
299 self.set_property('greyed', True)296 self.set_property('greyed', True)
300 self.warning_label.set_text('')297 self.warning_label.set_text('')
301298
299 def on_learn_more_button_clicked(self, *a, **kw):
300 """User wants to learn more."""
301 uri_hook(self.learn_more_button, self.LEARN_MORE_LINK)
302
302 @filter_by_app_name303 @filter_by_app_name
303 @log_call(logger.info, with_args=False)304 @log_call(logger.info, with_args=False)
304 def on_credentials_found(self, app_name, credentials):305 def on_credentials_found(self, app_name, credentials):
@@ -325,23 +326,18 @@
325 def on_authorization_denied(self, app_name):326 def on_authorization_denied(self, app_name):
326 """SSO backend notifies that user refused auth for 'app_name'."""327 """SSO backend notifies that user refused auth for 'app_name'."""
327 self.set_property('greyed', False)328 self.set_property('greyed', False)
328 self._set_warning(self.AUTHORIZATION_DENIED)
329329
330 @log_call(logger.info)330 @log_call(logger.info)
331 def on_network_state_changed(self, state):331 def on_network_state_changed(self, state):
332 """Network state is reported."""332 """Network state is reported."""
333 msg = None333 msg = ''
334 if state is networkstate.OFFLINE:334 if state is networkstate.OFFLINE:
335 msg = self.NETWORK_OFFLINE % {'app_name': U1_APP_NAME}335 msg = self.NETWORK_OFFLINE % {'app_name': U1_APP_NAME}
336 elif state is networkstate.UNKNOWN:
337 msg = self.NETWORK_UNKNOWN
338
339 if msg is not None:
340 self.set_sensitive(False)336 self.set_sensitive(False)
341 self._set_warning(msg)337 self._set_warning(msg)
342 else:338 else:
343 self.set_sensitive(True)339 self.set_sensitive(True)
344 self.warning_label.set_text('')340 self.warning_label.set_text(msg)
345 self.sso_backend.find_credentials(U1_APP_NAME, {},341 self.sso_backend.find_credentials(U1_APP_NAME, {},
346 reply_handler=NO_OP, error_handler=error_handler)342 reply_handler=NO_OP, error_handler=error_handler)
347343
@@ -350,6 +346,8 @@
350 """The dashboard panel. The user can manage the subscription."""346 """The dashboard panel. The user can manage the subscription."""
351347
352 TITLE = _('Welcome to Ubuntu One!')348 TITLE = _('Welcome to Ubuntu One!')
349 VALUE_ERROR = _('The information could not be retrieved. '
350 'Maybe your internet connection is down?')
353351
354 def __init__(self, main_window=None):352 def __init__(self, main_window=None):
355 UbuntuOneBin.__init__(self)353 UbuntuOneBin.__init__(self)
@@ -380,26 +378,32 @@
380 @log_call(logger.error)378 @log_call(logger.error)
381 def on_account_info_error(self, error_dict=None):379 def on_account_info_error(self, error_dict=None):
382 """Backend notifies of an error when fetching account info."""380 """Backend notifies of an error when fetching account info."""
383 self.on_error()381 self.on_error(message=self.VALUE_ERROR)
384 self.is_processing = False382 self.is_processing = False
385383
386384
387class VolumesPanel(UbuntuOneBin, ControlPanelMixin):385class VolumesPanel(UbuntuOneBin, ControlPanelMixin):
388 """The volumes panel."""386 """The volumes panel."""
389387
390 TITLE = _('Select the folders from your personal cloud that you want '388 TITLE = _('Select which folders from your cloud you want to sync with '
391 'synchronized in this device.')389 'this computer')
392 MY_FOLDERS = _('My folders')390 MY_FOLDERS = _('My folders')
393 ALWAYS_SUBSCRIBED = _('Always in sync!')391 ALWAYS_SUBSCRIBED = _('Always in sync!')
394 FREE_SPACE = _('%(free_space)s available storage')392 FREE_SPACE = _('%(free_space)s available storage')
395 NO_VOLUMES = _('No folders to show.')393 NO_VOLUMES = _('No folders to show.')
396 NAME_NOT_SET = _('[unknown user name]')394 NAME_NOT_SET = _('[unknown user name]')
395 CONFIRM_MERGE = _('The contents of your cloud folder will be merged with '
396 'your local folder "%(folder_path)s" when subscribing.\n'
397 'Do you want to subscribe to this cloud folder?')
398 MUSIC_DISPLAY_NAME = _('Purchased Music')
399 MUSIC_REAL_PATH = '~/.ubuntuone/Purchased from Ubuntu One'
397400
398 MAX_COLS = 8401 MAX_COLS = 8
399402
400 CONTACT_ICON_NAME = 'system-users'403 CONTACT_ICON_NAME = 'avatar-default'
401 FOLDER_ICON_NAME = 'folder'404 FOLDER_ICON_NAME = 'folder'
402 SHARE_ICON_NAME = 'folder-remote'405 SHARE_ICON_NAME = 'folder-remote'
406 MUSIC_ICON_NAME = 'audio-x-generic'
403 ROW_HEADER = '<span font_size="large"><b>%s</b></span> ' \407 ROW_HEADER = '<span font_size="large"><b>%s</b></span> ' \
404 '<span foreground="grey">%s</span>'408 '<span foreground="grey">%s</span>'
405 ROOT = '%s - <span foreground="%s" font_size="small">%s</span>'409 ROOT = '%s - <span foreground="%s" font_size="small">%s</span>'
@@ -410,6 +414,12 @@
410 self.add(self.itself)414 self.add(self.itself)
411 self.show_all()415 self.show_all()
412416
417 kw = dict(parent=main_window,
418 flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
419 type=gtk.MESSAGE_WARNING,
420 buttons=gtk.BUTTONS_YES_NO)
421 self.confirm_dialog = gtk.MessageDialog(**kw)
422
413 # name, subscribed, icon name, show toggle, sensitive, icon size,423 # name, subscribed, icon name, show toggle, sensitive, icon size,
414 # id, path424 # id, path
415 self._empty_row = ('', False, '', False, False, gtk.ICON_SIZE_MENU,425 self._empty_row = ('', False, '', False, False, gtk.ICON_SIZE_MENU,
@@ -427,7 +437,14 @@
427 def _process_path(self, path):437 def _process_path(self, path):
428 """Trim 'path' so the '~' is removed."""438 """Trim 'path' so the '~' is removed."""
429 home = os.path.expanduser('~')439 home = os.path.expanduser('~')
430 return path.replace(os.path.join(home, ''), '')440 music_path = os.path.expanduser(self.MUSIC_REAL_PATH)
441
442 if path == music_path:
443 result = self.MUSIC_DISPLAY_NAME
444 else:
445 result = path.replace(os.path.join(home, ''), '')
446
447 return result
431448
432 def on_volumes_info_ready(self, info):449 def on_volumes_info_ready(self, info):
433 """Backend notifies of volumes info."""450 """Backend notifies of volumes info."""
@@ -445,13 +462,10 @@
445462
446 if name:463 if name:
447 name = name + "'s"464 name = name + "'s"
448 icon_name = self.SHARE_ICON_NAME
449
450 # we already added user folders, let's add an empty row465 # we already added user folders, let's add an empty row
451 treeiter = self.volumes_store.append(None, self._empty_row)466 treeiter = self.volumes_store.append(None, self._empty_row)
452 else:467 else:
453 name = self.MY_FOLDERS468 name = self.MY_FOLDERS
454 icon_name = self.FOLDER_ICON_NAME
455469
456 free_bytes_args = {'free_space': self.humanize(int(free_bytes))}470 free_bytes_args = {'free_space': self.humanize(int(free_bytes))}
457 row = (self.ROW_HEADER % (name, self.FREE_SPACE % free_bytes_args),471 row = (self.ROW_HEADER % (name, self.FREE_SPACE % free_bytes_args),
@@ -463,6 +477,7 @@
463 for volume in volumes:477 for volume in volumes:
464 sensitive = True478 sensitive = True
465 name = self._process_path(volume[u'path'])479 name = self._process_path(volume[u'path'])
480 icon_name = self.FOLDER_ICON_NAME
466481
467 is_root = volume[u'type'] == backend.ControlBackend.ROOT_TYPE482 is_root = volume[u'type'] == backend.ControlBackend.ROOT_TYPE
468 is_share = volume[u'type'] == backend.ControlBackend.SHARE_TYPE483 is_share = volume[u'type'] == backend.ControlBackend.SHARE_TYPE
@@ -472,6 +487,9 @@
472 name = self.ROOT % (name, ORANGE, self.ALWAYS_SUBSCRIBED)487 name = self.ROOT % (name, ORANGE, self.ALWAYS_SUBSCRIBED)
473 elif is_share:488 elif is_share:
474 name = volume[u'name']489 name = volume[u'name']
490 icon_name = self.SHARE_ICON_NAME
491 elif name == self.MUSIC_DISPLAY_NAME:
492 icon_name = self.MUSIC_ICON_NAME
475493
476 row = (name, bool(volume[u'subscribed']), icon_name, True,494 row = (name, bool(volume[u'subscribed']), icon_name, True,
477 sensitive, gtk.ICON_SIZE_MENU, volume['volume_id'],495 sensitive, gtk.ICON_SIZE_MENU, volume['volume_id'],
@@ -506,15 +524,24 @@
506 """The user toggled 'widget'."""524 """The user toggled 'widget'."""
507 treeiter = self.volumes_store.get_iter(path)525 treeiter = self.volumes_store.get_iter(path)
508 volume_id = self.volumes_store.get_value(treeiter, 6)526 volume_id = self.volumes_store.get_value(treeiter, 6)
509 subscribed = not self.volumes_store.get_value(treeiter, 1)527 volume_path = self.volumes_store.get_value(treeiter, 7)
510528 subscribed = self.volumes_store.get_value(treeiter, 1)
511 self.volumes_store.set_value(treeiter, 1, subscribed)529
512530 response = gtk.RESPONSE_YES
513 self.backend.change_volume_settings(volume_id,531 if not subscribed and os.path.exists(volume_path):
514 {'subscribed': bool_str(subscribed)},532 self.confirm_dialog.set_markup(self.CONFIRM_MERGE %
515 reply_handler=NO_OP, error_handler=error_handler)533 {'folder_path': volume_path})
516534 response = self.confirm_dialog.run()
517 self.is_processing = True535 self.confirm_dialog.hide()
536
537 if response == gtk.RESPONSE_YES:
538 subscribed = not subscribed
539 self.volumes_store.set_value(treeiter, 1, subscribed)
540 self.backend.change_volume_settings(volume_id,
541 {'subscribed': bool_str(subscribed)},
542 reply_handler=NO_OP, error_handler=error_handler)
543
544 self.is_processing = True
518545
519 def on_volumes_view_row_activated(self, widget, path, *args, **kwargs):546 def on_volumes_view_row_activated(self, widget, path, *args, **kwargs):
520 """The user double clicked on a row."""547 """The user double clicked on a row."""
@@ -607,10 +634,14 @@
607 return inner634 return inner
608635
609 on_show_all_notifications_toggled = _change_device_settings636 on_show_all_notifications_toggled = _change_device_settings
610 on_limit_bandwidth_toggled = _change_device_settings
611 on_max_upload_speed_value_changed = _change_device_settings637 on_max_upload_speed_value_changed = _change_device_settings
612 on_max_download_speed_value_changed = _change_device_settings638 on_max_download_speed_value_changed = _change_device_settings
613639
640 def on_limit_bandwidth_toggled(self, *args, **kwargs):
641 """The limit bandwidth checkbox was toggled."""
642 self.throttling_limits.set_sensitive(self.limit_bandwidth.get_active())
643 self._change_device_settings()
644
614 def on_remove_clicked(self, widget):645 def on_remove_clicked(self, widget):
615 """Remove button was clicked or activated."""646 """Remove button was clicked or activated."""
616 response = gtk.RESPONSE_YES647 response = gtk.RESPONSE_YES
@@ -659,14 +690,16 @@
659690
660 if 'configurable' in kwargs:691 if 'configurable' in kwargs:
661 self.configurable = bool(kwargs['configurable'])692 self.configurable = bool(kwargs['configurable'])
662 self.throttling.set_visible(self.configurable)693 self.config_settings.set_visible(self.configurable)
663694
664 if 'show_all_notifications' in kwargs:695 if 'show_all_notifications' in kwargs:
665 value = bool(kwargs['show_all_notifications'])696 value = bool(kwargs['show_all_notifications'])
666 self.show_all_notifications.set_active(value)697 self.show_all_notifications.set_active(value)
667698
668 if 'limit_bandwidth' in kwargs:699 if 'limit_bandwidth' in kwargs:
669 self.limit_bandwidth.set_active(bool(kwargs['limit_bandwidth']))700 enabled = bool(kwargs['limit_bandwidth'])
701 self.limit_bandwidth.set_active(enabled)
702 self.throttling_limits.set_sensitive(enabled)
670703
671 for speed in ('max_upload_speed', 'max_download_speed'):704 for speed in ('max_upload_speed', 'max_download_speed'):
672 if speed in kwargs:705 if speed in kwargs:
@@ -821,14 +854,12 @@
821 }854 }
822855
823 INSTALL_PACKAGE = _('You need to install the package <i>%(package_name)s'856 INSTALL_PACKAGE = _('You need to install the package <i>%(package_name)s'
824 '</i> in order to enable replication.')857 '</i> in order to enable more sync services.')
825 INSTALLING = _('The package <i>%(package_name)s</i> is being installed, '858 INSTALLING = _('installation of <i>%(package_name)s</i> in progress')
826 'please wait...')859 FAILED_INSTALL = _('<i>%(package_name)s</i> could not be installed')
827 FAILED_INSTALL = _('The installation of <i>%(package_name)s</i> failed.')860 SUCCESS_INSTALL = _('<i>%(package_name)s</i> was successfully installed')
828 SUCCESS_INSTALL = _('The installation of <i>%(package_name)s</i> '
829 'was successful.')
830861
831 def __init__(self, package_name):862 def __init__(self, package_name, message=None):
832 gtk.VBox.__init__(self)863 gtk.VBox.__init__(self)
833 ControlPanelMixin.__init__(self, filename='install.ui')864 ControlPanelMixin.__init__(self, filename='install.ui')
834 self.add(self.itself)865 self.add(self.itself)
@@ -839,10 +870,23 @@
839 self.transaction = None870 self.transaction = None
840871
841 self.progress_bar = None872 self.progress_bar = None
842 self.install_label.set_markup(self.INSTALL_PACKAGE % self.args)873
874 self.message = message
875 if self.message is None:
876 self.message = self.INSTALL_PACKAGE % self.args
877 self.reset()
843878
844 self.show()879 self.show()
845880
881 def reset(self):
882 """Reset this interface."""
883 children = self.itself.get_children()
884 if self.progress_bar in children:
885 self.itself.remove(self.progress_bar)
886 if self.install_button_box not in children:
887 self.itself.pack_start(self.install_button_box)
888 self.install_label.set_markup(self.message)
889
846 @package_manager.inline_callbacks890 @package_manager.inline_callbacks
847 def on_install_button_clicked(self, button):891 def on_install_button_clicked(self, button):
848 """The install button was clicked."""892 """The install button was clicked."""
@@ -869,10 +913,14 @@
869 self.transaction.connect('finished', self.on_install_finished)913 self.transaction.connect('finished', self.on_install_finished)
870 self.install_label.set_markup(self.INSTALLING % self.args)914 self.install_label.set_markup(self.INSTALLING % self.args)
871 yield self.transaction.run()915 yield self.transaction.run()
916 except package_manager.aptdaemon.errors.NotAuthorizedError:
917 self.reset()
872 except: # pylint: disable=W0702918 except: # pylint: disable=W0702
873 logger.exception('on_install_button_clicked')919 logger.exception('on_install_button_clicked')
874 self._set_warning(self.FAILED_INSTALL % self.args,920 self._set_warning(self.FAILED_INSTALL % self.args,
875 self.install_label)921 self.install_label)
922 if self.progress_bar is not None:
923 self.progress_bar.hide()
876924
877 @log_call(logger.info)925 @log_call(logger.info)
878 def on_install_finished(self, transaction, exit_code):926 def on_install_finished(self, transaction, exit_code):
@@ -880,6 +928,8 @@
880 if self.progress_bar is not None:928 if self.progress_bar is not None:
881 self.progress_bar.set_sensitive(False)929 self.progress_bar.set_sensitive(False)
882930
931 logger.info('on_install_finished: installation of %r was %r',
932 self.package_name, exit_code)
883 if exit_code != package_manager.aptdaemon.enums.EXIT_SUCCESS:933 if exit_code != package_manager.aptdaemon.enums.EXIT_SUCCESS:
884 if hasattr(transaction, 'error'):934 if hasattr(transaction, 'error'):
885 logger.error('transaction failed: %r', transaction.error)935 logger.error('transaction failed: %r', transaction.error)
@@ -896,10 +946,15 @@
896 CHANGE_ERROR = _('The settings could not be changed,\n'946 CHANGE_ERROR = _('The settings could not be changed,\n'
897 'previous values were restored.')947 'previous values were restored.')
898948
899 def __init__(self, service_id, name, *args, **kwargs):949 def __init__(self, service_id, name,
950 container=None, check_button=None, action_button=None,
951 *args, **kwargs):
900 gtk.VBox.__init__(self)952 gtk.VBox.__init__(self)
901 ControlPanelMixin.__init__(self)953 ControlPanelMixin.__init__(self)
902 self.id = service_id954 self.id = service_id
955 self.container = container
956 self.check_button = check_button
957 self.action_button = action_button
903958
904 self.warning_label = gtk.Label()959 self.warning_label = gtk.Label()
905 self.pack_start(self.warning_label, expand=False)960 self.pack_start(self.warning_label, expand=False)
@@ -915,11 +970,14 @@
915970
916 FILES_SERVICE_NAME = _('File Sync')971 FILES_SERVICE_NAME = _('File Sync')
917972
918 def __init__(self):973 def __init__(self, container, check_button, action_button):
919 Service.__init__(self, service_id='file-sync',974 Service.__init__(self, service_id='file-sync',
920 name=self.FILES_SERVICE_NAME)975 name=self.FILES_SERVICE_NAME,
976 container=container,
977 check_button=check_button,
978 action_button=action_button)
921979
922 self.set_sensitive(False)980 self.container.set_sensitive(False)
923981
924 self.backend.connect_to_signal('FileSyncStatusChanged',982 self.backend.connect_to_signal('FileSyncStatusChanged',
925 self.on_file_sync_status_changed)983 self.on_file_sync_status_changed)
@@ -933,12 +991,15 @@
933 def on_file_sync_status_changed(self, status):991 def on_file_sync_status_changed(self, status):
934 """File Sync status changed."""992 """File Sync status changed."""
935 enabled = status != backend.FILE_SYNC_DISABLED993 enabled = status != backend.FILE_SYNC_DISABLED
936 self.button.set_active(enabled)994 logger.info('FileSyncService: enabled? %r', enabled)
995 self.check_button.set_active(enabled)
996 # if service is disabled, disable the action_button
997 self.action_button.set_sensitive(enabled)
937998
938 if not self.is_sensitive():999 if not self.container.is_sensitive():
939 # first time we're getting this event1000 # first time we're getting this event
940 self.button.connect('toggled', self.on_button_toggled)1001 self.check_button.connect('toggled', self.on_button_toggled)
941 self.set_sensitive(True)1002 self.container.set_sensitive(True)
9421003
943 def on_files_enabled(self):1004 def on_files_enabled(self):
944 """Files service was enabled."""1005 """Files service was enabled."""
@@ -951,8 +1012,8 @@
951 @log_call(logger.debug)1012 @log_call(logger.debug)
952 def on_button_toggled(self, button):1013 def on_button_toggled(self, button):
953 """Button was toggled, exclude/replicate the service properly."""1014 """Button was toggled, exclude/replicate the service properly."""
954 logger.info('File Sync enabled? %r', self.button.get_active())1015 logger.info('File Sync enabled? %r', self.check_button.get_active())
955 if self.button.get_active():1016 if self.check_button.get_active():
956 self.backend.enable_files(reply_handler=NO_OP,1017 self.backend.enable_files(reply_handler=NO_OP,
957 error_handler=error_handler)1018 error_handler=error_handler)
958 else:1019 else:
@@ -963,38 +1024,49 @@
963class DesktopcouchService(Service):1024class DesktopcouchService(Service):
964 """A desktopcouch service."""1025 """A desktopcouch service."""
9651026
966 def __init__(self, service_id, name, enabled, dependency=None):1027 INSTALL_PACKAGE = _('Install <i>%(plugin_name)s</i> plugin '
967 Service.__init__(self, service_id, name)1028 'for %(service_name)s sync')
1029
1030 def __init__(self, service_id, name, enabled,
1031 container, check_button,
1032 dependency=None, dependency_name=None):
1033 Service.__init__(self, service_id, name,
1034 container, check_button, action_button=None)
9681035
969 self.backend.connect_to_signal('ReplicationSettingsChanged',1036 self.backend.connect_to_signal('ReplicationSettingsChanged',
970 self.on_replication_settings_changed)1037 self.on_replication_settings_changed)
971 self.backend.connect_to_signal('ReplicationSettingsChangeError',1038 self.backend.connect_to_signal('ReplicationSettingsChangeError',
972 self.on_replication_settings_change_error)1039 self.on_replication_settings_change_error)
9731040
974 self.button.set_active(enabled)1041 self.check_button.set_active(enabled)
9751042
976 self.dependency = None1043 self.dependency = None
977 if dependency is not None:1044 if dependency is not None:
978 self.dependency = InstallPackage(dependency)1045 if dependency_name is None:
1046 dependency_name = dependency
1047 args = {'plugin_name': dependency_name, 'service_name': service_id}
1048 message = self.INSTALL_PACKAGE % args
1049 self.dependency = InstallPackage(dependency, message)
979 self.dependency.connect('finished', self.on_depedency_finished)1050 self.dependency.connect('finished', self.on_depedency_finished)
980 self.pack_start(self.dependency, expand=False)1051
981 self.button.set_sensitive(False)1052 self.container.pack_end(self.dependency, expand=False)
9821053 self.check_button.set_sensitive(False)
983 self.button.connect('toggled', self.on_button_toggled)1054
1055 self.check_button.connect('toggled', self.on_button_toggled)
9841056
985 def on_depedency_finished(self, widget):1057 def on_depedency_finished(self, widget):
986 """The dependency was installed."""1058 """The dependency was installed."""
987 self.button.set_sensitive(True)1059 self.check_button.set_sensitive(True)
988 self.remove(self.dependency)1060 self.container.remove(self.dependency)
989 self.dependency = None1061 self.dependency = None
9901062
991 @log_call(logger.debug)1063 @log_call(logger.debug)
992 def on_button_toggled(self, button):1064 def on_button_toggled(self, button):
993 """Button was toggled, exclude/replicate the service properly."""1065 """Button was toggled, exclude/replicate the service properly."""
994 logger.info('Starting replication for %r? %r',1066 logger.info('Starting replication for %r? %r',
995 self.id, self.button.get_active())1067 self.id, self.check_button.get_active())
9961068
997 args = {'enabled': bool_str(self.button.get_active())}1069 args = {'enabled': bool_str(self.check_button.get_active())}
998 self.backend.change_replication_settings(self.id, args,1070 self.backend.change_replication_settings(self.id, args,
999 reply_handler=NO_OP, error_handler=error_handler)1071 reply_handler=NO_OP, error_handler=error_handler)
10001072
@@ -1011,26 +1083,28 @@
1011 """The change of settings for this replication failed."""1083 """The change of settings for this replication failed."""
1012 if replication_id != self.id:1084 if replication_id != self.id:
1013 return1085 return
1014 self.button.set_active(not self.button.get_active())1086 self.check_button.set_active(not self.check_button.get_active())
1015 self._set_warning(self.CHANGE_ERROR, self.warning_label)1087 self._set_warning(self.CHANGE_ERROR, self.warning_label)
10161088
10171089
1018class ServicesPanel(UbuntuOneBin, ControlPanelMixin):1090class ServicesPanel(UbuntuOneBin, ControlPanelMixin):
1019 """The services panel."""1091 """The services panel."""
10201092
1021 TITLE = _('Ubuntu One services including data sync are enabled for the '1093 TITLE = _('Enable the sync services for this computer.')
1022 'data types and services listed below.')
1023 CHOOSE_SERVICES = _('Choose services to synchronize with this computer:')
1024 DESKTOPCOUCH_PKG = 'desktopcouch-ubuntuone'1094 DESKTOPCOUCH_PKG = 'desktopcouch-ubuntuone'
1025 BOOKMARKS = _('Bookmarks (Firefox)')1095 BOOKMARKS = 'Firefox'
1026 CONTACTS = _('Contacts (Evolution)')1096 CONTACTS = 'Evolution'
1027 NO_PAIRING_RECORD = _('There is no Ubuntu One pairing record.')1097 NO_PAIRING_RECORD = _('There is no Ubuntu One pairing record.')
1098 CONTACTS_LINK = 'https://one.ubuntu.com/'
10281099
1029 def __init__(self, main_window=None):1100 def __init__(self, main_window=None):
1030 UbuntuOneBin.__init__(self)1101 UbuntuOneBin.__init__(self)
1031 ControlPanelMixin.__init__(self, filename='services.ui')1102 ControlPanelMixin.__init__(self, filename='services.ui')
1032 self.add(self.itself)1103 self.add(self.itself)
10331104
1105 self.plugin_names = {'contacts': self.CONTACTS,
1106 'bookmarks': self.BOOKMARKS}
1107
1034 self.package_manager = package_manager.PackageManager()1108 self.package_manager = package_manager.PackageManager()
1035 self.install_box = None1109 self.install_box = None
10361110
@@ -1039,7 +1113,9 @@
1039 self.backend.connect_to_signal('ReplicationsInfoError',1113 self.backend.connect_to_signal('ReplicationsInfoError',
1040 self.on_replications_info_error)1114 self.on_replications_info_error)
10411115
1042 self.files.pack_start(FileSyncService(), expand=False)1116 self.file_sync_service = FileSyncService(container=self.files,
1117 check_button=self.file_sync_check,
1118 action_button=self.file_sync_button)
10431119
1044 self.show()1120 self.show()
10451121
@@ -1048,6 +1124,30 @@
1048 """Is desktopcouch installed?"""1124 """Is desktopcouch installed?"""
1049 return self.package_manager.is_installed(self.DESKTOPCOUCH_PKG)1125 return self.package_manager.is_installed(self.DESKTOPCOUCH_PKG)
10501126
1127 def on_file_sync_button_clicked(self, *args, **kwargs):
1128 """The "Show me my U1 folder" button was clicked.
1129
1130 XXX: this should be part of the FileSyncService widget.
1131 XXX: the Ubuntu One folder should be the user's root.
1132
1133 """
1134 uri_hook(None, FILE_URI_PREFIX + os.path.expanduser('~/Ubuntu One'))
1135
1136 def on_contacts_button_clicked(self, *args, **kwargs):
1137 """The "Take me to the Ubuntu One website" button was clicked.
1138
1139 XXX: this should be part of the DesktopcouchService widget.
1140
1141 """
1142 uri_hook(None, self.CONTACTS)
1143
1144 def on_bookmarks_button_clicked(self, *args, **kwargs):
1145 """The bookmarks button was clicked.
1146
1147 XXX: this should be part of the DesktopcouchService widget.
1148
1149 """
1150
1051 @log_call(logger.debug)1151 @log_call(logger.debug)
1052 def load(self):1152 def load(self):
1053 """Load info."""1153 """Load info."""
@@ -1062,7 +1162,7 @@
10621162
1063 self.install_box = InstallPackage(self.DESKTOPCOUCH_PKG)1163 self.install_box = InstallPackage(self.DESKTOPCOUCH_PKG)
1064 self.install_box.connect('finished', self.load_replications)1164 self.install_box.connect('finished', self.load_replications)
1065 self.itself.pack_start(self.install_box, expand=False)1165 self.itself.pack_end(self.install_box, expand=False)
1066 self.itself.reorder_child(self.install_box, 0)1166 self.itself.reorder_child(self.install_box, 0)
1067 else:1167 else:
1068 self.load_replications()1168 self.load_replications()
@@ -1080,7 +1180,7 @@
1080 @log_call(logger.debug)1180 @log_call(logger.debug)
1081 def on_replications_info_ready(self, info):1181 def on_replications_info_ready(self, info):
1082 """The replication info is ready."""1182 """The replication info is ready."""
1083 self.on_success(self.CHOOSE_SERVICES)1183 self.on_success()
10841184
1085 self.replications.show()1185 self.replications.show()
10861186
@@ -1088,18 +1188,20 @@
1088 self.itself.remove(self.install_box)1188 self.itself.remove(self.install_box)
1089 self.install_box = None1189 self.install_box = None
10901190
1091 for child in self.replications.get_children():
1092 self.replications.remove(child)
1093
1094 for item in info:1191 for item in info:
1095 pkg = item['dependency']1192 pkg = item['dependency']
1096 if not pkg or self.package_manager.is_installed(pkg):1193 if not pkg or self.package_manager.is_installed(pkg):
1097 pkg = None1194 pkg = None
1098 child = DesktopcouchService(service_id=item['replication_id'],1195
1099 name=item['name'],1196 sid = item['replication_id']
1100 enabled=bool(item['enabled']),1197 container = getattr(self, sid, None)
1101 dependency=pkg)1198 check_button = getattr(self, '%s_check' % sid, None)
1102 self.replications.pack_start(child, expand=False)1199 name = self.plugin_names.get(sid, None)
1200 child = DesktopcouchService(service_id=sid, name=item['name'],
1201 enabled=bool(item['enabled']), container=container,
1202 check_button=check_button,
1203 dependency=pkg, dependency_name=name)
1204 setattr(self, '%s_service' % sid, child)
11031205
1104 @log_call(logger.error)1206 @log_call(logger.error)
1105 def on_replications_info_error(self, error_dict=None):1207 def on_replications_info_error(self, error_dict=None):
@@ -1143,7 +1245,7 @@
1143 ControlPanelMixin.__init__(self)1245 ControlPanelMixin.__init__(self)
11441246
1145 self.label = LabelLoading(LOADING)1247 self.label = LabelLoading(LOADING)
1146 self.pack_start(self.label, expand=False)1248 self.pack_start(self.label, expand=True)
11471249
1148 self.button = gtk.LinkButton(uri='')1250 self.button = gtk.LinkButton(uri='')
1149 self.button.connect('clicked', self._on_button_clicked)1251 self.button.connect('clicked', self._on_button_clicked)
@@ -1237,7 +1339,11 @@
1237 @log_call(logger.error)1339 @log_call(logger.error)
1238 def on_file_sync_status_error(self, error_dict=None):1340 def on_file_sync_status_error(self, error_dict=None):
1239 """Backend notifies of an error when fetching file sync status."""1341 """Backend notifies of an error when fetching file sync status."""
1240 self._update_status(WARNING_MARKUP % self.FILE_SYNC_ERROR,1342 msg = self.FILE_SYNC_ERROR
1343 reason = error_dict.get('error_msg', '') if error_dict else ''
1344 if reason:
1345 msg += ' (' + reason + ')'
1346 self._update_status(WARNING_MARKUP % msg,
1241 self.RESTART, self.on_restart_clicked,1347 self.RESTART, self.on_restart_clicked,
1242 tooltip=self.RESTART_TOOLTIP)1348 tooltip=self.RESTART_TOOLTIP)
12431349
@@ -1291,7 +1397,8 @@
1291 gobject.TYPE_NONE, ()),1397 gobject.TYPE_NONE, ()),
1292 }1398 }
12931399
1294 QUOTA_LABEL = _('Using %(used)s of %(total)s (%(percentage).1f%%)')1400 QUOTA_LABEL = _('Using %(used)s of %(total)s (%(percentage).0f%%)')
1401 QUOTA_THRESHOLD = 0.95
1295 DASHBOARD_BUTTON_NAME = 'Account'1402 DASHBOARD_BUTTON_NAME = 'Account'
1296 SERVICES_BUTTON_NAME = 'Devices' # Intentional until the theme is fixed1403 SERVICES_BUTTON_NAME = 'Devices' # Intentional until the theme is fixed
12971404
@@ -1321,7 +1428,7 @@
1321 self.quota_box.reorder_child(self.quota_label, 0)1428 self.quota_box.reorder_child(self.quota_label, 0)
13221429
1323 self.status_label = FileSyncStatus()1430 self.status_label = FileSyncStatus()
1324 self.status_box.pack_end(self.status_label, expand=False)1431 self.status_box.pack_end(self.status_label, expand=True)
13251432
1326 self.dashboard = DashboardPanel(main_window=main_window)1433 self.dashboard = DashboardPanel(main_window=main_window)
1327 self.volumes = VolumesPanel(main_window=main_window)1434 self.volumes = VolumesPanel(main_window=main_window)
@@ -1352,20 +1459,32 @@
1352 lambda widget: self.emit('local-device-removed'))1459 lambda widget: self.emit('local-device-removed'))
13531460
1354 self.services_button.set_name(self.SERVICES_BUTTON_NAME)1461 self.services_button.set_name(self.SERVICES_BUTTON_NAME)
1355 self.services_button.connect('clicked', lambda b: self.services.load())
1356 self.services_button.set_tooltip_text(self.SERVICES_BUTTON_TOOLTIP)1462 self.services_button.set_tooltip_text(self.SERVICES_BUTTON_TOOLTIP)
1463 self.services.load()
13571464
1358 def _update_quota(self, msg, data=None):1465 def _update_quota(self, msg, data=None):
1359 """Update the quota info."""1466 """Update the quota info."""
1360 self.quota_label.set_markup(msg)
1361 self.quota_label.stop()
1362
1363 fraction = 0.01467 fraction = 0.0
1364 if data is not None:1468 if data is not None:
1365 fraction = data.get('percentage', 0.0) / 1001469 fraction = data.get('percentage', 0.0) / 100
1366 if fraction > 0 and fraction < 0.05:1470 if fraction > 0 and fraction < 0.05:
1367 fraction = 0.051471 fraction = 0.05
1368 self.quota_progressbar.set_fraction(fraction)1472 else:
1473 fraction = round(fraction, 2)
1474
1475 logger.debug('ManagementPanel: updating quota to %r.', fraction)
1476 if fraction >= self.QUOTA_THRESHOLD:
1477 self.quota_label.set_markup(WARNING_MARKUP % msg)
1478 else:
1479 self.quota_label.set_markup(msg)
1480 self.quota_label.stop()
1481
1482 if fraction == 0.0:
1483 self.quota_progressbar.set_sensitive(False)
1484 else:
1485 self.quota_progressbar.set_sensitive(True)
1486
1487 self.quota_progressbar.set_fraction(min(fraction, 1))
13691488
1370 def load(self):1489 def load(self):
1371 """Load the account info and file sync status list."""1490 """Load the account info and file sync status list."""
@@ -1384,7 +1503,7 @@
1384 @log_call(logger.error)1503 @log_call(logger.error)
1385 def on_account_info_error(self, error_dict=None):1504 def on_account_info_error(self, error_dict=None):
1386 """Backend notifies of an error when fetching account info."""1505 """Backend notifies of an error when fetching account info."""
1387 self._update_quota(WARNING_MARKUP % VALUE_ERROR)1506 self._update_quota(msg='')
13881507
13891508
1390class ControlPanel(gtk.Notebook):1509class ControlPanel(gtk.Notebook):
@@ -1439,7 +1558,7 @@
14391558
1440 TITLE = _('%(app_name)s Control Panel')1559 TITLE = _('%(app_name)s Control Panel')
14411560
1442 def __init__(self, switch_to=None):1561 def __init__(self, switch_to=None, alert=False):
1443 super(ControlPanelWindow, self).__init__()1562 super(ControlPanelWindow, self).__init__()
14441563
1445 self.set_title(self.TITLE % {'app_name': U1_APP_NAME})1564 self.set_title(self.TITLE % {'app_name': U1_APP_NAME})
@@ -1448,7 +1567,13 @@
1448 self.set_size_request(-1, 525) # bug #6831641567 self.set_size_request(-1, 525) # bug #683164
14491568
1450 self.connect('delete-event', lambda w, e: gtk.main_quit())1569 self.connect('delete-event', lambda w, e: gtk.main_quit())
1451 self.show()1570 if alert:
1571 print "YES"
1572 # NOTE this should prevent focus stealing but it does not :(
1573 self.present_with_time(1)
1574 self.set_urgency_hint(True)
1575 else:
1576 self.present()
14521577
1453 self.control_panel = ControlPanel(main_window=self)1578 self.control_panel = ControlPanel(main_window=self)
1454 self.add(self.control_panel)1579 self.add(self.control_panel)
14551580
=== modified file 'ubuntuone/controlpanel/gtk/tests/__init__.py'
--- ubuntuone/controlpanel/gtk/tests/__init__.py 2011-02-23 13:57:42 +0000
+++ ubuntuone/controlpanel/gtk/tests/__init__.py 2011-03-10 03:11:54 +0000
@@ -18,11 +18,21 @@
1818
19"""The test suite for the GTK UI for the control panel for Ubuntu One."""19"""The test suite for the GTK UI for the control panel for Ubuntu One."""
2020
21import logging
22
21from collections import defaultdict23from collections import defaultdict
2224
25from ubuntuone.devtools.handlers import MementoHandler
26
27from ubuntuone.controlpanel.backend import ControlBackend
23from ubuntuone.controlpanel.gtk import gui28from ubuntuone.controlpanel.gtk import gui
24from ubuntuone.controlpanel.gtk.tests.test_package_manager import (29from ubuntuone.controlpanel.gtk.tests.test_package_manager import (
25 FakedTransaction)30 FakedTransaction)
31from ubuntuone.controlpanel.tests import TestCase
32
33
34# Attribute 'yyy' defined outside __init__, access to a protected member
35# pylint: disable=W0201, W0212
2636
2737
28FAKE_ACCOUNT_INFO = {'type': 'Payed', 'name': 'Test me',38FAKE_ACCOUNT_INFO = {'type': 'Payed', 'name': 'Test me',
@@ -32,26 +42,36 @@
3242
33ROOT = {43ROOT = {
34 u'volume_id': '', u'path': '/home/tester/My Ubuntu',44 u'volume_id': '', u'path': '/home/tester/My Ubuntu',
35 u'subscribed': 'True', u'type': u'ROOT',45 u'subscribed': 'True', u'type': ControlBackend.ROOT_TYPE,
46}
47
48MUSIC_FOLDER = {
49 u'volume_id': u'58236', u'subscribed': u'True',
50 u'type': ControlBackend.FOLDER_TYPE,
51 u'path': u'/home/tester/.ubuntuone/Purchased from Ubuntu One',
52 u'suggested_path': u'~/.ubuntuone/Purchased from Ubuntu One',
36}53}
3754
38FAKE_FOLDERS_INFO = [55FAKE_FOLDERS_INFO = [
39 {u'volume_id': u'0', u'path': u'/home/tester/foo',56 {u'volume_id': u'0', u'path': u'/home/tester/foo',
40 u'suggested_path': u'~/foo', u'subscribed': u'', u'type': u'UDF'},57 u'suggested_path': u'~/foo', u'subscribed': u'',
58 u'type': ControlBackend.FOLDER_TYPE},
41 {u'volume_id': u'1', u'path': u'/home/tester/bar',59 {u'volume_id': u'1', u'path': u'/home/tester/bar',
42 u'suggested_path': u'~/bar', u'subscribed': u'True', u'type': u'UDF'},60 u'suggested_path': u'~/bar', u'subscribed': u'True',
61 u'type': ControlBackend.FOLDER_TYPE},
43 {u'volume_id': u'2', u'path': u'/home/tester/baz',62 {u'volume_id': u'2', u'path': u'/home/tester/baz',
44 u'suggested_path': u'~/baz', u'subscribed': u'True', u'type': u'UDF'},63 u'suggested_path': u'~/baz', u'subscribed': u'True',
64 u'type': ControlBackend.FOLDER_TYPE},
45]65]
4666
47FAKE_SHARES_INFO = [67FAKE_SHARES_INFO = [
48 {u'volume_id': u'1234', u'name': u'do',68 {u'volume_id': u'1234', u'name': u'do',
49 u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User',69 u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User',
50 u'subscribed': u'', u'type': u'SHARE'},70 u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE},
5171
52 {u'volume_id': u'5678', u'name': u're',72 {u'volume_id': u'5678', u'name': u're',
53 u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User',73 u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User',
54 u'subscribed': u'True', u'type': u'SHARE'},74 u'subscribed': u'True', u'type': ControlBackend.SHARE_TYPE},
55]75]
5676
57FAKE_VOLUMES_INFO = [77FAKE_VOLUMES_INFO = [
@@ -207,7 +227,8 @@
207 self._args = args227 self._args = args
208 self._kwargs = kwargs228 self._kwargs = kwargs
209 self.was_run = False229 self.was_run = False
210 self.is_visible = True230 self.is_visible = False
231 self.markup = kwargs.get('message_format', None)
211 self.show = lambda: setattr(self, 'is_visible', True)232 self.show = lambda: setattr(self, 'is_visible', True)
212 self.hide = lambda: setattr(self, 'is_visible', False)233 self.hide = lambda: setattr(self, 'is_visible', False)
213 self.response_code = None234 self.response_code = None
@@ -216,3 +237,67 @@
216 """Set flag and return 'self.response_code'."""237 """Set flag and return 'self.response_code'."""
217 self.was_run = True238 self.was_run = True
218 return self.response_code239 return self.response_code
240
241 def set_markup(self, msg):
242 """Set the markup."""
243 self.markup = msg
244
245
246class BaseTestCase(TestCase):
247 """Basics for testing."""
248
249 # self.klass is not callable
250 # pylint: disable=E1102
251 klass = None
252 kwargs = {}
253
254 def setUp(self):
255 super(BaseTestCase, self).setUp()
256 self.patch(gui.os.path, 'expanduser',
257 lambda path: path.replace('~', USER_HOME))
258 self.patch(gui.gtk, 'main', lambda: None)
259 self.patch(gui.gtk, 'MessageDialog', FakedConfirmDialog)
260 self.patch(gui.dbus, 'SessionBus', FakedSessionBus)
261 self.patch(gui.dbus, 'Interface', FakedInterface)
262 self.patch(gui.networkstate, 'NetworkManagerState', FakedNMState)
263 self.patch(gui.package_manager, 'PackageManager', FakedPackageManager)
264
265 if self.klass is not None:
266 self.ui = self.klass(**self.kwargs)
267
268 self.memento = MementoHandler()
269 self.memento.setLevel(logging.DEBUG)
270 gui.logger.addHandler(self.memento)
271
272 def tearDown(self):
273 try:
274 self.ui.hide()
275 del self.ui
276 self.ui = None
277 except AttributeError:
278 pass
279 super(BaseTestCase, self).tearDown()
280
281 def assert_image_equal(self, image, filename):
282 """Check that expected and actual represent the same image."""
283 pb = gui.gtk.gdk.pixbuf_new_from_file(gui.get_data_file(filename))
284 self.assertEqual(image.get_pixbuf().get_pixels(), pb.get_pixels())
285
286 def assert_backend_called(self, method_name, args, backend=None):
287 """Check that the control panel backend 'method_name' was called."""
288 if backend is None:
289 backend = self.ui.backend
290 self.assertIn(method_name, backend._called)
291 kwargs = {'reply_handler': gui.NO_OP,
292 'error_handler': gui.error_handler}
293 self.assertEqual(backend._called[method_name], (args, kwargs))
294
295 def assert_warning_correct(self, warning, text):
296 """Check that 'warning' is visible, showing 'text'."""
297 self.assertTrue(warning.get_visible(), 'Must be visible.')
298 self.assertEqual(warning.get_label(), gui.WARNING_MARKUP % text)
299
300 def assert_function_decorated(self, decorator, func):
301 """Check that 'func' is decorated with 'decorator'."""
302 expected = decorator(lambda: None)
303 self.assertEqual(expected.func_code, func.im_func.func_code)
219304
=== modified file 'ubuntuone/controlpanel/gtk/tests/test_gui.py'
--- ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-02-28 15:38:15 +0000
+++ ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-03-10 03:11:54 +0000
@@ -20,645 +20,25 @@
2020
21from __future__ import division21from __future__ import division
2222
23import logging
24
25from ubuntuone.devtools.handlers import MementoHandler
26
27from ubuntuone.controlpanel.gtk import gui23from ubuntuone.controlpanel.gtk import gui
28from ubuntuone.controlpanel.gtk.tests import (FAKE_ACCOUNT_INFO,24from ubuntuone.controlpanel.gtk.tests import (FAKE_ACCOUNT_INFO,
29 FAKE_DEVICE_INFO, FAKE_DEVICES_INFO,25 FAKE_DEVICE_INFO, FAKE_DEVICES_INFO, FAKE_FOLDERS_INFO,
30 FAKE_VOLUMES_INFO, FAKE_REPLICATIONS_INFO, ROOT, USER_HOME,26 FAKE_VOLUMES_INFO, FAKE_REPLICATIONS_INFO,
31 FakedNMState, FakedSSOBackend, FakedSessionBus, FakedInterface,27 MUSIC_FOLDER, ROOT, USER_HOME,
32 FakedPackageManager, FakedConfirmDialog,28 FakedConfirmDialog,
33)29)
34from ubuntuone.controlpanel.tests import TOKEN, TestCase30from ubuntuone.controlpanel.gtk.tests.test_gui_basic import (
31 ControlPanelMixinTestCase,
32)
35from ubuntuone.controlpanel.gtk.tests.test_package_manager import (33from ubuntuone.controlpanel.gtk.tests.test_package_manager import (
36 SUCCESS, FAILURE)34 SUCCESS, FAILURE)
3735
3836
39# Attribute 'yyy' defined outside __init__, access to a protected member37# Attribute 'yyy' defined outside __init__, access to a protected member
40# pylint: disable=W0201, W021238# pylint: disable=W0201, W0212
41# Too many lines in module39
42# pylint: disable=C030240# Unused variable 'skip'
4341#pylint: disable=W0612
44
45class BaseTestCase(TestCase):
46 """Basics for testing."""
47
48 # self.klass is not callable
49 # pylint: disable=E1102
50 klass = None
51 kwargs = {}
52
53 def setUp(self):
54 super(BaseTestCase, self).setUp()
55 self.patch(gui.os.path, 'expanduser',
56 lambda path: path.replace('~', USER_HOME))
57 self.patch(gui.gtk, 'main', lambda: None)
58 self.patch(gui.gtk, 'MessageDialog', FakedConfirmDialog)
59 self.patch(gui.dbus, 'SessionBus', FakedSessionBus)
60 self.patch(gui.dbus, 'Interface', FakedInterface)
61 self.patch(gui.networkstate, 'NetworkManagerState', FakedNMState)
62 self.patch(gui.package_manager, 'PackageManager', FakedPackageManager)
63
64 if self.klass is not None:
65 self.ui = self.klass(**self.kwargs)
66
67 self.memento = MementoHandler()
68 self.memento.setLevel(logging.DEBUG)
69 gui.logger.addHandler(self.memento)
70
71 def tearDown(self):
72 try:
73 self.ui.hide()
74 del self.ui
75 self.ui = None
76 except AttributeError:
77 pass
78 super(BaseTestCase, self).tearDown()
79
80 def assert_image_equal(self, image, filename):
81 """Check that expected and actual represent the same image."""
82 pb = gui.gtk.gdk.pixbuf_new_from_file(gui.get_data_file(filename))
83 self.assertEqual(image.get_pixbuf().get_pixels(), pb.get_pixels())
84
85 def assert_backend_called(self, method_name, args, backend=None):
86 """Check that the control panel backend 'method_name' was called."""
87 if backend is None:
88 backend = self.ui.backend
89 self.assertIn(method_name, backend._called)
90 kwargs = {'reply_handler': gui.NO_OP,
91 'error_handler': gui.error_handler}
92 self.assertEqual(backend._called[method_name], (args, kwargs))
93
94 def assert_warning_correct(self, warning, text):
95 """Check that 'warning' is visible, showing 'text'."""
96 self.assertTrue(warning.get_visible(), 'Must be visible.')
97 self.assertEqual(warning.get_label(), gui.WARNING_MARKUP % text)
98
99 def assert_function_decorated(self, decorator, func):
100 """Check that 'func' is decorated with 'decorator'."""
101 expected = decorator(lambda: None)
102 self.assertEqual(expected.func_code, func.im_func.func_code)
103
104
105class ControlPanelMixinTestCase(BaseTestCase):
106 """The test suite for the control panel widget."""
107
108 klass = gui.ControlPanelMixin
109 ui_filename = None
110
111 def test_is_a_control_panel_mixin(self):
112 """Inherits from ControlPanelMixin."""
113 self.assertIsInstance(self.ui, gui.ControlPanelMixin)
114
115 def test_ui_can_be_created(self):
116 """UI main class exists and can be created."""
117 self.assertTrue(self.ui is not None)
118
119
120class ControlPanelWindowTestCase(BaseTestCase):
121 """The test suite for the control panel window."""
122
123 klass = gui.ControlPanelWindow
124
125 def test_is_a_window(self):
126 """Inherits from gtk.Window."""
127 self.assertIsInstance(self.ui, gui.gtk.Window)
128
129 def test_startup_visibility(self):
130 """The widget is visible at startup."""
131 self.assertTrue(self.ui.get_visible(), 'must be visible at startup.')
132
133 def test_main_start_gtk_main_loop(self):
134 """The GTK main loop is started when calling main()."""
135 self.patch(gui.gtk, 'main', self._set_called)
136 self.ui.main()
137 self.assertEqual(self._called, ((), {}), 'gtk.main was called.')
138
139 def test_closing_stops_the_main_lopp(self):
140 """The GTK main loop is stopped when closing the window."""
141 self.patch(gui.gtk, 'main_quit', self._set_called)
142 self.ui.emit('delete-event', None)
143 self.assertEqual(self._called, ((), {}), 'gtk.main_quit was called.')
144
145 def test_title_is_correct(self):
146 """The window title is correct."""
147 expected = self.ui.TITLE % {'app_name': gui.U1_APP_NAME}
148 self.assertEqual(self.ui.get_title(), expected)
149
150 def test_control_panel_is_the_only_child(self):
151 """The control panel is the window's content."""
152 children = self.ui.get_children()
153 self.assertEqual(1, len(children))
154
155 control_panel = self.ui.get_children()[0]
156 self.assertTrue(control_panel is self.ui.control_panel)
157 self.assertIsInstance(self.ui.control_panel, gui.ControlPanel)
158 self.assertTrue(self.ui.control_panel.get_visible())
159
160 def test_main_window_is_passed_to_child(self):
161 """The child gets the main_window."""
162 self.assertEqual(self.ui.control_panel.main_window, self.ui)
163
164 def test_icon_name_is_correct(self):
165 """The icon name is correct."""
166 self.assertEqual(self.ui.get_icon_name(), 'ubuntuone')
167
168 def test_max_size(self):
169 """Max size is not bigger than 736x525 (LP: #645526, LP: #683164)."""
170 self.assertTrue(self.ui.get_size_request() <= (736, 525))
171
172
173class ControlPanelWindowParamsTestCase(ControlPanelWindowTestCase):
174 """The test suite for the control panel window when passing params."""
175
176 kwargs = {'switch_to': 'devices'}
177
178 def test_switch_to(self):
179 """Can pass a 'switch_to' parameter to start on a particular tab."""
180 actual = self.ui.control_panel.management.notebook.get_current_page()
181 self.assertEqual(actual, self.ui.control_panel.management.DEVICES_PAGE)
182
183
184class ControlPanelWindowParamsNoneTestCase(ControlPanelWindowTestCase):
185 """The suite for the control panel window when passing None params."""
186
187 kwargs = {'switch_to': None}
188
189 def test_switch_to(self):
190 """Can pass a 'switch_to' being None. Should default to dashboard."""
191 actual = self.ui.control_panel.management.notebook.get_current_page()
192 expected = self.ui.control_panel.management.DASHBOARD_PAGE
193 self.assertEqual(actual, expected)
194
195
196class ControlPanelWindowInvalidParamsTestCase(ControlPanelWindowTestCase):
197 """The suite for the control panel window when passing invalid params."""
198
199 kwargs = {'switch_to': 'yadda-yadda'}
200
201 def test_switch_to(self):
202 """Can pass an invalid 'switch_to'. Should default to dashboard."""
203 actual = self.ui.control_panel.management.notebook.get_current_page()
204 expected = self.ui.control_panel.management.DASHBOARD_PAGE
205 self.assertEqual(actual, expected)
206
207
208class ControlPanelTestCase(BaseTestCase):
209 """The test suite for the control panel itself."""
210
211 klass = gui.ControlPanel
212 kwargs = {'main_window': object()}
213
214 def assert_current_tab_correct(self, expected_tab):
215 """Check that the wiget 'expected_tab' is the current page."""
216 actual = self.ui.get_nth_page(self.ui.get_current_page())
217 self.assertTrue(expected_tab is actual)
218
219 def test_is_a_notebook(self):
220 """Inherits from gtk.VBox."""
221 self.assertIsInstance(self.ui, gui.gtk.Notebook)
222
223 def test_startup_visibility(self):
224 """The widget is visible at startup."""
225 self.assertTrue(self.ui.get_visible(),
226 'must be visible at startup.')
227
228 def test_startup_props(self):
229 """The tabs and border are not shown."""
230 self.assertFalse(self.ui.get_show_border(), 'must not show border.')
231 self.assertFalse(self.ui.get_show_tabs(), 'must not show tabs.')
232
233 def test_overview_is_shown_at_startup(self):
234 """The overview is shown at startup."""
235 self.assertIsInstance(self.ui.overview, gui.OverviewPanel)
236 self.assert_current_tab_correct(self.ui.overview)
237
238 def test_main_window_is_passed_to_child(self):
239 """The child gets the main_window."""
240 self.assertEqual(self.ui.overview.main_window,
241 self.kwargs['main_window'])
242
243 def test_on_show_management_panel(self):
244 """A ManagementPanel is shown when the callback is executed."""
245 self.ui.on_show_management_panel()
246 self.assert_current_tab_correct(self.ui.management)
247
248 def test_on_show_management_panel_is_idempotent(self):
249 """Only one ManagementPanel is shown."""
250 self.ui.on_show_management_panel()
251 self.ui.on_show_management_panel()
252
253 self.assert_current_tab_correct(self.ui.management)
254
255 def test_credentials_found_shows_dashboard_management_panel(self):
256 """On 'credentials-found' signal, the management panel is shown.
257
258 If first signal parameter is False, visible tab should be dashboard.
259
260 """
261 self.patch(self.ui.management, 'load', self._set_called)
262 self.ui.overview.emit('credentials-found', False, object())
263
264 self.assert_current_tab_correct(self.ui.management)
265 self.assertEqual(self.ui.management.notebook.get_current_page(),
266 self.ui.management.DASHBOARD_PAGE)
267 self.assertEqual(self._called, ((), {}))
268
269 def test_credentials_found_shows_volumes_management_panel(self):
270 """On 'credentials-found' signal, the management panel is shown.
271
272 If first signal parameter is True, visible tab should be volumes.
273
274 """
275 a_token = object()
276 self.ui.overview.emit('credentials-found', True, a_token)
277
278 self.assert_current_tab_correct(self.ui.management)
279 self.assertEqual(self.ui.management.notebook.get_current_page(),
280 self.ui.management.VOLUMES_PAGE)
281
282 def test_local_device_removed_shows_overview_panel(self):
283 """On 'local-device-removed' signal, the overview panel is shown."""
284 self.ui.overview.emit('credentials-found', True, object())
285 self.ui.management.emit('local-device-removed')
286
287 self.assert_current_tab_correct(self.ui.overview)
288
289
290class UbuntuOneBinTestCase(BaseTestCase):
291 """The test suite for a Ubuntu One panel."""
292
293 klass = gui.UbuntuOneBin
294 kwargs = {'title': 'Something old, something new and something blue.'}
295
296 def test_is_a_vbox(self):
297 """Inherits from proper gtk widget."""
298 self.assertIsInstance(self.ui, gui.gtk.VBox)
299
300 def test_startup_visibility(self):
301 """The widget is visible at startup."""
302 self.assertTrue(self.ui.get_visible(),
303 'must be visible at startup.')
304 for child in self.ui.get_children():
305 self.assertTrue(child.get_visible())
306
307 def test_title_is_a_panel_title(self):
308 """Title is the correct widget."""
309 self.assertIsInstance(self.ui.title, gui.PanelTitle)
310 self.assertIn(self.ui.title, self.ui.get_children())
311
312 def test_title_markup_is_correct(self):
313 """The title markup is correctly set when passed as argument."""
314 self.assertEqual(self.ui.title.label.get_text(), self.kwargs['title'])
315
316 def test_title_is_correct(self):
317 """The title markup is correctly set when defined at class level."""
318 ui = self.klass() # no title given
319 self.assertEqual(ui.title.label.get_text(), '')
320
321 def test_message_is_a_label_loading(self):
322 """Message is the correct widget."""
323 self.assertIsInstance(self.ui.message, gui.LabelLoading)
324 self.assertIn(self.ui.message, self.ui.get_children())
325
326 def test_on_success(self):
327 """Callback to stop the Loading and clear messages."""
328 self.ui.on_success()
329 self.assertEqual(self.ui.message.get_label(), '')
330 self.assertFalse(self.ui.message.active)
331
332 def test_on_success_with_message(self):
333 """Callback to stop the Loading and show a info message."""
334 msg = 'WOW! <i>this rocks</i>'
335 self.ui.on_success(message=msg)
336 self.assertEqual(self.ui.message.get_label(), msg)
337 self.assertFalse(self.ui.message.active)
338
339 def test_on_error(self):
340 """Callback to stop the Loading and clear messages."""
341 self.ui.on_error()
342 self.assert_warning_correct(self.ui.message, gui.VALUE_ERROR)
343 self.assertFalse(self.ui.message.active)
344
345 def test_on_error_with_message(self):
346 """Callback to stop the Loading and show a info message."""
347 msg = 'WOW! <i>this does not rock</i> :-/'
348 self.ui.on_error(message=msg)
349 self.assert_warning_correct(self.ui.message, msg)
350 self.assertFalse(self.ui.message.active)
351
352 def test_is_processing(self):
353 """The flag 'is_processing' is False on start."""
354 self.assertFalse(self.ui.is_processing)
355 self.assertTrue(self.ui.is_sensitive())
356
357 def test_set_is_processing(self):
358 """When setting 'is_processing', the spinner is shown."""
359 self.ui.is_processing = False
360 self.ui.is_processing = True
361
362 self.assertTrue(self.ui.message.get_visible())
363 self.assertTrue(self.ui.message.active)
364 self.assertFalse(self.ui.is_sensitive())
365
366 def test_unset_is_processing(self):
367 """When unsetting 'is_processing', the spinner is not shown."""
368 self.ui.is_processing = True
369 self.ui.is_processing = False
370
371 self.assertTrue(self.ui.message.get_visible())
372 self.assertFalse(self.ui.message.active)
373 self.assertTrue(self.ui.is_sensitive())
374
375
376class OverwiewPanelTestCase(ControlPanelMixinTestCase):
377 """The test suite for the overview panel."""
378
379 klass = gui.OverviewPanel
380 kwargs = {'main_window': gui.gtk.Window()}
381 ui_filename = 'overview.ui'
382
383 def test_is_a_greyable_bin(self):
384 """Inherits from GreyableBin."""
385 self.assertIsInstance(self.ui, gui.GreyableBin)
386
387 def test_inner_widget_is_packed(self):
388 """The 'itself' vbox is packed into the widget."""
389 self.assertIn(self.ui.itself, self.ui.get_children())
390
391 def test_join_now_is_default(self):
392 """The 'join_now' button is the default widget."""
393 self.assertTrue(self.ui.join_now_button.get_property('can-default'))
394
395 def test_sso_backend(self):
396 """Has a correct SSO backend."""
397 self.assertIsInstance(self.ui.sso_backend, FakedSSOBackend)
398
399 def test_sso_backend_signals(self):
400 """The proper signals are connected to the backend."""
401 self.assertEqual(self.ui.sso_backend._signals['CredentialsFound'],
402 [self.ui.on_credentials_found])
403 self.assertEqual(self.ui.sso_backend._signals['CredentialsNotFound'],
404 [self.ui.on_credentials_not_found])
405 self.assertEqual(self.ui.sso_backend._signals['CredentialsError'],
406 [self.ui.on_credentials_error])
407 self.assertEqual(self.ui.sso_backend._signals['AuthorizationDenied'],
408 [self.ui.on_authorization_denied])
409
410
411class OverwiewNetworkStatePanelTestCase(OverwiewPanelTestCase):
412 """The test suite for the overview panel regarding network state."""
413
414 def test_network_state_is_created(self):
415 """The network state is created."""
416 self.assertIsInstance(self.ui.network_manager_state,
417 gui.networkstate.NetworkManagerState)
418 self.assertEqual(self.ui.network_manager_state._kwargs['result_cb'],
419 self.ui.on_network_state_changed)
420
421 def test_network_state_is_queried_at_startup(self):
422 """The network state is asked to the NetworkManagerState."""
423 self.assertTrue('find_online_state' in
424 self.ui.network_manager_state._called)
425
426 def test_state_online(self):
427 """Network connection is online."""
428 self.ui.on_network_state_changed(gui.networkstate.ONLINE)
429 # all green, no warning
430 self.assertEqual(self.ui.warning_label.get_text(), '')
431 self.assertTrue(self.ui.get_sensitive())
432
433 def test_state_offline(self):
434 """Network connection is offline."""
435 self.ui.on_network_state_changed(gui.networkstate.OFFLINE)
436 msg = self.ui.NETWORK_OFFLINE % {'app_name': gui.U1_APP_NAME}
437
438 self.assert_warning_correct(self.ui.warning_label, msg)
439 self.assertFalse(self.ui.get_sensitive())
440
441 def test_state_unknown(self):
442 """Network connection is unknown."""
443 self.ui.on_network_state_changed(gui.networkstate.UNKNOWN)
444
445 self.assert_warning_correct(self.ui.warning_label,
446 self.ui.NETWORK_UNKNOWN)
447 self.assertFalse(self.ui.get_sensitive())
448
449
450class OverwiewPanelOnlineTestCase(OverwiewPanelTestCase):
451 """The test suite for the overview panel."""
452
453 def setUp(self):
454 super(OverwiewPanelOnlineTestCase, self).setUp()
455 self.ui.on_network_state_changed(gui.networkstate.ONLINE)
456
457 def test_find_credentials_is_called(self):
458 """Credentials are asked to SSO backend."""
459 self.assertFalse(self.ui._credentials_are_new)
460 self.assert_backend_called('find_credentials', (gui.U1_APP_NAME, {}),
461 backend=self.ui.sso_backend)
462
463 def test_on_credentials_found(self):
464 """Callback 'on_credentials_found' is correct."""
465 self.ui.connect('credentials-found', self._set_called)
466
467 self.ui.on_credentials_found(gui.U1_APP_NAME, TOKEN)
468
469 self.assertFalse(self.ui.get_property('greyed'), 'Must not be greyed.')
470 # assume credentials were in local keyring
471 self.assertEqual(self._called, ((self.ui, False, TOKEN), {}))
472
473 def test_on_credentials_found_when_creds_are_not_new(self):
474 """Callback 'on_credentials_found' distinguish if creds are new."""
475 self.ui.connect('credentials-found', self._set_called)
476
477 # credentials weren't in the system
478 self.ui.on_credentials_not_found(gui.U1_APP_NAME)
479 # now they are!
480 self.ui.on_credentials_found(gui.U1_APP_NAME, TOKEN)
481
482 self.assertFalse(self.ui.get_property('greyed'), 'Must not be greyed.')
483 # assume credentials were not in local keyring
484 self.assertEqual(self._called, ((self.ui, True, TOKEN), {}))
485
486 def test_on_credentials_not_found(self):
487 """Callback 'on_credentials_not_found' is correct."""
488 self.ui.on_credentials_not_found(gui.U1_APP_NAME)
489 self.assertTrue(self.ui.get_visible())
490 self.assertTrue(self.ui._credentials_are_new)
491
492 def test_on_credentials_error(self):
493 """Callback 'on_credentials_error' is correct."""
494 self.ui.on_credentials_error(gui.U1_APP_NAME, {})
495 self.assertTrue(self.ui.get_visible())
496 self.assert_warning_correct(self.ui.warning_label,
497 self.ui.CREDENTIALS_ERROR)
498
499 def test_on_authorization_denied(self):
500 """Callback 'on_authorization_denied' is correct."""
501 self.ui.on_authorization_denied(gui.U1_APP_NAME)
502 self.assertTrue(self.ui.get_visible())
503 self.assert_warning_correct(self.ui.warning_label,
504 self.ui.AUTHORIZATION_DENIED)
505
506
507class OverwiewPanelAppNameMismatchTestCase(OverwiewPanelTestCase):
508 """The test suite for the overview panel when the app_name won't match."""
509
510 NOT_U1_APP = 'Not ' + gui.U1_APP_NAME
511
512 def test_filter_by_app_name(self):
513 """The filter_by_app_name decorator is correct."""
514 f = gui.filter_by_app_name(self._set_called)
515 f(self.ui, self.NOT_U1_APP)
516 self.assertFalse(self._called)
517 self.assertTrue(self.memento.check_info('ignoring', self.NOT_U1_APP))
518
519 args = ('test', object())
520 kwargs = {'really': 'AWESOME'}
521 f(self.ui, gui.U1_APP_NAME, *args, **kwargs)
522 self.assertEqual(self._called,
523 ((self.ui, gui.U1_APP_NAME,) + args, kwargs))
524
525 def test_on_credentials_found(self):
526 """Callback 'on_credentials_found' is not executed."""
527 self.assert_function_decorated(gui.filter_by_app_name,
528 self.ui.on_credentials_found)
529
530 def test_on_credentials_not_found(self):
531 """Callback 'on_credentials_not_found' is not executed."""
532 self.assert_function_decorated(gui.filter_by_app_name,
533 self.ui.on_credentials_not_found)
534
535 def test_on_credentials_error(self):
536 """Callback 'on_credentials_error' is not executed."""
537 self.assert_function_decorated(gui.filter_by_app_name,
538 self.ui.on_credentials_error)
539
540 def test_on_authorization_denied(self):
541 """Callback 'on_authorization_denied' is not executed."""
542 self.assert_function_decorated(gui.filter_by_app_name,
543 self.ui.on_authorization_denied)
544
545
546class OverwiewPanelNoCredsTestCase(OverwiewPanelTestCase):
547 """The test suite for the overview panel when no credentials are found."""
548
549 def setUp(self):
550 super(OverwiewPanelNoCredsTestCase, self).setUp()
551 self.ui.on_credentials_not_found(gui.U1_APP_NAME)
552
553 def test_startup_visibility(self):
554 """The widget is visible at startup."""
555 self.assertTrue(self.ui.get_visible(),
556 'must be visible at startup if credentials not found.')
557
558 def test_warning_label_is_hidden(self):
559 """The warning label is not shown by default."""
560 self.assertEqual(self.ui.warning_label.get_text(), '')
561
562 def test_image_is_correct(self):
563 """There is an image attribute and is correct."""
564 self.assert_image_equal(self.ui.image, 'overview.png')
565
566 def test_join_now_is_default_widget(self):
567 """The join now button is the default widget."""
568 self.assertTrue(self.ui.join_now_button.get_property('can_default'))
569
570 def test_join_now_button_clicked(self):
571 """Test the 'join now' button callback."""
572 self.kwargs['main_window'].show() # ensure parent window is realized
573 self.addCleanup(self.kwargs['main_window'].hide)
574
575 self.ui.join_now_button.clicked()
576
577 window_id = self.kwargs['main_window'].window.xid
578 args = (gui.U1_APP_NAME,
579 {gui.TC_URL_KEY: gui.U1_TC_URL,
580 gui.HELP_TEXT_KEY: gui.U1_DESCRIPTION,
581 gui.WINDOW_ID_KEY: str(window_id),
582 gui.PING_URL_KEY: gui.U1_PING_URL})
583 self.assert_backend_called('register', args,
584 backend=self.ui.sso_backend)
585
586 def test_connect_button_clicked(self):
587 """Test the 'join now' button callback."""
588 self.kwargs['main_window'].show() # ensure parent window is realized
589 self.addCleanup(self.kwargs['main_window'].hide)
590
591 self.ui.connect_button.clicked()
592
593 window_id = self.kwargs['main_window'].window.xid
594 args = (gui.U1_APP_NAME,
595 {gui.TC_URL_KEY: gui.U1_TC_URL,
596 gui.HELP_TEXT_KEY: gui.U1_DESCRIPTION,
597 gui.WINDOW_ID_KEY: str(window_id),
598 gui.PING_URL_KEY: gui.U1_PING_URL})
599 self.assert_backend_called('login', args,
600 backend=self.ui.sso_backend)
601
602 def test_join_now_button_clicked_set_greyed(self):
603 """Clicking on 'join_now' self is greyed."""
604 self.ui.join_now_button.clicked()
605 self.assertTrue(self.ui.get_property('greyed'), 'Must be greyed.')
606
607 def test_join_now_button_clicked_removes_warning(self):
608 """Clicking on 'join_now' the warnings are removed."""
609 self.ui.on_authorization_denied(gui.U1_APP_NAME) # show warning
610 self.ui.join_now_button.clicked()
611
612 self.assertEqual(self.ui.warning_label.get_text(), '')
613
614 def test_connect_button_clicked_set_greyed(self):
615 """Clicking on 'connect' self is greyed."""
616 self.ui.connect_button.clicked()
617 self.assertTrue(self.ui.get_property('greyed'), 'Must be greyed.')
618
619 def test_connect_button_clicked_removes_warning(self):
620 """Clicking on 'connect' the warnings are removed."""
621 self.ui.on_authorization_denied(gui.U1_APP_NAME) # show warning
622 self.ui.connect_button.clicked()
623
624 self.assertEqual(self.ui.warning_label.get_text(), '')
625
626 def test_on_credentials_not_found_unset_greyed(self):
627 """Callback 'on_credentials_not_found' unsets the 'greyed' prop."""
628 self.ui.connect_button.clicked()
629 self.ui.on_credentials_not_found(gui.U1_APP_NAME)
630
631 self.assertFalse(self.ui.get_property('greyed'), 'Must not be greyed.')
632
633 def test_on_credentials_error_unset_greyed(self):
634 """Callback 'on_credentials_error' unsets the 'greyed' prop."""
635 self.ui.connect_button.clicked()
636 self.ui.on_credentials_error(gui.U1_APP_NAME, {})
637
638 self.assertFalse(self.ui.get_property('greyed'), 'Must not be greyed.')
639
640 def test_on_authorization_denied_unset_greyed(self):
641 """Callback 'on_authorization_denied' unsets the 'greyed' prop."""
642 self.ui.connect_button.clicked()
643 self.ui.on_authorization_denied(gui.U1_APP_NAME)
644
645 self.assertFalse(self.ui.get_property('greyed'), 'Must not be greyed.')
646
647 def test_buttons_disabled_when_greyed(self):
648 """Buttons should be disabled when widget is greyed."""
649 self.ui.set_sensitive(True)
650 self.ui.set_property('greyed', True)
651
652 self.assertFalse(self.ui.join_now_button.is_sensitive())
653 self.assertFalse(self.ui.connect_button.is_sensitive())
654
655 def test_buttons_enabled_when_not_greyed(self):
656 """Buttons should be enabled when widget is not greyed."""
657 self.ui.set_sensitive(False)
658 self.ui.set_property('greyed', False)
659
660 self.assertTrue(self.ui.join_now_button.is_sensitive())
661 self.assertTrue(self.ui.connect_button.is_sensitive())
66242
66343
664class DashboardTestCase(ControlPanelMixinTestCase):44class DashboardTestCase(ControlPanelMixinTestCase):
@@ -727,7 +107,7 @@
727 self.ui.on_account_info_error()107 self.ui.on_account_info_error()
728108
729 self.assertFalse(self.ui.account.get_visible())109 self.assertFalse(self.ui.account.get_visible())
730 self.assert_warning_correct(self.ui.message, gui.VALUE_ERROR)110 self.assert_warning_correct(self.ui.message, self.ui.VALUE_ERROR)
731111
732112
733class VolumesTestCase(ControlPanelMixinTestCase):113class VolumesTestCase(ControlPanelMixinTestCase):
@@ -896,10 +276,61 @@
896 self.test_on_volumes_info_error()276 self.test_on_volumes_info_error()
897 self.test_on_volumes_info_ready_with_no_volumes()277 self.test_on_volumes_info_ready_with_no_volumes()
898278
279 def test_clicking_on_row_opens_folder(self):
280 """The folder activated is opened."""
281 self.patch(gui, 'uri_hook', self._set_called)
282 self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
283
284 self.ui.volumes_view.row_activated('0:0',
285 self.ui.volumes_view.get_column(0))
286
287 self.assertEqual(self._called,
288 ((None, gui.FILE_URI_PREFIX + ROOT['path']), {}))
289
290 def test_on_volumes_info_ready_with_music_folder(self):
291 """The volumes info is processed when ready."""
292 info = [(u'', u'147852369', [ROOT] + [MUSIC_FOLDER])]
293
294 self.ui.on_volumes_info_ready(info)
295
296 treeiter = self.ui.volumes_store.get_iter_root()
297 row = self.ui.volumes_store.get(treeiter, *xrange(self.ui.MAX_COLS))
298
299 # walk 'Mine' folders children
300 treeiter = self.ui.volumes_store.iter_children(treeiter)
301
302 # grab next row since first one is root
303 treeiter = self.ui.volumes_store.iter_next(treeiter)
304 row = self.ui.volumes_store.get(treeiter, *xrange(self.ui.MAX_COLS))
305
306 volume = MUSIC_FOLDER
307 expected_path = volume['path'].replace(USER_HOME, '~')
308 expected_path = expected_path.replace(self.ui.MUSIC_REAL_PATH,
309 self.ui.MUSIC_DISPLAY_NAME)
310 self.assertEqual(row[0], expected_path)
311 self.assertEqual(row[1], bool(volume['subscribed']))
312 self.assertEqual(row[2], self.ui.MUSIC_ICON_NAME)
313 self.assertTrue(row[3], 'toggle should be shown on child!')
314 self.assertTrue(row[4], 'toggle should be sensitive')
315 self.assertEqual(row[5], gui.gtk.ICON_SIZE_MENU)
316 self.assertEqual(row[6], volume['volume_id'])
317 self.assertEqual(row[7], volume['path'])
318
319
320class VolumesSubscriptionTestCase(VolumesTestCase):
321 """The test suite for the volumes panel."""
322
323 kwargs = {'main_window': object()}
324 tree_path = '0:3' # this is the /home/tester/foo folder, not subscribed
325
326 def setUp(self):
327 super(VolumesSubscriptionTestCase, self).setUp()
328 self.patch(gui.os.path, 'exists', lambda path: True)
329 self.ui.confirm_dialog.response_code = gui.gtk.RESPONSE_YES
330 self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
331
899 def test_on_subscribed_toggled(self):332 def test_on_subscribed_toggled(self):
900 """Clicking on 'subscribed' updates the folder subscription."""333 """Clicking on 'subscribed' updates the folder subscription."""
901 self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)
902
903 real_rows = len(FAKE_VOLUMES_INFO)334 real_rows = len(FAKE_VOLUMES_INFO)
904 data = zip(range(real_rows)[::2], FAKE_VOLUMES_INFO) # skip emtpy rows335 data = zip(range(real_rows)[::2], FAKE_VOLUMES_INFO) # skip emtpy rows
905 for parent, (_, _, volumes) in data:336 for parent, (_, _, volumes) in data:
@@ -930,8 +361,7 @@
930361
931 def test_on_volume_setting_changed(self):362 def test_on_volume_setting_changed(self):
932 """The setting for a volume was successfully changed."""363 """The setting for a volume was successfully changed."""
933 self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)364 self.ui.on_subscribed_toggled(None, self.tree_path)
934 self.ui.on_subscribed_toggled(None, "0:0")
935365
936 self.ui.on_volume_settings_changed(volume_id=None) # id not used366 self.ui.on_volume_settings_changed(volume_id=None) # id not used
937367
@@ -940,8 +370,7 @@
940370
941 def test_on_volume_setting_change_error(self):371 def test_on_volume_setting_change_error(self):
942 """The setting for a volume was not successfully changed."""372 """The setting for a volume was not successfully changed."""
943 self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)373 self.ui.on_subscribed_toggled(None, self.tree_path)
944 self.ui.on_subscribed_toggled(None, "0:0")
945374
946 self.patch(self.ui, 'load', self._set_called)375 self.patch(self.ui, 'load', self._set_called)
947 self.ui.on_volume_settings_change_error(volume_id=None,376 self.ui.on_volume_settings_change_error(volume_id=None,
@@ -949,16 +378,66 @@
949 # reload folders list to sanitize the info in volumes_store378 # reload folders list to sanitize the info in volumes_store
950 self.assertTrue(self._called, ((), {}))379 self.assertTrue(self._called, ((), {}))
951380
952 def test_clicking_on_row_opens_folder(self):381 def test_confirm_dialog(self):
953 """The folder activated is opened."""382 """The confirmation dialog is correct."""
954 self.patch(gui, 'uri_hook', self._set_called)383 dialog = self.ui.confirm_dialog
955 self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO)384
956385 self.assertEqual(dialog._args, ())
957 self.ui.volumes_view.row_activated('0:0',386 flags = gui.gtk.DIALOG_MODAL | gui.gtk.DIALOG_DESTROY_WITH_PARENT
958 self.ui.volumes_view.get_column(0))387 kwargs = dict(parent=self.kwargs['main_window'],
959388 flags=flags, type=gui.gtk.MESSAGE_WARNING,
960 self.assertEqual(self._called,389 buttons=gui.gtk.BUTTONS_YES_NO)
961 ((None, gui.FILE_URI_PREFIX + ROOT['path']), {}))390 self.assertEqual(dialog._kwargs, kwargs)
391
392 def test_subscribe_shows_confirmation_dialog(self):
393 """Clicking on subscribe displays a confirmation dialog."""
394 self.ui.on_subscribed_toggled(None, self.tree_path)
395
396 path = FAKE_FOLDERS_INFO[0]['path']
397 self.assertTrue(self.ui.confirm_dialog.was_run, 'dialog was run')
398 self.assertEqual(self.ui.confirm_dialog.markup,
399 self.ui.CONFIRM_MERGE % {'folder_path': path})
400 self.assertFalse(self.ui.confirm_dialog.is_visible, 'dialog was hid')
401
402 def test_subscribe_does_not_call_backend_if_dialog_closed(self):
403 """Backend is not called if users closes the confirmation dialog."""
404 self.ui.confirm_dialog.response_code = gui.gtk.RESPONSE_DELETE_EVENT
405 self.ui.on_subscribed_toggled(None, self.tree_path)
406
407 self.assertNotIn('change_volume_settings', self.ui.backend._called)
408 self.assertFalse(self.ui.is_processing)
409
410 def test_subscribe_does_not_call_backend_if_answer_is_no(self):
411 """Backend is not called if users clicks on 'No'."""
412 self.ui.confirm_dialog.response_code = gui.gtk.RESPONSE_NO
413 self.ui.on_subscribed_toggled(None, self.tree_path)
414
415 self.assertNotIn('change_volume_settings', self.ui.backend._called)
416 self.assertFalse(self.ui.is_processing)
417
418 def test_no_confirmation_if_no_local_folder(self):
419 """The confirmation dialog is not shown if local folder not present."""
420 self.patch(gui.os.path, 'exists', lambda path: False)
421 self.ui.on_subscribed_toggled(None, self.tree_path)
422
423 self.assertFalse(self.ui.confirm_dialog.was_run, 'dialog was not run')
424 self.assertFalse(self.ui.confirm_dialog.is_visible, 'dialog was hid')
425
426 def test_no_confirmation_if_unsubscribing(self):
427 """The confirmation dialog is not shown if unsubscribing."""
428 self.ui.on_subscribed_toggled(None, self.tree_path)
429
430 treeiter = self.ui.volumes_store.get_iter(self.tree_path)
431 assert self.ui.volumes_store.get_value(treeiter, 1)
432
433 # reset flags
434 self.ui.confirm_dialog.was_run = False
435 self.ui.confirm_dialog.is_visible = False
436
437 self.ui.on_subscribed_toggled(None, self.tree_path)
438
439 self.assertFalse(self.ui.confirm_dialog.was_run, 'dialog was not run')
440 self.assertFalse(self.ui.confirm_dialog.is_visible, 'dialog was hid')
962441
963442
964class DeviceTestCase(ControlPanelMixinTestCase):443class DeviceTestCase(ControlPanelMixinTestCase):
@@ -984,6 +463,12 @@
984 self.assertEqual(device.limit_bandwidth.get_active(),463 self.assertEqual(device.limit_bandwidth.get_active(),
985 bool(expected['limit_bandwidth']))464 bool(expected['limit_bandwidth']))
986465
466 config_enabled = self.ui.config_settings.get_sensitive()
467 self.assertEqual(device.configurable, config_enabled)
468
469 limit_enabled = self.ui.throttling_limits.get_sensitive()
470 self.assertEqual(device.limit_bandwidth.get_active(), limit_enabled)
471
987 value = int(expected['max_upload_speed']) // gui.KILOBYTES472 value = int(expected['max_upload_speed']) // gui.KILOBYTES
988 self.assertEqual(device.max_upload_speed.get_value_as_int(), value)473 self.assertEqual(device.max_upload_speed.get_value_as_int(), value)
989 value = int(expected['max_download_speed']) // gui.KILOBYTES474 value = int(expected['max_download_speed']) // gui.KILOBYTES
@@ -996,6 +481,9 @@
996 (self.ui.id, expected))481 (self.ui.id, expected))
997 self.assertEqual(self.ui.warning_label.get_text(), '')482 self.assertEqual(self.ui.warning_label.get_text(), '')
998483
484 limit_enabled = self.ui.throttling_limits.get_sensitive()
485 self.assertEqual(self.ui.limit_bandwidth.get_active(), limit_enabled)
486
999 def modify_settings(self):487 def modify_settings(self):
1000 """Modify settings so values actually change."""488 """Modify settings so values actually change."""
1001 new_val = not self.ui.show_all_notifications.get_active()489 new_val = not self.ui.show_all_notifications.get_active()
@@ -1087,13 +575,13 @@
1087 """A device can be updated from a dict."""575 """A device can be updated from a dict."""
1088 self.ui.update(configurable='')576 self.ui.update(configurable='')
1089 self.assertFalse(self.ui.configurable)577 self.assertFalse(self.ui.configurable)
1090 self.assertFalse(self.ui.throttling.get_visible())578 self.assertFalse(self.ui.config_settings.get_visible())
1091579
1092 def test_update_configurable(self):580 def test_update_configurable(self):
1093 """A device can be updated from a dict."""581 """A device can be updated from a dict."""
1094 self.ui.update(configurable='True')582 self.ui.update(configurable='True')
1095 self.assertTrue(self.ui.configurable)583 self.assertTrue(self.ui.configurable)
1096 self.assertTrue(self.ui.throttling.get_visible())584 self.assertTrue(self.ui.config_settings.get_visible())
1097585
1098 def test_update_show_all_notifications(self):586 def test_update_show_all_notifications(self):
1099 """A device can be updated from a dict."""587 """A device can be updated from a dict."""
@@ -1107,9 +595,11 @@
1107 """A device can be updated from a dict."""595 """A device can be updated from a dict."""
1108 self.ui.update(limit_bandwidth='')596 self.ui.update(limit_bandwidth='')
1109 self.assertFalse(self.ui.limit_bandwidth.get_active())597 self.assertFalse(self.ui.limit_bandwidth.get_active())
598 self.assertFalse(self.ui.throttling_limits.get_sensitive())
1110599
1111 self.ui.update(limit_bandwidth='True')600 self.ui.update(limit_bandwidth='True')
1112 self.assertTrue(self.ui.limit_bandwidth.get_active())601 self.assertTrue(self.ui.limit_bandwidth.get_active())
602 self.assertTrue(self.ui.throttling_limits.get_sensitive())
1113603
1114 def test_update_upload_speed(self):604 def test_update_upload_speed(self):
1115 """A device can be updated from a dict."""605 """A device can be updated from a dict."""
@@ -1610,7 +1100,8 @@
1610 klass = gui.Service1100 klass = gui.Service
1611 service_id = 'dc_test'1101 service_id = 'dc_test'
1612 name = u'Qué lindo test!'1102 name = u'Qué lindo test!'
1613 kwargs = {'service_id': service_id, 'name': name}1103 kwargs = {'service_id': service_id, 'name': name,
1104 'container': None, 'check_button': None}
16141105
1615 def test_is_an_box(self):1106 def test_is_an_box(self):
1616 """Inherits from gtk.VBox."""1107 """Inherits from gtk.VBox."""
@@ -1647,7 +1138,7 @@
1647 klass = gui.FileSyncService1138 klass = gui.FileSyncService
1648 service_id = 'file-sync'1139 service_id = 'file-sync'
1649 name = gui.FileSyncService.FILES_SERVICE_NAME1140 name = gui.FileSyncService.FILES_SERVICE_NAME
1650 kwargs = {}1141 kwargs = {'container': None, 'check_button': None, 'action_button': None}
16511142
1652 def test_backend_account_signals(self):1143 def test_backend_account_signals(self):
1653 """The proper signals are connected to the backend."""1144 """The proper signals are connected to the backend."""
@@ -1708,6 +1199,8 @@
1708 self.ui.on_files_disabled()1199 self.ui.on_files_disabled()
1709 self.assertFalse(self.ui.button.get_active())1200 self.assertFalse(self.ui.button.get_active())
17101201
1202FileSyncServiceTestCase.skip = 'LP: #729349'
1203
17111204
1712class DesktopcouchServiceTestCase(ServiceTestCase):1205class DesktopcouchServiceTestCase(ServiceTestCase):
1713 """The test suite for a desktopcouch service."""1206 """The test suite for a desktopcouch service."""
@@ -1812,6 +1305,8 @@
18121305
1813 self.assertEqual(self.ui.warning_label.get_text(), '')1306 self.assertEqual(self.ui.warning_label.get_text(), '')
18141307
1308DesktopcouchServiceTestCase.skip = 'LP: #729349'
1309
18151310
1816class DesktopcouchServiceDisabledAtStartupTestCase(ServiceTestCase):1311class DesktopcouchServiceDisabledAtStartupTestCase(ServiceTestCase):
1817 """The test suite for a desktopcouch service when enabled=False."""1312 """The test suite for a desktopcouch service when enabled=False."""
@@ -1854,6 +1349,8 @@
1854 self.assertEqual(sorted(self.ui.get_children()),1349 self.assertEqual(sorted(self.ui.get_children()),
1855 sorted([self.ui.button, self.ui.warning_label]))1350 sorted([self.ui.button, self.ui.warning_label]))
18561351
1352DesktopcouchServiceWithDependencyTestCase.skip = 'LP: #729349'
1353
18571354
1858class ServicesTestCase(ControlPanelMixinTestCase):1355class ServicesTestCase(ControlPanelMixinTestCase):
1859 """The test suite for the services panel."""1356 """The test suite for the services panel."""
@@ -1902,6 +1399,8 @@
1902 child, = self.ui.files.get_children()1399 child, = self.ui.files.get_children()
1903 self.assertIsInstance(child, gui.FileSyncService)1400 self.assertIsInstance(child, gui.FileSyncService)
19041401
1402 test_files_is_a_file_sync_service.skip = 'LP: #729349'
1403
19051404
1906class ServicesWithoutDesktopcouchTestCase(ServicesTestCase):1405class ServicesWithoutDesktopcouchTestCase(ServicesTestCase):
1907 """The test suite for the services panel when DC is not installed."""1406 """The test suite for the services panel when DC is not installed."""
@@ -2004,6 +1503,30 @@
2004 self.ui.on_replications_info_ready(info=FAKE_REPLICATIONS_INFO)1503 self.ui.on_replications_info_ready(info=FAKE_REPLICATIONS_INFO)
2005 self.test_replications()1504 self.test_replications()
20061505
1506 def test_service_name_in_mapping(self):
1507 """If available, use a user-friendly, translatable service name."""
1508 for sid, name in self.ui.service_names.iteritems():
1509 info = [{'replication_id': sid, 'name': 'Bar',
1510 'enabled': 'True', 'dependency': ''}]
1511 self.ui.on_replications_info_ready(info=info)
1512
1513 child, = self.ui.replications.get_children()
1514 self.assertEqual(child.button.get_label(), name)
1515
1516 def test_service_name_not_in_mapping(self):
1517 """If available, use a user-friendly, translatable service name."""
1518 sid = 'not-in-mapping'
1519 assert sid not in self.ui.service_names
1520
1521 info = [{'replication_id': sid, 'name': 'Bar',
1522 'enabled': 'True', 'dependency': ''}]
1523 self.ui.on_replications_info_ready(info=info)
1524
1525 child, = self.ui.replications.get_children()
1526 self.assertEqual(child.button.get_label(), info[0]['name'])
1527
1528ServicesWithDesktopcouchTestCase.skip = 'LP: #729349'
1529
20071530
2008class ServicesWithDesktopcouchErrorTestCase(ServicesTestCase):1531class ServicesWithDesktopcouchErrorTestCase(ServicesTestCase):
2009 """The test suite for the services panel."""1532 """The test suite for the services panel."""
@@ -2046,6 +1569,8 @@
2046 self.assertFalse(self.ui.message.active)1569 self.assertFalse(self.ui.message.active)
2047 self.assert_warning_correct(self.ui.message, gui.VALUE_ERROR)1570 self.assert_warning_correct(self.ui.message, gui.VALUE_ERROR)
20481571
1572ServicesWithDesktopcouchErrorTestCase.skip = 'LP: #729349'
1573
20491574
2050class FileSyncStatusTestCase(ControlPanelMixinTestCase):1575class FileSyncStatusTestCase(ControlPanelMixinTestCase):
2051 """Test case for a file sync status widget."""1576 """Test case for a file sync status widget."""
@@ -2065,7 +1590,8 @@
2065 """1590 """
2066 self.assertTrue(self.ui.label.get_visible())1591 self.assertTrue(self.ui.label.get_visible())
2067 self.assertFalse(self.ui.label.active)1592 self.assertFalse(self.ui.label.active)
2068 self.assertTrue(self.ui.label.get_label().endswith(status))1593 msg = '%r does not end with %r' % (self.ui.label.get_label(), status)
1594 self.assertTrue(self.ui.label.get_label().endswith(status), msg)
20691595
2070 self.assertTrue(self.ui.button.is_sensitive())1596 self.assertTrue(self.ui.button.is_sensitive())
2071 self.assertFalse(self.ui.button.get_visited())1597 self.assertFalse(self.ui.button.get_visited())
@@ -2212,10 +1738,21 @@
2212 action=self.ui.DISCONNECT,1738 action=self.ui.DISCONNECT,
2213 tooltip=self.ui.DISCONNECT_TOOLTIP)1739 tooltip=self.ui.DISCONNECT_TOOLTIP)
22141740
2215 def test_on_file_sync_status_error(self):1741 def test_on_file_sync_status_error_with_error_msg(self):
2216 """The file sync status couldn't be retrieved."""1742 """The file sync status couldn't be retrieved."""
2217 self.patch(self.ui, 'on_restart_clicked', self._set_called)1743 self.patch(self.ui, 'on_restart_clicked', self._set_called)
2218 self.ui.on_file_sync_status_error({'error_msg': 'error msg'})1744 msg = 'error message'
1745 self.ui.on_file_sync_status_error({'error_msg': msg})
1746
1747 msg = gui.WARNING_MARKUP % (self.ui.FILE_SYNC_ERROR + ' (' + msg + ')')
1748 self.assert_status_correct(msg,
1749 action=self.ui.RESTART,
1750 tooltip=self.ui.RESTART_TOOLTIP)
1751
1752 def test_on_file_sync_status_error_without_error_msg(self):
1753 """The file sync status couldn't be retrieved."""
1754 self.patch(self.ui, 'on_restart_clicked', self._set_called)
1755 self.ui.on_file_sync_status_error()
22191756
2220 msg = gui.WARNING_MARKUP % self.ui.FILE_SYNC_ERROR1757 msg = gui.WARNING_MARKUP % self.ui.FILE_SYNC_ERROR
2221 self.assert_status_correct(msg,1758 self.assert_status_correct(msg,
@@ -2276,17 +1813,21 @@
2276 """Check that the displayed account info matches 'info'."""1813 """Check that the displayed account info matches 'info'."""
2277 used = int(info['quota_used'])1814 used = int(info['quota_used'])
2278 total = int(info['quota_total'])1815 total = int(info['quota_total'])
2279 percentage = (used / total) * 1001816 percentage = round((used / total) * 100, 2)
2280 expected = {'used': self.ui.humanize(used),1817 expected = {'used': self.ui.humanize(used),
2281 'total': self.ui.humanize(total),1818 'total': self.ui.humanize(total),
2282 'percentage': percentage}1819 'percentage': percentage}
2283 self.assertEqual(self.ui.quota_label.get_text(),1820 msg = self.ui.QUOTA_LABEL % expected
2284 self.ui.QUOTA_LABEL % expected)1821 self.assertEqual(self.ui.quota_label.get_text(), msg)
1822
1823 if percentage >= self.ui.QUOTA_THRESHOLD * 100:
1824 self.assert_warning_correct(self.ui.quota_label, msg)
22851825
2286 if progressbar_fraction is None:1826 if progressbar_fraction is None:
2287 progressbar_fraction = percentage / 1001827 progressbar_fraction = min(percentage / 100, 1)
2288 self.assertEqual(self.ui.quota_progressbar.get_fraction(),1828 self.assertEqual(self.ui.quota_progressbar.get_fraction(),
2289 progressbar_fraction)1829 progressbar_fraction)
1830 self.assertTrue(self.ui.quota_progressbar.get_sensitive())
22901831
2291 def test_is_a_vbox(self):1832 def test_is_a_vbox(self):
2292 """Inherits from gtk.VBox."""1833 """Inherits from gtk.VBox."""
@@ -2386,13 +1927,13 @@
23861927
2387 self.assertEqual(self._called, ((), {}))1928 self.assertEqual(self._called, ((), {}))
23881929
2389 def test_entering_services_tab_loads_content(self):1930 def test_entering_services_tab_does_not_load_content(self):
2390 """The services info is loaded when entering the Devices tab."""1931 """The services info is not loaded when entering the Services tab."""
2391 self.patch(self.ui.services, 'load', self._set_called)1932 self.patch(self.ui.services, 'load', self._set_called)
2392 # clean backend calls1933 # clean backend calls
2393 self.ui.services_button.clicked()1934 self.ui.services_button.clicked()
23941935
2395 self.assertEqual(self._called, ((), {}))1936 self.assertEqual(self._called, False)
23961937
2397 def test_quota_placeholder_is_loading(self):1938 def test_quota_placeholder_is_loading(self):
2398 """Placeholders for quota label is a Loading widget."""1939 """Placeholders for quota label is a Loading widget."""
@@ -2403,16 +1944,20 @@
2403 """The account info is processed when ready."""1944 """The account info is processed when ready."""
2404 self.ui.on_account_info_ready(FAKE_ACCOUNT_INFO)1945 self.ui.on_account_info_ready(FAKE_ACCOUNT_INFO)
2405 self.assert_account_info_correct(FAKE_ACCOUNT_INFO)1946 self.assert_account_info_correct(FAKE_ACCOUNT_INFO)
24061947 self.assertFalse(self.ui.quota_label.active)
2407 for widget in (self.ui.quota_label,):
2408 self.assertFalse(widget.active)
24091948
2410 def test_on_account_info_error(self):1949 def test_on_account_info_error(self):
2411 """The account info couldn't be retrieved."""1950 """The account info couldn't be retrieved."""
2412 self.ui.on_account_info_error()1951 self.ui.on_account_info_error()
2413 for widget in (self.ui.quota_label,):1952 self.assertEqual(self.ui.quota_label.get_text(), '')
2414 self.assert_warning_correct(widget, gui.VALUE_ERROR)1953 self.assertEqual(self.ui.quota_progressbar.get_fraction(), 0)
2415 self.assertFalse(widget.active)1954 self.assertFalse(self.ui.quota_progressbar.get_sensitive())
1955 self.assertFalse(self.ui.quota_label.active)
1956
1957 def test_on_account_info_error_after_success(self):
1958 """The account info couldn't be retrieved."""
1959 self.test_on_account_info_ready()
1960 self.test_on_account_info_error()
24161961
2417 def test_on_account_info_ready_quota_unused(self):1962 def test_on_account_info_ready_quota_unused(self):
2418 """The used quota is correct when unused."""1963 """The used quota is correct when unused."""
@@ -2429,6 +1974,26 @@
24291974
2430 self.assert_account_info_correct(info, progressbar_fraction=0.05)1975 self.assert_account_info_correct(info, progressbar_fraction=0.05)
24311976
1977 def test_on_account_info_ready_quota_used_at_threshold(self):
1978 """Show red notification when quota usage is same as threshold."""
1979 info = FAKE_ACCOUNT_INFO.copy()
1980
1981 info['quota_total'] = '12345678'
1982 info['quota_used'] = str(int(int(info['quota_total']) *
1983 self.ui.QUOTA_THRESHOLD))
1984 self.ui.on_account_info_ready(info)
1985
1986 self.assert_account_info_correct(info)
1987
1988 def test_on_account_info_ready_quota_over_threshold(self):
1989 """Show red notification when quota usage is higher than threshold."""
1990 info = FAKE_ACCOUNT_INFO.copy()
1991 info['quota_total'] = '12345678'
1992 info['quota_used'] = info['quota_total'] + '0'
1993 self.ui.on_account_info_ready(info)
1994
1995 self.assert_account_info_correct(info)
1996
2432 def test_file_sync_status(self):1997 def test_file_sync_status(self):
2433 """The file sync status is shown correctly."""1998 """The file sync status is shown correctly."""
2434 self.assertIsInstance(self.ui.status_label, gui.FileSyncStatus)1999 self.assertIsInstance(self.ui.status_label, gui.FileSyncStatus)
24352000
=== added file 'ubuntuone/controlpanel/gtk/tests/test_gui_basic.py'
--- ubuntuone/controlpanel/gtk/tests/test_gui_basic.py 1970-01-01 00:00:00 +0000
+++ ubuntuone/controlpanel/gtk/tests/test_gui_basic.py 2011-03-10 03:11:54 +0000
@@ -0,0 +1,595 @@
1# -*- coding: utf-8 -*-
2
3# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
4#
5# Copyright 2010 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""The test suite for the control panel user interface (basics)."""
20
21from __future__ import division
22
23from ubuntuone.controlpanel.gtk import gui
24from ubuntuone.controlpanel.gtk.tests import BaseTestCase, FakedSSOBackend
25from ubuntuone.controlpanel.tests import TOKEN
26
27
28# Attribute 'yyy' defined outside __init__, access to a protected member
29# pylint: disable=W0201, W0212
30
31
32class ControlPanelMixinTestCase(BaseTestCase):
33 """The test suite for the control panel widget."""
34
35 klass = gui.ControlPanelMixin
36 ui_filename = None
37
38 def test_is_a_control_panel_mixin(self):
39 """Inherits from ControlPanelMixin."""
40 self.assertIsInstance(self.ui, gui.ControlPanelMixin)
41
42 def test_ui_can_be_created(self):
43 """UI main class exists and can be created."""
44 self.assertTrue(self.ui is not None)
45
46
47class ControlPanelWindowTestCase(BaseTestCase):
48 """The test suite for the control panel window."""
49
50 klass = gui.ControlPanelWindow
51
52 def test_is_a_window(self):
53 """Inherits from gtk.Window."""
54 self.assertIsInstance(self.ui, gui.gtk.Window)
55
56 def test_startup_visibility(self):
57 """The widget is visible at startup."""
58 self.assertTrue(self.ui.get_visible(), 'must be visible at startup.')
59
60 def test_main_start_gtk_main_loop(self):
61 """The GTK main loop is started when calling main()."""
62 self.patch(gui.gtk, 'main', self._set_called)
63 self.ui.main()
64 self.assertEqual(self._called, ((), {}), 'gtk.main was called.')
65
66 def test_closing_stops_the_main_lopp(self):
67 """The GTK main loop is stopped when closing the window."""
68 self.patch(gui.gtk, 'main_quit', self._set_called)
69 self.ui.emit('delete-event', None)
70 self.assertEqual(self._called, ((), {}), 'gtk.main_quit was called.')
71
72 def test_title_is_correct(self):
73 """The window title is correct."""
74 expected = self.ui.TITLE % {'app_name': gui.U1_APP_NAME}
75 self.assertEqual(self.ui.get_title(), expected)
76
77 def test_control_panel_is_the_only_child(self):
78 """The control panel is the window's content."""
79 children = self.ui.get_children()
80 self.assertEqual(1, len(children))
81
82 control_panel = self.ui.get_children()[0]
83 self.assertTrue(control_panel is self.ui.control_panel)
84 self.assertIsInstance(self.ui.control_panel, gui.ControlPanel)
85 self.assertTrue(self.ui.control_panel.get_visible())
86
87 def test_main_window_is_passed_to_child(self):
88 """The child gets the main_window."""
89 self.assertEqual(self.ui.control_panel.main_window, self.ui)
90
91 def test_icon_name_is_correct(self):
92 """The icon name is correct."""
93 self.assertEqual(self.ui.get_icon_name(), 'ubuntuone')
94
95 def test_max_size(self):
96 """Max size is not bigger than 736x525 (LP: #645526, LP: #683164)."""
97 self.assertTrue(self.ui.get_size_request() <= (736, 525))
98
99
100class ControlPanelWindowParamsTestCase(ControlPanelWindowTestCase):
101 """The test suite for the control panel window when passing params."""
102
103 kwargs = {'switch_to': 'devices'}
104
105 def test_switch_to(self):
106 """Can pass a 'switch_to' parameter to start on a particular tab."""
107 actual = self.ui.control_panel.management.notebook.get_current_page()
108 self.assertEqual(actual, self.ui.control_panel.management.DEVICES_PAGE)
109
110
111class ControlPanelWindowParamsNoneTestCase(ControlPanelWindowTestCase):
112 """The suite for the control panel window when passing None params."""
113
114 kwargs = {'switch_to': None}
115
116 def test_switch_to(self):
117 """Can pass a 'switch_to' being None. Should default to dashboard."""
118 actual = self.ui.control_panel.management.notebook.get_current_page()
119 expected = self.ui.control_panel.management.DASHBOARD_PAGE
120 self.assertEqual(actual, expected)
121
122
123class ControlPanelWindowInvalidParamsTestCase(ControlPanelWindowTestCase):
124 """The suite for the control panel window when passing invalid params."""
125
126 kwargs = {'switch_to': 'yadda-yadda'}
127
128 def test_switch_to(self):
129 """Can pass an invalid 'switch_to'. Should default to dashboard."""
130 actual = self.ui.control_panel.management.notebook.get_current_page()
131 expected = self.ui.control_panel.management.DASHBOARD_PAGE
132 self.assertEqual(actual, expected)
133
134
135class ControlPanelTestCase(BaseTestCase):
136 """The test suite for the control panel itself."""
137
138 klass = gui.ControlPanel
139 kwargs = {'main_window': object()}
140
141 def assert_current_tab_correct(self, expected_tab):
142 """Check that the wiget 'expected_tab' is the current page."""
143 actual = self.ui.get_nth_page(self.ui.get_current_page())
144 self.assertTrue(expected_tab is actual)
145
146 def test_is_a_notebook(self):
147 """Inherits from gtk.VBox."""
148 self.assertIsInstance(self.ui, gui.gtk.Notebook)
149
150 def test_startup_visibility(self):
151 """The widget is visible at startup."""
152 self.assertTrue(self.ui.get_visible(),
153 'must be visible at startup.')
154
155 def test_startup_props(self):
156 """The tabs and border are not shown."""
157 self.assertFalse(self.ui.get_show_border(), 'must not show border.')
158 self.assertFalse(self.ui.get_show_tabs(), 'must not show tabs.')
159
160 def test_overview_is_shown_at_startup(self):
161 """The overview is shown at startup."""
162 self.assertIsInstance(self.ui.overview, gui.OverviewPanel)
163 self.assert_current_tab_correct(self.ui.overview)
164
165 def test_main_window_is_passed_to_child(self):
166 """The child gets the main_window."""
167 self.assertEqual(self.ui.overview.main_window,
168 self.kwargs['main_window'])
169
170 def test_on_show_management_panel(self):
171 """A ManagementPanel is shown when the callback is executed."""
172 self.ui.on_show_management_panel()
173 self.assert_current_tab_correct(self.ui.management)
174
175 def test_on_show_management_panel_is_idempotent(self):
176 """Only one ManagementPanel is shown."""
177 self.ui.on_show_management_panel()
178 self.ui.on_show_management_panel()
179
180 self.assert_current_tab_correct(self.ui.management)
181
182 def test_credentials_found_shows_dashboard_management_panel(self):
183 """On 'credentials-found' signal, the management panel is shown.
184
185 If first signal parameter is False, visible tab should be dashboard.
186
187 """
188 self.patch(self.ui.management, 'load', self._set_called)
189 self.ui.overview.emit('credentials-found', False, object())
190
191 self.assert_current_tab_correct(self.ui.management)
192 self.assertEqual(self.ui.management.notebook.get_current_page(),
193 self.ui.management.DASHBOARD_PAGE)
194 self.assertEqual(self._called, ((), {}))
195
196 def test_credentials_found_shows_volumes_management_panel(self):
197 """On 'credentials-found' signal, the management panel is shown.
198
199 If first signal parameter is True, visible tab should be volumes.
200
201 """
202 a_token = object()
203 self.ui.overview.emit('credentials-found', True, a_token)
204
205 self.assert_current_tab_correct(self.ui.management)
206 self.assertEqual(self.ui.management.notebook.get_current_page(),
207 self.ui.management.VOLUMES_PAGE)
208
209 def test_local_device_removed_shows_overview_panel(self):
210 """On 'local-device-removed' signal, the overview panel is shown."""
211 self.ui.overview.emit('credentials-found', True, object())
212 self.ui.management.emit('local-device-removed')
213
214 self.assert_current_tab_correct(self.ui.overview)
215
216
217class UbuntuOneBinTestCase(BaseTestCase):
218 """The test suite for a Ubuntu One panel."""
219
220 klass = gui.UbuntuOneBin
221 kwargs = {'title': 'Something old, something new and something blue.'}
222
223 def test_is_a_vbox(self):
224 """Inherits from proper gtk widget."""
225 self.assertIsInstance(self.ui, gui.gtk.VBox)
226
227 def test_startup_visibility(self):
228 """The widget is visible at startup."""
229 self.assertTrue(self.ui.get_visible(),
230 'must be visible at startup.')
231 for child in self.ui.get_children():
232 self.assertTrue(child.get_visible())
233
234 def test_title_is_a_panel_title(self):
235 """Title is the correct widget."""
236 self.assertIsInstance(self.ui.title, gui.PanelTitle)
237 self.assertIn(self.ui.title, self.ui.get_children())
238
239 def test_title_markup_is_correct(self):
240 """The title markup is correctly set when passed as argument."""
241 self.assertEqual(self.ui.title.label.get_text(), self.kwargs['title'])
242
243 def test_title_is_correct(self):
244 """The title markup is correctly set when defined at class level."""
245 ui = self.klass() # no title given
246 self.assertEqual(ui.title.label.get_text(), '')
247
248 def test_message_is_a_label_loading(self):
249 """Message is the correct widget."""
250 self.assertIsInstance(self.ui.message, gui.LabelLoading)
251 self.assertIn(self.ui.message, self.ui.get_children())
252
253 def test_on_success(self):
254 """Callback to stop the Loading and clear messages."""
255 self.ui.on_success()
256 self.assertEqual(self.ui.message.get_label(), '')
257 self.assertFalse(self.ui.message.active)
258
259 def test_on_success_with_message(self):
260 """Callback to stop the Loading and show a info message."""
261 msg = 'WOW! <i>this rocks</i>'
262 self.ui.on_success(message=msg)
263 self.assertEqual(self.ui.message.get_label(), msg)
264 self.assertFalse(self.ui.message.active)
265
266 def test_on_error(self):
267 """Callback to stop the Loading and clear messages."""
268 self.ui.on_error()
269 self.assert_warning_correct(self.ui.message, gui.VALUE_ERROR)
270 self.assertFalse(self.ui.message.active)
271
272 def test_on_error_with_message(self):
273 """Callback to stop the Loading and show a info message."""
274 msg = 'WOW! <i>this does not rock</i> :-/'
275 self.ui.on_error(message=msg)
276 self.assert_warning_correct(self.ui.message, msg)
277 self.assertFalse(self.ui.message.active)
278
279 def test_is_processing(self):
280 """The flag 'is_processing' is False on start."""
281 self.assertFalse(self.ui.is_processing)
282 self.assertTrue(self.ui.is_sensitive())
283
284 def test_set_is_processing(self):
285 """When setting 'is_processing', the spinner is shown."""
286 self.ui.is_processing = False
287 self.ui.is_processing = True
288
289 self.assertTrue(self.ui.message.get_visible())
290 self.assertTrue(self.ui.message.active)
291 self.assertFalse(self.ui.is_sensitive())
292
293 def test_unset_is_processing(self):
294 """When unsetting 'is_processing', the spinner is not shown."""
295 self.ui.is_processing = True
296 self.ui.is_processing = False
297
298 self.assertTrue(self.ui.message.get_visible())
299 self.assertFalse(self.ui.message.active)
300 self.assertTrue(self.ui.is_sensitive())
301
302
303class OverwiewPanelTestCase(ControlPanelMixinTestCase):
304 """The test suite for the overview panel."""
305
306 klass = gui.OverviewPanel
307 kwargs = {'main_window': gui.gtk.Window()}
308 ui_filename = 'overview.ui'
309
310 def test_is_a_greyable_bin(self):
311 """Inherits from GreyableBin."""
312 self.assertIsInstance(self.ui, gui.GreyableBin)
313
314 def test_inner_widget_is_packed(self):
315 """The 'itself' vbox is packed into the widget."""
316 self.assertIn(self.ui.itself, self.ui.get_children())
317
318 def test_join_now_is_default(self):
319 """The 'join_now' button is the default widget."""
320 self.assertTrue(self.ui.join_now_button.get_property('can-default'))
321
322 def test_sso_backend(self):
323 """Has a correct SSO backend."""
324 self.assertIsInstance(self.ui.sso_backend, FakedSSOBackend)
325
326 def test_sso_backend_signals(self):
327 """The proper signals are connected to the backend."""
328 self.assertEqual(self.ui.sso_backend._signals['CredentialsFound'],
329 [self.ui.on_credentials_found])
330 self.assertEqual(self.ui.sso_backend._signals['CredentialsNotFound'],
331 [self.ui.on_credentials_not_found])
332 self.assertEqual(self.ui.sso_backend._signals['CredentialsError'],
333 [self.ui.on_credentials_error])
334 self.assertEqual(self.ui.sso_backend._signals['AuthorizationDenied'],
335 [self.ui.on_authorization_denied])
336
337
338class OverwiewNetworkStatePanelTestCase(OverwiewPanelTestCase):
339 """The test suite for the overview panel regarding network state."""
340
341 def test_network_state_is_created(self):
342 """The network state is created."""
343 self.assertIsInstance(self.ui.network_manager_state,
344 gui.networkstate.NetworkManagerState)
345 self.assertEqual(self.ui.network_manager_state._kwargs['result_cb'],
346 self.ui.on_network_state_changed)
347
348 def test_network_state_is_queried_at_startup(self):
349 """The network state is asked to the NetworkManagerState."""
350 self.assertTrue('find_online_state' in
351 self.ui.network_manager_state._called)
352
353 def test_state_online(self):
354 """Network connection is online."""
355 self.ui.on_network_state_changed(gui.networkstate.ONLINE)
356 # all green, no warning
357 self.assertEqual(self.ui.warning_label.get_text(), '')
358 self.assertTrue(self.ui.get_sensitive())
359
360 def test_state_offline(self):
361 """Network connection is offline."""
362 self.ui.on_network_state_changed(gui.networkstate.OFFLINE)
363 msg = self.ui.NETWORK_OFFLINE % {'app_name': gui.U1_APP_NAME}
364
365 self.assert_warning_correct(self.ui.warning_label, msg)
366 self.assertFalse(self.ui.get_sensitive())
367
368 def test_state_unknown(self):
369 """Network connection is unknown. Assume that connection is present."""
370 self.ui.on_network_state_changed(gui.networkstate.UNKNOWN)
371
372 self.assertEqual(self.ui.warning_label.get_text(), '')
373 self.assertTrue(self.ui.get_sensitive())
374
375
376class OverwiewPanelOnlineTestCase(OverwiewPanelTestCase):
377 """The test suite for the overview panel."""
378
379 def setUp(self):
380 super(OverwiewPanelOnlineTestCase, self).setUp()
381 self.ui.on_network_state_changed(gui.networkstate.ONLINE)
382
383 def test_find_credentials_is_called(self):
384 """Credentials are asked to SSO backend."""
385 self.assertFalse(self.ui._credentials_are_new)
386 self.assert_backend_called('find_credentials', (gui.U1_APP_NAME, {}),
387 backend=self.ui.sso_backend)
388
389 def test_on_credentials_found(self):
390 """Callback 'on_credentials_found' is correct."""
391 self.ui.connect('credentials-found', self._set_called)
392
393 self.ui.on_credentials_found(gui.U1_APP_NAME, TOKEN)
394
395 self.assertFalse(self.ui.get_property('greyed'), 'Must not be greyed.')
396 # assume credentials were in local keyring
397 self.assertEqual(self._called, ((self.ui, False, TOKEN), {}))
398
399 def test_on_credentials_found_when_creds_are_not_new(self):
400 """Callback 'on_credentials_found' distinguish if creds are new."""
401 self.ui.connect('credentials-found', self._set_called)
402
403 # credentials weren't in the system
404 self.ui.on_credentials_not_found(gui.U1_APP_NAME)
405 # now they are!
406 self.ui.on_credentials_found(gui.U1_APP_NAME, TOKEN)
407
408 self.assertFalse(self.ui.get_property('greyed'), 'Must not be greyed.')
409 # assume credentials were not in local keyring
410 self.assertEqual(self._called, ((self.ui, True, TOKEN), {}))
411
412 def test_on_credentials_not_found(self):
413 """Callback 'on_credentials_not_found' is correct."""
414 self.ui.on_credentials_not_found(gui.U1_APP_NAME)
415 self.assertTrue(self.ui.get_visible())
416 self.assertTrue(self.ui._credentials_are_new)
417
418 def test_on_credentials_error(self):
419 """Callback 'on_credentials_error' is correct."""
420 self.ui.on_credentials_error(gui.U1_APP_NAME, {})
421 self.assertTrue(self.ui.get_visible())
422 self.assert_warning_correct(self.ui.warning_label,
423 self.ui.CREDENTIALS_ERROR)
424
425 def test_on_authorization_denied(self):
426 """Callback 'on_authorization_denied' is correct."""
427 self.ui.on_authorization_denied(gui.U1_APP_NAME)
428 self.assertTrue(self.ui.get_visible())
429 self.assertFalse(self.ui.get_property('greyed'), 'Must not be greyed.')
430 self.assertEqual(self.ui.warning_label.get_text(), '')
431
432
433class OverwiewPanelAppNameMismatchTestCase(OverwiewPanelTestCase):
434 """The test suite for the overview panel when the app_name won't match."""
435
436 NOT_U1_APP = 'Not ' + gui.U1_APP_NAME
437
438 def test_filter_by_app_name(self):
439 """The filter_by_app_name decorator is correct."""
440 f = gui.filter_by_app_name(self._set_called)
441 f(self.ui, self.NOT_U1_APP)
442 self.assertFalse(self._called)
443 self.assertTrue(self.memento.check_info('ignoring', self.NOT_U1_APP))
444
445 args = ('test', object())
446 kwargs = {'really': 'AWESOME'}
447 f(self.ui, gui.U1_APP_NAME, *args, **kwargs)
448 self.assertEqual(self._called,
449 ((self.ui, gui.U1_APP_NAME,) + args, kwargs))
450
451 def test_on_credentials_found(self):
452 """Callback 'on_credentials_found' is not executed."""
453 self.assert_function_decorated(gui.filter_by_app_name,
454 self.ui.on_credentials_found)
455
456 def test_on_credentials_not_found(self):
457 """Callback 'on_credentials_not_found' is not executed."""
458 self.assert_function_decorated(gui.filter_by_app_name,
459 self.ui.on_credentials_not_found)
460
461 def test_on_credentials_error(self):
462 """Callback 'on_credentials_error' is not executed."""
463 self.assert_function_decorated(gui.filter_by_app_name,
464 self.ui.on_credentials_error)
465
466 def test_on_authorization_denied(self):
467 """Callback 'on_authorization_denied' is not executed."""
468 self.assert_function_decorated(gui.filter_by_app_name,
469 self.ui.on_authorization_denied)
470
471
472class OverwiewPanelNoCredsTestCase(OverwiewPanelTestCase):
473 """The test suite for the overview panel when no credentials are found."""
474
475 def setUp(self):
476 super(OverwiewPanelNoCredsTestCase, self).setUp()
477 self.ui.on_credentials_not_found(gui.U1_APP_NAME)
478
479 def test_startup_visibility(self):
480 """The widget is visible at startup."""
481 self.assertTrue(self.ui.get_visible(),
482 'must be visible at startup if credentials not found.')
483
484 def test_warning_label_is_hidden(self):
485 """The warning label is not shown by default."""
486 self.assertEqual(self.ui.warning_label.get_text(), '')
487
488 def test_image_is_correct(self):
489 """There is an image attribute and is correct."""
490 self.assert_image_equal(self.ui.image, 'overview.png')
491
492 def test_join_now_is_default_widget(self):
493 """The join now button is the default widget."""
494 self.assertTrue(self.ui.join_now_button.get_property('can_default'))
495
496 def test_join_now_button_clicked(self):
497 """Test the 'join now' button callback."""
498 self.kwargs['main_window'].show() # ensure parent window is realized
499 self.addCleanup(self.kwargs['main_window'].hide)
500
501 self.ui.join_now_button.clicked()
502
503 window_id = self.kwargs['main_window'].window.xid
504 args = (gui.U1_APP_NAME,
505 {gui.TC_URL_KEY: gui.U1_TC_URL,
506 gui.HELP_TEXT_KEY: gui.U1_DESCRIPTION,
507 gui.WINDOW_ID_KEY: str(window_id),
508 gui.PING_URL_KEY: gui.U1_PING_URL})
509 self.assert_backend_called('register', args,
510 backend=self.ui.sso_backend)
511
512 def test_connect_button_clicked(self):
513 """Test the 'join now' button callback."""
514 self.kwargs['main_window'].show() # ensure parent window is realized
515 self.addCleanup(self.kwargs['main_window'].hide)
516
517 self.ui.connect_button.clicked()
518
519 window_id = self.kwargs['main_window'].window.xid
520 args = (gui.U1_APP_NAME,
521 {gui.TC_URL_KEY: gui.U1_TC_URL,
522 gui.HELP_TEXT_KEY: gui.U1_DESCRIPTION,
523 gui.WINDOW_ID_KEY: str(window_id),
524 gui.PING_URL_KEY: gui.U1_PING_URL})
525 self.assert_backend_called('login', args,
526 backend=self.ui.sso_backend)
527
528 def test_join_now_button_clicked_set_greyed(self):
529 """Clicking on 'join_now' self is greyed."""
530 self.ui.join_now_button.clicked()
531 self.assertTrue(self.ui.get_property('greyed'), 'Must be greyed.')
532
533 def test_join_now_button_clicked_removes_warning(self):
534 """Clicking on 'join_now' the warnings are removed."""
535 self.ui.on_authorization_denied(gui.U1_APP_NAME) # show warning
536 self.ui.join_now_button.clicked()
537
538 self.assertEqual(self.ui.warning_label.get_text(), '')
539
540 def test_connect_button_clicked_set_greyed(self):
541 """Clicking on 'connect' self is greyed."""
542 self.ui.connect_button.clicked()
543 self.assertTrue(self.ui.get_property('greyed'), 'Must be greyed.')
544
545 def test_connect_button_clicked_removes_warning(self):
546 """Clicking on 'connect' the warnings are removed."""
547 self.ui.on_authorization_denied(gui.U1_APP_NAME) # show warning
548 self.ui.connect_button.clicked()
549
550 self.assertEqual(self.ui.warning_label.get_text(), '')
551
552 def test_learn_more_button_clicked(self):
553 """Test the 'learn more' button callback."""
554 self.patch(gui, 'uri_hook', self._set_called)
555 self.ui.learn_more_button.clicked()
556
557 expected = (self.ui.learn_more_button, self.ui.LEARN_MORE_LINK)
558 self.assertEqual(self._called, (expected, {}))
559
560 def test_on_credentials_not_found_unset_greyed(self):
561 """Callback 'on_credentials_not_found' unsets the 'greyed' prop."""
562 self.ui.connect_button.clicked()
563 self.ui.on_credentials_not_found(gui.U1_APP_NAME)
564
565 self.assertFalse(self.ui.get_property('greyed'), 'Must not be greyed.')
566
567 def test_on_credentials_error_unset_greyed(self):
568 """Callback 'on_credentials_error' unsets the 'greyed' prop."""
569 self.ui.connect_button.clicked()
570 self.ui.on_credentials_error(gui.U1_APP_NAME, {})
571
572 self.assertFalse(self.ui.get_property('greyed'), 'Must not be greyed.')
573
574 def test_on_authorization_denied_unset_greyed(self):
575 """Callback 'on_authorization_denied' unsets the 'greyed' prop."""
576 self.ui.connect_button.clicked()
577 self.ui.on_authorization_denied(gui.U1_APP_NAME)
578
579 self.assertFalse(self.ui.get_property('greyed'), 'Must not be greyed.')
580
581 def test_buttons_disabled_when_greyed(self):
582 """Buttons should be disabled when widget is greyed."""
583 self.ui.set_sensitive(True)
584 self.ui.set_property('greyed', True)
585
586 self.assertFalse(self.ui.join_now_button.is_sensitive())
587 self.assertFalse(self.ui.connect_button.is_sensitive())
588
589 def test_buttons_enabled_when_not_greyed(self):
590 """Buttons should be enabled when widget is not greyed."""
591 self.ui.set_sensitive(False)
592 self.ui.set_property('greyed', False)
593
594 self.assertTrue(self.ui.join_now_button.is_sensitive())
595 self.assertTrue(self.ui.connect_button.is_sensitive())
0596
=== modified file 'ubuntuone/controlpanel/tests/__init__.py'
--- ubuntuone/controlpanel/tests/__init__.py 2011-02-23 13:57:42 +0000
+++ ubuntuone/controlpanel/tests/__init__.py 2011-03-10 03:11:54 +0000
@@ -88,6 +88,8 @@
88 "email": "andrewpz@protocultura.net",88 "email": "andrewpz@protocultura.net",
89}89}
9090
91
92# note that local computer is not first, do not change!
91SAMPLE_DEVICES_JSON = """93SAMPLE_DEVICES_JSON = """
92[94[
93 {95 {
@@ -108,15 +110,9 @@
108]110]
109"""111"""
110112
113# note that local computer should be first, do not change!
111EXPECTED_DEVICES_INFO = [114EXPECTED_DEVICES_INFO = [
112 {115 {
113 "device_id": "ComputerABCDEF01234token",
114 "name": "Ubuntu One @ darkstar",
115 "type": "Computer",
116 "is_local": '',
117 "configurable": '',
118 },
119 {
120 'is_local': 'True',116 'is_local': 'True',
121 'configurable': 'True',117 'configurable': 'True',
122 'device_id': 'ComputerABCDEF01234-localtoken',118 'device_id': 'ComputerABCDEF01234-localtoken',
@@ -125,7 +121,14 @@
125 'max_download_speed': '-1',121 'max_download_speed': '-1',
126 'max_upload_speed': '-1',122 'max_upload_speed': '-1',
127 'name': 'Ubuntu One @ localhost',123 'name': 'Ubuntu One @ localhost',
128 'type': 'Computer'124 'type': 'Computer',
125 },
126 {
127 "device_id": "ComputerABCDEF01234token",
128 "name": "Ubuntu One @ darkstar",
129 "type": "Computer",
130 "is_local": '',
131 "configurable": '',
129 },132 },
130 {133 {
131 "device_id": "Phone1000",134 "device_id": "Phone1000",
132135
=== modified file 'ubuntuone/controlpanel/tests/test_backend.py'
--- ubuntuone/controlpanel/tests/test_backend.py 2011-02-23 13:57:42 +0000
+++ ubuntuone/controlpanel/tests/test_backend.py 2011-03-10 03:11:54 +0000
@@ -274,7 +274,7 @@
274 result = yield self.be.device_is_local(self.local_token)274 result = yield self.be.device_is_local(self.local_token)
275 self.assertTrue(result)275 self.assertTrue(result)
276276
277 did = EXPECTED_DEVICES_INFO[0]['device_id']277 did = EXPECTED_DEVICES_INFO[-1]['device_id']
278 result = yield self.be.device_is_local(did)278 result = yield self.be.device_is_local(did)
279 self.assertFalse(result)279 self.assertFalse(result)
280280

Subscribers

People subscribed via source and target branches

to all changes: