Merge lp:~nataliabidart/magicicada-gui/build-gui into lp:magicicada-gui

Proposed by Natalia Bidart
Status: Merged
Approved by: Facundo Batista
Approved revision: 13
Merged at revision: 15
Proposed branch: lp:~nataliabidart/magicicada-gui/build-gui
Merge into: lp:magicicada-gui
Diff against target: 1396 lines (+599/-638)
14 files modified
bin/magicicada (+3/-56)
data/ui/AboutMagicicadaDialog.ui (+0/-40)
data/ui/MagicicadaWindow.ui (+0/-232)
data/ui/PreferencesMagicicadaDialog.ui (+0/-67)
data/ui/about_magicicada_dialog.xml (+0/-9)
data/ui/gui.glade (+219/-52)
data/ui/magicicada_window.xml (+0/-8)
data/ui/preferences_magicicada_dialog.xml (+0/-9)
magicicada/AboutMagicicadaDialog.py (+0/-48)
magicicada/PreferencesMagicicadaDialog.py (+0/-111)
magicicada/__init__.py (+204/-0)
magicicada/helpers.py (+15/-3)
magicicada/syncdaemon.py (+8/-3)
magicicada/tests/test_magicicada.py (+150/-0)
To merge this branch: bzr merge lp:~nataliabidart/magicicada-gui/build-gui
Reviewer Review Type Date Requested Status
Facundo Batista Approve
Review via email: mp+24962@code.launchpad.net

Description of the change

First schema of Magicicada GUI.

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

facundo@exepus:~/devel/reps/magicicada/review_build-gui$ nosetests

