Merge lp:~nataliabidart/magicicada-gui/list-folders into lp:magicicada-gui
- list-folders
- Merge into trunk
Proposed by
Natalia Bidart
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Facundo Batista | ||||||||
Approved revision: | 43 | ||||||||
Merged at revision: | 35 | ||||||||
Proposed branch: | lp:~nataliabidart/magicicada-gui/list-folders | ||||||||
Merge into: | lp:magicicada-gui | ||||||||
Diff against target: |
1260 lines (+775/-115) 5 files modified
.bzrignore (+1/-0) data/ui/gui.glade (+449/-40) magicicada/__init__.py (+70/-10) magicicada/tests/test_magicicada.py (+253/-65) magicicada/tests/test_syncdaemon.py (+2/-0) |
||||||||
To merge this branch: | bzr merge lp:~nataliabidart/magicicada-gui/list-folders | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Facundo Batista | Approve | ||
Review via email: mp+26447@code.launchpad.net |
Commit message
Description of the change
Implemented Folders and Shares to me functionality.
(Still pending Shares to others)
To post a comment you must log in.
- 42. By Natalia Bidart
-
Making trila avoiding tests for an Abstrac class.
- 43. By Natalia Bidart
-
Merged trunk in.
Revision history for this message
Facundo Batista (facundo) wrote : | # |
Now it's ok, but please active the buttons on SD's start.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file '.bzrignore' | |||
2 | --- .bzrignore 1970-01-01 00:00:00 +0000 | |||
3 | +++ .bzrignore 2010-05-31 22:49:23 +0000 | |||
4 | @@ -0,0 +1,1 @@ | |||
5 | 1 | _trial_temp | ||
6 | 0 | 2 | ||
7 | === modified file 'data/ui/gui.glade' | |||
8 | --- data/ui/gui.glade 2010-05-27 12:34:26 +0000 | |||
9 | +++ data/ui/gui.glade 2010-05-31 22:49:23 +0000 | |||
10 | @@ -2,33 +2,70 @@ | |||
11 | 2 | <interface> | 2 | <interface> |
12 | 3 | <requires lib="gtk+" version="2.16"/> | 3 | <requires lib="gtk+" version="2.16"/> |
13 | 4 | <!-- interface-naming-policy project-wide --> | 4 | <!-- interface-naming-policy project-wide --> |
14 | 5 | <object class="GtkListStore" id="folders_store"> | ||
15 | 6 | <columns> | ||
16 | 7 | <!-- column-name node --> | ||
17 | 8 | <column type="gchararray"/> | ||
18 | 9 | <!-- column-name path --> | ||
19 | 10 | <column type="gchararray"/> | ||
20 | 11 | <!-- column-name suggested_path --> | ||
21 | 12 | <column type="gchararray"/> | ||
22 | 13 | <!-- column-name subscribed --> | ||
23 | 14 | <column type="gboolean"/> | ||
24 | 15 | <!-- column-name volume --> | ||
25 | 16 | <column type="gchararray"/> | ||
26 | 17 | </columns> | ||
27 | 18 | </object> | ||
28 | 19 | <object class="GtkListStore" id="contentq_store"> | ||
29 | 20 | <columns> | ||
30 | 21 | <!-- column-name operation --> | ||
31 | 22 | <column type="gchararray"/> | ||
32 | 23 | <!-- column-name path --> | ||
33 | 24 | <column type="gchararray"/> | ||
34 | 25 | <!-- column-name share --> | ||
35 | 26 | <column type="gchararray"/> | ||
36 | 27 | <!-- column-name node --> | ||
37 | 28 | <column type="gchararray"/> | ||
38 | 29 | </columns> | ||
39 | 30 | </object> | ||
40 | 5 | <object class="GtkListStore" id="metaq_store"> | 31 | <object class="GtkListStore" id="metaq_store"> |
41 | 6 | <columns> | 32 | <columns> |
42 | 7 | <!-- column-name operation --> | 33 | <!-- column-name operation --> |
43 | 8 | <column type="gchararray"/> | 34 | <column type="gchararray"/> |
44 | 9 | <!-- column-name path --> | 35 | <!-- column-name path --> |
45 | 10 | <column type="gchararray"/> | 36 | <column type="gchararray"/> |
46 | 37 | <!-- column-name share --> | ||
47 | 38 | <column type="gchararray"/> | ||
48 | 11 | <!-- column-name node --> | 39 | <!-- column-name node --> |
49 | 12 | <column type="gchararray"/> | 40 | <column type="gchararray"/> |
50 | 13 | <!-- column-name share --> | ||
51 | 14 | <column type="gchararray"/> | ||
52 | 15 | </columns> | 41 | </columns> |
53 | 16 | </object> | 42 | </object> |
55 | 17 | <object class="GtkListStore" id="contentq_store"> | 43 | <object class="GtkListStore" id="shares_to_me_store"> |
56 | 18 | <columns> | 44 | <columns> |
64 | 19 | <!-- column-name Operation --> | 45 | <!-- column-name accepted --> |
65 | 20 | <column type="gchararray"/> | 46 | <column type="gboolean"/> |
66 | 21 | <!-- column-name Path --> | 47 | <!-- column-name access_level --> |
67 | 22 | <column type="gchararray"/> | 48 | <column type="gchararray"/> |
68 | 23 | <!-- column-name Node --> | 49 | <!-- column-name free_bytes --> |
69 | 24 | <column type="gchararray"/> | 50 | <column type="gchararray"/> |
70 | 25 | <!-- column-name Share --> | 51 | <!-- column-name name --> |
71 | 52 | <column type="gchararray"/> | ||
72 | 53 | <!-- column-name node_id --> | ||
73 | 54 | <column type="gchararray"/> | ||
74 | 55 | <!-- column-name other_username --> | ||
75 | 56 | <column type="gchararray"/> | ||
76 | 57 | <!-- column-name other_visible_name --> | ||
77 | 58 | <column type="gchararray"/> | ||
78 | 59 | <!-- column-name path --> | ||
79 | 60 | <column type="gchararray"/> | ||
80 | 61 | <!-- column-name volume_id --> | ||
81 | 26 | <column type="gchararray"/> | 62 | <column type="gchararray"/> |
82 | 27 | </columns> | 63 | </columns> |
83 | 28 | </object> | 64 | </object> |
84 | 29 | <object class="GtkWindow" id="main_window"> | 65 | <object class="GtkWindow" id="main_window"> |
85 | 30 | <property name="width_request">800</property> | 66 | <property name="width_request">800</property> |
86 | 31 | <property name="height_request">600</property> | 67 | <property name="height_request">600</property> |
87 | 68 | <property name="visible">True</property> | ||
88 | 32 | <property name="title" translatable="yes">Magicicada</property> | 69 | <property name="title" translatable="yes">Magicicada</property> |
89 | 33 | <property name="window_position">center</property> | 70 | <property name="window_position">center</property> |
90 | 34 | <signal name="destroy" handler="on_main_window_destroy"/> | 71 | <signal name="destroy" handler="on_main_window_destroy"/> |
91 | @@ -145,6 +182,71 @@ | |||
92 | 145 | <property name="homogeneous">True</property> | 182 | <property name="homogeneous">True</property> |
93 | 146 | </packing> | 183 | </packing> |
94 | 147 | </child> | 184 | </child> |
95 | 185 | <child> | ||
96 | 186 | <object class="GtkSeparatorToolItem" id="separator"> | ||
97 | 187 | <property name="visible">True</property> | ||
98 | 188 | </object> | ||
99 | 189 | <packing> | ||
100 | 190 | <property name="expand">False</property> | ||
101 | 191 | <property name="homogeneous">True</property> | ||
102 | 192 | </packing> | ||
103 | 193 | </child> | ||
104 | 194 | <child> | ||
105 | 195 | <object class="GtkToolButton" id="folders"> | ||
106 | 196 | <property name="visible">True</property> | ||
107 | 197 | <property name="sensitive">False</property> | ||
108 | 198 | <property name="label" translatable="yes">Folders</property> | ||
109 | 199 | <property name="use_underline">True</property> | ||
110 | 200 | <property name="stock_id">gtk-directory</property> | ||
111 | 201 | <signal name="clicked" handler="on_folders_clicked"/> | ||
112 | 202 | </object> | ||
113 | 203 | <packing> | ||
114 | 204 | <property name="expand">False</property> | ||
115 | 205 | <property name="homogeneous">True</property> | ||
116 | 206 | </packing> | ||
117 | 207 | </child> | ||
118 | 208 | <child> | ||
119 | 209 | <object class="GtkToolButton" id="shares_to_me"> | ||
120 | 210 | <property name="visible">True</property> | ||
121 | 211 | <property name="sensitive">False</property> | ||
122 | 212 | <property name="label" translatable="yes">Shares to me</property> | ||
123 | 213 | <property name="use_underline">True</property> | ||
124 | 214 | <property name="stock_id">gtk-network</property> | ||
125 | 215 | <signal name="clicked" handler="on_shares_to_me_clicked"/> | ||
126 | 216 | </object> | ||
127 | 217 | <packing> | ||
128 | 218 | <property name="expand">False</property> | ||
129 | 219 | <property name="homogeneous">True</property> | ||
130 | 220 | </packing> | ||
131 | 221 | </child> | ||
132 | 222 | <child> | ||
133 | 223 | <object class="GtkToolButton" id="shares_to_others"> | ||
134 | 224 | <property name="visible">True</property> | ||
135 | 225 | <property name="sensitive">False</property> | ||
136 | 226 | <property name="label" translatable="yes">Shares to others</property> | ||
137 | 227 | <property name="use_underline">True</property> | ||
138 | 228 | <property name="stock_id">gtk-network</property> | ||
139 | 229 | <signal name="clicked" handler="on_shares_to_others_clicked"/> | ||
140 | 230 | </object> | ||
141 | 231 | <packing> | ||
142 | 232 | <property name="expand">False</property> | ||
143 | 233 | <property name="homogeneous">True</property> | ||
144 | 234 | </packing> | ||
145 | 235 | </child> | ||
146 | 236 | <child> | ||
147 | 237 | <object class="GtkToolButton" id="raw_metadata"> | ||
148 | 238 | <property name="visible">True</property> | ||
149 | 239 | <property name="sensitive">False</property> | ||
150 | 240 | <property name="label" translatable="yes">Metadata</property> | ||
151 | 241 | <property name="use_underline">True</property> | ||
152 | 242 | <property name="stock_id">gtk-find</property> | ||
153 | 243 | <signal name="clicked" handler="on_raw_metadata_clicked"/> | ||
154 | 244 | </object> | ||
155 | 245 | <packing> | ||
156 | 246 | <property name="expand">False</property> | ||
157 | 247 | <property name="homogeneous">True</property> | ||
158 | 248 | </packing> | ||
159 | 249 | </child> | ||
160 | 148 | </object> | 250 | </object> |
161 | 149 | <packing> | 251 | <packing> |
162 | 150 | <property name="expand">False</property> | 252 | <property name="expand">False</property> |
163 | @@ -199,7 +301,6 @@ | |||
164 | 199 | </object> | 301 | </object> |
165 | 200 | <packing> | 302 | <packing> |
166 | 201 | <property name="expand">False</property> | 303 | <property name="expand">False</property> |
167 | 202 | <property name="padding">3</property> | ||
168 | 203 | <property name="position">0</property> | 304 | <property name="position">0</property> |
169 | 204 | </packing> | 305 | </packing> |
170 | 205 | </child> | 306 | </child> |
171 | @@ -215,6 +316,7 @@ | |||
172 | 215 | </object> | 316 | </object> |
173 | 216 | <packing> | 317 | <packing> |
174 | 217 | <property name="expand">False</property> | 318 | <property name="expand">False</property> |
175 | 319 | <property name="padding">3</property> | ||
176 | 218 | <property name="position">2</property> | 320 | <property name="position">2</property> |
177 | 219 | </packing> | 321 | </packing> |
178 | 220 | </child> | 322 | </child> |
179 | @@ -279,24 +381,24 @@ | |||
180 | 279 | </object> | 381 | </object> |
181 | 280 | </child> | 382 | </child> |
182 | 281 | <child> | 383 | <child> |
183 | 384 | <object class="GtkTreeViewColumn" id="metaq_share"> | ||
184 | 385 | <property name="title">Share</property> | ||
185 | 386 | <property name="expand">True</property> | ||
186 | 387 | <child> | ||
187 | 388 | <object class="GtkCellRendererText" id="cellrenderertext4"/> | ||
188 | 389 | <attributes> | ||
189 | 390 | <attribute name="text">2</attribute> | ||
190 | 391 | </attributes> | ||
191 | 392 | </child> | ||
192 | 393 | </object> | ||
193 | 394 | </child> | ||
194 | 395 | <child> | ||
195 | 282 | <object class="GtkTreeViewColumn" id="metaq_node"> | 396 | <object class="GtkTreeViewColumn" id="metaq_node"> |
196 | 283 | <property name="title">Node</property> | 397 | <property name="title">Node</property> |
197 | 284 | <property name="expand">True</property> | 398 | <property name="expand">True</property> |
198 | 285 | <child> | 399 | <child> |
199 | 286 | <object class="GtkCellRendererText" id="cellrenderertext3"/> | 400 | <object class="GtkCellRendererText" id="cellrenderertext3"/> |
200 | 287 | <attributes> | 401 | <attributes> |
201 | 288 | <attribute name="text">2</attribute> | ||
202 | 289 | </attributes> | ||
203 | 290 | </child> | ||
204 | 291 | </object> | ||
205 | 292 | </child> | ||
206 | 293 | <child> | ||
207 | 294 | <object class="GtkTreeViewColumn" id="metaq_share"> | ||
208 | 295 | <property name="title">Share</property> | ||
209 | 296 | <property name="expand">True</property> | ||
210 | 297 | <child> | ||
211 | 298 | <object class="GtkCellRendererText" id="cellrenderertext4"/> | ||
212 | 299 | <attributes> | ||
213 | 300 | <attribute name="text">3</attribute> | 402 | <attribute name="text">3</attribute> |
214 | 301 | </attributes> | 403 | </attributes> |
215 | 302 | </child> | 404 | </child> |
216 | @@ -371,24 +473,24 @@ | |||
217 | 371 | </object> | 473 | </object> |
218 | 372 | </child> | 474 | </child> |
219 | 373 | <child> | 475 | <child> |
220 | 476 | <object class="GtkTreeViewColumn" id="contentq_share"> | ||
221 | 477 | <property name="title">Share</property> | ||
222 | 478 | <property name="expand">True</property> | ||
223 | 479 | <child> | ||
224 | 480 | <object class="GtkCellRendererText" id="cellrenderertext8"/> | ||
225 | 481 | <attributes> | ||
226 | 482 | <attribute name="text">2</attribute> | ||
227 | 483 | </attributes> | ||
228 | 484 | </child> | ||
229 | 485 | </object> | ||
230 | 486 | </child> | ||
231 | 487 | <child> | ||
232 | 374 | <object class="GtkTreeViewColumn" id="contentq_node"> | 488 | <object class="GtkTreeViewColumn" id="contentq_node"> |
233 | 375 | <property name="title">Node</property> | 489 | <property name="title">Node</property> |
234 | 376 | <property name="expand">True</property> | 490 | <property name="expand">True</property> |
235 | 377 | <child> | 491 | <child> |
236 | 378 | <object class="GtkCellRendererText" id="cellrenderertext7"/> | 492 | <object class="GtkCellRendererText" id="cellrenderertext7"/> |
237 | 379 | <attributes> | 493 | <attributes> |
238 | 380 | <attribute name="text">2</attribute> | ||
239 | 381 | </attributes> | ||
240 | 382 | </child> | ||
241 | 383 | </object> | ||
242 | 384 | </child> | ||
243 | 385 | <child> | ||
244 | 386 | <object class="GtkTreeViewColumn" id="contentq_share"> | ||
245 | 387 | <property name="title">Share</property> | ||
246 | 388 | <property name="expand">True</property> | ||
247 | 389 | <child> | ||
248 | 390 | <object class="GtkCellRendererText" id="cellrenderertext8"/> | ||
249 | 391 | <attributes> | ||
250 | 392 | <attribute name="text">3</attribute> | 494 | <attribute name="text">3</attribute> |
251 | 393 | </attributes> | 495 | </attributes> |
252 | 394 | </child> | 496 | </child> |
253 | @@ -426,13 +528,25 @@ | |||
254 | 426 | <property name="type_hint">normal</property> | 528 | <property name="type_hint">normal</property> |
255 | 427 | <property name="has_separator">False</property> | 529 | <property name="has_separator">False</property> |
256 | 428 | <property name="program_name">Magicicada</property> | 530 | <property name="program_name">Magicicada</property> |
260 | 429 | <property name="copyright" translatable="yes">Copyright 2010 Natalia Bidart <natalia.bidart@gmail.com> | 531 | <property name="copyright" translatable="yes">Copyright 2010 Chicharreros |
261 | 430 | Copyright 2010 Facundo Batista <facundo@taniquetil.com.ar> | 532 | Copyright 2010 Natalia Bidart <natalia.bidart@gmail.com> |
262 | 431 | </property> | 533 | Copyright 2010 Facundo Batista <facundo@taniquetil.com.ar></property> |
263 | 432 | <property name="website">http://launchpad.net/magicicada</property> | 534 | <property name="website">http://launchpad.net/magicicada</property> |
265 | 433 | <property name="license" translatable="yes">GPL v3.0</property> | 535 | <property name="license" translatable="yes">GNU General Public License |
266 | 536 | |||
267 | 537 | This program is free software: you can redistribute it and/or modify it | ||
268 | 538 | under the terms of the GNU General Public License version 3, as published | ||
269 | 539 | by the Free Software Foundation. | ||
270 | 540 | |||
271 | 541 | This program is distributed in the hope that it will be useful, but | ||
272 | 542 | WITHOUT ANY WARRANTY; without even the implied warranties of | ||
273 | 543 | MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
274 | 544 | PURPOSE. See the GNU General Public License for more details. | ||
275 | 545 | |||
276 | 546 | You should have received a copy of the GNU General Public License along | ||
277 | 547 | with this program. If not, see <http://www.gnu.org/licenses/>.</property> | ||
278 | 434 | <property name="authors">Natalia Bidart <natalia.bidart@gmail.com> | 548 | <property name="authors">Natalia Bidart <natalia.bidart@gmail.com> |
280 | 435 | Facundo Batista <facundo.batista@gmail.com></property> | 549 | Facundo Batista <facundo@taniquetil.com.ar></property> |
281 | 436 | <child internal-child="vbox"> | 550 | <child internal-child="vbox"> |
282 | 437 | <object class="GtkVBox" id="dialog-vbox1"> | 551 | <object class="GtkVBox" id="dialog-vbox1"> |
283 | 438 | <property name="visible">True</property> | 552 | <property name="visible">True</property> |
284 | @@ -454,4 +568,299 @@ | |||
285 | 454 | </object> | 568 | </object> |
286 | 455 | </child> | 569 | </child> |
287 | 456 | </object> | 570 | </object> |
288 | 571 | <object class="GtkDialog" id="folders_dialog"> | ||
289 | 572 | <property name="width_request">600</property> | ||
290 | 573 | <property name="height_request">300</property> | ||
291 | 574 | <property name="border_width">5</property> | ||
292 | 575 | <property name="title" translatable="yes">Folders</property> | ||
293 | 576 | <property name="modal">True</property> | ||
294 | 577 | <property name="window_position">center</property> | ||
295 | 578 | <property name="type_hint">normal</property> | ||
296 | 579 | <property name="skip_taskbar_hint">True</property> | ||
297 | 580 | <property name="has_separator">False</property> | ||
298 | 581 | <child internal-child="vbox"> | ||
299 | 582 | <object class="GtkVBox" id="dialog-vbox2"> | ||
300 | 583 | <property name="visible">True</property> | ||
301 | 584 | <property name="spacing">2</property> | ||
302 | 585 | <child> | ||
303 | 586 | <object class="GtkScrolledWindow" id="scrolledwindow3"> | ||
304 | 587 | <property name="visible">True</property> | ||
305 | 588 | <property name="can_focus">True</property> | ||
306 | 589 | <property name="hscrollbar_policy">automatic</property> | ||
307 | 590 | <child> | ||
308 | 591 | <object class="GtkTreeView" id="folders_view"> | ||
309 | 592 | <property name="visible">True</property> | ||
310 | 593 | <property name="can_focus">True</property> | ||
311 | 594 | <property name="model">folders_store</property> | ||
312 | 595 | <property name="headers_clickable">False</property> | ||
313 | 596 | <property name="rules_hint">True</property> | ||
314 | 597 | <property name="search_column">0</property> | ||
315 | 598 | <property name="enable_grid_lines">both</property> | ||
316 | 599 | <property name="enable_tree_lines">True</property> | ||
317 | 600 | <child> | ||
318 | 601 | <object class="GtkTreeViewColumn" id="folders_node"> | ||
319 | 602 | <property name="resizable">True</property> | ||
320 | 603 | <property name="title">Node</property> | ||
321 | 604 | <property name="expand">True</property> | ||
322 | 605 | <child> | ||
323 | 606 | <object class="GtkCellRendererText" id="cellrenderertext9"/> | ||
324 | 607 | <attributes> | ||
325 | 608 | <attribute name="text">0</attribute> | ||
326 | 609 | </attributes> | ||
327 | 610 | </child> | ||
328 | 611 | </object> | ||
329 | 612 | </child> | ||
330 | 613 | <child> | ||
331 | 614 | <object class="GtkTreeViewColumn" id="folders_path"> | ||
332 | 615 | <property name="resizable">True</property> | ||
333 | 616 | <property name="title">Path</property> | ||
334 | 617 | <property name="expand">True</property> | ||
335 | 618 | <child> | ||
336 | 619 | <object class="GtkCellRendererText" id="cellrenderertext10"/> | ||
337 | 620 | <attributes> | ||
338 | 621 | <attribute name="text">1</attribute> | ||
339 | 622 | </attributes> | ||
340 | 623 | </child> | ||
341 | 624 | </object> | ||
342 | 625 | </child> | ||
343 | 626 | <child> | ||
344 | 627 | <object class="GtkTreeViewColumn" id="folders_suggested_path"> | ||
345 | 628 | <property name="resizable">True</property> | ||
346 | 629 | <property name="title">Suggested Path</property> | ||
347 | 630 | <property name="expand">True</property> | ||
348 | 631 | <child> | ||
349 | 632 | <object class="GtkCellRendererText" id="cellrenderertext11"/> | ||
350 | 633 | <attributes> | ||
351 | 634 | <attribute name="text">2</attribute> | ||
352 | 635 | </attributes> | ||
353 | 636 | </child> | ||
354 | 637 | </object> | ||
355 | 638 | </child> | ||
356 | 639 | <child> | ||
357 | 640 | <object class="GtkTreeViewColumn" id="folders_subscribed"> | ||
358 | 641 | <property name="resizable">True</property> | ||
359 | 642 | <property name="title">Subscribed</property> | ||
360 | 643 | <property name="expand">True</property> | ||
361 | 644 | <child> | ||
362 | 645 | <object class="GtkCellRendererToggle" id="cellrenderertoggle1"/> | ||
363 | 646 | <attributes> | ||
364 | 647 | <attribute name="active">3</attribute> | ||
365 | 648 | </attributes> | ||
366 | 649 | </child> | ||
367 | 650 | </object> | ||
368 | 651 | </child> | ||
369 | 652 | <child> | ||
370 | 653 | <object class="GtkTreeViewColumn" id="folders_volume"> | ||
371 | 654 | <property name="resizable">True</property> | ||
372 | 655 | <property name="title">Volume</property> | ||
373 | 656 | <property name="expand">True</property> | ||
374 | 657 | <child> | ||
375 | 658 | <object class="GtkCellRendererText" id="cellrenderertext12"/> | ||
376 | 659 | <attributes> | ||
377 | 660 | <attribute name="text">4</attribute> | ||
378 | 661 | </attributes> | ||
379 | 662 | </child> | ||
380 | 663 | </object> | ||
381 | 664 | </child> | ||
382 | 665 | </object> | ||
383 | 666 | </child> | ||
384 | 667 | </object> | ||
385 | 668 | <packing> | ||
386 | 669 | <property name="position">1</property> | ||
387 | 670 | </packing> | ||
388 | 671 | </child> | ||
389 | 672 | <child internal-child="action_area"> | ||
390 | 673 | <object class="GtkHButtonBox" id="dialog-action_area2"> | ||
391 | 674 | <property name="visible">True</property> | ||
392 | 675 | <property name="layout_style">end</property> | ||
393 | 676 | <child> | ||
394 | 677 | <object class="GtkButton" id="folders_close"> | ||
395 | 678 | <property name="label">gtk-close</property> | ||
396 | 679 | <property name="visible">True</property> | ||
397 | 680 | <property name="can_focus">False</property> | ||
398 | 681 | <property name="receives_default">False</property> | ||
399 | 682 | <property name="use_stock">True</property> | ||
400 | 683 | <signal name="clicked" handler="on_folders_close_clicked"/> | ||
401 | 684 | </object> | ||
402 | 685 | <packing> | ||
403 | 686 | <property name="expand">False</property> | ||
404 | 687 | <property name="fill">False</property> | ||
405 | 688 | <property name="position">0</property> | ||
406 | 689 | </packing> | ||
407 | 690 | </child> | ||
408 | 691 | </object> | ||
409 | 692 | <packing> | ||
410 | 693 | <property name="expand">False</property> | ||
411 | 694 | <property name="pack_type">end</property> | ||
412 | 695 | <property name="position">0</property> | ||
413 | 696 | </packing> | ||
414 | 697 | </child> | ||
415 | 698 | </object> | ||
416 | 699 | </child> | ||
417 | 700 | <action-widgets> | ||
418 | 701 | <action-widget response="0">folders_close</action-widget> | ||
419 | 702 | </action-widgets> | ||
420 | 703 | </object> | ||
421 | 704 | <object class="GtkDialog" id="shares_to_me_dialog"> | ||
422 | 705 | <property name="width_request">600</property> | ||
423 | 706 | <property name="height_request">300</property> | ||
424 | 707 | <property name="border_width">5</property> | ||
425 | 708 | <property name="title" translatable="yes">Shares to me</property> | ||
426 | 709 | <property name="modal">True</property> | ||
427 | 710 | <property name="window_position">center</property> | ||
428 | 711 | <property name="type_hint">normal</property> | ||
429 | 712 | <property name="has_separator">False</property> | ||
430 | 713 | <child internal-child="vbox"> | ||
431 | 714 | <object class="GtkVBox" id="dialog-vbox3"> | ||
432 | 715 | <property name="visible">True</property> | ||
433 | 716 | <property name="spacing">2</property> | ||
434 | 717 | <child> | ||
435 | 718 | <object class="GtkScrolledWindow" id="scrolledwindow4"> | ||
436 | 719 | <property name="visible">True</property> | ||
437 | 720 | <property name="can_focus">True</property> | ||
438 | 721 | <property name="hscrollbar_policy">automatic</property> | ||
439 | 722 | <property name="vscrollbar_policy">automatic</property> | ||
440 | 723 | <child> | ||
441 | 724 | <object class="GtkTreeView" id="shares_to_me_view"> | ||
442 | 725 | <property name="visible">True</property> | ||
443 | 726 | <property name="can_focus">True</property> | ||
444 | 727 | <property name="model">shares_to_me_store</property> | ||
445 | 728 | <property name="rules_hint">True</property> | ||
446 | 729 | <property name="enable_grid_lines">both</property> | ||
447 | 730 | <property name="enable_tree_lines">True</property> | ||
448 | 731 | <child> | ||
449 | 732 | <object class="GtkTreeViewColumn" id="shares_to_me_name"> | ||
450 | 733 | <property name="title">Name</property> | ||
451 | 734 | <property name="expand">True</property> | ||
452 | 735 | <child> | ||
453 | 736 | <object class="GtkCellRendererText" id="cellrenderertext15"/> | ||
454 | 737 | <attributes> | ||
455 | 738 | <attribute name="text">3</attribute> | ||
456 | 739 | </attributes> | ||
457 | 740 | </child> | ||
458 | 741 | </object> | ||
459 | 742 | </child> | ||
460 | 743 | <child> | ||
461 | 744 | <object class="GtkTreeViewColumn" id="shares_to_me_other"> | ||
462 | 745 | <property name="title">Other</property> | ||
463 | 746 | <property name="expand">True</property> | ||
464 | 747 | <child> | ||
465 | 748 | <object class="GtkCellRendererText" id="cellrenderertext19"/> | ||
466 | 749 | <attributes> | ||
467 | 750 | <attribute name="text">6</attribute> | ||
468 | 751 | </attributes> | ||
469 | 752 | </child> | ||
470 | 753 | </object> | ||
471 | 754 | </child> | ||
472 | 755 | <child> | ||
473 | 756 | <object class="GtkTreeViewColumn" id="shates_to_me_accepted"> | ||
474 | 757 | <property name="title">Accepted</property> | ||
475 | 758 | <property name="expand">True</property> | ||
476 | 759 | <child> | ||
477 | 760 | <object class="GtkCellRendererToggle" id="cellrenderertoggle2"/> | ||
478 | 761 | <attributes> | ||
479 | 762 | <attribute name="activatable">0</attribute> | ||
480 | 763 | </attributes> | ||
481 | 764 | </child> | ||
482 | 765 | </object> | ||
483 | 766 | </child> | ||
484 | 767 | <child> | ||
485 | 768 | <object class="GtkTreeViewColumn" id="shares_to_me_access_level"> | ||
486 | 769 | <property name="title">Access Level</property> | ||
487 | 770 | <property name="expand">True</property> | ||
488 | 771 | <child> | ||
489 | 772 | <object class="GtkCellRendererText" id="cellrenderertext13"/> | ||
490 | 773 | <attributes> | ||
491 | 774 | <attribute name="text">1</attribute> | ||
492 | 775 | </attributes> | ||
493 | 776 | </child> | ||
494 | 777 | </object> | ||
495 | 778 | </child> | ||
496 | 779 | <child> | ||
497 | 780 | <object class="GtkTreeViewColumn" id="shares-to_me_free_bytes"> | ||
498 | 781 | <property name="title">Free bytes</property> | ||
499 | 782 | <property name="expand">True</property> | ||
500 | 783 | <child> | ||
501 | 784 | <object class="GtkCellRendererText" id="cellrenderertext14"/> | ||
502 | 785 | <attributes> | ||
503 | 786 | <attribute name="text">2</attribute> | ||
504 | 787 | </attributes> | ||
505 | 788 | </child> | ||
506 | 789 | </object> | ||
507 | 790 | </child> | ||
508 | 791 | <child> | ||
509 | 792 | <object class="GtkTreeViewColumn" id="shares_to_me_node"> | ||
510 | 793 | <property name="title">Node</property> | ||
511 | 794 | <property name="expand">True</property> | ||
512 | 795 | <child> | ||
513 | 796 | <object class="GtkCellRendererText" id="cellrenderertext16"/> | ||
514 | 797 | <attributes> | ||
515 | 798 | <attribute name="text">4</attribute> | ||
516 | 799 | </attributes> | ||
517 | 800 | </child> | ||
518 | 801 | </object> | ||
519 | 802 | </child> | ||
520 | 803 | <child> | ||
521 | 804 | <object class="GtkTreeViewColumn" id="shares_to_me_path"> | ||
522 | 805 | <property name="title">Path</property> | ||
523 | 806 | <property name="expand">True</property> | ||
524 | 807 | <child> | ||
525 | 808 | <object class="GtkCellRendererText" id="cellrenderertext18"/> | ||
526 | 809 | <attributes> | ||
527 | 810 | <attribute name="text">7</attribute> | ||
528 | 811 | </attributes> | ||
529 | 812 | </child> | ||
530 | 813 | </object> | ||
531 | 814 | </child> | ||
532 | 815 | <child> | ||
533 | 816 | <object class="GtkTreeViewColumn" id="shares_to_me_volume"> | ||
534 | 817 | <property name="title">Volume</property> | ||
535 | 818 | <property name="expand">True</property> | ||
536 | 819 | <child> | ||
537 | 820 | <object class="GtkCellRendererText" id="cellrenderertext17"/> | ||
538 | 821 | <attributes> | ||
539 | 822 | <attribute name="text">8</attribute> | ||
540 | 823 | </attributes> | ||
541 | 824 | </child> | ||
542 | 825 | </object> | ||
543 | 826 | </child> | ||
544 | 827 | </object> | ||
545 | 828 | </child> | ||
546 | 829 | </object> | ||
547 | 830 | <packing> | ||
548 | 831 | <property name="position">1</property> | ||
549 | 832 | </packing> | ||
550 | 833 | </child> | ||
551 | 834 | <child internal-child="action_area"> | ||
552 | 835 | <object class="GtkHButtonBox" id="dialog-action_area3"> | ||
553 | 836 | <property name="visible">True</property> | ||
554 | 837 | <property name="layout_style">end</property> | ||
555 | 838 | <child> | ||
556 | 839 | <object class="GtkButton" id="shares_to_me_close"> | ||
557 | 840 | <property name="label">gtk-close</property> | ||
558 | 841 | <property name="visible">True</property> | ||
559 | 842 | <property name="can_focus">True</property> | ||
560 | 843 | <property name="receives_default">True</property> | ||
561 | 844 | <property name="use_stock">True</property> | ||
562 | 845 | <signal name="clicked" handler="on_shares_to_me_close_clicked"/> | ||
563 | 846 | </object> | ||
564 | 847 | <packing> | ||
565 | 848 | <property name="expand">False</property> | ||
566 | 849 | <property name="fill">False</property> | ||
567 | 850 | <property name="position">0</property> | ||
568 | 851 | </packing> | ||
569 | 852 | </child> | ||
570 | 853 | </object> | ||
571 | 854 | <packing> | ||
572 | 855 | <property name="expand">False</property> | ||
573 | 856 | <property name="pack_type">end</property> | ||
574 | 857 | <property name="position">0</property> | ||
575 | 858 | </packing> | ||
576 | 859 | </child> | ||
577 | 860 | </object> | ||
578 | 861 | </child> | ||
579 | 862 | <action-widgets> | ||
580 | 863 | <action-widget response="0">shares_to_me_close</action-widget> | ||
581 | 864 | </action-widgets> | ||
582 | 865 | </object> | ||
583 | 457 | </interface> | 866 | </interface> |
584 | 458 | 867 | ||
585 | === modified file 'magicicada/__init__.py' | |||
586 | --- magicicada/__init__.py 2010-05-28 12:33:53 +0000 | |||
587 | +++ magicicada/__init__.py 2010-05-31 22:49:23 +0000 | |||
588 | @@ -64,26 +64,37 @@ | |||
589 | 64 | 64 | ||
590 | 65 | widgets = ( | 65 | widgets = ( |
591 | 66 | 'start', 'stop', 'connect', 'disconnect', # toolbar buttons | 66 | 'start', 'stop', 'connect', 'disconnect', # toolbar buttons |
592 | 67 | 'folders', 'folders_dialog', | ||
593 | 68 | 'folders_store', 'folders_close', # folders | ||
594 | 69 | 'shares_to_me', 'shares_to_me_dialog', | ||
595 | 70 | 'shares_to_me_store', 'shares_to_me_close', # shares_to_me | ||
596 | 71 | 'shares_to_others', # toolbar buttons | ||
597 | 72 | 'raw_metadata', # more toolbar buttons | ||
598 | 67 | 'is_started', 'is_connected', 'is_online', # status bar images | 73 | 'is_started', 'is_connected', 'is_online', # status bar images |
599 | 68 | 'status_label', 'status_icon', # status label and systray icon | 74 | 'status_label', 'status_icon', # status label and systray icon |
600 | 69 | 'metaq_view', 'contentq_view', # queues tree views | 75 | 'metaq_view', 'contentq_view', # queues tree views |
601 | 70 | 'metaq_store', 'contentq_store', # queues list stores | 76 | 'metaq_store', 'contentq_store', # queues list stores |
603 | 71 | 'main_window', 'about_dialog', | 77 | 'about_dialog', # dialogs |
604 | 78 | 'main_window' | ||
605 | 72 | ) | 79 | ) |
606 | 73 | for widget in widgets: | 80 | for widget in widgets: |
607 | 74 | obj = self.builder.get_object(widget) | 81 | obj = self.builder.get_object(widget) |
608 | 75 | setattr(self, widget, obj) | 82 | setattr(self, widget, obj) |
609 | 76 | assert obj is not None, '%s must not be None' % widget | 83 | assert obj is not None, '%s must not be None' % widget |
610 | 77 | 84 | ||
611 | 85 | self.volumes = (self.folders, self.shares_to_me, self.shares_to_others) | ||
612 | 86 | self.windows = (self.main_window, self.about_dialog, | ||
613 | 87 | self.folders_dialog) | ||
614 | 88 | |||
615 | 78 | icon_filename = get_data_file('media', 'logo-016.png') | 89 | icon_filename = get_data_file('media', 'logo-016.png') |
616 | 90 | self._icon = gtk.gdk.pixbuf_new_from_file(icon_filename) | ||
617 | 79 | self.status_icon.set_from_file(icon_filename) | 91 | self.status_icon.set_from_file(icon_filename) |
619 | 80 | self.main_window.set_icon_from_file(icon_filename) | 92 | for w in self.windows: |
620 | 93 | w.set_icon(self._icon) | ||
621 | 81 | 94 | ||
622 | 82 | about_filename = get_data_file('media', 'logo-128.png') | 95 | about_filename = get_data_file('media', 'logo-128.png') |
623 | 83 | self.about_dialog.set_logo(gtk.gdk.pixbuf_new_from_file(about_filename)) | 96 | self.about_dialog.set_logo(gtk.gdk.pixbuf_new_from_file(about_filename)) |
624 | 84 | 97 | ||
625 | 85 | self.main_window.show() | ||
626 | 86 | |||
627 | 87 | self.sd = syncdaemon_class() | 98 | self.sd = syncdaemon_class() |
628 | 88 | self.sd.on_started_callback = self.on_started | 99 | self.sd.on_started_callback = self.on_started |
629 | 89 | self.sd.on_stopped_callback = self.on_stopped | 100 | self.sd.on_stopped_callback = self.on_stopped |
630 | @@ -95,8 +106,9 @@ | |||
631 | 95 | self.sd.content_queue_changed_callback = self.on_content_queue_changed | 106 | self.sd.content_queue_changed_callback = self.on_content_queue_changed |
632 | 96 | self.sd.meta_queue_changed_callback = self.on_meta_queue_changed | 107 | self.sd.meta_queue_changed_callback = self.on_meta_queue_changed |
633 | 97 | 108 | ||
636 | 98 | self.widget_enabled = lambda w: \ | 109 | self.widget_is_visible = lambda w: w.get_property('visible') |
637 | 99 | w.get_property('visible') and w.is_sensitive() | 110 | self.widget_enabled = lambda w: self.widget_is_visible(w) and \ |
638 | 111 | w.is_sensitive() | ||
639 | 100 | 112 | ||
640 | 101 | self.update() | 113 | self.update() |
641 | 102 | 114 | ||
642 | @@ -105,8 +117,6 @@ | |||
643 | 105 | def on_main_window_destroy(self, widget, data=None): | 117 | def on_main_window_destroy(self, widget, data=None): |
644 | 106 | """Called when the MagicicadaWindow is closed.""" | 118 | """Called when the MagicicadaWindow is closed.""" |
645 | 107 | # Clean up code for saving application state should be added here. | 119 | # Clean up code for saving application state should be added here. |
646 | 108 | if self.widget_enabled(self.stop): | ||
647 | 109 | self.on_stop_clicked(self.stop) | ||
648 | 110 | self.sd.shutdown() | 120 | self.sd.shutdown() |
649 | 111 | self.on_destroy() | 121 | self.on_destroy() |
650 | 112 | 122 | ||
651 | @@ -145,9 +155,55 @@ | |||
652 | 145 | self.disconnect.set_sensitive(False) | 155 | self.disconnect.set_sensitive(False) |
653 | 146 | self.sd.disconnect() | 156 | self.sd.disconnect() |
654 | 147 | 157 | ||
655 | 158 | def on_folders_close_clicked(self, widget, data=None): | ||
656 | 159 | """Close the folders dialog.""" | ||
657 | 160 | self.folders_dialog.response(gtk.RESPONSE_CLOSE) | ||
658 | 161 | |||
659 | 162 | def on_folders_clicked(self, widget, data=None): | ||
660 | 163 | """List user folders.""" | ||
661 | 164 | items = self.sd.folders | ||
662 | 165 | if items is None: | ||
663 | 166 | items = [] | ||
664 | 167 | |||
665 | 168 | self.folders_store.clear() | ||
666 | 169 | for item in items: | ||
667 | 170 | row = (item.node, item.path, item.suggested_path, | ||
668 | 171 | item.subscribed, item.volume) | ||
669 | 172 | self.folders_store.append(row) | ||
670 | 173 | |||
671 | 174 | res = self.folders_dialog.run() | ||
672 | 175 | self.folders_dialog.hide() | ||
673 | 176 | |||
674 | 177 | def on_shares_to_me_close_clicked(self, widget, data=None): | ||
675 | 178 | """Close the shares_to_me dialog.""" | ||
676 | 179 | self.shares_to_me_dialog.response(gtk.RESPONSE_CLOSE) | ||
677 | 180 | |||
678 | 181 | def on_shares_to_me_clicked(self, widget, data=None): | ||
679 | 182 | """List shares to the user.""" | ||
680 | 183 | items = self.sd.shares_to_me | ||
681 | 184 | if items is None: | ||
682 | 185 | items = [] | ||
683 | 186 | |||
684 | 187 | self.shares_to_me_store.clear() | ||
685 | 188 | for item in items: | ||
686 | 189 | #free_bytes = 0 if item.free_bytes is None else item.free_bytes | ||
687 | 190 | row = (item.accepted, item.access_level, item.free_bytes, item.name, | ||
688 | 191 | item.node_id, item.other_username, item.other_visible_name, | ||
689 | 192 | item.path, item.volume_id) | ||
690 | 193 | self.shares_to_me_store.append(row) | ||
691 | 194 | |||
692 | 195 | res = self.shares_to_me_dialog.run() | ||
693 | 196 | self.shares_to_me_dialog.hide() | ||
694 | 197 | |||
695 | 198 | def on_shares_to_others_clicked(self, widget, data=None): | ||
696 | 199 | """List user shares to others.""" | ||
697 | 200 | |||
698 | 201 | def on_raw_metadata_clicked(self, widget, data=None): | ||
699 | 202 | """Show raw metadata for a path choosen by the user.""" | ||
700 | 203 | |||
701 | 148 | def on_status_icon_activate(self, widget, data=None): | 204 | def on_status_icon_activate(self, widget, data=None): |
702 | 149 | """Systray icon was clicked.""" | 205 | """Systray icon was clicked.""" |
704 | 150 | if self.main_window.get_property('visible'): | 206 | if self.widget_is_visible(self.main_window): |
705 | 151 | self.main_window.hide() | 207 | self.main_window.hide() |
706 | 152 | else: | 208 | else: |
707 | 153 | self.main_window.show() | 209 | self.main_window.show() |
708 | @@ -201,9 +257,13 @@ | |||
709 | 201 | """Callback'ed when syncadaemon is online.""" | 257 | """Callback'ed when syncadaemon is online.""" |
710 | 202 | self.is_online.set_sensitive(True) | 258 | self.is_online.set_sensitive(True) |
711 | 203 | self._activate_indicator(self.is_online) | 259 | self._activate_indicator(self.is_online) |
712 | 260 | for v in self.volumes: | ||
713 | 261 | v.set_sensitive(True) | ||
714 | 204 | 262 | ||
715 | 205 | def on_offline(self, *args, **kwargs): | 263 | def on_offline(self, *args, **kwargs): |
716 | 206 | """Callback'ed when syncadaemon is offline.""" | 264 | """Callback'ed when syncadaemon is offline.""" |
717 | 265 | for v in self.volumes: | ||
718 | 266 | v.set_sensitive(False) | ||
719 | 207 | self._activate_indicator(self.is_online, sensitive=False) | 267 | self._activate_indicator(self.is_online, sensitive=False) |
720 | 208 | 268 | ||
721 | 209 | def on_status_changed(self, name=None, description=None, | 269 | def on_status_changed(self, name=None, description=None, |
722 | @@ -224,7 +284,7 @@ | |||
723 | 224 | queue_store = getattr(self, '%sq_store' % queue_name) | 284 | queue_store = getattr(self, '%sq_store' % queue_name) |
724 | 225 | queue_store.clear() | 285 | queue_store.clear() |
725 | 226 | for item in items: | 286 | for item in items: |
727 | 227 | row = (item.operation, item.path, item.node, item.share) | 287 | row = (item.operation, item.path, item.share, item.node) |
728 | 228 | queue_store.append(row) | 288 | queue_store.append(row) |
729 | 229 | 289 | ||
730 | 230 | if not queue_view.is_sensitive() and len(items) > 0: | 290 | if not queue_view.is_sensitive() and len(items) > 0: |
731 | 231 | 291 | ||
732 | === modified file 'magicicada/tests/test_magicicada.py' | |||
733 | --- magicicada/tests/test_magicicada.py 2010-05-27 12:21:19 +0000 | |||
734 | +++ magicicada/tests/test_magicicada.py 2010-05-31 22:49:23 +0000 | |||
735 | @@ -20,14 +20,30 @@ | |||
736 | 20 | 20 | ||
737 | 21 | from functools import wraps | 21 | from functools import wraps |
738 | 22 | 22 | ||
739 | 23 | import gobject | ||
740 | 24 | import gtk | ||
741 | 23 | import pango | 25 | import pango |
742 | 24 | 26 | ||
743 | 25 | from twisted.trial.unittest import TestCase | 27 | from twisted.trial.unittest import TestCase |
744 | 26 | 28 | ||
745 | 27 | from magicicada import MagicicadaUI, CONTENT_QUEUE, META_QUEUE, syncdaemon | 29 | from magicicada import MagicicadaUI, CONTENT_QUEUE, META_QUEUE, syncdaemon |
747 | 28 | from magicicada.dbusiface import QueueData | 30 | from magicicada.dbusiface import QueueData, FolderData, ShareData |
748 | 29 | from magicicada.helpers import NO_OP | 31 | from magicicada.helpers import NO_OP |
749 | 30 | 32 | ||
750 | 33 | def process_gtk_pendings(): | ||
751 | 34 | while gtk.events_pending(): gtk.main_iteration() | ||
752 | 35 | |||
753 | 36 | def close_dialog((dialog, test)): | ||
754 | 37 | """Call the 'test', close 'dialog'.""" | ||
755 | 38 | try: | ||
756 | 39 | process_gtk_pendings() | ||
757 | 40 | test() | ||
758 | 41 | process_gtk_pendings() | ||
759 | 42 | finally: | ||
760 | 43 | dialog.response(gtk.RESPONSE_CLOSE) | ||
761 | 44 | process_gtk_pendings() | ||
762 | 45 | return False # do not be called again | ||
763 | 46 | |||
764 | 31 | 47 | ||
765 | 32 | class FakedSyncdaemon(object): | 48 | class FakedSyncdaemon(object): |
766 | 33 | """A faked syncdaemon.""" | 49 | """A faked syncdaemon.""" |
767 | @@ -36,6 +52,7 @@ | |||
768 | 36 | self.current_state = syncdaemon.State() | 52 | self.current_state = syncdaemon.State() |
769 | 37 | self.meta_queue = [] | 53 | self.meta_queue = [] |
770 | 38 | self.content_queue = [] | 54 | self.content_queue = [] |
771 | 55 | self.folders = [] | ||
772 | 39 | 56 | ||
773 | 40 | self.on_started_callback = NO_OP | 57 | self.on_started_callback = NO_OP |
774 | 41 | self.on_stopped_callback = NO_OP | 58 | self.on_stopped_callback = NO_OP |
775 | @@ -47,6 +64,7 @@ | |||
776 | 47 | self.content_queue_changed_callback = NO_OP | 64 | self.content_queue_changed_callback = NO_OP |
777 | 48 | self.meta_queue_changed_callback = NO_OP | 65 | self.meta_queue_changed_callback = NO_OP |
778 | 49 | self.shutdown = NO_OP | 66 | self.shutdown = NO_OP |
779 | 67 | |||
780 | 50 | self.start = lambda: setattr(self.current_state, 'is_started', True) | 68 | self.start = lambda: setattr(self.current_state, 'is_started', True) |
781 | 51 | self.quit = lambda: setattr(self.current_state, 'is_started', False) | 69 | self.quit = lambda: setattr(self.current_state, 'is_started', False) |
782 | 52 | self.connect = lambda: setattr(self.current_state, 'is_connected', True) | 70 | self.connect = lambda: setattr(self.current_state, 'is_connected', True) |
783 | @@ -79,6 +97,35 @@ | |||
784 | 79 | self.ui.on_connect_clicked(self.ui.connect) | 97 | self.ui.on_connect_clicked(self.ui.connect) |
785 | 80 | self.ui.on_connected() | 98 | self.ui.on_connected() |
786 | 81 | 99 | ||
787 | 100 | def build_some_data(self, data_type, limit=5): | ||
788 | 101 | """Build some data using named_tuple 'data_type'.""" | ||
789 | 102 | attrs = data_type._fields | ||
790 | 103 | result = [] | ||
791 | 104 | for i in xrange(limit): | ||
792 | 105 | kwargs = dict([(attr, '%s %i' % (attr, i)) for attr in attrs]) | ||
793 | 106 | result.append(data_type(**kwargs)) | ||
794 | 107 | return result | ||
795 | 108 | |||
796 | 109 | def assert_store_correct(self, store, items): | ||
797 | 110 | """Test that 'store' has 'items' as content.""" | ||
798 | 111 | msg = 'amount of rows for %s must be %s (got %s).' | ||
799 | 112 | self.assertEqual(len(store), len(items), | ||
800 | 113 | msg % (store, len(items), len(store))) | ||
801 | 114 | # assert rows content equal to items content | ||
802 | 115 | tree_iter = store.get_iter_root() | ||
803 | 116 | tmp = list(reversed(items)) | ||
804 | 117 | msg = "column %i ('%s') must be '%s' (got '%s' instead)" | ||
805 | 118 | while tree_iter is not None: | ||
806 | 119 | head = tmp.pop() | ||
807 | 120 | for i, field in enumerate(head._fields): | ||
808 | 121 | actual, = store.get(tree_iter, i) | ||
809 | 122 | expected = getattr(head, field) | ||
810 | 123 | if store.get_column_type(i).name == 'gboolean': | ||
811 | 124 | expected = bool(expected) | ||
812 | 125 | self.assertEqual(expected, actual, msg % (i, field, expected, actual)) | ||
813 | 126 | |||
814 | 127 | tree_iter = store.iter_next(tree_iter) | ||
815 | 128 | |||
816 | 82 | def assert_indicator_disabled(self, indicator): | 129 | def assert_indicator_disabled(self, indicator): |
817 | 83 | """Test that 'indicator' is not sensitive.""" | 130 | """Test that 'indicator' is not sensitive.""" |
818 | 84 | self.assertFalse(indicator.is_sensitive(), 'indicator is not sensitive') | 131 | self.assertFalse(indicator.is_sensitive(), 'indicator is not sensitive') |
819 | @@ -114,21 +161,26 @@ | |||
820 | 114 | 'syncdaemon.shutdown must be called at destroy time.') | 161 | 'syncdaemon.shutdown must be called at destroy time.') |
821 | 115 | 162 | ||
822 | 116 | def test_main_window_is_visible(self): | 163 | def test_main_window_is_visible(self): |
825 | 117 | """UI can be created.""" | 164 | """UI can be created and main_window is visible.""" |
826 | 118 | self.assertTrue(self.ui.main_window.get_property('visible')) | 165 | self.assertTrue(self.ui.widget_is_visible(self.ui.main_window)) |
827 | 166 | |||
828 | 167 | def test_windows_have_correct_icon(self): | ||
829 | 168 | """Every window has the icon set.""" | ||
830 | 169 | for w in self.ui.windows: | ||
831 | 170 | self.assertEqual(w.get_icon(), self.ui._icon) | ||
832 | 119 | 171 | ||
833 | 120 | def test_start_connect_are_visible(self): | 172 | def test_start_connect_are_visible(self): |
834 | 121 | """Start and Connect buttons are visible.""" | 173 | """Start and Connect buttons are visible.""" |
836 | 122 | self.assertTrue(self.ui.start.get_property('visible')) | 174 | self.assertTrue(self.ui.widget_is_visible(self.ui.start)) |
837 | 123 | self.assertTrue(self.ui.start.is_sensitive()) | 175 | self.assertTrue(self.ui.start.is_sensitive()) |
838 | 124 | 176 | ||
840 | 125 | self.assertTrue(self.ui.connect.get_property('visible')) | 177 | self.assertTrue(self.ui.widget_is_visible(self.ui.connect)) |
841 | 126 | self.assertFalse(self.ui.connect.is_sensitive()) | 178 | self.assertFalse(self.ui.connect.is_sensitive()) |
842 | 127 | 179 | ||
843 | 128 | def test_stop_disconnect_are_not_visible(self): | 180 | def test_stop_disconnect_are_not_visible(self): |
844 | 129 | """Start and Connect buttons are visible.""" | 181 | """Start and Connect buttons are visible.""" |
847 | 130 | self.assertFalse(self.ui.stop.get_property('visible')) | 182 | self.assertFalse(self.ui.widget_is_visible(self.ui.stop)) |
848 | 131 | self.assertFalse(self.ui.disconnect.get_property('visible')) | 183 | self.assertFalse(self.ui.widget_is_visible(self.ui.disconnect)) |
849 | 132 | 184 | ||
850 | 133 | def test_indicators_are_non_sensitive(self): | 185 | def test_indicators_are_non_sensitive(self): |
851 | 134 | """Test default sensitivity for indicators.""" | 186 | """Test default sensitivity for indicators.""" |
852 | @@ -151,9 +203,9 @@ | |||
853 | 151 | """Test on_start_clicked.""" | 203 | """Test on_start_clicked.""" |
854 | 152 | self.ui.on_start_clicked(self.ui.start) | 204 | self.ui.on_start_clicked(self.ui.start) |
855 | 153 | 205 | ||
857 | 154 | self.assertTrue(self.ui.start.get_property('visible')) | 206 | self.assertTrue(self.ui.widget_is_visible(self.ui.start)) |
858 | 155 | self.assertFalse(self.ui.start.is_sensitive()) | 207 | self.assertFalse(self.ui.start.is_sensitive()) |
860 | 156 | self.assertFalse(self.ui.stop.get_property('visible')) | 208 | self.assertFalse(self.ui.widget_is_visible(self.ui.stop)) |
861 | 157 | 209 | ||
862 | 158 | self.assert_indicator_loading(self.ui.is_started) | 210 | self.assert_indicator_loading(self.ui.is_started) |
863 | 159 | self.assert_indicator_disabled(self.ui.is_connected) | 211 | self.assert_indicator_disabled(self.ui.is_connected) |
864 | @@ -170,9 +222,9 @@ | |||
865 | 170 | self.do_start() # need to be started | 222 | self.do_start() # need to be started |
866 | 171 | self.ui.on_connect_clicked(self.ui.connect) | 223 | self.ui.on_connect_clicked(self.ui.connect) |
867 | 172 | 224 | ||
869 | 173 | self.assertTrue(self.ui.connect.get_property('visible')) | 225 | self.assertTrue(self.ui.widget_is_visible(self.ui.connect)) |
870 | 174 | self.assertFalse(self.ui.connect.is_sensitive()) | 226 | self.assertFalse(self.ui.connect.is_sensitive()) |
872 | 175 | self.assertFalse(self.ui.disconnect.get_property('visible')) | 227 | self.assertFalse(self.ui.widget_is_visible(self.ui.disconnect)) |
873 | 176 | 228 | ||
874 | 177 | self.assert_indicator_ready(self.ui.is_started) | 229 | self.assert_indicator_ready(self.ui.is_started) |
875 | 178 | self.assert_indicator_loading(self.ui.is_connected) | 230 | self.assert_indicator_loading(self.ui.is_connected) |
876 | @@ -193,13 +245,13 @@ | |||
877 | 193 | 245 | ||
878 | 194 | self.assertFalse(self._called, 'on_disconnect_clicked was not called.') | 246 | self.assertFalse(self._called, 'on_disconnect_clicked was not called.') |
879 | 195 | 247 | ||
882 | 196 | self.assertFalse(self.ui.start.get_property('visible')) | 248 | self.assertFalse(self.ui.widget_is_visible(self.ui.start)) |
883 | 197 | self.assertTrue(self.ui.stop.get_property('visible')) | 249 | self.assertTrue(self.ui.widget_is_visible(self.ui.stop)) |
884 | 198 | self.assertFalse(self.ui.stop.is_sensitive()) | 250 | self.assertFalse(self.ui.stop.is_sensitive()) |
885 | 199 | 251 | ||
887 | 200 | self.assertTrue(self.ui.connect.get_property('visible')) | 252 | self.assertTrue(self.ui.widget_is_visible(self.ui.connect)) |
888 | 201 | self.assertFalse(self.ui.connect.is_sensitive()) | 253 | self.assertFalse(self.ui.connect.is_sensitive()) |
890 | 202 | self.assertFalse(self.ui.disconnect.get_property('visible')) | 254 | self.assertFalse(self.ui.widget_is_visible(self.ui.disconnect)) |
891 | 203 | 255 | ||
892 | 204 | def test_on_stop_clicked_if_connected(self): | 256 | def test_on_stop_clicked_if_connected(self): |
893 | 205 | """Test on_stop_clicked.""" | 257 | """Test on_stop_clicked.""" |
894 | @@ -220,8 +272,8 @@ | |||
895 | 220 | self.do_connect() | 272 | self.do_connect() |
896 | 221 | self.ui.on_disconnect_clicked(self.ui.disconnect) | 273 | self.ui.on_disconnect_clicked(self.ui.disconnect) |
897 | 222 | 274 | ||
900 | 223 | self.assertFalse(self.ui.connect.get_property('visible')) | 275 | self.assertFalse(self.ui.widget_is_visible(self.ui.connect)) |
901 | 224 | self.assertTrue(self.ui.disconnect.get_property('visible')) | 276 | self.assertTrue(self.ui.widget_is_visible(self.ui.disconnect)) |
902 | 225 | self.assertFalse(self.ui.disconnect.is_sensitive()) | 277 | self.assertFalse(self.ui.disconnect.is_sensitive()) |
903 | 226 | 278 | ||
904 | 227 | def test_on_disconnect_clicked_disconnects_syncdaemon(self): | 279 | def test_on_disconnect_clicked_disconnects_syncdaemon(self): |
905 | @@ -237,7 +289,7 @@ | |||
906 | 237 | def test_main_window_is_hid_when_icon_clicked(self): | 289 | def test_main_window_is_hid_when_icon_clicked(self): |
907 | 238 | """Main window is hid when the systray icon is clicked.""" | 290 | """Main window is hid when the systray icon is clicked.""" |
908 | 239 | self.ui.on_status_icon_activate(self.ui.status_icon) | 291 | self.ui.on_status_icon_activate(self.ui.status_icon) |
910 | 240 | self.assertFalse(self.ui.main_window.get_property('visible'), | 292 | self.assertFalse(self.ui.widget_is_visible(self.ui.main_window), |
911 | 241 | 'main_window should be invisible when icon clicked.') | 293 | 'main_window should be invisible when icon clicked.') |
912 | 242 | 294 | ||
913 | 243 | def test_main_window_is_shown_when_clicked_after_hidden(self): | 295 | def test_main_window_is_shown_when_clicked_after_hidden(self): |
914 | @@ -245,7 +297,7 @@ | |||
915 | 245 | self.ui.on_status_icon_activate(self.ui.status_icon) # hide | 297 | self.ui.on_status_icon_activate(self.ui.status_icon) # hide |
916 | 246 | self.ui.on_status_icon_activate(self.ui.status_icon) # show | 298 | self.ui.on_status_icon_activate(self.ui.status_icon) # show |
917 | 247 | msg = 'main_window should be visible when icon clicked after hidden.' | 299 | msg = 'main_window should be visible when icon clicked after hidden.' |
919 | 248 | self.assertTrue(self.ui.main_window.get_property('visible'), msg) | 300 | self.assertTrue(self.ui.widget_is_visible(self.ui.main_window), msg) |
920 | 249 | 301 | ||
921 | 250 | 302 | ||
922 | 251 | def skip_abstract_class(test): | 303 | def skip_abstract_class(test): |
923 | @@ -253,7 +305,7 @@ | |||
924 | 253 | @wraps(test) | 305 | @wraps(test) |
925 | 254 | def inner(klass): | 306 | def inner(klass): |
926 | 255 | """Execute 'test' only if not in an abstract class.""" | 307 | """Execute 'test' only if not in an abstract class.""" |
928 | 256 | if klass.queue is not None: | 308 | if klass.name is not None: |
929 | 257 | test(klass) | 309 | test(klass) |
930 | 258 | return inner | 310 | return inner |
931 | 259 | 311 | ||
932 | @@ -261,54 +313,32 @@ | |||
933 | 261 | class _MagicicadaUIQueueTestCase(MagicicadaUITestCase): | 313 | class _MagicicadaUIQueueTestCase(MagicicadaUITestCase): |
934 | 262 | """Abstratc UI test cases for queue tree views.""" | 314 | """Abstratc UI test cases for queue tree views.""" |
935 | 263 | 315 | ||
937 | 264 | queue = None | 316 | name = None |
938 | 265 | 317 | ||
939 | 266 | def setUp(self): | 318 | def setUp(self): |
940 | 267 | """Init.""" | 319 | """Init.""" |
941 | 268 | super(_MagicicadaUIQueueTestCase, self).setUp() | 320 | super(_MagicicadaUIQueueTestCase, self).setUp() |
943 | 269 | if self.queue is None: | 321 | if self.name is None: |
944 | 270 | return | 322 | return |
945 | 271 | self.sd_changed = getattr(self.ui.sd, | 323 | self.sd_changed = getattr(self.ui.sd, |
947 | 272 | '%s_queue_changed_callback' % self.queue) | 324 | '%s_queue_changed_callback' % self.name) |
948 | 273 | self.ui_changed = getattr(self.ui, | 325 | self.ui_changed = getattr(self.ui, |
952 | 274 | 'on_%s_queue_changed' % self.queue) | 326 | 'on_%s_queue_changed' % self.name) |
953 | 275 | self.queue_store = getattr(self.ui, '%sq_store' % self.queue) | 327 | self.queue_store = getattr(self.ui, '%sq_store' % self.name) |
954 | 276 | self.queue_view = getattr(self.ui, '%sq_view' % self.queue) | 328 | self.queue_view = getattr(self.ui, '%sq_view' % self.name) |
955 | 277 | 329 | ||
956 | 278 | def build_some_data(self, limit=5): | 330 | def build_some_data(self, limit=5): |
984 | 279 | """Build some data to pass to queue changed callback and related.""" | 331 | """Build some data to act as queue data.""" |
985 | 280 | items = [] | 332 | kwargs = dict(data_type=QueueData, limit=limit) |
986 | 281 | for i in xrange(limit): | 333 | res = super(_MagicicadaUIQueueTestCase, self).build_some_data(**kwargs) |
987 | 282 | cq = QueueData(operation='operation %i' % i, | 334 | # operation path share node |
988 | 283 | path='path %i' % i, node='node %i' % i, | 335 | return res |
962 | 284 | share='share %i' % i) | ||
963 | 285 | items.append(cq) | ||
964 | 286 | return items | ||
965 | 287 | |||
966 | 288 | def assert_queue_store_correct(self, queue_store, items): | ||
967 | 289 | """Test that 'queue_store' has 'items' as content.""" | ||
968 | 290 | msg = 'amount of rows for %s must be %s (got %s).' | ||
969 | 291 | self.assertEqual(len(queue_store), len(items), | ||
970 | 292 | msg % (queue_store, len(items), len(queue_store))) | ||
971 | 293 | # assert rows content equal to items content | ||
972 | 294 | tree_iter = queue_store.get_iter_root() | ||
973 | 295 | tmp = list(reversed(items)) | ||
974 | 296 | while tree_iter is not None: | ||
975 | 297 | expected = tmp.pop() | ||
976 | 298 | |||
977 | 299 | op, path, node, share = queue_store.get(tree_iter, 0, 1, 2, 3) | ||
978 | 300 | self.assertEqual(expected.operation, op) | ||
979 | 301 | self.assertEqual(expected.path, path) | ||
980 | 302 | self.assertEqual(expected.node, node) | ||
981 | 303 | self.assertEqual(expected.share, share) | ||
982 | 304 | |||
983 | 305 | tree_iter = queue_store.iter_next(tree_iter) | ||
989 | 306 | 336 | ||
990 | 307 | @skip_abstract_class | 337 | @skip_abstract_class |
991 | 308 | def test_callback_is_connected(self): | 338 | def test_callback_is_connected(self): |
992 | 309 | """Queue changed callback is connected.""" | 339 | """Queue changed callback is connected.""" |
993 | 310 | self.assertEqual(self.sd_changed, self.ui_changed, | 340 | self.assertEqual(self.sd_changed, self.ui_changed, |
995 | 311 | '%s queue callback must be set' % self.queue) | 341 | '%s queue callback must be set' % self.name) |
996 | 312 | 342 | ||
997 | 313 | @skip_abstract_class | 343 | @skip_abstract_class |
998 | 314 | def test_model_is_binded(self): | 344 | def test_model_is_binded(self): |
999 | @@ -316,20 +346,20 @@ | |||
1000 | 316 | actual = self.queue_view.get_model() | 346 | actual = self.queue_view.get_model() |
1001 | 317 | msg = 'model for view %s differs from %s' | 347 | msg = 'model for view %s differs from %s' |
1002 | 318 | self.assertEqual(self.queue_store, actual, | 348 | self.assertEqual(self.queue_store, actual, |
1004 | 319 | msg % (self.queue, self.queue_store)) | 349 | msg % (self.name, self.queue_store)) |
1005 | 320 | 350 | ||
1006 | 321 | @skip_abstract_class | 351 | @skip_abstract_class |
1007 | 322 | def test_on_queue_changed_updates_view(self): | 352 | def test_on_queue_changed_updates_view(self): |
1008 | 323 | """On queue changed the view is updated.""" | 353 | """On queue changed the view is updated.""" |
1009 | 324 | items = self.build_some_data() | 354 | items = self.build_some_data() |
1010 | 325 | self.sd_changed(items) | 355 | self.sd_changed(items) |
1012 | 326 | self.assert_queue_store_correct(self.queue_store, items) | 356 | self.assert_store_correct(self.queue_store, items) |
1013 | 327 | 357 | ||
1014 | 328 | @skip_abstract_class | 358 | @skip_abstract_class |
1015 | 329 | def test_on_queue_changed_handles_none(self): | 359 | def test_on_queue_changed_handles_none(self): |
1016 | 330 | """On queue changed handles None as items.""" | 360 | """On queue changed handles None as items.""" |
1017 | 331 | self.sd_changed(None) | 361 | self.sd_changed(None) |
1019 | 332 | self.assert_queue_store_correct(self.queue_store, []) | 362 | self.assert_store_correct(self.queue_store, []) |
1020 | 333 | 363 | ||
1021 | 334 | @skip_abstract_class | 364 | @skip_abstract_class |
1022 | 335 | def test_model_is_cleared_before_updating(self): | 365 | def test_model_is_cleared_before_updating(self): |
1023 | @@ -356,16 +386,16 @@ | |||
1024 | 356 | def test_update_is_correct_for_queue(self): | 386 | def test_update_is_correct_for_queue(self): |
1025 | 357 | """Correctly updates the queue state.""" | 387 | """Correctly updates the queue state.""" |
1026 | 358 | data = self.build_some_data() | 388 | data = self.build_some_data() |
1028 | 359 | setattr(self.ui.sd, '%s_queue' % self.queue, data) | 389 | setattr(self.ui.sd, '%s_queue' % self.name, data) |
1029 | 360 | 390 | ||
1030 | 361 | self.ui.update() | 391 | self.ui.update() |
1031 | 362 | 392 | ||
1033 | 363 | self.assert_queue_store_correct(self.queue_store, data) | 393 | self.assert_store_correct(self.queue_store, data) |
1034 | 364 | 394 | ||
1035 | 365 | @skip_abstract_class | 395 | @skip_abstract_class |
1036 | 366 | def test_on_stopped_updates_queue(self): | 396 | def test_on_stopped_updates_queue(self): |
1037 | 367 | """On SD stoppped, the UI updates the queue state.""" | 397 | """On SD stoppped, the UI updates the queue state.""" |
1039 | 368 | cb = 'on_%s_queue_changed' % self.queue | 398 | cb = 'on_%s_queue_changed' % self.name |
1040 | 369 | self.patch(self.ui, cb, self.set_called) | 399 | self.patch(self.ui, cb, self.set_called) |
1041 | 370 | self.ui.on_stopped() | 400 | self.ui.on_stopped() |
1042 | 371 | self.assertTrue(self._called, | 401 | self.assertTrue(self._called, |
1043 | @@ -375,13 +405,13 @@ | |||
1044 | 375 | class MagicicadaUIContentQueueTestCase(_MagicicadaUIQueueTestCase): | 405 | class MagicicadaUIContentQueueTestCase(_MagicicadaUIQueueTestCase): |
1045 | 376 | """UI test cases for content queue view.""" | 406 | """UI test cases for content queue view.""" |
1046 | 377 | 407 | ||
1048 | 378 | queue = CONTENT_QUEUE | 408 | name = CONTENT_QUEUE |
1049 | 379 | 409 | ||
1050 | 380 | 410 | ||
1051 | 381 | class MagicicadaUIMetaQueueTestCase(_MagicicadaUIQueueTestCase): | 411 | class MagicicadaUIMetaQueueTestCase(_MagicicadaUIQueueTestCase): |
1052 | 382 | """UI test cases for meta queue view.""" | 412 | """UI test cases for meta queue view.""" |
1053 | 383 | 413 | ||
1055 | 384 | queue = META_QUEUE | 414 | name = META_QUEUE |
1056 | 385 | 415 | ||
1057 | 386 | 416 | ||
1058 | 387 | class MagicicadaUIStatusTestCase(MagicicadaUITestCase): | 417 | class MagicicadaUIStatusTestCase(MagicicadaUITestCase): |
1059 | @@ -472,7 +502,7 @@ | |||
1060 | 472 | 502 | ||
1061 | 473 | 503 | ||
1062 | 474 | class MagicicadaUIConnectionTestCase(MagicicadaUITestCase): | 504 | class MagicicadaUIConnectionTestCase(MagicicadaUITestCase): |
1064 | 475 | """UI test cases for.""" | 505 | """UI test cases for connection buttons/indicators.""" |
1065 | 476 | 506 | ||
1066 | 477 | def assert_indicator_is_updated_correctly(self, indicator): | 507 | def assert_indicator_is_updated_correctly(self, indicator): |
1067 | 478 | """Test that correctly updates the 'indicator'.""" | 508 | """Test that correctly updates the 'indicator'.""" |
1068 | @@ -503,7 +533,7 @@ | |||
1069 | 503 | else: | 533 | else: |
1070 | 504 | self.assertFalse(self.ui.connect.is_sensitive(), | 534 | self.assertFalse(self.ui.connect.is_sensitive(), |
1071 | 505 | 'connect must be disabled when %s' % cs) | 535 | 'connect must be disabled when %s' % cs) |
1073 | 506 | self.assertTrue(self.ui.connect.get_property('visible'), | 536 | self.assertTrue(self.ui.widget_is_visible(self.ui.connect), |
1074 | 507 | 'connect must be visible when %s' % cs) | 537 | 'connect must be visible when %s' % cs) |
1075 | 508 | actual = self.ui.widget_enabled(getattr(self.ui, indicator)) | 538 | actual = self.ui.widget_enabled(getattr(self.ui, indicator)) |
1076 | 509 | self.assertFalse(actual, | 539 | self.assertFalse(actual, |
1077 | @@ -562,7 +592,7 @@ | |||
1078 | 562 | self.ui.on_stopped() | 592 | self.ui.on_stopped() |
1079 | 563 | 593 | ||
1080 | 564 | self.assertTrue(self.ui.start.is_sensitive()) | 594 | self.assertTrue(self.ui.start.is_sensitive()) |
1082 | 565 | self.assertTrue(self.ui.start.get_property('visible')) | 595 | self.assertTrue(self.ui.widget_is_visible(self.ui.start)) |
1083 | 566 | self.assert_indicator_disabled(self.ui.is_started) | 596 | self.assert_indicator_disabled(self.ui.is_started) |
1084 | 567 | self.assert_indicator_disabled(self.ui.is_connected) | 597 | self.assert_indicator_disabled(self.ui.is_connected) |
1085 | 568 | self.assert_indicator_disabled(self.ui.is_online) | 598 | self.assert_indicator_disabled(self.ui.is_online) |
1086 | @@ -593,3 +623,161 @@ | |||
1087 | 593 | """Correctly updates the indicators and buttons state.""" | 623 | """Correctly updates the indicators and buttons state.""" |
1088 | 594 | for i in ('is_started', 'is_connected', 'is_online'): | 624 | for i in ('is_started', 'is_connected', 'is_online'): |
1089 | 595 | self.assert_indicator_is_updated_correctly(i) | 625 | self.assert_indicator_is_updated_correctly(i) |
1090 | 626 | |||
1091 | 627 | |||
1092 | 628 | class _MagicicadaUIVolumeTestCase(MagicicadaUITestCase): | ||
1093 | 629 | """Abstract UI test cases for volumes (folders/shares).""" | ||
1094 | 630 | |||
1095 | 631 | name = None | ||
1096 | 632 | data_type = None | ||
1097 | 633 | |||
1098 | 634 | def setUp(self): | ||
1099 | 635 | """Init.""" | ||
1100 | 636 | super(_MagicicadaUIVolumeTestCase, self).setUp() | ||
1101 | 637 | if self.name is None: | ||
1102 | 638 | return | ||
1103 | 639 | self.volume = getattr(self.ui, self.name) | ||
1104 | 640 | self.volume_store = getattr(self.ui, '%s_store' % self.name) | ||
1105 | 641 | self.volume_dialog_name = '%s_dialog' % self.name | ||
1106 | 642 | self.volume_dialog = getattr(self.ui, self.volume_dialog_name) | ||
1107 | 643 | self.on_volume_clicked = getattr(self.ui, 'on_%s_clicked' % self.name) | ||
1108 | 644 | |||
1109 | 645 | def build_some_data(self, limit=5): | ||
1110 | 646 | """Build some data to act as volume.""" | ||
1111 | 647 | kwargs = dict(data_type=self.data_type, limit=limit) | ||
1112 | 648 | res = super(_MagicicadaUIVolumeTestCase, self).build_some_data(**kwargs) | ||
1113 | 649 | return res | ||
1114 | 650 | |||
1115 | 651 | def assert_volume_availability(self, enabled): | ||
1116 | 652 | """Check volume availability according to 'enabled'.""" | ||
1117 | 653 | self.assertTrue(self.ui.widget_is_visible(self.volume), | ||
1118 | 654 | '%s should be visible' % self.name) | ||
1119 | 655 | sensitive = self.volume.is_sensitive() | ||
1120 | 656 | msg = '%s should %sbe sensitive' | ||
1121 | 657 | self.assertTrue(sensitive if enabled else not sensitive, | ||
1122 | 658 | msg % (self.name, '' if enabled else 'not ')) | ||
1123 | 659 | |||
1124 | 660 | @skip_abstract_class | ||
1125 | 661 | def test_volume_are_disabled_until_online(self): | ||
1126 | 662 | """Folders and shares are disabled until online.""" | ||
1127 | 663 | # disabled at startup | ||
1128 | 664 | self.assert_volume_availability(enabled=False) | ||
1129 | 665 | |||
1130 | 666 | # disabled even if connected | ||
1131 | 667 | self.do_connect() | ||
1132 | 668 | self.assert_volume_availability(enabled=False) | ||
1133 | 669 | |||
1134 | 670 | # enabled when online | ||
1135 | 671 | self.ui.on_online() | ||
1136 | 672 | self.assert_volume_availability(enabled=True) | ||
1137 | 673 | |||
1138 | 674 | @skip_abstract_class | ||
1139 | 675 | def test_volume_are_enabled_until_offline(self): | ||
1140 | 676 | """Folders and shares are enabled until offline.""" | ||
1141 | 677 | self.do_connect() | ||
1142 | 678 | self.ui.on_online() | ||
1143 | 679 | |||
1144 | 680 | # disabled when offline | ||
1145 | 681 | self.ui.on_offline() | ||
1146 | 682 | self.assert_volume_availability(enabled=False) | ||
1147 | 683 | |||
1148 | 684 | @skip_abstract_class | ||
1149 | 685 | def test_volume_close_emits_response_close(self): | ||
1150 | 686 | """Test volume close button emits RESPONSE_CLOSE when clicked.""" | ||
1151 | 687 | self.response = None | ||
1152 | 688 | def record_response(value): | ||
1153 | 689 | """Record the response received.""" | ||
1154 | 690 | self.response = value | ||
1155 | 691 | self.patch(self.volume_dialog, 'response', record_response) | ||
1156 | 692 | |||
1157 | 693 | volume_close = '%s_close' % self.name | ||
1158 | 694 | getattr(self.ui, volume_close).clicked() | ||
1159 | 695 | self.assertEqual(gtk.RESPONSE_CLOSE, self.response, | ||
1160 | 696 | '%s should emit RESPONSE_CLOSE.' % volume_close) | ||
1161 | 697 | |||
1162 | 698 | @skip_abstract_class | ||
1163 | 699 | def test_on_volume_clicked(self): | ||
1164 | 700 | """Test on_volume_clicked.""" | ||
1165 | 701 | self.assertFalse(self.ui.widget_is_visible(self.volume_dialog), | ||
1166 | 702 | '%s should not be visible.' % self.volume_dialog_name) | ||
1167 | 703 | |||
1168 | 704 | def test(): | ||
1169 | 705 | """Perform the test per se before closing the dialog.""" | ||
1170 | 706 | self.assertTrue(self.ui.widget_is_visible(self.volume_dialog), | ||
1171 | 707 | '%s should be visible.' % self.volume_dialog_name) | ||
1172 | 708 | self.assert_store_correct(self.volume_store, items) | ||
1173 | 709 | |||
1174 | 710 | items = self.build_some_data() | ||
1175 | 711 | setattr(self.ui.sd, self.name, items) | ||
1176 | 712 | gobject.timeout_add(100, close_dialog, | ||
1177 | 713 | (self.volume_dialog, test)) | ||
1178 | 714 | self.on_volume_clicked(self.volume) | ||
1179 | 715 | |||
1180 | 716 | # dialog was closed already | ||
1181 | 717 | self.assertFalse(self.ui.widget_is_visible(self.volume_dialog), | ||
1182 | 718 | '%s should not be visible.' % self.volume_dialog_name) | ||
1183 | 719 | |||
1184 | 720 | @skip_abstract_class | ||
1185 | 721 | def test_on_volume_clicked_twice(self): | ||
1186 | 722 | """Test on_volume_clicked twice.""" | ||
1187 | 723 | |||
1188 | 724 | def test(): | ||
1189 | 725 | """Perform the test per se before closing the dialog.""" | ||
1190 | 726 | self.assertTrue(self.ui.widget_is_visible(self.volume_dialog), | ||
1191 | 727 | '%s should be visible.' % self.volume_dialog_name) | ||
1192 | 728 | self.assert_store_correct(self.volume_store, items) | ||
1193 | 729 | |||
1194 | 730 | items = self.build_some_data() | ||
1195 | 731 | setattr(self.ui.sd, self.name, items) | ||
1196 | 732 | |||
1197 | 733 | gobject.timeout_add(100, close_dialog, | ||
1198 | 734 | (self.volume_dialog, test)) | ||
1199 | 735 | self.on_volume_clicked(self.volume) | ||
1200 | 736 | |||
1201 | 737 | gobject.timeout_add(100, close_dialog, | ||
1202 | 738 | (self.volume_dialog, test)) | ||
1203 | 739 | self.on_volume_clicked(self.volume) | ||
1204 | 740 | |||
1205 | 741 | @skip_abstract_class | ||
1206 | 742 | def test_on_volume_clicked_handles_none(self): | ||
1207 | 743 | """On volume clicked handles None as items.""" | ||
1208 | 744 | setattr(self.ui.sd, self.name, None) | ||
1209 | 745 | test = lambda: self.assert_store_correct(self.volume_store, []) | ||
1210 | 746 | gobject.timeout_add(100, close_dialog, | ||
1211 | 747 | (self.volume_dialog, test)) | ||
1212 | 748 | self.on_volume_clicked(self.volume) | ||
1213 | 749 | |||
1214 | 750 | @skip_abstract_class | ||
1215 | 751 | def test_volume_dialog_props(self): | ||
1216 | 752 | """The volume dialog has correct properties.""" | ||
1217 | 753 | size = self.volume_dialog.size_request() | ||
1218 | 754 | self.assertEquals((600, 300), size) | ||
1219 | 755 | |||
1220 | 756 | self.assertTrue(self.volume_dialog.get_modal(), | ||
1221 | 757 | '%s must be modal.' % self.volume_dialog_name) | ||
1222 | 758 | |||
1223 | 759 | position = self.volume_dialog.get_property('window-position') | ||
1224 | 760 | self.assertEqual(gtk.WIN_POS_CENTER, position, | ||
1225 | 761 | '%s must be centered.' % self.volume_dialog_name) | ||
1226 | 762 | |||
1227 | 763 | actual = self.volume_dialog.get_title() | ||
1228 | 764 | expected = self.name.replace('_', ' ').capitalize() | ||
1229 | 765 | msg = '%s title must be %s (got %s instead)' | ||
1230 | 766 | self.assertEqual(expected, actual, | ||
1231 | 767 | msg % (self.volume_dialog_name, expected, actual)) | ||
1232 | 768 | |||
1233 | 769 | |||
1234 | 770 | class MagicicadaUIFoldersTestCase(_MagicicadaUIVolumeTestCase): | ||
1235 | 771 | """UI test cases for folders.""" | ||
1236 | 772 | |||
1237 | 773 | name = 'folders' | ||
1238 | 774 | data_type = FolderData # node path suggested_path subscribed volume | ||
1239 | 775 | |||
1240 | 776 | |||
1241 | 777 | class MagicicadaUISharesToMeTestCase(_MagicicadaUIVolumeTestCase): | ||
1242 | 778 | """UI test cases for shares_to_me.""" | ||
1243 | 779 | |||
1244 | 780 | name = 'shares_to_me' | ||
1245 | 781 | data_type = ShareData # accepted access_level free_bytes name node_id | ||
1246 | 782 | # other_username other_visible_name path volume_id | ||
1247 | 783 | |||
1248 | 596 | 784 | ||
1249 | === modified file 'magicicada/tests/test_syncdaemon.py' | |||
1250 | --- magicicada/tests/test_syncdaemon.py 2010-05-31 00:31:17 +0000 | |||
1251 | +++ magicicada/tests/test_syncdaemon.py 2010-05-31 22:49:23 +0000 | |||
1252 | @@ -306,6 +306,8 @@ | |||
1253 | 306 | class MetaQueueChangedTests(BaseTest): | 306 | class MetaQueueChangedTests(BaseTest): |
1254 | 307 | """Check the MetaQueueChanged handling.""" | 307 | """Check the MetaQueueChanged handling.""" |
1255 | 308 | 308 | ||
1256 | 309 | timeout = 3 | ||
1257 | 310 | |||
1258 | 309 | def setUp(self): | 311 | def setUp(self): |
1259 | 310 | """Set up.""" | 312 | """Set up.""" |
1260 | 311 | BaseTest.setUp(self) | 313 | BaseTest.setUp(self) |
Got some errors (see below).
Also, testing it manually, when the folder/shares buttons become active?
======= ======= ======= ======= ======= ======= ======= ======= ======= ======= ======= == tests.test_ magicicada. _MagicicadaUIVo lumeTestCase. test_on_ volume_ clicked
[ERROR]: magicicada.
Traceback (most recent call last): facundo/ devel/reps/ magicicada/ review_ list-folders/ magicicada/ tests/test_ magicicada. py", line 637, in setUp TypeError: getattr(): attribute name must be string ======= ======= ======= ======= ======= ======= ======= ======= ======= ======= == tests.test_ magicicada. _MagicicadaUIVo lumeTestCase. test_on_ volume_ clicked_ handles_ none
File "/home/
self.volume = getattr(self.ui, self.name)
exceptions.
=======
[ERROR]: magicicada.
Traceback (most recent call last): facundo/ devel/reps/ magicicada/ review_ list-folders/ magicicada/ tests/test_ magicicada. py", line 637, in setUp TypeError: getattr(): attribute name must be string ======= ======= ======= ======= ======= ======= ======= ======= ======= ======= == tests.test_ magicicada. _MagicicadaUIVo lumeTestCase. test_on_ volume_ clicked_ twice
File "/home/
self.volume = getattr(self.ui, self.name)
exceptions.
=======
[ERROR]: magicicada.
Traceback (most recent call last): facundo/ devel/reps/ magicicada/ review_ list-folders/ magicicada/ tests/test_ magicicada. py", line 637, in setUp TypeError: getattr(): attribute name must be string ======= ======= ======= ======= ======= ======= ======= ======= ======= ======= == tests.test_ magicicada. _MagicicadaUIVo lumeTestCase. test_volume_ are_disabled_ until_online
File "/home/
self.volume = getattr(self.ui, self.name)
exceptions.
=======
[ERROR]: magicicada.
Traceback (most recent call last): facundo/ devel/reps/ magicicada/ review_ list-folders/ magicicada/ tests/test_ magicicada. py", line 637, in setUp TypeError: getattr(): attribute name must be string ======= ======= ======= ======= ======= ======= ======= ======= ======= ======= == tests.test_ magicicada. _MagicicadaUIVo lumeTestCase. test_volume_ are_enabled_ until_offline
File "/home/
self.volume = getattr(self.ui, self.name)
exceptions.
=======
[ERROR]: magicicada.
Traceback (most recent call last): facundo/ devel/reps/ magicicada/ review_ list-folders/ magicicada/ tests/test_ magicicada. py", line 637, in setUp TypeError: getattr(): attribute name must be string ======= ======= ======= ======= ======= ======= ======= ======= ======= ======= == tests.test_ magicicada. _MagicicadaUIVo lumeTestCase. test_volume_ close_emits_ response_ close
File "/home/
self.volume = getattr(self.ui, self.name)
exceptions.
=======
[ERROR]: magicicada.
Traceback (most recent call last): facundo/ devel/reps/ magicicada/ review_ list-folders/ magicicada/ tests/test_ magicicada. py", line 637, in setUp TypeError: getattr(): attribute name must be string ======= ======= ======= ======= ======= ======= ======= ======= ======= ======= == tests.test_ magicicada. _MagicicadaUIVo lumeTestCase. test_volume_ dialog_ props
File "/home/
self.volume = getattr(self.ui, self.name)
exceptions.
=======
[ERROR]: magicicada.
Traceback (most recent call last): facundo/ devel/reps/ magicicada/ review_ list-folders/ magicicada/ tests/test_ magicicada. py", line 637, in setUp TypeErr. ..
File "/home/
self.volume = getattr(self.ui, self.name)
exceptions.