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