syncdaemon.py: Not installing glib2reactor because: reactor already installed.
..........................................EEE......
======================================================================
ERROR: Check that it polls mq until no more is needed.
----------------------------------------------------------------------
DirtyReactorAggregateError: Reactor was unclean.
DelayedCalls: (set twisted.internet.base.DelayedCall.debug = True to debug)
<DelayedCall 0xac7ab6c [3.80157804489s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7a8ac [3.79958200455s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7a96c [3.80020308495s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7aa6c [3.80084300041s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7ae6c [3.80354785919s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7ac6c [3.80206394196s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7ad6c [3.80287098885s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7fb8c [3.81115484238s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7af6c [3.80402112007s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f08c [3.80454802513s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f18c [3.80509400368s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f28c [3.80576300621s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f38c [3.80635905266s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f48c [3.80693697929s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f58c [3.80750989914s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f68c [3.80805492401s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f78c [3.80859208107s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f88c [3.80918884277s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f98c [3.80973696709s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7fa8c [3.81028389931s] called=0 cancelled=0 SyncDaemon._check_mq()>

======================================================================
ERROR: Check that it polls mq while working in both.
----------------------------------------------------------------------
DirtyReactorAggregateError: Reactor was unclean.
DelayedCalls: (set twisted.internet.base.DelayedCall.debug = True to debug)
<DelayedCall 0xac7a72c [4.99101114273s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f8ec [4.98898601532s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f24c [4.98936009407s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7a86c [4.98973798752s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7a7cc [4.99011516571s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7a7ec [4.99048709869s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7f4cc [4.99738693237s] called=0 cancelled=0 SyncDaemon._check_mq()>
<DelayedCall 0xac7ad0c [4.99150681496s] called=0 cancelled=0 Sy...

Read more...

review: Needs Fixing
12. By Natalia Bidart

Fising some tests.

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

All fixed now!

13. By Natalia Bidart

Removing no longer needed patch def.

Revision history for this message
Facundo Batista (facundo) wrote :

Approving, but one comment.

Why the decorator that logs to stdout is called "dummy"? When you see a method decorated dummy you expect it to do nothing, but here it *is* executed.

review: Approve
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

> Approving, but one comment.
>
> Why the decorator that logs to stdout is called "dummy"? When you see a method
> decorated dummy you expect it to do nothing, but here it *is* executed.

I renamed it to print_debug. Thanks for pointing this out!

14. By Natalia Bidart

Renaming dumy decorator to print_debug.

15. By Natalia Bidart

Merged trunk in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/magicicada'
2--- bin/magicicada 2010-04-21 23:50:09 +0000
3+++ bin/magicicada 2010-05-15 15:48:32 +0000
4@@ -6,7 +6,6 @@
5
6 import sys
7 import os
8-import gtk
9
10 import gettext
11 from gettext import gettext as _
12@@ -29,59 +28,7 @@
13 sys.path.insert(0, PROJECT_ROOT_DIRECTORY)
14 os.putenv('PYTHONPATH', PROJECT_ROOT_DIRECTORY) # for subprocesses
15
16-from magicicada import (
17- AboutMagicicadaDialog, PreferencesMagicicadaDialog)
18-from magicicada.helpers import get_builder
19-
20-
21-class MagicicadaUI(object):
22-
23- def __init__(self):
24- """Init."""
25- self.builder = get_builder('gui.glade')
26- self.builder.connect_signals(self)
27-
28- global launchpad_available
29- if launchpad_available:
30- # see https://wiki.ubuntu.com/UbuntuDevelopment/Internationalisation/Coding for more information
31- # about LaunchpadIntegration
32- helpmenu = self.builder.get_object('helpMenu')
33- if helpmenu:
34- LaunchpadIntegration.set_sourcepackagename('magicicada')
35- LaunchpadIntegration.add_items(helpmenu, 0, False, True)
36- else:
37- launchpad_available = False
38-
39- # Uncomment the following code to read in preferences at start up.
40- #dlg = PreferencesMagicicadaDialog.NewPreferencesMagicicadaDialog()
41- #self.preferences = dlg.get_preferences()
42-
43- # Code for other initialization actions should be added here.
44- self.builder.get_object('main_window').show_all()
45-
46- def about(self, widget, data=None):
47- """Display the about box for magicicada."""
48- about = AboutMagicicadaDialog.AboutMagicicadaDialog()
49- response = about.run()
50- about.destroy()
51-
52- def preferences(self, widget, data=None):
53- """Display the preferences window for magicicada."""
54- prefs = PreferencesMagicicadaDialog.PreferencesMagicicadaDialog()
55- response = prefs.run()
56- if response == gtk.RESPONSE_OK:
57- # Make any updates based on changed preferences here.
58- pass
59- prefs.destroy()
60-
61- def quit(self, widget, data=None):
62- """Signal handler for closing the MagicicadaWindow."""
63- self.destroy()
64-
65- def on_destroy(self, widget, data=None):
66- """Called when the MagicicadaWindow is closed."""
67- # Clean up code for saving application state should be added here.
68- gtk.main_quit()
69+from magicicada import MagicicadaUI
70
71 if __name__ == "__main__":
72 # Support for command line options.
73@@ -99,5 +46,5 @@
74 logging.debug('logging enabled')
75
76 # Run the application.
77- window = MagicicadaUI()
78- gtk.main()
79+ window = MagicicadaUI(launchpad_available=launchpad_available)
80+ window.run()
81
82=== added file 'data/media/loader-ball.gif'
83Binary files data/media/loader-ball.gif 1970-01-01 00:00:00 +0000 and data/media/loader-ball.gif 2010-05-15 15:48:32 +0000 differ
84=== added file 'data/media/ubuntuone.png'
85Binary files data/media/ubuntuone.png 1970-01-01 00:00:00 +0000 and data/media/ubuntuone.png 2010-05-15 15:48:32 +0000 differ
86=== removed file 'data/ui/AboutMagicicadaDialog.ui'
87--- data/ui/AboutMagicicadaDialog.ui 2010-04-21 21:18:31 +0000
88+++ data/ui/AboutMagicicadaDialog.ui 1970-01-01 00:00:00 +0000
89@@ -1,40 +0,0 @@
90-<?xml version="1.0"?>
91-<interface>
92- <requires lib="gtk+" version="2.16"/>
93- <!-- interface-requires about_magicicada_dialog 1.0 -->
94- <!-- interface-naming-policy project-wide -->
95- <object class="AboutMagicicadaDialog" id="about_magicicada_dialog">
96- <property name="border_width">5</property>
97- <property name="icon">../media/icon.png</property>
98- <property name="type_hint">normal</property>
99- <property name="has_separator">False</property>
100- <property name="program_name">Magicicada</property>
101- <property name="version"></property>
102- <property name="copyright"></property>
103- <property name="website"></property>
104- <property name="license"></property>
105- <property name="authors"></property>
106- <property name="logo">../media/logo.png</property>
107- <child internal-child="vbox">
108- <object class="GtkVBox" id="dialog-vbox1">
109- <property name="visible">True</property>
110- <property name="orientation">vertical</property>
111- <property name="spacing">2</property>
112- <child>
113- <placeholder/>
114- </child>
115- <child internal-child="action_area">
116- <object class="GtkHButtonBox" id="dialog-action_area1">
117- <property name="visible">True</property>
118- <property name="layout_style">end</property>
119- </object>
120- <packing>
121- <property name="expand">False</property>
122- <property name="pack_type">end</property>
123- <property name="position">0</property>
124- </packing>
125- </child>
126- </object>
127- </child>
128- </object>
129-</interface>
130
131=== removed file 'data/ui/MagicicadaWindow.ui'
132--- data/ui/MagicicadaWindow.ui 2010-04-21 21:18:31 +0000
133+++ data/ui/MagicicadaWindow.ui 1970-01-01 00:00:00 +0000
134@@ -1,232 +0,0 @@
135-<?xml version="1.0"?>
136-<interface>
137- <requires lib="gtk+" version="2.16"/>
138- <!-- interface-requires magicicada_window 1.0 -->
139- <!-- interface-naming-policy project-wide -->
140- <!-- interface-local-resource-path ../media -->
141- <object class="MagicicadaWindow" id="magicicada_window">
142- <property name="title" translatable="yes">Magicicada</property>
143- <property name="icon">../media/icon.png</property>
144- <signal name="destroy" handler="on_destroy"/>
145- <child>
146- <object class="GtkVBox" id="vbox1">
147- <property name="visible">True</property>
148- <property name="orientation">vertical</property>
149- <property name="spacing">5</property>
150- <child>
151- <object class="GtkMenuBar" id="menubar1">
152- <property name="visible">True</property>
153- <child>
154- <object class="GtkMenuItem" id="menuitem1">
155- <property name="visible">True</property>
156- <property name="label" translatable="yes">_File</property>
157- <property name="use_underline">True</property>
158- <child type="submenu">
159- <object class="GtkMenu" id="menu1">
160- <property name="visible">True</property>
161- <child>
162- <object class="GtkImageMenuItem" id="imagemenuitem1">
163- <property name="label">gtk-new</property>
164- <property name="visible">True</property>
165- <property name="use_action_appearance">True</property>
166- <property name="use_underline">True</property>
167- <property name="use_stock">True</property>
168- <accelerator key="n" signal="activate" modifiers="GDK_CONTROL_MASK"/>
169- </object>
170- </child>
171- <child>
172- <object class="GtkImageMenuItem" id="imagemenuitem2">
173- <property name="label">gtk-open</property>
174- <property name="visible">True</property>
175- <property name="use_underline">True</property>
176- <property name="use_stock">True</property>
177- <accelerator key="o" signal="activate" modifiers="GDK_CONTROL_MASK"/>
178- </object>
179- </child>
180- <child>
181- <object class="GtkImageMenuItem" id="imagemenuitem3">
182- <property name="label">gtk-save</property>
183- <property name="visible">True</property>
184- <property name="use_underline">True</property>
185- <property name="use_stock">True</property>
186- <accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/>
187- </object>
188- </child>
189- <child>
190- <object class="GtkImageMenuItem" id="imagemenuitem4">
191- <property name="label">gtk-save-as</property>
192- <property name="visible">True</property>
193- <property name="use_underline">True</property>
194- <property name="use_stock">True</property>
195- <accelerator key="s" signal="activate" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
196- </object>
197- </child>
198- <child>
199- <object class="GtkSeparatorMenuItem" id="separatormenuitem1">
200- <property name="visible">True</property>
201- </object>
202- </child>
203- <child>
204- <object class="GtkImageMenuItem" id="imagemenuitem5">
205- <property name="label">gtk-quit</property>
206- <property name="visible">True</property>
207- <property name="use_underline">True</property>
208- <property name="use_stock">True</property>
209- <accelerator key="q" signal="activate" modifiers="GDK_CONTROL_MASK"/>
210- <signal name="activate" handler="quit"/>
211- </object>
212- </child>
213- </object>
214- </child>
215- </object>
216- </child>
217- <child>
218- <object class="GtkMenuItem" id="menuitem2">
219- <property name="visible">True</property>
220- <property name="label" translatable="yes">_Edit</property>
221- <property name="use_underline">True</property>
222- <child type="submenu">
223- <object class="GtkMenu" id="menu2">
224- <property name="visible">True</property>
225- <child>
226- <object class="GtkImageMenuItem" id="imagemenuitem6">
227- <property name="label">gtk-cut</property>
228- <property name="visible">True</property>
229- <property name="use_underline">True</property>
230- <property name="use_stock">True</property>
231- <accelerator key="x" signal="activate" modifiers="GDK_CONTROL_MASK"/>
232- </object>
233- </child>
234- <child>
235- <object class="GtkImageMenuItem" id="imagemenuitem7">
236- <property name="label">gtk-copy</property>
237- <property name="visible">True</property>
238- <property name="use_underline">True</property>
239- <property name="use_stock">True</property>
240- <accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
241- </object>
242- </child>
243- <child>
244- <object class="GtkImageMenuItem" id="imagemenuitem8">
245- <property name="label">gtk-paste</property>
246- <property name="visible">True</property>
247- <property name="use_underline">True</property>
248- <property name="use_stock">True</property>
249- <accelerator key="v" signal="activate" modifiers="GDK_CONTROL_MASK"/>
250- </object>
251- </child>
252- <child>
253- <object class="GtkImageMenuItem" id="imagemenuitem9">
254- <property name="label">gtk-delete</property>
255- <property name="visible">True</property>
256- <property name="use_underline">True</property>
257- <property name="use_stock">True</property>
258- <accelerator key="Delete" signal="activate"/>
259- </object>
260- </child>
261- <child>
262- <object class="GtkSeparatorMenuItem" id="separatormenuitem2">
263- <property name="visible">True</property>
264- </object>
265- </child>
266- <child>
267- <object class="GtkImageMenuItem" id="imagemenuitem11">
268- <property name="label">gtk-preferences</property>
269- <property name="visible">True</property>
270- <property name="use_underline">True</property>
271- <property name="use_stock">True</property>
272- <signal name="activate" handler="preferences"/>
273- </object>
274- </child>
275- </object>
276- </child>
277- </object>
278- </child>
279- <child>
280- <object class="GtkMenuItem" id="menuitem3">
281- <property name="visible">True</property>
282- <property name="label" translatable="yes">_View</property>
283- <property name="use_underline">True</property>
284- </object>
285- </child>
286- <child>
287- <object class="GtkMenuItem" id="menuitem4">
288- <property name="visible">True</property>
289- <property name="label" translatable="yes">_Help</property>
290- <property name="use_underline">True</property>
291- <child type="submenu">
292- <object class="GtkMenu" id="helpMenu">
293- <property name="visible">True</property>
294- <child>
295- <object class="GtkImageMenuItem" id="imagemenuitem10">
296- <property name="label">gtk-about</property>
297- <property name="visible">True</property>
298- <property name="use_underline">True</property>
299- <property name="use_stock">True</property>
300- <signal name="activate" handler="about"/>
301- </object>
302- </child>
303- </object>
304- </child>
305- </object>
306- </child>
307- </object>
308- <packing>
309- <property name="expand">False</property>
310- <property name="position">0</property>
311- </packing>
312- </child>
313- <child>
314- <object class="GtkLabel" id="label1">
315- <property name="visible">True</property>
316- <property name="xpad">30</property>
317- <property name="ypad">5</property>
318- <property name="label" translatable="yes">Your application has been created!
319-
320-To start changing this user interface, run 'quickly glade', which will open Glade so you can edit the default windows and dialogs.
321-
322-To change the behavior and edit the python code, run 'quickly edit', which will bring up a text editor.</property>
323- <property name="wrap">True</property>
324- </object>
325- <packing>
326- <property name="position">1</property>
327- </packing>
328- </child>
329- <child>
330- <object class="GtkImage" id="image1">
331- <property name="visible">True</property>
332- <property name="xpad">5</property>
333- <property name="ypad">5</property>
334- <property name="pixbuf">../media/background.png</property>
335- </object>
336- <packing>
337- <property name="padding">15</property>
338- <property name="position">2</property>
339- </packing>
340- </child>
341- <child>
342- <object class="GtkStatusbar" id="statusbar1">
343- <property name="visible">True</property>
344- <property name="spacing">2</property>
345- <child>
346- <object class="GtkLabel" id="label2">
347- <property name="visible">True</property>
348- <property name="xalign">0</property>
349- <property name="xpad">5</property>
350- <property name="ypad">5</property>
351- <property name="label" translatable="yes">Status Area</property>
352- </object>
353- <packing>
354- <property name="position">0</property>
355- </packing>
356- </child>
357- </object>
358- <packing>
359- <property name="expand">False</property>
360- <property name="position">3</property>
361- </packing>
362- </child>
363- </object>
364- </child>
365- </object>
366-</interface>
367
368=== removed file 'data/ui/PreferencesMagicicadaDialog.ui'
369--- data/ui/PreferencesMagicicadaDialog.ui 2010-04-21 21:18:31 +0000
370+++ data/ui/PreferencesMagicicadaDialog.ui 1970-01-01 00:00:00 +0000
371@@ -1,67 +0,0 @@
372-<?xml version="1.0"?>
373-<interface>
374- <requires lib="gtk+" version="2.16"/>
375- <!-- interface-requires preferences_magicicada_dialog 1.0 -->
376- <!-- interface-naming-policy project-wide -->
377- <object class="PreferencesMagicicadaDialog" id="preferences_magicicada_dialog">
378- <property name="border_width">5</property>
379- <property name="icon">../media/icon.png</property>
380- <property name="type_hint">normal</property>
381- <property name="has_separator">False</property>
382- <child internal-child="vbox">
383- <object class="GtkVBox" id="dialog-vbox1">
384- <property name="visible">True</property>
385- <property name="orientation">vertical</property>
386- <property name="spacing">2</property>
387- <child>
388- <placeholder/>
389- </child>
390- <child internal-child="action_area">
391- <object class="GtkHButtonBox" id="dialog-action_area1">
392- <property name="visible">True</property>
393- <property name="layout_style">end</property>
394- <child>
395- <object class="GtkButton" id="button2">
396- <property name="label">gtk-cancel</property>
397- <property name="visible">True</property>
398- <property name="can_focus">True</property>
399- <property name="receives_default">True</property>
400- <property name="use_stock">True</property>
401- <signal name="clicked" handler="cancel"/>
402- </object>
403- <packing>
404- <property name="expand">False</property>
405- <property name="fill">False</property>
406- <property name="position">0</property>
407- </packing>
408- </child>
409- <child>
410- <object class="GtkButton" id="button1">
411- <property name="label">gtk-ok</property>
412- <property name="visible">True</property>
413- <property name="can_focus">True</property>
414- <property name="receives_default">True</property>
415- <property name="use_stock">True</property>
416- <signal name="clicked" handler="ok"/>
417- </object>
418- <packing>
419- <property name="expand">False</property>
420- <property name="fill">False</property>
421- <property name="position">1</property>
422- </packing>
423- </child>
424- </object>
425- <packing>
426- <property name="expand">False</property>
427- <property name="pack_type">end</property>
428- <property name="position">0</property>
429- </packing>
430- </child>
431- </object>
432- </child>
433- <action-widgets>
434- <action-widget response="-6">button2</action-widget>
435- <action-widget response="-5">button1</action-widget>
436- </action-widgets>
437- </object>
438-</interface>
439
440=== removed file 'data/ui/about_magicicada_dialog.xml'
441--- data/ui/about_magicicada_dialog.xml 2010-04-21 21:18:31 +0000
442+++ data/ui/about_magicicada_dialog.xml 1970-01-01 00:00:00 +0000
443@@ -1,9 +0,0 @@
444-<glade-catalog name="about_magicicada_dialog" domain="glade-3"
445- depends="gtk+" version="1.0">
446- <glade-widget-classes>
447- <glade-widget-class title="About Magicicada Dialog" name="AboutMagicicadaDialog"
448- generic-name="AboutMagicicadaDialog" parent="GtkAboutDialog"
449- icon-name="widget-gtk-about-dialog"/>
450- </glade-widget-classes>
451-
452-</glade-catalog>
453
454=== modified file 'data/ui/gui.glade'
455--- data/ui/gui.glade 2010-04-21 23:50:09 +0000
456+++ data/ui/gui.glade 2010-05-15 15:48:32 +0000
457@@ -2,83 +2,196 @@
458 <interface>
459 <requires lib="gtk+" version="2.16"/>
460 <!-- interface-naming-policy project-wide -->
461+ <object class="GtkListStore" id="liststore1"/>
462+ <object class="GtkListStore" id="liststore2"/>
463 <object class="GtkWindow" id="main_window">
464+ <property name="width_request">800</property>
465+ <property name="height_request">600</property>
466 <property name="title" translatable="yes">Magicicada</property>
467- <signal name="destroy_event" handler="on_destroy"/>
468+ <signal name="destroy" handler="on_main_window_destroy"/>
469 <child>
470 <object class="GtkVBox" id="vbox1">
471 <property name="visible">True</property>
472 <child>
473- <object class="GtkVBox" id="vbox2">
474- <property name="visible">True</property>
475- <child>
476- <object class="GtkToolbar" id="toolbar">
477- <property name="visible">True</property>
478- <property name="icon_size_set">True</property>
479- </object>
480- <packing>
481- <property name="expand">False</property>
482- <property name="position">0</property>
483- </packing>
484- </child>
485- <child>
486- <object class="GtkHBox" id="hbox1">
487+ <object class="GtkMenuBar" id="menubar">
488+ <property name="visible">True</property>
489+ <child>
490+ <object class="GtkMenuItem" id="menuitem1">
491+ <property name="visible">True</property>
492+ <property name="label" translatable="yes">_File</property>
493+ <property name="use_underline">True</property>
494+ <child type="submenu">
495+ <object class="GtkMenu" id="menu1">
496+ <property name="visible">True</property>
497+ <child>
498+ <object class="GtkImageMenuItem" id="quit">
499+ <property name="label">gtk-quit</property>
500+ <property name="visible">True</property>
501+ <property name="use_underline">True</property>
502+ <property name="use_stock">True</property>
503+ <signal name="activate" handler="on_quit_activate"/>
504+ </object>
505+ </child>
506+ </object>
507+ </child>
508+ </object>
509+ </child>
510+ <child>
511+ <object class="GtkMenuItem" id="menuitem4">
512+ <property name="visible">True</property>
513+ <property name="label" translatable="yes">_Help</property>
514+ <property name="use_underline">True</property>
515+ <child type="submenu">
516+ <object class="GtkMenu" id="menu3">
517+ <property name="visible">True</property>
518+ <child>
519+ <object class="GtkImageMenuItem" id="about">
520+ <property name="label">gtk-about</property>
521+ <property name="visible">True</property>
522+ <property name="use_underline">True</property>
523+ <property name="use_stock">True</property>
524+ <signal name="activate" handler="on_about_activate"/>
525+ </object>
526+ </child>
527+ </object>
528+ </child>
529+ </object>
530+ </child>
531+ </object>
532+ <packing>
533+ <property name="expand">False</property>
534+ <property name="position">0</property>
535+ </packing>
536+ </child>
537+ <child>
538+ <object class="GtkToolbar" id="toolbar">
539+ <property name="visible">True</property>
540+ <property name="toolbar_style">both</property>
541+ <child>
542+ <object class="GtkToolButton" id="start">
543+ <property name="width_request">50</property>
544+ <property name="visible">True</property>
545+ <property name="label" translatable="yes">Start</property>
546+ <property name="use_underline">True</property>
547+ <property name="stock_id">gtk-apply</property>
548+ <signal name="clicked" handler="on_start_clicked"/>
549+ </object>
550+ <packing>
551+ <property name="expand">False</property>
552+ <property name="homogeneous">True</property>
553+ </packing>
554+ </child>
555+ <child>
556+ <object class="GtkToolButton" id="stop">
557+ <property name="width_request">50</property>
558+ <property name="label" translatable="yes">Stop</property>
559+ <property name="use_underline">True</property>
560+ <property name="stock_id">gtk-stop</property>
561+ <signal name="clicked" handler="on_stop_clicked"/>
562+ </object>
563+ <packing>
564+ <property name="expand">False</property>
565+ <property name="homogeneous">True</property>
566+ </packing>
567+ </child>
568+ <child>
569+ <object class="GtkToolButton" id="connect">
570+ <property name="width_request">80</property>
571+ <property name="visible">True</property>
572+ <property name="sensitive">False</property>
573+ <property name="label" translatable="yes">Connect</property>
574+ <property name="use_underline">True</property>
575+ <property name="stock_id">gtk-connect</property>
576+ <signal name="clicked" handler="on_connect_clicked"/>
577+ </object>
578+ <packing>
579+ <property name="expand">False</property>
580+ <property name="homogeneous">True</property>
581+ </packing>
582+ </child>
583+ <child>
584+ <object class="GtkToolButton" id="disconnect">
585+ <property name="width_request">80</property>
586+ <property name="label" translatable="yes">Disconnect</property>
587+ <property name="use_underline">True</property>
588+ <property name="stock_id">gtk-disconnect</property>
589+ <signal name="clicked" handler="on_disconnect_clicked"/>
590+ </object>
591+ <packing>
592+ <property name="expand">False</property>
593+ <property name="homogeneous">True</property>
594+ </packing>
595+ </child>
596+ </object>
597+ <packing>
598+ <property name="expand">False</property>
599+ <property name="position">1</property>
600+ </packing>
601+ </child>
602+ <child>
603+ <object class="GtkHBox" id="hbox1">
604+ <property name="visible">True</property>
605+ <child>
606+ <object class="GtkHBox" id="hbox2">
607 <property name="visible">True</property>
608 <child>
609- <object class="GtkHBox" id="hbox2">
610+ <object class="GtkImage" id="is_started">
611+ <property name="width_request">30</property>
612 <property name="visible">True</property>
613- <child>
614- <object class="GtkImage" id="image1">
615- <property name="visible">True</property>
616- <property name="stock">gtk-yes</property>
617- </object>
618- <packing>
619- <property name="position">0</property>
620- </packing>
621- </child>
622- <child>
623- <object class="GtkImage" id="image2">
624- <property name="visible">True</property>
625- <property name="stock">gtk-yes</property>
626- </object>
627- <packing>
628- <property name="position">1</property>
629- </packing>
630- </child>
631- <child>
632- <object class="GtkImage" id="image3">
633- <property name="visible">True</property>
634- <property name="stock">gtk-no</property>
635- </object>
636- <packing>
637- <property name="position">2</property>
638- </packing>
639- </child>
640+ <property name="sensitive">False</property>
641+ <property name="xpad">3</property>
642+ <property name="ypad">3</property>
643+ <property name="stock">gtk-yes</property>
644 </object>
645 <packing>
646 <property name="position">0</property>
647 </packing>
648 </child>
649 <child>
650- <object class="GtkLabel" id="status">
651+ <object class="GtkImage" id="is_connected">
652+ <property name="width_request">30</property>
653 <property name="visible">True</property>
654- <property name="label" translatable="yes">Status</property>
655+ <property name="sensitive">False</property>
656+ <property name="xpad">3</property>
657+ <property name="ypad">3</property>
658+ <property name="stock">gtk-yes</property>
659 </object>
660 <packing>
661 <property name="position">1</property>
662 </packing>
663 </child>
664+ <child>
665+ <object class="GtkImage" id="is_online">
666+ <property name="width_request">30</property>
667+ <property name="visible">True</property>
668+ <property name="sensitive">False</property>
669+ <property name="xpad">3</property>
670+ <property name="ypad">3</property>
671+ <property name="stock">gtk-yes</property>
672+ </object>
673+ <packing>
674+ <property name="position">2</property>
675+ </packing>
676+ </child>
677+ </object>
678+ <packing>
679+ <property name="expand">False</property>
680+ <property name="position">0</property>
681+ </packing>
682+ </child>
683+ <child>
684+ <object class="GtkLabel" id="status_label">
685+ <property name="visible">True</property>
686+ <property name="label" translatable="yes">Service not started, click Start to continue.</property>
687 </object>
688 <packing>
689 <property name="position">1</property>
690 </packing>
691 </child>
692- <child>
693- <placeholder/>
694- </child>
695 </object>
696 <packing>
697- <property name="position">0</property>
698+ <property name="expand">False</property>
699+ <property name="position">2</property>
700 </packing>
701 </child>
702 <child>
703@@ -86,14 +199,68 @@
704 <property name="visible">True</property>
705 <property name="can_focus">True</property>
706 <child>
707- <placeholder/>
708+ <object class="GtkTreeView" id="metaq_view">
709+ <property name="visible">True</property>
710+ <property name="can_focus">True</property>
711+ <property name="model">liststore1</property>
712+ </object>
713+ <packing>
714+ <property name="resize">True</property>
715+ <property name="shrink">True</property>
716+ </packing>
717 </child>
718 <child>
719- <placeholder/>
720+ <object class="GtkTreeView" id="contentq_view">
721+ <property name="visible">True</property>
722+ <property name="can_focus">True</property>
723+ <property name="model">liststore2</property>
724+ </object>
725+ <packing>
726+ <property name="resize">True</property>
727+ <property name="shrink">True</property>
728+ </packing>
729 </child>
730 </object>
731 <packing>
732- <property name="position">1</property>
733+ <property name="position">3</property>
734+ </packing>
735+ </child>
736+ </object>
737+ </child>
738+ </object>
739+ <object class="GtkStatusIcon" id="status_icon">
740+ <property name="has_tooltip">True</property>
741+ <property name="tooltip_text">Magicicada</property>
742+ <property name="title">Magicicada</property>
743+ </object>
744+ <object class="GtkAboutDialog" id="about_dialog">
745+ <property name="border_width">5</property>
746+ <property name="type_hint">normal</property>
747+ <property name="has_separator">False</property>
748+ <property name="program_name">Magicicada</property>
749+ <property name="copyright" translatable="yes">Copyright 2010 Natalia Bidart &lt;natalia.bidart@gmail.com&gt;
750+Copyright 2010 Facundo Batista &lt;facundo.batista@gmail.com&gt;
751+</property>
752+ <property name="website">http://launchpad.net/magicicada</property>
753+ <property name="license" translatable="yes">GPL v3.0</property>
754+ <property name="authors">Natalia Bidart &lt;natalia.bidart@gmail.com&gt;
755+Facundo Batista &lt;facundo.batista@gmail.com&gt;</property>
756+ <child internal-child="vbox">
757+ <object class="GtkVBox" id="dialog-vbox1">
758+ <property name="visible">True</property>
759+ <property name="spacing">2</property>
760+ <child>
761+ <placeholder/>
762+ </child>
763+ <child internal-child="action_area">
764+ <object class="GtkHButtonBox" id="dialog-action_area1">
765+ <property name="visible">True</property>
766+ <property name="layout_style">end</property>
767+ </object>
768+ <packing>
769+ <property name="expand">False</property>
770+ <property name="pack_type">end</property>
771+ <property name="position">0</property>
772 </packing>
773 </child>
774 </object>
775
776=== removed file 'data/ui/magicicada_window.xml'
777--- data/ui/magicicada_window.xml 2010-04-21 21:18:31 +0000
778+++ data/ui/magicicada_window.xml 1970-01-01 00:00:00 +0000
779@@ -1,8 +0,0 @@
780-<glade-catalog name="magicicada_window" domain="glade-3"
781- depends="gtk+" version="1.0">
782- <glade-widget-classes>
783- <glade-widget-class title="Magicicada Window" name="MagicicadaWindow"
784- generic-name="MagicicadaWindow" parent="GtkWindow"
785- icon-name="widget-gtk-window"/>
786- </glade-widget-classes>
787-</glade-catalog>
788
789=== removed file 'data/ui/preferences_magicicada_dialog.xml'
790--- data/ui/preferences_magicicada_dialog.xml 2010-04-21 21:18:31 +0000
791+++ data/ui/preferences_magicicada_dialog.xml 1970-01-01 00:00:00 +0000
792@@ -1,9 +0,0 @@
793-<glade-catalog name="preferences_magicicada_dialog" domain="glade-3"
794- depends="gtk+" version="1.0">
795- <glade-widget-classes>
796- <glade-widget-class title="Magicicada Preferences Dialog" name="PreferencesMagicicadaDialog"
797- generic-name="PreferenceMagicicadaDialog" parent="GtkDialog"
798- icon-name="widget-gtk-dialog"/>
799- </glade-widget-classes>
800-
801-</glade-catalog>
802
803=== removed file 'magicicada/AboutMagicicadaDialog.py'
804--- magicicada/AboutMagicicadaDialog.py 2010-04-21 21:18:31 +0000
805+++ magicicada/AboutMagicicadaDialog.py 1970-01-01 00:00:00 +0000
806@@ -1,48 +0,0 @@
807-# -*- coding: utf-8 -*-
808-### BEGIN LICENSE
809-# This file is in the public domain
810-### END LICENSE
811-
812-import gtk
813-
814-from magicicada.helpers import get_builder
815-
816-import gettext
817-from gettext import gettext as _
818-gettext.textdomain('magicicada')
819-
820-class AboutMagicicadaDialog(gtk.AboutDialog):
821- __gtype_name__ = "AboutMagicicadaDialog"
822-
823- def __new__(cls):
824- """Special static method that's automatically called by Python when
825- constructing a new instance of this class.
826-
827- Returns a fully instantiated AboutMagicicadaDialog object.
828- """
829- builder = get_builder('AboutMagicicadaDialog')
830- new_object = builder.get_object("about_magicicada_dialog")
831- new_object.finish_initializing(builder)
832- return new_object
833-
834- def finish_initializing(self, builder):
835- """Called while initializing this instance in __new__
836-
837- finish_initalizing should be called after parsing the ui definition
838- and creating a AboutMagicicadaDialog object with it in order to
839- finish initializing the start of the new AboutMagicicadaDialog
840- instance.
841-
842- Put your initialization code in here and leave __init__ undefined.
843- """
844- # Get a reference to the builder and set up the signals.
845- self.builder = builder
846- self.builder.connect_signals(self)
847-
848- # Code for other initialization actions should be added here.
849-
850-
851-if __name__ == "__main__":
852- dialog = AboutMagicicadaDialog()
853- dialog.show()
854- gtk.main()
855
856=== removed file 'magicicada/PreferencesMagicicadaDialog.py'
857--- magicicada/PreferencesMagicicadaDialog.py 2010-04-21 21:18:31 +0000
858+++ magicicada/PreferencesMagicicadaDialog.py 1970-01-01 00:00:00 +0000
859@@ -1,111 +0,0 @@
860-# -*- coding: utf-8 -*-
861-### BEGIN LICENSE
862-# This file is in the public domain
863-### END LICENSE
864-
865-from desktopcouch.records.server import CouchDatabase
866-from desktopcouch.records.record import Record
867-import gtk
868-
869-from magicicada.helpers import get_builder
870-
871-import gettext
872-from gettext import gettext as _
873-gettext.textdomain('magicicada')
874-
875-class PreferencesMagicicadaDialog(gtk.Dialog):
876- __gtype_name__ = "PreferencesMagicicadaDialog"
877- preferences = {}
878-
879- def __new__(cls):
880- """Special static method that's automatically called by Python when
881- constructing a new instance of this class.
882-
883- Returns a fully instantiated PreferencesMagicicadaDialog object.
884- """
885- builder = get_builder('PreferencesMagicicadaDialog')
886- new_object = builder.get_object("preferences_magicicada_dialog")
887- new_object.finish_initializing(builder)
888- return new_object
889-
890- def finish_initializing(self, builder):
891- """Called while initializing this instance in __new__
892-
893- finish_initalizing should be called after parsing the ui definition
894- and creating a PreferencesMagicicadaDialog object with it in order to
895- finish initializing the start of the new PerferencesMagicicadaDialog
896- instance.
897-
898- Put your initialization code in here and leave __init__ undefined.
899- """
900-
901- # Get a reference to the builder and set up the signals.
902- self.builder = builder
903- self.builder.connect_signals(self)
904-
905- # Set up couchdb and the preference info.
906- self._db_name = "magicicada"
907- self._database = CouchDatabase(self._db_name, create=True)
908- self._preferences = None
909- self._key = None
910-
911- # Set the record type and then initalize the preferences.
912- self._record_type = (
913- "http://wiki.ubuntu.com/Quickly/RecordTypes/Magicicada/"
914- "Preferences")
915- self._preferences = self.get_preferences()
916- # TODO: code for other initialization actions should be added here
917-
918- def get_preferences(self):
919- """Return a dict of preferences for magicicada.
920-
921- Creates a couchdb record if necessary.
922- """
923- if self._preferences == None:
924- # The dialog is initializing.
925- self._load_preferences()
926-
927- # If there were no saved preference, this.
928- return self._preferences
929-
930- def _load_preferences(self):
931- # TODO: add preferences to the self._preferences dict default
932- # preferences that will be overwritten if some are saved
933- self._preferences = {"record_type": self._record_type}
934-
935- results = self._database.get_records(
936- record_type=self._record_type, create_view=True)
937-
938- if len(results.rows) == 0:
939- # No preferences have ever been saved, save them before returning.
940- self._key = self._database.put_record(Record(self._preferences))
941- else:
942- self._preferences = results.rows[0].value
943- del self._preferences['_rev']
944- self._key = results.rows[0].value["_id"]
945-
946- def _save_preferences(self):
947- self._database.update_fields(self._key, self._preferences)
948-
949- def ok(self, widget, data=None):
950- """The user has elected to save the changes.
951-
952- Called before the dialog returns gtk.RESONSE_OK from run().
953- """
954-
955- # Make any updates to self._preferences here. e.g.
956- #self._preferences["preference1"] = "value2"
957- self._save_preferences()
958-
959- def cancel(self, widget, data=None):
960- """The user has elected cancel changes.
961-
962- Called before the dialog returns gtk.RESPONSE_CANCEL for run()
963- """
964- # Restore any changes to self._preferences here.
965- pass
966-
967-if __name__ == "__main__":
968- dialog = PreferencesMagicicadaDialog()
969- dialog.show()
970- gtk.main()
971
972=== modified file 'magicicada/__init__.py'
973--- magicicada/__init__.py 2010-04-21 21:18:31 +0000
974+++ magicicada/__init__.py 2010-05-15 15:48:32 +0000
975@@ -0,0 +1,204 @@
976+# __init__.py
977+#
978+# Author: Natalia Bidart <natalia.bidart@gmail.com>
979+#
980+# Copyright 2010 Chicharreros
981+#
982+# This program is free software: you can redistribute it and/or modify it
983+# under the terms of the GNU General Public License version 3, as published
984+# by the Free Software Foundation.
985+#
986+# This program is distributed in the hope that it will be useful, but
987+# WITHOUT ANY WARRANTY; without even the implied warranties of
988+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
989+# PURPOSE. See the GNU General Public License for more details.
990+#
991+# You should have received a copy of the GNU General Public License along
992+# with this program. If not, see <http://www.gnu.org/licenses/>.
993+
994+"""Magicicada."""
995+
996+import gtk
997+
998+import gettext
999+from gettext import gettext as _
1000+gettext.textdomain('magicicada')
1001+
1002+from twisted.internet import gtk2reactor # for gtk-2.0
1003+gtk2reactor.install()
1004+
1005+from twisted.internet import reactor
1006+
1007+from magicicada.helpers import get_data_file, get_builder, print_debug
1008+from magicicada.syncdaemon import SyncDaemon
1009+
1010+
1011+class MagicicadaUI(object):
1012+
1013+ STATUS = {
1014+ 'started': _('Service started, click Connect to continue.'),
1015+ 'connected': _('Service connected. Doing internal synchronization...'),
1016+ 'online': _('Service reached Nirvana.'),
1017+ }
1018+
1019+ def __init__(self, launchpad_available=False):
1020+ """Init."""
1021+ self.builder = get_builder('gui.glade')
1022+ self.builder.connect_signals(self)
1023+
1024+ if launchpad_available:
1025+ # for more information about LaunchpadIntegration:
1026+ # wiki.ubuntu.com/UbuntuDevelopment/Internationalisation/Coding
1027+ helpmenu = self.builder.get_object('helpMenu')
1028+ if helpmenu:
1029+ LaunchpadIntegration.set_sourcepackagename('magicicada')
1030+ LaunchpadIntegration.add_items(helpmenu, 0, False, True)
1031+
1032+ animation_filename = get_data_file('media', 'loader-ball.gif')
1033+ self.loading_animation = gtk.gdk.PixbufAnimation(animation_filename)
1034+
1035+ self.started = self.connected = self.online = False
1036+
1037+ widgets = (
1038+ 'start', 'stop', 'connect', 'disconnect', # toolbar buttons
1039+ 'is_started', 'is_connected', 'is_online', # status bar images
1040+ 'status_label', 'status_icon', # status label and systray icon
1041+ 'main_window', 'about_dialog',
1042+ )
1043+ for widget in widgets:
1044+ setattr(self, widget, self.builder.get_object(widget))
1045+
1046+ icon_filename = get_data_file('media', 'ubuntuone.png')
1047+ self.status_icon.set_from_file(icon_filename)
1048+
1049+ self.main_window.set_icon_from_file(icon_filename)
1050+ self.main_window.show()
1051+
1052+ self.syncdaemon = SyncDaemon()
1053+
1054+ def run(self):
1055+ """Do the deed."""
1056+ reactor.run() # instead of: gtk.main()
1057+
1058+ def shutdown(self):
1059+ """Stop the deed."""
1060+ reactor.stop() # instead of: gtk.main_quit()
1061+
1062+ # GTK callbacks
1063+
1064+ def on_main_window_destroy(self, widget, data=None):
1065+ """Called when the MagicicadaWindow is closed."""
1066+ # Clean up code for saving application state should be added here.
1067+ if self.started:
1068+ self.on_stop_clicked(self.stop)
1069+ self.syncdaemon.shutdown()
1070+
1071+ def on_quit_activate(self, widget, data=None):
1072+ """Signal handler for closing the program."""
1073+ self.on_main_window_destroy(self.main_window)
1074+
1075+ def on_about_activate(self, widget, data=None):
1076+ """Display the about box."""
1077+ response = self.about_dialog.run()
1078+ self.about_dialog.hide()
1079+
1080+ @print_debug
1081+ def on_start_clicked(self, widget, data=None):
1082+ """Start syncdaemon."""
1083+ self.started = True
1084+ self.connect.set_sensitive(True)
1085+ self.start.hide()
1086+ self.stop.show()
1087+
1088+ self.doing_something(self.is_started)
1089+
1090+ @print_debug
1091+ def on_stop_clicked(self, widget, data=None):
1092+ """Stop syncdaemon."""
1093+ assert self.started
1094+
1095+ if self.connected:
1096+ self.on_disconnect_clicked(self.disconnect)
1097+ self.connect.set_sensitive(False)
1098+
1099+ self.started = False
1100+ self.start.show()
1101+ self.stop.hide()
1102+
1103+ self.on_stopped()
1104+
1105+ @print_debug
1106+ def on_connect_clicked(self, widget, data=None):
1107+ """Connect syncdaemon."""
1108+ assert self.started
1109+ self.connected = True
1110+ self.connect.hide()
1111+ self.disconnect.show()
1112+
1113+ self.on_started()
1114+ self.doing_something(self.is_connected)
1115+
1116+ @print_debug
1117+ def on_disconnect_clicked(self, widget, data=None):
1118+ """Disconnect syncdaemon."""
1119+ assert self.started
1120+ assert self.connected
1121+ self.connected = False
1122+ self.connect.show()
1123+ self.disconnect.hide()
1124+
1125+ self.on_disconnected()
1126+
1127+ # DBus callbacks
1128+
1129+ def on_started(self, *args, **kwargs):
1130+ """Callback'ed when syncadaemon is started."""
1131+ self.stop_doing_something(self.is_started)
1132+ self.status_label.set_text(self.STATUS['started'])
1133+
1134+ def on_stopped(self, *args, **kwargs):
1135+ """Callback'ed when syncadaemon is stopped."""
1136+
1137+ self.stop_doing_something(self.is_started, sensitive=False)
1138+
1139+ self.is_started.set_sensitive(False)
1140+ self.is_connected.set_sensitive(False)
1141+ self.is_online.set_sensitive(False)
1142+
1143+ def on_connected(self, *args, **kwargs):
1144+ """Callback'ed when syncadaemon is connected."""
1145+ self.is_connected.set_sensitive(True)
1146+ self.doing_something(self.is_online)
1147+ self.status_label.set_text(self.STATUS['connected'])
1148+
1149+ def on_disconnected(self, *args, **kwargs):
1150+ """Callback'ed when syncadaemon is disconnected."""
1151+
1152+ self.stop_doing_something(self.is_connected, sensitive=False)
1153+
1154+ self.is_connected.set_sensitive(False)
1155+ self.is_online.set_sensitive(False)
1156+
1157+ def on_online(self, *args, **kwargs):
1158+ """Callback'ed when syncadaemon is online."""
1159+ self.is_onlined.set_sensitive(True)
1160+ self.status_label.set_text(self.STATUS['online'])
1161+
1162+ def on_offline(self, *args, **kwargs):
1163+ """Callback'ed when syncadaemon is offline."""
1164+
1165+ self.stop_doing_something(self.is_online, sensitive=False)
1166+
1167+ self.is_online.set_sensitive(False)
1168+
1169+ # custom
1170+
1171+ def doing_something(self, what):
1172+ """Set a loader animation on 'what'."""
1173+ what.set_sensitive(True)
1174+ what.set_from_animation(self.loading_animation)
1175+
1176+ def stop_doing_something(self, what, sensitive=True):
1177+ """Set a loader animation on 'what'."""
1178+ what.set_from_stock(gtk.STOCK_YES, gtk.ICON_SIZE_BUTTON)
1179+ what.set_sensitive(sensitive)
1180
1181=== modified file 'magicicada/helpers.py'
1182--- magicicada/helpers.py 2010-04-21 23:50:09 +0000
1183+++ magicicada/helpers.py 2010-05-15 15:48:32 +0000
1184@@ -12,6 +12,8 @@
1185 import os
1186 import gtk
1187
1188+from functools import wraps
1189+
1190 from magicicada.magicicadaconfig import get_data_file
1191
1192 import gettext
1193@@ -19,9 +21,8 @@
1194 gettext.textdomain('magicicada')
1195
1196 def get_builder(builder_file_name):
1197- """Return a fully-instantiated gtk.Builder instance from specified ui
1198- file
1199-
1200+ """Return a fully-instantiated gtk.Builder instance from specified ui file.
1201+
1202 :param builder_file_name: The name of the builder file, without extension.
1203 Assumed to be in the 'ui' directory under the data path.
1204 """
1205@@ -34,3 +35,14 @@
1206 builder.set_translation_domain('magicicada')
1207 builder.add_from_file(ui_filename)
1208 return builder
1209+
1210+def print_debug(f):
1211+ """Print debug info for 'f'."""
1212+
1213+ @wraps(f)
1214+ def inner(*args, **kwargs):
1215+ """Wrap f."""
1216+ print('Calling', f.__name__, args, kwargs)
1217+ f(*args, **kwargs)
1218+
1219+ return inner
1220
1221=== modified file 'magicicada/syncdaemon.py'
1222--- magicicada/syncdaemon.py 2010-05-04 01:30:42 +0000
1223+++ magicicada/syncdaemon.py 2010-05-15 15:48:32 +0000
1224@@ -18,9 +18,14 @@
1225
1226 """The backend that communicates Magicicada with the SyncDaemon."""
1227
1228-# this always first
1229-from twisted.internet import glib2reactor
1230-glib2reactor.install()
1231+import sys
1232+
1233+try:
1234+ from twisted.internet import glib2reactor
1235+ glib2reactor.install()
1236+except AssertionError, e:
1237+ msg = '\nsyncdaemon.py: Not installing glib2reactor because: %s.\n'
1238+ sys.stderr.write(msg % e)
1239
1240 import collections
1241 import re
1242
1243=== added file 'magicicada/tests/test_magicicada.py'
1244--- magicicada/tests/test_magicicada.py 1970-01-01 00:00:00 +0000
1245+++ magicicada/tests/test_magicicada.py 2010-05-15 15:48:32 +0000
1246@@ -0,0 +1,150 @@
1247+# test_magicicada.py
1248+#
1249+# Author: Natalia Bidart <natalia.bidart@gmail.com>
1250+#
1251+# Copyright 2010 Chicharreros
1252+#
1253+# This program is free software: you can redistribute it and/or modify it
1254+# under the terms of the GNU General Public License version 3, as published
1255+# by the Free Software Foundation.
1256+#
1257+# This program is distributed in the hope that it will be useful, but
1258+# WITHOUT ANY WARRANTY; without even the implied warranties of
1259+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1260+# PURPOSE. See the GNU General Public License for more details.
1261+#
1262+# You should have received a copy of the GNU General Public License along
1263+# with this program. If not, see <http://www.gnu.org/licenses/>.
1264+
1265+"""Tests for magicicada."""
1266+
1267+import gobject
1268+import gtk
1269+import unittest
1270+
1271+from functools import wraps
1272+
1273+from twisted.internet import reactor
1274+from twisted.trial.unittest import TestCase
1275+
1276+from magicicada import MagicicadaUI
1277+from magicicada.helpers import get_builder
1278+from magicicada.syncdaemon import SyncDaemon
1279+
1280+DEFAULT_TIMEOUT = 200
1281+NO_OP = lambda *a, **kw: None
1282+
1283+def close_window_after(a_test):
1284+ """Decorator to close the main window after executing f."""
1285+ @wraps(a_test)
1286+ def inner(*args, **kwargs):
1287+ """Inner function."""
1288+ #gobject.timeout_add(DEFAULT_TIMEOUT, a_test)
1289+ #self.ui.run()
1290+
1291+ return inner
1292+
1293+
1294+class MagicicadaUITestCase(TestCase):
1295+ """UI test cases for Magicicada UI."""
1296+
1297+ def setUp(self):
1298+ """Init."""
1299+ self.builder = get_builder('gui.glade')
1300+ self.ui = MagicicadaUI()
1301+ self._patched = {}
1302+ self._called = False
1303+
1304+ def tearDown(self):
1305+ """Clenaup."""
1306+ self.ui.on_main_window_destroy(self.ui.main_window)
1307+ for (instance, attr), old_value in self._patched.iteritems():
1308+ setattr(instance, attr, old_value)
1309+ self._called = False
1310+ self.builder = None
1311+
1312+ def test_init_creates_sd_instance(self):
1313+ """SyncDaemon instance is created at creation time."""
1314+ self.assertTrue(isinstance(self.ui.syncdaemon, SyncDaemon))
1315+
1316+ def test_destroy_shutdowns_sd_instance(self):
1317+ """SyncDaemon instance is shutdown at destroy time."""
1318+ self.patch(self.ui.syncdaemon, 'shutdown',
1319+ lambda *_: setattr(self, '_called', True))
1320+ self.ui.on_main_window_destroy(self.ui.main_window)
1321+ self.assertTrue(self._called, 'syncdaemon.shutdown must be called at destroy time.')
1322+
1323+ def test_shutdown_stops_reactor(self):
1324+ """SyncDaemon instance is shutdown at destroy time."""
1325+ self.patch(reactor, 'stop',
1326+ lambda *_: setattr(self, '_called', True))
1327+ self.ui.shutdown()
1328+ self.assertTrue(self._called, 'reactor.stop must be called at destroy time.')
1329+
1330+
1331+class MagicicadaUIStartupTestCase(MagicicadaUITestCase):
1332+ """UI test cases for startup state."""
1333+
1334+ def test_main_window_is_visible(self):
1335+ """UI can be created."""
1336+ self.assertTrue(self.ui.main_window.get_property('visible'))
1337+
1338+ def test_start_connect_are_visible(self):
1339+ """Start and Connect buttons are visible."""
1340+ self.assertTrue(self.ui.start.get_property('visible'))
1341+ self.assertTrue(self.ui.start.is_sensitive())
1342+
1343+ self.assertTrue(self.ui.connect.get_property('visible'))
1344+ self.assertFalse(self.ui.connect.is_sensitive())
1345+
1346+ def test_stop_disconnect_are_not_visible(self):
1347+ """Start and Connect buttons are visible."""
1348+ self.assertFalse(self.ui.stop.get_property('visible'))
1349+ self.assertFalse(self.ui.disconnect.get_property('visible'))
1350+
1351+ def test_not_started_not_connected_not_online(self):
1352+ """Test default values for flags."""
1353+ self.assertFalse(self.ui.started)
1354+ self.assertFalse(self.ui.connected)
1355+ self.assertFalse(self.ui.online)
1356+
1357+ def test_indicators_are_non_sensitive(self):
1358+ """Test default sensitivity for indicators."""
1359+ #import pdb; pdb.set_trace()
1360+ self.assertFalse(self.ui.is_started.is_sensitive())
1361+ self.assertFalse(self.ui.is_connected.is_sensitive())
1362+ self.assertFalse(self.ui.is_online.is_sensitive())
1363+
1364+class MagicicadaUIClickedTestCase(MagicicadaUIStartupTestCase):
1365+ """UI test cases."""
1366+
1367+ def test_started_if_start_clicked(self):
1368+ """Test started if Start was clicked."""
1369+ self.ui.on_start_clicked(self.ui.start)
1370+ self.assertTrue(self.ui.started)
1371+ self.assertFalse(self.ui.connected)
1372+ self.assertFalse(self.ui.online)
1373+
1374+ def test_can_connect_can_stop_if_start_clicked(self):
1375+ """Test Connect and Stop are enabled if Start was clicked."""
1376+ self.ui.on_start_clicked(self.ui.start)
1377+ self.assertFalse(self.ui.start.get_property('visible'))
1378+ self.assertTrue(self.ui.stop.get_property('visible'))
1379+ self.assertTrue(self.ui.connect.is_sensitive())
1380+
1381+ def test_connected_if_connect_clicked(self):
1382+ """Test connected if Connect was clicked."""
1383+ self.ui.on_start_clicked(self.ui.start) # need to be started
1384+ self.ui.on_connect_clicked(self.ui.connect)
1385+
1386+ self.assertTrue(self.ui.started)
1387+ self.assertTrue(self.ui.connected)
1388+ self.assertFalse(self.ui.online)
1389+
1390+ def test_can_disconnect_if_connect_clicked(self):
1391+ """Test Disconnect is enabled if Connect was clicked."""
1392+ self.ui.on_start_clicked(self.ui.start) # need to be started
1393+ self.ui.on_connect_clicked(self.ui.connect)
1394+ self.assertFalse(self.ui.connect.get_property('visible'))
1395+ self.assertTrue(self.ui.disconnect.get_property('visible'))
1396+

Subscribers

People subscribed via source and target branches

to all changes: