Merge lp:~nataliabidart/magicicada-gui/list-folders into lp:magicicada-gui

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
Reviewer Review Type Date Requested Status
Facundo Batista Approve
Review via email: mp+26447@code.launchpad.net

Description of the change

Implemented Folders and Shares to me functionality.

(Still pending Shares to others)

To post a comment you must log in.
Revision history for this message
Facundo Batista (facundo) wrote :
Download full text (3.2 KiB)

Got some errors (see below).

Also, testing it manually, when the folder/shares buttons become active?

===============================================================================
[ERROR]: magicicada.tests.test_magicicada._MagicicadaUIVolumeTestCase.test_on_volume_clicked

Traceback (most recent call last):
  File "/home/facundo/devel/reps/magicicada/review_list-folders/magicicada/tests/test_magicicada.py", line 637, in setUp
    self.volume = getattr(self.ui, self.name)
exceptions.TypeError: getattr(): attribute name must be string
===============================================================================
[ERROR]: magicicada.tests.test_magicicada._MagicicadaUIVolumeTestCase.test_on_volume_clicked_handles_none

Traceback (most recent call last):
  File "/home/facundo/devel/reps/magicicada/review_list-folders/magicicada/tests/test_magicicada.py", line 637, in setUp
    self.volume = getattr(self.ui, self.name)
exceptions.TypeError: getattr(): attribute name must be string
===============================================================================
[ERROR]: magicicada.tests.test_magicicada._MagicicadaUIVolumeTestCase.test_on_volume_clicked_twice

Traceback (most recent call last):
  File "/home/facundo/devel/reps/magicicada/review_list-folders/magicicada/tests/test_magicicada.py", line 637, in setUp
    self.volume = getattr(self.ui, self.name)
exceptions.TypeError: getattr(): attribute name must be string
===============================================================================
[ERROR]: magicicada.tests.test_magicicada._MagicicadaUIVolumeTestCase.test_volume_are_disabled_until_online

Traceback (most recent call last):
  File "/home/facundo/devel/reps/magicicada/review_list-folders/magicicada/tests/test_magicicada.py", line 637, in setUp
    self.volume = getattr(self.ui, self.name)
exceptions.TypeError: getattr(): attribute name must be string
===============================================================================
[ERROR]: magicicada.tests.test_magicicada._MagicicadaUIVolumeTestCase.test_volume_are_enabled_until_offline

Traceback (most recent call last):
  File "/home/facundo/devel/reps/magicicada/review_list-folders/magicicada/tests/test_magicicada.py", line 637, in setUp
    self.volume = getattr(self.ui, self.name)
exceptions.TypeError: getattr(): attribute name must be string
===============================================================================
[ERROR]: magicicada.tests.test_magicicada._MagicicadaUIVolumeTestCase.test_volume_close_emits_response_close

Traceback (most recent call last):
  File "/home/facundo/devel/reps/magicicada/review_list-folders/magicicada/tests/test_magicicada.py", line 637, in setUp
    self.volume = getattr(self.ui, self.name)
exceptions.TypeError: getattr(): attribute name must be string
===============================================================================
[ERROR]: magicicada.tests.test_magicicada._MagicicadaUIVolumeTestCase.test_volume_dialog_props

Traceback (most recent call last):
  File "/home/facundo/devel/reps/magicicada/review_list-folders/magicicada/tests/test_magicicada.py", line 637, in setUp
    self.volume = getattr(self.ui, self.name)
exceptions.TypeErr...

Read more...

review: Needs Fixing
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
=== added file '.bzrignore'
--- .bzrignore 1970-01-01 00:00:00 +0000
+++ .bzrignore 2010-05-31 22:49:23 +0000
@@ -0,0 +1,1 @@
1_trial_temp
02
=== modified file 'data/ui/gui.glade'
--- data/ui/gui.glade 2010-05-27 12:34:26 +0000
+++ data/ui/gui.glade 2010-05-31 22:49:23 +0000
@@ -2,33 +2,70 @@
2<interface>2<interface>
3 <requires lib="gtk+" version="2.16"/>3 <requires lib="gtk+" version="2.16"/>
4 <!-- interface-naming-policy project-wide -->4 <!-- interface-naming-policy project-wide -->
5 <object class="GtkListStore" id="folders_store">
6 <columns>
7 <!-- column-name node -->
8 <column type="gchararray"/>
9 <!-- column-name path -->
10 <column type="gchararray"/>
11 <!-- column-name suggested_path -->
12 <column type="gchararray"/>
13 <!-- column-name subscribed -->
14 <column type="gboolean"/>
15 <!-- column-name volume -->
16 <column type="gchararray"/>
17 </columns>
18 </object>
19 <object class="GtkListStore" id="contentq_store">
20 <columns>
21 <!-- column-name operation -->
22 <column type="gchararray"/>
23 <!-- column-name path -->
24 <column type="gchararray"/>
25 <!-- column-name share -->
26 <column type="gchararray"/>
27 <!-- column-name node -->
28 <column type="gchararray"/>
29 </columns>
30 </object>
5 <object class="GtkListStore" id="metaq_store">31 <object class="GtkListStore" id="metaq_store">
6 <columns>32 <columns>
7 <!-- column-name operation -->33 <!-- column-name operation -->
8 <column type="gchararray"/>34 <column type="gchararray"/>
9 <!-- column-name path -->35 <!-- column-name path -->
10 <column type="gchararray"/>36 <column type="gchararray"/>
37 <!-- column-name share -->
38 <column type="gchararray"/>
11 <!-- column-name node -->39 <!-- column-name node -->
12 <column type="gchararray"/>40 <column type="gchararray"/>
13 <!-- column-name share -->
14 <column type="gchararray"/>
15 </columns>41 </columns>
16 </object>42 </object>
17 <object class="GtkListStore" id="contentq_store">43 <object class="GtkListStore" id="shares_to_me_store">
18 <columns>44 <columns>
19 <!-- column-name Operation -->45 <!-- column-name accepted -->
20 <column type="gchararray"/>46 <column type="gboolean"/>
21 <!-- column-name Path -->47 <!-- column-name access_level -->
22 <column type="gchararray"/>48 <column type="gchararray"/>
23 <!-- column-name Node -->49 <!-- column-name free_bytes -->
24 <column type="gchararray"/>50 <column type="gchararray"/>
25 <!-- column-name Share -->51 <!-- column-name name -->
52 <column type="gchararray"/>
53 <!-- column-name node_id -->
54 <column type="gchararray"/>
55 <!-- column-name other_username -->
56 <column type="gchararray"/>
57 <!-- column-name other_visible_name -->
58 <column type="gchararray"/>
59 <!-- column-name path -->
60 <column type="gchararray"/>
61 <!-- column-name volume_id -->
26 <column type="gchararray"/>62 <column type="gchararray"/>
27 </columns>63 </columns>
28 </object>64 </object>
29 <object class="GtkWindow" id="main_window">65 <object class="GtkWindow" id="main_window">
30 <property name="width_request">800</property>66 <property name="width_request">800</property>
31 <property name="height_request">600</property>67 <property name="height_request">600</property>
68 <property name="visible">True</property>
32 <property name="title" translatable="yes">Magicicada</property>69 <property name="title" translatable="yes">Magicicada</property>
33 <property name="window_position">center</property>70 <property name="window_position">center</property>
34 <signal name="destroy" handler="on_main_window_destroy"/>71 <signal name="destroy" handler="on_main_window_destroy"/>
@@ -145,6 +182,71 @@
145 <property name="homogeneous">True</property>182 <property name="homogeneous">True</property>
146 </packing>183 </packing>
147 </child>184 </child>
185 <child>
186 <object class="GtkSeparatorToolItem" id="separator">
187 <property name="visible">True</property>
188 </object>
189 <packing>
190 <property name="expand">False</property>
191 <property name="homogeneous">True</property>
192 </packing>
193 </child>
194 <child>
195 <object class="GtkToolButton" id="folders">
196 <property name="visible">True</property>
197 <property name="sensitive">False</property>
198 <property name="label" translatable="yes">Folders</property>
199 <property name="use_underline">True</property>
200 <property name="stock_id">gtk-directory</property>
201 <signal name="clicked" handler="on_folders_clicked"/>
202 </object>
203 <packing>
204 <property name="expand">False</property>
205 <property name="homogeneous">True</property>
206 </packing>
207 </child>
208 <child>
209 <object class="GtkToolButton" id="shares_to_me">
210 <property name="visible">True</property>
211 <property name="sensitive">False</property>
212 <property name="label" translatable="yes">Shares to me</property>
213 <property name="use_underline">True</property>
214 <property name="stock_id">gtk-network</property>
215 <signal name="clicked" handler="on_shares_to_me_clicked"/>
216 </object>
217 <packing>
218 <property name="expand">False</property>
219 <property name="homogeneous">True</property>
220 </packing>
221 </child>
222 <child>
223 <object class="GtkToolButton" id="shares_to_others">
224 <property name="visible">True</property>
225 <property name="sensitive">False</property>
226 <property name="label" translatable="yes">Shares to others</property>
227 <property name="use_underline">True</property>
228 <property name="stock_id">gtk-network</property>
229 <signal name="clicked" handler="on_shares_to_others_clicked"/>
230 </object>
231 <packing>
232 <property name="expand">False</property>
233 <property name="homogeneous">True</property>
234 </packing>
235 </child>
236 <child>
237 <object class="GtkToolButton" id="raw_metadata">
238 <property name="visible">True</property>
239 <property name="sensitive">False</property>
240 <property name="label" translatable="yes">Metadata</property>
241 <property name="use_underline">True</property>
242 <property name="stock_id">gtk-find</property>
243 <signal name="clicked" handler="on_raw_metadata_clicked"/>
244 </object>
245 <packing>
246 <property name="expand">False</property>
247 <property name="homogeneous">True</property>
248 </packing>
249 </child>
148 </object>250 </object>
149 <packing>251 <packing>
150 <property name="expand">False</property>252 <property name="expand">False</property>
@@ -199,7 +301,6 @@
199 </object>301 </object>
200 <packing>302 <packing>
201 <property name="expand">False</property>303 <property name="expand">False</property>
202 <property name="padding">3</property>
203 <property name="position">0</property>304 <property name="position">0</property>
204 </packing>305 </packing>
205 </child>306 </child>
@@ -215,6 +316,7 @@
215 </object>316 </object>
216 <packing>317 <packing>
217 <property name="expand">False</property>318 <property name="expand">False</property>
319 <property name="padding">3</property>
218 <property name="position">2</property>320 <property name="position">2</property>
219 </packing>321 </packing>
220 </child>322 </child>
@@ -279,24 +381,24 @@
279 </object>381 </object>
280 </child>382 </child>
281 <child>383 <child>
384 <object class="GtkTreeViewColumn" id="metaq_share">
385 <property name="title">Share</property>
386 <property name="expand">True</property>
387 <child>
388 <object class="GtkCellRendererText" id="cellrenderertext4"/>
389 <attributes>
390 <attribute name="text">2</attribute>
391 </attributes>
392 </child>
393 </object>
394 </child>
395 <child>
282 <object class="GtkTreeViewColumn" id="metaq_node">396 <object class="GtkTreeViewColumn" id="metaq_node">
283 <property name="title">Node</property>397 <property name="title">Node</property>
284 <property name="expand">True</property>398 <property name="expand">True</property>
285 <child>399 <child>
286 <object class="GtkCellRendererText" id="cellrenderertext3"/>400 <object class="GtkCellRendererText" id="cellrenderertext3"/>
287 <attributes>401 <attributes>
288 <attribute name="text">2</attribute>
289 </attributes>
290 </child>
291 </object>
292 </child>
293 <child>
294 <object class="GtkTreeViewColumn" id="metaq_share">
295 <property name="title">Share</property>
296 <property name="expand">True</property>
297 <child>
298 <object class="GtkCellRendererText" id="cellrenderertext4"/>
299 <attributes>
300 <attribute name="text">3</attribute>402 <attribute name="text">3</attribute>
301 </attributes>403 </attributes>
302 </child>404 </child>
@@ -371,24 +473,24 @@
371 </object>473 </object>
372 </child>474 </child>
373 <child>475 <child>
476 <object class="GtkTreeViewColumn" id="contentq_share">
477 <property name="title">Share</property>
478 <property name="expand">True</property>
479 <child>
480 <object class="GtkCellRendererText" id="cellrenderertext8"/>
481 <attributes>
482 <attribute name="text">2</attribute>
483 </attributes>
484 </child>
485 </object>
486 </child>
487 <child>
374 <object class="GtkTreeViewColumn" id="contentq_node">488 <object class="GtkTreeViewColumn" id="contentq_node">
375 <property name="title">Node</property>489 <property name="title">Node</property>
376 <property name="expand">True</property>490 <property name="expand">True</property>
377 <child>491 <child>
378 <object class="GtkCellRendererText" id="cellrenderertext7"/>492 <object class="GtkCellRendererText" id="cellrenderertext7"/>
379 <attributes>493 <attributes>
380 <attribute name="text">2</attribute>
381 </attributes>
382 </child>
383 </object>
384 </child>
385 <child>
386 <object class="GtkTreeViewColumn" id="contentq_share">
387 <property name="title">Share</property>
388 <property name="expand">True</property>
389 <child>
390 <object class="GtkCellRendererText" id="cellrenderertext8"/>
391 <attributes>
392 <attribute name="text">3</attribute>494 <attribute name="text">3</attribute>
393 </attributes>495 </attributes>
394 </child>496 </child>
@@ -426,13 +528,25 @@
426 <property name="type_hint">normal</property>528 <property name="type_hint">normal</property>
427 <property name="has_separator">False</property>529 <property name="has_separator">False</property>
428 <property name="program_name">Magicicada</property>530 <property name="program_name">Magicicada</property>
429 <property name="copyright" translatable="yes">Copyright 2010 Natalia Bidart &lt;natalia.bidart@gmail.com&gt;531 <property name="copyright" translatable="yes">Copyright 2010 Chicharreros
430Copyright 2010 Facundo Batista &lt;facundo@taniquetil.com.ar&gt;532Copyright 2010 Natalia Bidart &lt;natalia.bidart@gmail.com&gt;
431</property>533Copyright 2010 Facundo Batista &lt;facundo@taniquetil.com.ar&gt;</property>
432 <property name="website">http://launchpad.net/magicicada</property>534 <property name="website">http://launchpad.net/magicicada</property>
433 <property name="license" translatable="yes">GPL v3.0</property>535 <property name="license" translatable="yes">GNU General Public License
536
537This program is free software: you can redistribute it and/or modify it
538under the terms of the GNU General Public License version 3, as published
539by the Free Software Foundation.
540
541This program is distributed in the hope that it will be useful, but
542WITHOUT ANY WARRANTY; without even the implied warranties of
543MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
544PURPOSE. See the GNU General Public License for more details.
545
546You should have received a copy of the GNU General Public License along
547with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.</property>
434 <property name="authors">Natalia Bidart &lt;natalia.bidart@gmail.com&gt;548 <property name="authors">Natalia Bidart &lt;natalia.bidart@gmail.com&gt;
435Facundo Batista &lt;facundo.batista@gmail.com&gt;</property>549Facundo Batista &lt;facundo@taniquetil.com.ar&gt;</property>
436 <child internal-child="vbox">550 <child internal-child="vbox">
437 <object class="GtkVBox" id="dialog-vbox1">551 <object class="GtkVBox" id="dialog-vbox1">
438 <property name="visible">True</property>552 <property name="visible">True</property>
@@ -454,4 +568,299 @@
454 </object>568 </object>
455 </child>569 </child>
456 </object>570 </object>
571 <object class="GtkDialog" id="folders_dialog">
572 <property name="width_request">600</property>
573 <property name="height_request">300</property>
574 <property name="border_width">5</property>
575 <property name="title" translatable="yes">Folders</property>
576 <property name="modal">True</property>
577 <property name="window_position">center</property>
578 <property name="type_hint">normal</property>
579 <property name="skip_taskbar_hint">True</property>
580 <property name="has_separator">False</property>
581 <child internal-child="vbox">
582 <object class="GtkVBox" id="dialog-vbox2">
583 <property name="visible">True</property>
584 <property name="spacing">2</property>
585 <child>
586 <object class="GtkScrolledWindow" id="scrolledwindow3">
587 <property name="visible">True</property>
588 <property name="can_focus">True</property>
589 <property name="hscrollbar_policy">automatic</property>
590 <child>
591 <object class="GtkTreeView" id="folders_view">
592 <property name="visible">True</property>
593 <property name="can_focus">True</property>
594 <property name="model">folders_store</property>
595 <property name="headers_clickable">False</property>
596 <property name="rules_hint">True</property>
597 <property name="search_column">0</property>
598 <property name="enable_grid_lines">both</property>
599 <property name="enable_tree_lines">True</property>
600 <child>
601 <object class="GtkTreeViewColumn" id="folders_node">
602 <property name="resizable">True</property>
603 <property name="title">Node</property>
604 <property name="expand">True</property>
605 <child>
606 <object class="GtkCellRendererText" id="cellrenderertext9"/>
607 <attributes>
608 <attribute name="text">0</attribute>
609 </attributes>
610 </child>
611 </object>
612 </child>
613 <child>
614 <object class="GtkTreeViewColumn" id="folders_path">
615 <property name="resizable">True</property>
616 <property name="title">Path</property>
617 <property name="expand">True</property>
618 <child>
619 <object class="GtkCellRendererText" id="cellrenderertext10"/>
620 <attributes>
621 <attribute name="text">1</attribute>
622 </attributes>
623 </child>
624 </object>
625 </child>
626 <child>
627 <object class="GtkTreeViewColumn" id="folders_suggested_path">
628 <property name="resizable">True</property>
629 <property name="title">Suggested Path</property>
630 <property name="expand">True</property>
631 <child>
632 <object class="GtkCellRendererText" id="cellrenderertext11"/>
633 <attributes>
634 <attribute name="text">2</attribute>
635 </attributes>
636 </child>
637 </object>
638 </child>
639 <child>
640 <object class="GtkTreeViewColumn" id="folders_subscribed">
641 <property name="resizable">True</property>
642 <property name="title">Subscribed</property>
643 <property name="expand">True</property>
644 <child>
645 <object class="GtkCellRendererToggle" id="cellrenderertoggle1"/>
646 <attributes>
647 <attribute name="active">3</attribute>
648 </attributes>
649 </child>
650 </object>
651 </child>
652 <child>
653 <object class="GtkTreeViewColumn" id="folders_volume">
654 <property name="resizable">True</property>
655 <property name="title">Volume</property>
656 <property name="expand">True</property>
657 <child>
658 <object class="GtkCellRendererText" id="cellrenderertext12"/>
659 <attributes>
660 <attribute name="text">4</attribute>
661 </attributes>
662 </child>
663 </object>
664 </child>
665 </object>
666 </child>
667 </object>
668 <packing>
669 <property name="position">1</property>
670 </packing>
671 </child>
672 <child internal-child="action_area">
673 <object class="GtkHButtonBox" id="dialog-action_area2">
674 <property name="visible">True</property>
675 <property name="layout_style">end</property>
676 <child>
677 <object class="GtkButton" id="folders_close">
678 <property name="label">gtk-close</property>
679 <property name="visible">True</property>
680 <property name="can_focus">False</property>
681 <property name="receives_default">False</property>
682 <property name="use_stock">True</property>
683 <signal name="clicked" handler="on_folders_close_clicked"/>
684 </object>
685 <packing>
686 <property name="expand">False</property>
687 <property name="fill">False</property>
688 <property name="position">0</property>
689 </packing>
690 </child>
691 </object>
692 <packing>
693 <property name="expand">False</property>
694 <property name="pack_type">end</property>
695 <property name="position">0</property>
696 </packing>
697 </child>
698 </object>
699 </child>
700 <action-widgets>
701 <action-widget response="0">folders_close</action-widget>
702 </action-widgets>
703 </object>
704 <object class="GtkDialog" id="shares_to_me_dialog">
705 <property name="width_request">600</property>
706 <property name="height_request">300</property>
707 <property name="border_width">5</property>
708 <property name="title" translatable="yes">Shares to me</property>
709 <property name="modal">True</property>
710 <property name="window_position">center</property>
711 <property name="type_hint">normal</property>
712 <property name="has_separator">False</property>
713 <child internal-child="vbox">
714 <object class="GtkVBox" id="dialog-vbox3">
715 <property name="visible">True</property>
716 <property name="spacing">2</property>
717 <child>
718 <object class="GtkScrolledWindow" id="scrolledwindow4">
719 <property name="visible">True</property>
720 <property name="can_focus">True</property>
721 <property name="hscrollbar_policy">automatic</property>
722 <property name="vscrollbar_policy">automatic</property>
723 <child>
724 <object class="GtkTreeView" id="shares_to_me_view">
725 <property name="visible">True</property>
726 <property name="can_focus">True</property>
727 <property name="model">shares_to_me_store</property>
728 <property name="rules_hint">True</property>
729 <property name="enable_grid_lines">both</property>
730 <property name="enable_tree_lines">True</property>
731 <child>
732 <object class="GtkTreeViewColumn" id="shares_to_me_name">
733 <property name="title">Name</property>
734 <property name="expand">True</property>
735 <child>
736 <object class="GtkCellRendererText" id="cellrenderertext15"/>
737 <attributes>
738 <attribute name="text">3</attribute>
739 </attributes>
740 </child>
741 </object>
742 </child>
743 <child>
744 <object class="GtkTreeViewColumn" id="shares_to_me_other">
745 <property name="title">Other</property>
746 <property name="expand">True</property>
747 <child>
748 <object class="GtkCellRendererText" id="cellrenderertext19"/>
749 <attributes>
750 <attribute name="text">6</attribute>
751 </attributes>
752 </child>
753 </object>
754 </child>
755 <child>
756 <object class="GtkTreeViewColumn" id="shates_to_me_accepted">
757 <property name="title">Accepted</property>
758 <property name="expand">True</property>
759 <child>
760 <object class="GtkCellRendererToggle" id="cellrenderertoggle2"/>
761 <attributes>
762 <attribute name="activatable">0</attribute>
763 </attributes>
764 </child>
765 </object>
766 </child>
767 <child>
768 <object class="GtkTreeViewColumn" id="shares_to_me_access_level">
769 <property name="title">Access Level</property>
770 <property name="expand">True</property>
771 <child>
772 <object class="GtkCellRendererText" id="cellrenderertext13"/>
773 <attributes>
774 <attribute name="text">1</attribute>
775 </attributes>
776 </child>
777 </object>
778 </child>
779 <child>
780 <object class="GtkTreeViewColumn" id="shares-to_me_free_bytes">
781 <property name="title">Free bytes</property>
782 <property name="expand">True</property>
783 <child>
784 <object class="GtkCellRendererText" id="cellrenderertext14"/>
785 <attributes>
786 <attribute name="text">2</attribute>
787 </attributes>
788 </child>
789 </object>
790 </child>
791 <child>
792 <object class="GtkTreeViewColumn" id="shares_to_me_node">
793 <property name="title">Node</property>
794 <property name="expand">True</property>
795 <child>
796 <object class="GtkCellRendererText" id="cellrenderertext16"/>
797 <attributes>
798 <attribute name="text">4</attribute>
799 </attributes>
800 </child>
801 </object>
802 </child>
803 <child>
804 <object class="GtkTreeViewColumn" id="shares_to_me_path">
805 <property name="title">Path</property>
806 <property name="expand">True</property>
807 <child>
808 <object class="GtkCellRendererText" id="cellrenderertext18"/>
809 <attributes>
810 <attribute name="text">7</attribute>
811 </attributes>
812 </child>
813 </object>
814 </child>
815 <child>
816 <object class="GtkTreeViewColumn" id="shares_to_me_volume">
817 <property name="title">Volume</property>
818 <property name="expand">True</property>
819 <child>
820 <object class="GtkCellRendererText" id="cellrenderertext17"/>
821 <attributes>
822 <attribute name="text">8</attribute>
823 </attributes>
824 </child>
825 </object>
826 </child>
827 </object>
828 </child>
829 </object>
830 <packing>
831 <property name="position">1</property>
832 </packing>
833 </child>
834 <child internal-child="action_area">
835 <object class="GtkHButtonBox" id="dialog-action_area3">
836 <property name="visible">True</property>
837 <property name="layout_style">end</property>
838 <child>
839 <object class="GtkButton" id="shares_to_me_close">
840 <property name="label">gtk-close</property>
841 <property name="visible">True</property>
842 <property name="can_focus">True</property>
843 <property name="receives_default">True</property>
844 <property name="use_stock">True</property>
845 <signal name="clicked" handler="on_shares_to_me_close_clicked"/>
846 </object>
847 <packing>
848 <property name="expand">False</property>
849 <property name="fill">False</property>
850 <property name="position">0</property>
851 </packing>
852 </child>
853 </object>
854 <packing>
855 <property name="expand">False</property>
856 <property name="pack_type">end</property>
857 <property name="position">0</property>
858 </packing>
859 </child>
860 </object>
861 </child>
862 <action-widgets>
863 <action-widget response="0">shares_to_me_close</action-widget>
864 </action-widgets>
865 </object>
457</interface>866</interface>
458867
=== modified file 'magicicada/__init__.py'
--- magicicada/__init__.py 2010-05-28 12:33:53 +0000
+++ magicicada/__init__.py 2010-05-31 22:49:23 +0000
@@ -64,26 +64,37 @@
6464
65 widgets = (65 widgets = (
66 'start', 'stop', 'connect', 'disconnect', # toolbar buttons66 'start', 'stop', 'connect', 'disconnect', # toolbar buttons
67 'folders', 'folders_dialog',
68 'folders_store', 'folders_close', # folders
69 'shares_to_me', 'shares_to_me_dialog',
70 'shares_to_me_store', 'shares_to_me_close', # shares_to_me
71 'shares_to_others', # toolbar buttons
72 'raw_metadata', # more toolbar buttons
67 'is_started', 'is_connected', 'is_online', # status bar images73 'is_started', 'is_connected', 'is_online', # status bar images
68 'status_label', 'status_icon', # status label and systray icon74 'status_label', 'status_icon', # status label and systray icon
69 'metaq_view', 'contentq_view', # queues tree views75 'metaq_view', 'contentq_view', # queues tree views
70 'metaq_store', 'contentq_store', # queues list stores76 'metaq_store', 'contentq_store', # queues list stores
71 'main_window', 'about_dialog',77 'about_dialog', # dialogs
78 'main_window'
72 )79 )
73 for widget in widgets:80 for widget in widgets:
74 obj = self.builder.get_object(widget)81 obj = self.builder.get_object(widget)
75 setattr(self, widget, obj)82 setattr(self, widget, obj)
76 assert obj is not None, '%s must not be None' % widget83 assert obj is not None, '%s must not be None' % widget
7784
85 self.volumes = (self.folders, self.shares_to_me, self.shares_to_others)
86 self.windows = (self.main_window, self.about_dialog,
87 self.folders_dialog)
88
78 icon_filename = get_data_file('media', 'logo-016.png')89 icon_filename = get_data_file('media', 'logo-016.png')
90 self._icon = gtk.gdk.pixbuf_new_from_file(icon_filename)
79 self.status_icon.set_from_file(icon_filename)91 self.status_icon.set_from_file(icon_filename)
80 self.main_window.set_icon_from_file(icon_filename)92 for w in self.windows:
93 w.set_icon(self._icon)
8194
82 about_filename = get_data_file('media', 'logo-128.png')95 about_filename = get_data_file('media', 'logo-128.png')
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))
8497
85 self.main_window.show()
86
87 self.sd = syncdaemon_class()98 self.sd = syncdaemon_class()
88 self.sd.on_started_callback = self.on_started99 self.sd.on_started_callback = self.on_started
89 self.sd.on_stopped_callback = self.on_stopped100 self.sd.on_stopped_callback = self.on_stopped
@@ -95,8 +106,9 @@
95 self.sd.content_queue_changed_callback = self.on_content_queue_changed106 self.sd.content_queue_changed_callback = self.on_content_queue_changed
96 self.sd.meta_queue_changed_callback = self.on_meta_queue_changed107 self.sd.meta_queue_changed_callback = self.on_meta_queue_changed
97108
98 self.widget_enabled = lambda w: \109 self.widget_is_visible = lambda w: w.get_property('visible')
99 w.get_property('visible') and w.is_sensitive()110 self.widget_enabled = lambda w: self.widget_is_visible(w) and \
111 w.is_sensitive()
100112
101 self.update()113 self.update()
102114
@@ -105,8 +117,6 @@
105 def on_main_window_destroy(self, widget, data=None):117 def on_main_window_destroy(self, widget, data=None):
106 """Called when the MagicicadaWindow is closed."""118 """Called when the MagicicadaWindow is closed."""
107 # Clean up code for saving application state should be added here.119 # Clean up code for saving application state should be added here.
108 if self.widget_enabled(self.stop):
109 self.on_stop_clicked(self.stop)
110 self.sd.shutdown()120 self.sd.shutdown()
111 self.on_destroy()121 self.on_destroy()
112122
@@ -145,9 +155,55 @@
145 self.disconnect.set_sensitive(False)155 self.disconnect.set_sensitive(False)
146 self.sd.disconnect()156 self.sd.disconnect()
147157
158 def on_folders_close_clicked(self, widget, data=None):
159 """Close the folders dialog."""
160 self.folders_dialog.response(gtk.RESPONSE_CLOSE)
161
162 def on_folders_clicked(self, widget, data=None):
163 """List user folders."""
164 items = self.sd.folders
165 if items is None:
166 items = []
167
168 self.folders_store.clear()
169 for item in items:
170 row = (item.node, item.path, item.suggested_path,
171 item.subscribed, item.volume)
172 self.folders_store.append(row)
173
174 res = self.folders_dialog.run()
175 self.folders_dialog.hide()
176
177 def on_shares_to_me_close_clicked(self, widget, data=None):
178 """Close the shares_to_me dialog."""
179 self.shares_to_me_dialog.response(gtk.RESPONSE_CLOSE)
180
181 def on_shares_to_me_clicked(self, widget, data=None):
182 """List shares to the user."""
183 items = self.sd.shares_to_me
184 if items is None:
185 items = []
186
187 self.shares_to_me_store.clear()
188 for item in items:
189 #free_bytes = 0 if item.free_bytes is None else item.free_bytes
190 row = (item.accepted, item.access_level, item.free_bytes, item.name,
191 item.node_id, item.other_username, item.other_visible_name,
192 item.path, item.volume_id)
193 self.shares_to_me_store.append(row)
194
195 res = self.shares_to_me_dialog.run()
196 self.shares_to_me_dialog.hide()
197
198 def on_shares_to_others_clicked(self, widget, data=None):
199 """List user shares to others."""
200
201 def on_raw_metadata_clicked(self, widget, data=None):
202 """Show raw metadata for a path choosen by the user."""
203
148 def on_status_icon_activate(self, widget, data=None):204 def on_status_icon_activate(self, widget, data=None):
149 """Systray icon was clicked."""205 """Systray icon was clicked."""
150 if self.main_window.get_property('visible'):206 if self.widget_is_visible(self.main_window):
151 self.main_window.hide()207 self.main_window.hide()
152 else:208 else:
153 self.main_window.show()209 self.main_window.show()
@@ -201,9 +257,13 @@
201 """Callback'ed when syncadaemon is online."""257 """Callback'ed when syncadaemon is online."""
202 self.is_online.set_sensitive(True)258 self.is_online.set_sensitive(True)
203 self._activate_indicator(self.is_online)259 self._activate_indicator(self.is_online)
260 for v in self.volumes:
261 v.set_sensitive(True)
204262
205 def on_offline(self, *args, **kwargs):263 def on_offline(self, *args, **kwargs):
206 """Callback'ed when syncadaemon is offline."""264 """Callback'ed when syncadaemon is offline."""
265 for v in self.volumes:
266 v.set_sensitive(False)
207 self._activate_indicator(self.is_online, sensitive=False)267 self._activate_indicator(self.is_online, sensitive=False)
208268
209 def on_status_changed(self, name=None, description=None,269 def on_status_changed(self, name=None, description=None,
@@ -224,7 +284,7 @@
224 queue_store = getattr(self, '%sq_store' % queue_name)284 queue_store = getattr(self, '%sq_store' % queue_name)
225 queue_store.clear()285 queue_store.clear()
226 for item in items:286 for item in items:
227 row = (item.operation, item.path, item.node, item.share)287 row = (item.operation, item.path, item.share, item.node)
228 queue_store.append(row)288 queue_store.append(row)
229289
230 if not queue_view.is_sensitive() and len(items) > 0:290 if not queue_view.is_sensitive() and len(items) > 0:
231291
=== modified file 'magicicada/tests/test_magicicada.py'
--- magicicada/tests/test_magicicada.py 2010-05-27 12:21:19 +0000
+++ magicicada/tests/test_magicicada.py 2010-05-31 22:49:23 +0000
@@ -20,14 +20,30 @@
2020
21from functools import wraps21from functools import wraps
2222
23import gobject
24import gtk
23import pango25import pango
2426
25from twisted.trial.unittest import TestCase27from twisted.trial.unittest import TestCase
2628
27from magicicada import MagicicadaUI, CONTENT_QUEUE, META_QUEUE, syncdaemon29from magicicada import MagicicadaUI, CONTENT_QUEUE, META_QUEUE, syncdaemon
28from magicicada.dbusiface import QueueData30from magicicada.dbusiface import QueueData, FolderData, ShareData
29from magicicada.helpers import NO_OP31from magicicada.helpers import NO_OP
3032
33def process_gtk_pendings():
34 while gtk.events_pending(): gtk.main_iteration()
35
36def close_dialog((dialog, test)):
37 """Call the 'test', close 'dialog'."""
38 try:
39 process_gtk_pendings()
40 test()
41 process_gtk_pendings()
42 finally:
43 dialog.response(gtk.RESPONSE_CLOSE)
44 process_gtk_pendings()
45 return False # do not be called again
46
3147
32class FakedSyncdaemon(object):48class FakedSyncdaemon(object):
33 """A faked syncdaemon."""49 """A faked syncdaemon."""
@@ -36,6 +52,7 @@
36 self.current_state = syncdaemon.State()52 self.current_state = syncdaemon.State()
37 self.meta_queue = []53 self.meta_queue = []
38 self.content_queue = []54 self.content_queue = []
55 self.folders = []
3956
40 self.on_started_callback = NO_OP57 self.on_started_callback = NO_OP
41 self.on_stopped_callback = NO_OP58 self.on_stopped_callback = NO_OP
@@ -47,6 +64,7 @@
47 self.content_queue_changed_callback = NO_OP64 self.content_queue_changed_callback = NO_OP
48 self.meta_queue_changed_callback = NO_OP65 self.meta_queue_changed_callback = NO_OP
49 self.shutdown = NO_OP66 self.shutdown = NO_OP
67
50 self.start = lambda: setattr(self.current_state, 'is_started', True)68 self.start = lambda: setattr(self.current_state, 'is_started', True)
51 self.quit = lambda: setattr(self.current_state, 'is_started', False)69 self.quit = lambda: setattr(self.current_state, 'is_started', False)
52 self.connect = lambda: setattr(self.current_state, 'is_connected', True)70 self.connect = lambda: setattr(self.current_state, 'is_connected', True)
@@ -79,6 +97,35 @@
79 self.ui.on_connect_clicked(self.ui.connect)97 self.ui.on_connect_clicked(self.ui.connect)
80 self.ui.on_connected()98 self.ui.on_connected()
8199
100 def build_some_data(self, data_type, limit=5):
101 """Build some data using named_tuple 'data_type'."""
102 attrs = data_type._fields
103 result = []
104 for i in xrange(limit):
105 kwargs = dict([(attr, '%s %i' % (attr, i)) for attr in attrs])
106 result.append(data_type(**kwargs))
107 return result
108
109 def assert_store_correct(self, store, items):
110 """Test that 'store' has 'items' as content."""
111 msg = 'amount of rows for %s must be %s (got %s).'
112 self.assertEqual(len(store), len(items),
113 msg % (store, len(items), len(store)))
114 # assert rows content equal to items content
115 tree_iter = store.get_iter_root()
116 tmp = list(reversed(items))
117 msg = "column %i ('%s') must be '%s' (got '%s' instead)"
118 while tree_iter is not None:
119 head = tmp.pop()
120 for i, field in enumerate(head._fields):
121 actual, = store.get(tree_iter, i)
122 expected = getattr(head, field)
123 if store.get_column_type(i).name == 'gboolean':
124 expected = bool(expected)
125 self.assertEqual(expected, actual, msg % (i, field, expected, actual))
126
127 tree_iter = store.iter_next(tree_iter)
128
82 def assert_indicator_disabled(self, indicator):129 def assert_indicator_disabled(self, indicator):
83 """Test that 'indicator' is not sensitive."""130 """Test that 'indicator' is not sensitive."""
84 self.assertFalse(indicator.is_sensitive(), 'indicator is not sensitive')131 self.assertFalse(indicator.is_sensitive(), 'indicator is not sensitive')
@@ -114,21 +161,26 @@
114 'syncdaemon.shutdown must be called at destroy time.')161 'syncdaemon.shutdown must be called at destroy time.')
115162
116 def test_main_window_is_visible(self):163 def test_main_window_is_visible(self):
117 """UI can be created."""164 """UI can be created and main_window is visible."""
118 self.assertTrue(self.ui.main_window.get_property('visible'))165 self.assertTrue(self.ui.widget_is_visible(self.ui.main_window))
166
167 def test_windows_have_correct_icon(self):
168 """Every window has the icon set."""
169 for w in self.ui.windows:
170 self.assertEqual(w.get_icon(), self.ui._icon)
119171
120 def test_start_connect_are_visible(self):172 def test_start_connect_are_visible(self):
121 """Start and Connect buttons are visible."""173 """Start and Connect buttons are visible."""
122 self.assertTrue(self.ui.start.get_property('visible'))174 self.assertTrue(self.ui.widget_is_visible(self.ui.start))
123 self.assertTrue(self.ui.start.is_sensitive())175 self.assertTrue(self.ui.start.is_sensitive())
124176
125 self.assertTrue(self.ui.connect.get_property('visible'))177 self.assertTrue(self.ui.widget_is_visible(self.ui.connect))
126 self.assertFalse(self.ui.connect.is_sensitive())178 self.assertFalse(self.ui.connect.is_sensitive())
127179
128 def test_stop_disconnect_are_not_visible(self):180 def test_stop_disconnect_are_not_visible(self):
129 """Start and Connect buttons are visible."""181 """Start and Connect buttons are visible."""
130 self.assertFalse(self.ui.stop.get_property('visible'))182 self.assertFalse(self.ui.widget_is_visible(self.ui.stop))
131 self.assertFalse(self.ui.disconnect.get_property('visible'))183 self.assertFalse(self.ui.widget_is_visible(self.ui.disconnect))
132184
133 def test_indicators_are_non_sensitive(self):185 def test_indicators_are_non_sensitive(self):
134 """Test default sensitivity for indicators."""186 """Test default sensitivity for indicators."""
@@ -151,9 +203,9 @@
151 """Test on_start_clicked."""203 """Test on_start_clicked."""
152 self.ui.on_start_clicked(self.ui.start)204 self.ui.on_start_clicked(self.ui.start)
153205
154 self.assertTrue(self.ui.start.get_property('visible'))206 self.assertTrue(self.ui.widget_is_visible(self.ui.start))
155 self.assertFalse(self.ui.start.is_sensitive())207 self.assertFalse(self.ui.start.is_sensitive())
156 self.assertFalse(self.ui.stop.get_property('visible'))208 self.assertFalse(self.ui.widget_is_visible(self.ui.stop))
157209
158 self.assert_indicator_loading(self.ui.is_started)210 self.assert_indicator_loading(self.ui.is_started)
159 self.assert_indicator_disabled(self.ui.is_connected)211 self.assert_indicator_disabled(self.ui.is_connected)
@@ -170,9 +222,9 @@
170 self.do_start() # need to be started222 self.do_start() # need to be started
171 self.ui.on_connect_clicked(self.ui.connect)223 self.ui.on_connect_clicked(self.ui.connect)
172224
173 self.assertTrue(self.ui.connect.get_property('visible'))225 self.assertTrue(self.ui.widget_is_visible(self.ui.connect))
174 self.assertFalse(self.ui.connect.is_sensitive())226 self.assertFalse(self.ui.connect.is_sensitive())
175 self.assertFalse(self.ui.disconnect.get_property('visible'))227 self.assertFalse(self.ui.widget_is_visible(self.ui.disconnect))
176228
177 self.assert_indicator_ready(self.ui.is_started)229 self.assert_indicator_ready(self.ui.is_started)
178 self.assert_indicator_loading(self.ui.is_connected)230 self.assert_indicator_loading(self.ui.is_connected)
@@ -193,13 +245,13 @@
193245
194 self.assertFalse(self._called, 'on_disconnect_clicked was not called.')246 self.assertFalse(self._called, 'on_disconnect_clicked was not called.')
195247
196 self.assertFalse(self.ui.start.get_property('visible'))248 self.assertFalse(self.ui.widget_is_visible(self.ui.start))
197 self.assertTrue(self.ui.stop.get_property('visible'))249 self.assertTrue(self.ui.widget_is_visible(self.ui.stop))
198 self.assertFalse(self.ui.stop.is_sensitive())250 self.assertFalse(self.ui.stop.is_sensitive())
199251
200 self.assertTrue(self.ui.connect.get_property('visible'))252 self.assertTrue(self.ui.widget_is_visible(self.ui.connect))
201 self.assertFalse(self.ui.connect.is_sensitive())253 self.assertFalse(self.ui.connect.is_sensitive())
202 self.assertFalse(self.ui.disconnect.get_property('visible'))254 self.assertFalse(self.ui.widget_is_visible(self.ui.disconnect))
203255
204 def test_on_stop_clicked_if_connected(self):256 def test_on_stop_clicked_if_connected(self):
205 """Test on_stop_clicked."""257 """Test on_stop_clicked."""
@@ -220,8 +272,8 @@
220 self.do_connect()272 self.do_connect()
221 self.ui.on_disconnect_clicked(self.ui.disconnect)273 self.ui.on_disconnect_clicked(self.ui.disconnect)
222274
223 self.assertFalse(self.ui.connect.get_property('visible'))275 self.assertFalse(self.ui.widget_is_visible(self.ui.connect))
224 self.assertTrue(self.ui.disconnect.get_property('visible'))276 self.assertTrue(self.ui.widget_is_visible(self.ui.disconnect))
225 self.assertFalse(self.ui.disconnect.is_sensitive())277 self.assertFalse(self.ui.disconnect.is_sensitive())
226278
227 def test_on_disconnect_clicked_disconnects_syncdaemon(self):279 def test_on_disconnect_clicked_disconnects_syncdaemon(self):
@@ -237,7 +289,7 @@
237 def test_main_window_is_hid_when_icon_clicked(self):289 def test_main_window_is_hid_when_icon_clicked(self):
238 """Main window is hid when the systray icon is clicked."""290 """Main window is hid when the systray icon is clicked."""
239 self.ui.on_status_icon_activate(self.ui.status_icon)291 self.ui.on_status_icon_activate(self.ui.status_icon)
240 self.assertFalse(self.ui.main_window.get_property('visible'),292 self.assertFalse(self.ui.widget_is_visible(self.ui.main_window),
241 'main_window should be invisible when icon clicked.')293 'main_window should be invisible when icon clicked.')
242294
243 def test_main_window_is_shown_when_clicked_after_hidden(self):295 def test_main_window_is_shown_when_clicked_after_hidden(self):
@@ -245,7 +297,7 @@
245 self.ui.on_status_icon_activate(self.ui.status_icon) # hide297 self.ui.on_status_icon_activate(self.ui.status_icon) # hide
246 self.ui.on_status_icon_activate(self.ui.status_icon) # show298 self.ui.on_status_icon_activate(self.ui.status_icon) # show
247 msg = 'main_window should be visible when icon clicked after hidden.'299 msg = 'main_window should be visible when icon clicked after hidden.'
248 self.assertTrue(self.ui.main_window.get_property('visible'), msg)300 self.assertTrue(self.ui.widget_is_visible(self.ui.main_window), msg)
249301
250302
251def skip_abstract_class(test):303def skip_abstract_class(test):
@@ -253,7 +305,7 @@
253 @wraps(test)305 @wraps(test)
254 def inner(klass):306 def inner(klass):
255 """Execute 'test' only if not in an abstract class."""307 """Execute 'test' only if not in an abstract class."""
256 if klass.queue is not None:308 if klass.name is not None:
257 test(klass)309 test(klass)
258 return inner310 return inner
259311
@@ -261,54 +313,32 @@
261class _MagicicadaUIQueueTestCase(MagicicadaUITestCase):313class _MagicicadaUIQueueTestCase(MagicicadaUITestCase):
262 """Abstratc UI test cases for queue tree views."""314 """Abstratc UI test cases for queue tree views."""
263315
264 queue = None316 name = None
265317
266 def setUp(self):318 def setUp(self):
267 """Init."""319 """Init."""
268 super(_MagicicadaUIQueueTestCase, self).setUp()320 super(_MagicicadaUIQueueTestCase, self).setUp()
269 if self.queue is None:321 if self.name is None:
270 return322 return
271 self.sd_changed = getattr(self.ui.sd,323 self.sd_changed = getattr(self.ui.sd,
272 '%s_queue_changed_callback' % self.queue)324 '%s_queue_changed_callback' % self.name)
273 self.ui_changed = getattr(self.ui,325 self.ui_changed = getattr(self.ui,
274 'on_%s_queue_changed' % self.queue)326 'on_%s_queue_changed' % self.name)
275 self.queue_store = getattr(self.ui, '%sq_store' % self.queue)327 self.queue_store = getattr(self.ui, '%sq_store' % self.name)
276 self.queue_view = getattr(self.ui, '%sq_view' % self.queue)328 self.queue_view = getattr(self.ui, '%sq_view' % self.name)
277329
278 def build_some_data(self, limit=5):330 def build_some_data(self, limit=5):
279 """Build some data to pass to queue changed callback and related."""331 """Build some data to act as queue data."""
280 items = []332 kwargs = dict(data_type=QueueData, limit=limit)
281 for i in xrange(limit):333 res = super(_MagicicadaUIQueueTestCase, self).build_some_data(**kwargs)
282 cq = QueueData(operation='operation %i' % i,334 # operation path share node
283 path='path %i' % i, node='node %i' % i,335 return res
284 share='share %i' % i)
285 items.append(cq)
286 return items
287
288 def assert_queue_store_correct(self, queue_store, items):
289 """Test that 'queue_store' has 'items' as content."""
290 msg = 'amount of rows for %s must be %s (got %s).'
291 self.assertEqual(len(queue_store), len(items),
292 msg % (queue_store, len(items), len(queue_store)))
293 # assert rows content equal to items content
294 tree_iter = queue_store.get_iter_root()
295 tmp = list(reversed(items))
296 while tree_iter is not None:
297 expected = tmp.pop()
298
299 op, path, node, share = queue_store.get(tree_iter, 0, 1, 2, 3)
300 self.assertEqual(expected.operation, op)
301 self.assertEqual(expected.path, path)
302 self.assertEqual(expected.node, node)
303 self.assertEqual(expected.share, share)
304
305 tree_iter = queue_store.iter_next(tree_iter)
306336
307 @skip_abstract_class337 @skip_abstract_class
308 def test_callback_is_connected(self):338 def test_callback_is_connected(self):
309 """Queue changed callback is connected."""339 """Queue changed callback is connected."""
310 self.assertEqual(self.sd_changed, self.ui_changed,340 self.assertEqual(self.sd_changed, self.ui_changed,
311 '%s queue callback must be set' % self.queue)341 '%s queue callback must be set' % self.name)
312342
313 @skip_abstract_class343 @skip_abstract_class
314 def test_model_is_binded(self):344 def test_model_is_binded(self):
@@ -316,20 +346,20 @@
316 actual = self.queue_view.get_model()346 actual = self.queue_view.get_model()
317 msg = 'model for view %s differs from %s'347 msg = 'model for view %s differs from %s'
318 self.assertEqual(self.queue_store, actual,348 self.assertEqual(self.queue_store, actual,
319 msg % (self.queue, self.queue_store))349 msg % (self.name, self.queue_store))
320350
321 @skip_abstract_class351 @skip_abstract_class
322 def test_on_queue_changed_updates_view(self):352 def test_on_queue_changed_updates_view(self):
323 """On queue changed the view is updated."""353 """On queue changed the view is updated."""
324 items = self.build_some_data()354 items = self.build_some_data()
325 self.sd_changed(items)355 self.sd_changed(items)
326 self.assert_queue_store_correct(self.queue_store, items)356 self.assert_store_correct(self.queue_store, items)
327357
328 @skip_abstract_class358 @skip_abstract_class
329 def test_on_queue_changed_handles_none(self):359 def test_on_queue_changed_handles_none(self):
330 """On queue changed handles None as items."""360 """On queue changed handles None as items."""
331 self.sd_changed(None)361 self.sd_changed(None)
332 self.assert_queue_store_correct(self.queue_store, [])362 self.assert_store_correct(self.queue_store, [])
333363
334 @skip_abstract_class364 @skip_abstract_class
335 def test_model_is_cleared_before_updating(self):365 def test_model_is_cleared_before_updating(self):
@@ -356,16 +386,16 @@
356 def test_update_is_correct_for_queue(self):386 def test_update_is_correct_for_queue(self):
357 """Correctly updates the queue state."""387 """Correctly updates the queue state."""
358 data = self.build_some_data()388 data = self.build_some_data()
359 setattr(self.ui.sd, '%s_queue' % self.queue, data)389 setattr(self.ui.sd, '%s_queue' % self.name, data)
360390
361 self.ui.update()391 self.ui.update()
362392
363 self.assert_queue_store_correct(self.queue_store, data)393 self.assert_store_correct(self.queue_store, data)
364394
365 @skip_abstract_class395 @skip_abstract_class
366 def test_on_stopped_updates_queue(self):396 def test_on_stopped_updates_queue(self):
367 """On SD stoppped, the UI updates the queue state."""397 """On SD stoppped, the UI updates the queue state."""
368 cb = 'on_%s_queue_changed' % self.queue398 cb = 'on_%s_queue_changed' % self.name
369 self.patch(self.ui, cb, self.set_called)399 self.patch(self.ui, cb, self.set_called)
370 self.ui.on_stopped()400 self.ui.on_stopped()
371 self.assertTrue(self._called,401 self.assertTrue(self._called,
@@ -375,13 +405,13 @@
375class MagicicadaUIContentQueueTestCase(_MagicicadaUIQueueTestCase):405class MagicicadaUIContentQueueTestCase(_MagicicadaUIQueueTestCase):
376 """UI test cases for content queue view."""406 """UI test cases for content queue view."""
377407
378 queue = CONTENT_QUEUE408 name = CONTENT_QUEUE
379409
380410
381class MagicicadaUIMetaQueueTestCase(_MagicicadaUIQueueTestCase):411class MagicicadaUIMetaQueueTestCase(_MagicicadaUIQueueTestCase):
382 """UI test cases for meta queue view."""412 """UI test cases for meta queue view."""
383413
384 queue = META_QUEUE414 name = META_QUEUE
385415
386416
387class MagicicadaUIStatusTestCase(MagicicadaUITestCase):417class MagicicadaUIStatusTestCase(MagicicadaUITestCase):
@@ -472,7 +502,7 @@
472502
473503
474class MagicicadaUIConnectionTestCase(MagicicadaUITestCase):504class MagicicadaUIConnectionTestCase(MagicicadaUITestCase):
475 """UI test cases for."""505 """UI test cases for connection buttons/indicators."""
476506
477 def assert_indicator_is_updated_correctly(self, indicator):507 def assert_indicator_is_updated_correctly(self, indicator):
478 """Test that correctly updates the 'indicator'."""508 """Test that correctly updates the 'indicator'."""
@@ -503,7 +533,7 @@
503 else:533 else:
504 self.assertFalse(self.ui.connect.is_sensitive(),534 self.assertFalse(self.ui.connect.is_sensitive(),
505 'connect must be disabled when %s' % cs)535 'connect must be disabled when %s' % cs)
506 self.assertTrue(self.ui.connect.get_property('visible'),536 self.assertTrue(self.ui.widget_is_visible(self.ui.connect),
507 'connect must be visible when %s' % cs)537 'connect must be visible when %s' % cs)
508 actual = self.ui.widget_enabled(getattr(self.ui, indicator))538 actual = self.ui.widget_enabled(getattr(self.ui, indicator))
509 self.assertFalse(actual,539 self.assertFalse(actual,
@@ -562,7 +592,7 @@
562 self.ui.on_stopped()592 self.ui.on_stopped()
563593
564 self.assertTrue(self.ui.start.is_sensitive())594 self.assertTrue(self.ui.start.is_sensitive())
565 self.assertTrue(self.ui.start.get_property('visible'))595 self.assertTrue(self.ui.widget_is_visible(self.ui.start))
566 self.assert_indicator_disabled(self.ui.is_started)596 self.assert_indicator_disabled(self.ui.is_started)
567 self.assert_indicator_disabled(self.ui.is_connected)597 self.assert_indicator_disabled(self.ui.is_connected)
568 self.assert_indicator_disabled(self.ui.is_online)598 self.assert_indicator_disabled(self.ui.is_online)
@@ -593,3 +623,161 @@
593 """Correctly updates the indicators and buttons state."""623 """Correctly updates the indicators and buttons state."""
594 for i in ('is_started', 'is_connected', 'is_online'):624 for i in ('is_started', 'is_connected', 'is_online'):
595 self.assert_indicator_is_updated_correctly(i)625 self.assert_indicator_is_updated_correctly(i)
626
627
628class _MagicicadaUIVolumeTestCase(MagicicadaUITestCase):
629 """Abstract UI test cases for volumes (folders/shares)."""
630
631 name = None
632 data_type = None
633
634 def setUp(self):
635 """Init."""
636 super(_MagicicadaUIVolumeTestCase, self).setUp()
637 if self.name is None:
638 return
639 self.volume = getattr(self.ui, self.name)
640 self.volume_store = getattr(self.ui, '%s_store' % self.name)
641 self.volume_dialog_name = '%s_dialog' % self.name
642 self.volume_dialog = getattr(self.ui, self.volume_dialog_name)
643 self.on_volume_clicked = getattr(self.ui, 'on_%s_clicked' % self.name)
644
645 def build_some_data(self, limit=5):
646 """Build some data to act as volume."""
647 kwargs = dict(data_type=self.data_type, limit=limit)
648 res = super(_MagicicadaUIVolumeTestCase, self).build_some_data(**kwargs)
649 return res
650
651 def assert_volume_availability(self, enabled):
652 """Check volume availability according to 'enabled'."""
653 self.assertTrue(self.ui.widget_is_visible(self.volume),
654 '%s should be visible' % self.name)
655 sensitive = self.volume.is_sensitive()
656 msg = '%s should %sbe sensitive'
657 self.assertTrue(sensitive if enabled else not sensitive,
658 msg % (self.name, '' if enabled else 'not '))
659
660 @skip_abstract_class
661 def test_volume_are_disabled_until_online(self):
662 """Folders and shares are disabled until online."""
663 # disabled at startup
664 self.assert_volume_availability(enabled=False)
665
666 # disabled even if connected
667 self.do_connect()
668 self.assert_volume_availability(enabled=False)
669
670 # enabled when online
671 self.ui.on_online()
672 self.assert_volume_availability(enabled=True)
673
674 @skip_abstract_class
675 def test_volume_are_enabled_until_offline(self):
676 """Folders and shares are enabled until offline."""
677 self.do_connect()
678 self.ui.on_online()
679
680 # disabled when offline
681 self.ui.on_offline()
682 self.assert_volume_availability(enabled=False)
683
684 @skip_abstract_class
685 def test_volume_close_emits_response_close(self):
686 """Test volume close button emits RESPONSE_CLOSE when clicked."""
687 self.response = None
688 def record_response(value):
689 """Record the response received."""
690 self.response = value
691 self.patch(self.volume_dialog, 'response', record_response)
692
693 volume_close = '%s_close' % self.name
694 getattr(self.ui, volume_close).clicked()
695 self.assertEqual(gtk.RESPONSE_CLOSE, self.response,
696 '%s should emit RESPONSE_CLOSE.' % volume_close)
697
698 @skip_abstract_class
699 def test_on_volume_clicked(self):
700 """Test on_volume_clicked."""
701 self.assertFalse(self.ui.widget_is_visible(self.volume_dialog),
702 '%s should not be visible.' % self.volume_dialog_name)
703
704 def test():
705 """Perform the test per se before closing the dialog."""
706 self.assertTrue(self.ui.widget_is_visible(self.volume_dialog),
707 '%s should be visible.' % self.volume_dialog_name)
708 self.assert_store_correct(self.volume_store, items)
709
710 items = self.build_some_data()
711 setattr(self.ui.sd, self.name, items)
712 gobject.timeout_add(100, close_dialog,
713 (self.volume_dialog, test))
714 self.on_volume_clicked(self.volume)
715
716 # dialog was closed already
717 self.assertFalse(self.ui.widget_is_visible(self.volume_dialog),
718 '%s should not be visible.' % self.volume_dialog_name)
719
720 @skip_abstract_class
721 def test_on_volume_clicked_twice(self):
722 """Test on_volume_clicked twice."""
723
724 def test():
725 """Perform the test per se before closing the dialog."""
726 self.assertTrue(self.ui.widget_is_visible(self.volume_dialog),
727 '%s should be visible.' % self.volume_dialog_name)
728 self.assert_store_correct(self.volume_store, items)
729
730 items = self.build_some_data()
731 setattr(self.ui.sd, self.name, items)
732
733 gobject.timeout_add(100, close_dialog,
734 (self.volume_dialog, test))
735 self.on_volume_clicked(self.volume)
736
737 gobject.timeout_add(100, close_dialog,
738 (self.volume_dialog, test))
739 self.on_volume_clicked(self.volume)
740
741 @skip_abstract_class
742 def test_on_volume_clicked_handles_none(self):
743 """On volume clicked handles None as items."""
744 setattr(self.ui.sd, self.name, None)
745 test = lambda: self.assert_store_correct(self.volume_store, [])
746 gobject.timeout_add(100, close_dialog,
747 (self.volume_dialog, test))
748 self.on_volume_clicked(self.volume)
749
750 @skip_abstract_class
751 def test_volume_dialog_props(self):
752 """The volume dialog has correct properties."""
753 size = self.volume_dialog.size_request()
754 self.assertEquals((600, 300), size)
755
756 self.assertTrue(self.volume_dialog.get_modal(),
757 '%s must be modal.' % self.volume_dialog_name)
758
759 position = self.volume_dialog.get_property('window-position')
760 self.assertEqual(gtk.WIN_POS_CENTER, position,
761 '%s must be centered.' % self.volume_dialog_name)
762
763 actual = self.volume_dialog.get_title()
764 expected = self.name.replace('_', ' ').capitalize()
765 msg = '%s title must be %s (got %s instead)'
766 self.assertEqual(expected, actual,
767 msg % (self.volume_dialog_name, expected, actual))
768
769
770class MagicicadaUIFoldersTestCase(_MagicicadaUIVolumeTestCase):
771 """UI test cases for folders."""
772
773 name = 'folders'
774 data_type = FolderData # node path suggested_path subscribed volume
775
776
777class MagicicadaUISharesToMeTestCase(_MagicicadaUIVolumeTestCase):
778 """UI test cases for shares_to_me."""
779
780 name = 'shares_to_me'
781 data_type = ShareData # accepted access_level free_bytes name node_id
782 # other_username other_visible_name path volume_id
783
596784
=== modified file 'magicicada/tests/test_syncdaemon.py'
--- magicicada/tests/test_syncdaemon.py 2010-05-31 00:31:17 +0000
+++ magicicada/tests/test_syncdaemon.py 2010-05-31 22:49:23 +0000
@@ -306,6 +306,8 @@
306class MetaQueueChangedTests(BaseTest):306class MetaQueueChangedTests(BaseTest):
307 """Check the MetaQueueChanged handling."""307 """Check the MetaQueueChanged handling."""
308308
309 timeout = 3
310
309 def setUp(self):311 def setUp(self):
310 """Set up."""312 """Set up."""
311 BaseTest.setUp(self)313 BaseTest.setUp(self)

Subscribers

People subscribed via source and target branches

to all changes: