Merge lp:~facundo/ubuntu/maverick/magicicada/0.1.3-update into lp:ubuntu/maverick/magicicada
- Maverick (10.10)
- 0.1.3-update
- Merge into maverick
Proposed by
Facundo Batista
Status: | Merged |
---|---|
Merged at revision: | 4 |
Proposed branch: | lp:~facundo/ubuntu/maverick/magicicada/0.1.3-update |
Merge into: | lp:ubuntu/maverick/magicicada |
Diff against target: |
956 lines (+334/-196) 9 files modified
PKG-INFO (+1/-1) README.txt (+21/-5) data/ui/gui.glade (+82/-155) debian/changelog (+6/-0) magicicada/__init__.py (+63/-15) magicicada/syncdaemon.py (+5/-0) magicicada/tests/test_magicicada.py (+147/-19) magicicada/tests/test_syncdaemon.py (+8/-0) setup.py (+1/-1) |
To merge this branch: | bzr merge lp:~facundo/ubuntu/maverick/magicicada/0.1.3-update |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Sponsors | Pending | ||
Review via email: mp+31425@code.launchpad.net |
Commit message
Description of the change
0.1.3 release
To post a comment you must log in.
Revision history for this message
James Westby (james-w) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'PKG-INFO' |
2 | --- PKG-INFO 2010-07-09 18:14:53 +0000 |
3 | +++ PKG-INFO 2010-07-30 20:32:43 +0000 |
4 | @@ -1,6 +1,6 @@ |
5 | Metadata-Version: 1.1 |
6 | Name: magicicada |
7 | -Version: 0.1.2 |
8 | +Version: 0.1.3 |
9 | Summary: A GTK+ frontend for the "Chicharra" part of Ubuntu One. |
10 | Home-page: https://launchpad.net/magicicada |
11 | Author: Natalia Bidart |
12 | |
13 | === modified file 'README.txt' |
14 | --- README.txt 2010-07-09 18:14:53 +0000 |
15 | +++ README.txt 2010-07-30 20:32:43 +0000 |
16 | @@ -2,15 +2,31 @@ |
17 | |
18 | A GTK+ frontend for the "Chicharra" part of Ubuntu One client. |
19 | |
20 | ------------ |
21 | -HOWTO do a source release: |
22 | + |
23 | + |
24 | +HOWTO do a source release |
25 | +------------------------- |
26 | |
27 | * edit setup.py and increment the version number. |
28 | * 'python setup.py sdist' |
29 | * look at the contents of the tarball created in dist/ to be sure they are ok |
30 | + * step into the dist directory for the following commands |
31 | * sign the tarball by a command like: |
32 | - gpg -a --detach-sign magicicada-0.2.tar.gz |
33 | - this should create a file like magicicada-0.2.tar.gz.asc |
34 | + gpg -a --detach-sign magicicada-VERSION.tar.gz |
35 | + this should create a file like magicicada-VERSION.tar.gz.asc |
36 | * Upload the new release to launchpad with a command like: |
37 | - lp-project-upload magicicada 0.2 magicicada-0.2.tar.gz |
38 | + lp-project-upload magicicada VERSION magicicada-VERSION.tar.gz |
39 | * Announce the release, ping someone to build updated packages for the PPA and Ubuntu. |
40 | + |
41 | + |
42 | +HOWTO prepare an updated Ubuntu package |
43 | +--------------------------------------- |
44 | + |
45 | + * bzr get lp:ubuntu/magicicada |
46 | + * cd magicicada |
47 | + * uscan --verbose --rename (this gets the new upstream release from launchpad) |
48 | + * bzr merge-package ../magicicada_0.1.2.orig.tar.gz --version=0.1.2 |
49 | + * vim debian/changelog, check version, distro, and changes are correct. |
50 | + * you will need to build versions for lucid (for the PPA) and for the current dev release of Ubuntu. For example, if you are working on updating to release 0.1.2 of magicicada, and you want to build a package for lucid in the chicharreros PPA, the version number would be magicicada-0.1.2-0ubuntu1~lucid1. Then for the maverick version in the PPA, the version number would be magicicada-0.1.2-0ubuntu1~maverick1. And, for the version you upload to ubuntu universe, the version number would be magicicada-0.1.2-0ubuntu1. |
51 | + * To upload to the chicharreros PPA: do dput ppa:chicharreros/ppa <source.changes> |
52 | + * To get an upload into Ubuntu, prepare the source package and ask for a sponsor. |
53 | |
54 | === modified file 'data/ui/gui.glade' |
55 | --- data/ui/gui.glade 2010-07-09 18:14:53 +0000 |
56 | +++ data/ui/gui.glade 2010-07-30 20:32:43 +0000 |
57 | @@ -2,85 +2,85 @@ |
58 | <interface> |
59 | <requires lib="gtk+" version="2.16"/> |
60 | <!-- interface-naming-policy project-wide --> |
61 | + <object class="GtkListStore" id="contentq_store"> |
62 | + <columns> |
63 | + <!-- column-name operation --> |
64 | + <column type="gchararray"/> |
65 | + <!-- column-name path --> |
66 | + <column type="gchararray"/> |
67 | + <!-- column-name share --> |
68 | + <column type="gchararray"/> |
69 | + <!-- column-name node --> |
70 | + <column type="gchararray"/> |
71 | + </columns> |
72 | + </object> |
73 | + <object class="GtkListStore" id="metaq_store"> |
74 | + <columns> |
75 | + <!-- column-name operation --> |
76 | + <column type="gchararray"/> |
77 | + <!-- column-name path --> |
78 | + <column type="gchararray"/> |
79 | + <!-- column-name share --> |
80 | + <column type="gchararray"/> |
81 | + <!-- column-name node --> |
82 | + <column type="gchararray"/> |
83 | + </columns> |
84 | + </object> |
85 | <object class="GtkListStore" id="folders_store"> |
86 | <columns> |
87 | - <!-- column-name node --> |
88 | - <column type="gchararray"/> |
89 | <!-- column-name path --> |
90 | <column type="gchararray"/> |
91 | <!-- column-name suggested_path --> |
92 | <column type="gchararray"/> |
93 | <!-- column-name subscribed --> |
94 | <column type="gboolean"/> |
95 | - <!-- column-name volume --> |
96 | - <column type="gchararray"/> |
97 | - </columns> |
98 | - </object> |
99 | - <object class="GtkListStore" id="contentq_store"> |
100 | - <columns> |
101 | - <!-- column-name operation --> |
102 | - <column type="gchararray"/> |
103 | - <!-- column-name path --> |
104 | - <column type="gchararray"/> |
105 | - <!-- column-name share --> |
106 | - <column type="gchararray"/> |
107 | - <!-- column-name node --> |
108 | - <column type="gchararray"/> |
109 | - </columns> |
110 | - </object> |
111 | - <object class="GtkListStore" id="metaq_store"> |
112 | - <columns> |
113 | - <!-- column-name operation --> |
114 | - <column type="gchararray"/> |
115 | - <!-- column-name path --> |
116 | - <column type="gchararray"/> |
117 | - <!-- column-name share --> |
118 | - <column type="gchararray"/> |
119 | - <!-- column-name node --> |
120 | + <!-- column-name node --> |
121 | + <column type="gchararray"/> |
122 | + <!-- column-name volume --> |
123 | + <column type="gchararray"/> |
124 | + </columns> |
125 | + </object> |
126 | + <object class="GtkListStore" id="shares_to_others_store"> |
127 | + <columns> |
128 | + <!-- column-name name --> |
129 | + <column type="gchararray"/> |
130 | + <!-- column-name other_visible_name --> |
131 | + <column type="gchararray"/> |
132 | + <!-- column-name accepted --> |
133 | + <column type="gboolean"/> |
134 | + <!-- column-name access_level --> |
135 | + <column type="gchararray"/> |
136 | + <!-- column-name free_bytes --> |
137 | + <column type="gchararray"/> |
138 | + <!-- column-name path --> |
139 | + <column type="gchararray"/> |
140 | + <!-- column-name other_username --> |
141 | + <column type="gchararray"/> |
142 | + <!-- column-name node --> |
143 | + <column type="gchararray"/> |
144 | + <!-- column-name volume --> |
145 | <column type="gchararray"/> |
146 | </columns> |
147 | </object> |
148 | <object class="GtkListStore" id="shares_to_me_store"> |
149 | <columns> |
150 | - <!-- column-name accepted --> |
151 | - <column type="gboolean"/> |
152 | - <!-- column-name access_level --> |
153 | - <column type="gchararray"/> |
154 | - <!-- column-name free_bytes --> |
155 | - <column type="gchararray"/> |
156 | - <!-- column-name name --> |
157 | - <column type="gchararray"/> |
158 | - <!-- column-name node_id --> |
159 | - <column type="gchararray"/> |
160 | - <!-- column-name other_username --> |
161 | - <column type="gchararray"/> |
162 | - <!-- column-name other_visible_name --> |
163 | - <column type="gchararray"/> |
164 | - <!-- column-name path --> |
165 | - <column type="gchararray"/> |
166 | - <!-- column-name volume_id --> |
167 | - <column type="gchararray"/> |
168 | - </columns> |
169 | - </object> |
170 | - <object class="GtkListStore" id="shares_to_others_store"> |
171 | - <columns> |
172 | - <!-- column-name accepted --> |
173 | - <column type="gboolean"/> |
174 | - <!-- column-name access_level --> |
175 | - <column type="gchararray"/> |
176 | - <!-- column-name free_bytes --> |
177 | - <column type="gchararray"/> |
178 | - <!-- column-name name --> |
179 | - <column type="gchararray"/> |
180 | - <!-- column-name node_id --> |
181 | - <column type="gchararray"/> |
182 | - <!-- column-name other_username --> |
183 | - <column type="gchararray"/> |
184 | - <!-- column-name other_visible_name --> |
185 | - <column type="gchararray"/> |
186 | - <!-- column-name path --> |
187 | - <column type="gchararray"/> |
188 | - <!-- column-name volume_id --> |
189 | + <!-- column-name name --> |
190 | + <column type="gchararray"/> |
191 | + <!-- column-name other_visible_name --> |
192 | + <column type="gchararray"/> |
193 | + <!-- column-name accepted --> |
194 | + <column type="gboolean"/> |
195 | + <!-- column-name access_level --> |
196 | + <column type="gchararray"/> |
197 | + <!-- column-name free_bytes --> |
198 | + <column type="gchararray"/> |
199 | + <!-- column-name path --> |
200 | + <column type="gchararray"/> |
201 | + <!-- column-name other_username --> |
202 | + <column type="gchararray"/> |
203 | + <!-- column-name node --> |
204 | + <column type="gchararray"/> |
205 | + <!-- column-name volume --> |
206 | <column type="gchararray"/> |
207 | </columns> |
208 | </object> |
209 | @@ -627,7 +627,7 @@ |
210 | <child> |
211 | <object class="GtkCellRendererText" id="cellrenderertext10"/> |
212 | <attributes> |
213 | - <attribute name="text">1</attribute> |
214 | + <attribute name="text">0</attribute> |
215 | </attributes> |
216 | </child> |
217 | </object> |
218 | @@ -640,7 +640,7 @@ |
219 | <child> |
220 | <object class="GtkCellRendererText" id="cellrenderertext11"/> |
221 | <attributes> |
222 | - <attribute name="text">2</attribute> |
223 | + <attribute name="text">1</attribute> |
224 | </attributes> |
225 | </child> |
226 | </object> |
227 | @@ -653,33 +653,7 @@ |
228 | <child> |
229 | <object class="GtkCellRendererToggle" id="cellrenderertoggle1"/> |
230 | <attributes> |
231 | - <attribute name="active">3</attribute> |
232 | - </attributes> |
233 | - </child> |
234 | - </object> |
235 | - </child> |
236 | - <child> |
237 | - <object class="GtkTreeViewColumn" id="folders_node"> |
238 | - <property name="resizable">True</property> |
239 | - <property name="title">Node</property> |
240 | - <property name="expand">True</property> |
241 | - <child> |
242 | - <object class="GtkCellRendererText" id="cellrenderertext9"/> |
243 | - <attributes> |
244 | - <attribute name="text">0</attribute> |
245 | - </attributes> |
246 | - </child> |
247 | - </object> |
248 | - </child> |
249 | - <child> |
250 | - <object class="GtkTreeViewColumn" id="folders_volume"> |
251 | - <property name="resizable">True</property> |
252 | - <property name="title">Volume</property> |
253 | - <property name="expand">True</property> |
254 | - <child> |
255 | - <object class="GtkCellRendererText" id="cellrenderertext12"/> |
256 | - <attributes> |
257 | - <attribute name="text">4</attribute> |
258 | + <attribute name="active">2</attribute> |
259 | </attributes> |
260 | </child> |
261 | </object> |
262 | @@ -758,7 +732,7 @@ |
263 | <child> |
264 | <object class="GtkCellRendererText" id="cellrenderertext15"/> |
265 | <attributes> |
266 | - <attribute name="text">3</attribute> |
267 | + <attribute name="text">0</attribute> |
268 | </attributes> |
269 | </child> |
270 | </object> |
271 | @@ -770,7 +744,7 @@ |
272 | <child> |
273 | <object class="GtkCellRendererText" id="cellrenderertext19"/> |
274 | <attributes> |
275 | - <attribute name="text">6</attribute> |
276 | + <attribute name="text">1</attribute> |
277 | </attributes> |
278 | </child> |
279 | </object> |
280 | @@ -782,7 +756,7 @@ |
281 | <child> |
282 | <object class="GtkCellRendererToggle" id="cellrenderertoggle2"/> |
283 | <attributes> |
284 | - <attribute name="active">0</attribute> |
285 | + <attribute name="active">2</attribute> |
286 | </attributes> |
287 | </child> |
288 | </object> |
289 | @@ -794,7 +768,7 @@ |
290 | <child> |
291 | <object class="GtkCellRendererText" id="cellrenderertext13"/> |
292 | <attributes> |
293 | - <attribute name="text">1</attribute> |
294 | + <attribute name="text">3</attribute> |
295 | </attributes> |
296 | </child> |
297 | </object> |
298 | @@ -806,7 +780,7 @@ |
299 | <child> |
300 | <object class="GtkCellRendererText" id="cellrenderertext14"/> |
301 | <attributes> |
302 | - <attribute name="text">2</attribute> |
303 | + <attribute name="text">4</attribute> |
304 | </attributes> |
305 | </child> |
306 | </object> |
307 | @@ -818,31 +792,7 @@ |
308 | <child> |
309 | <object class="GtkCellRendererText" id="cellrenderertext18"/> |
310 | <attributes> |
311 | - <attribute name="text">7</attribute> |
312 | - </attributes> |
313 | - </child> |
314 | - </object> |
315 | - </child> |
316 | - <child> |
317 | - <object class="GtkTreeViewColumn" id="shares_to_me_node"> |
318 | - <property name="title">Node</property> |
319 | - <property name="expand">True</property> |
320 | - <child> |
321 | - <object class="GtkCellRendererText" id="cellrenderertext16"/> |
322 | - <attributes> |
323 | - <attribute name="text">4</attribute> |
324 | - </attributes> |
325 | - </child> |
326 | - </object> |
327 | - </child> |
328 | - <child> |
329 | - <object class="GtkTreeViewColumn" id="shares_to_me_volume"> |
330 | - <property name="title">Volume</property> |
331 | - <property name="expand">True</property> |
332 | - <child> |
333 | - <object class="GtkCellRendererText" id="cellrenderertext17"/> |
334 | - <attributes> |
335 | - <attribute name="text">8</attribute> |
336 | + <attribute name="text">5</attribute> |
337 | </attributes> |
338 | </child> |
339 | </object> |
340 | @@ -923,7 +873,7 @@ |
341 | <child> |
342 | <object class="GtkCellRendererText" id="cellrenderertext20"/> |
343 | <attributes> |
344 | - <attribute name="text">3</attribute> |
345 | + <attribute name="text">0</attribute> |
346 | </attributes> |
347 | </child> |
348 | </object> |
349 | @@ -935,7 +885,7 @@ |
350 | <child> |
351 | <object class="GtkCellRendererText" id="cellrenderertext21"/> |
352 | <attributes> |
353 | - <attribute name="text">6</attribute> |
354 | + <attribute name="text">1</attribute> |
355 | </attributes> |
356 | </child> |
357 | </object> |
358 | @@ -947,7 +897,7 @@ |
359 | <child> |
360 | <object class="GtkCellRendererToggle" id="cellrenderertoggle3"/> |
361 | <attributes> |
362 | - <attribute name="active">0</attribute> |
363 | + <attribute name="active">2</attribute> |
364 | </attributes> |
365 | </child> |
366 | </object> |
367 | @@ -959,7 +909,7 @@ |
368 | <child> |
369 | <object class="GtkCellRendererText" id="cellrenderertext22"/> |
370 | <attributes> |
371 | - <attribute name="text">1</attribute> |
372 | + <attribute name="text">3</attribute> |
373 | </attributes> |
374 | </child> |
375 | </object> |
376 | @@ -971,7 +921,7 @@ |
377 | <child> |
378 | <object class="GtkCellRendererText" id="cellrenderertext23"/> |
379 | <attributes> |
380 | - <attribute name="text">2</attribute> |
381 | + <attribute name="text">4</attribute> |
382 | </attributes> |
383 | </child> |
384 | </object> |
385 | @@ -983,31 +933,7 @@ |
386 | <child> |
387 | <object class="GtkCellRendererText" id="cellrenderertext24"/> |
388 | <attributes> |
389 | - <attribute name="text">7</attribute> |
390 | - </attributes> |
391 | - </child> |
392 | - </object> |
393 | - </child> |
394 | - <child> |
395 | - <object class="GtkTreeViewColumn" id="shares_to_others_node"> |
396 | - <property name="title">Node</property> |
397 | - <property name="expand">True</property> |
398 | - <child> |
399 | - <object class="GtkCellRendererText" id="cellrenderertext25"/> |
400 | - <attributes> |
401 | - <attribute name="text">4</attribute> |
402 | - </attributes> |
403 | - </child> |
404 | - </object> |
405 | - </child> |
406 | - <child> |
407 | - <object class="GtkTreeViewColumn" id="shares_to_others_volume"> |
408 | - <property name="title">Volume</property> |
409 | - <property name="expand">True</property> |
410 | - <child> |
411 | - <object class="GtkCellRendererText" id="cellrenderertext26"/> |
412 | - <attributes> |
413 | - <attribute name="text">8</attribute> |
414 | + <attribute name="text">5</attribute> |
415 | </attributes> |
416 | </child> |
417 | </object> |
418 | @@ -1058,6 +984,7 @@ |
419 | <property name="has_separator">False</property> |
420 | <property name="create_folders">False</property> |
421 | <signal name="file_activated" handler="on_file_chooser_open_clicked"/> |
422 | + <signal name="show" handler="on_file_chooser_show"/> |
423 | <child internal-child="vbox"> |
424 | <object class="GtkVBox" id="dialog-vbox7"> |
425 | <property name="visible">True</property> |
426 | |
427 | === modified file 'debian/changelog' |
428 | --- debian/changelog 2010-07-09 18:28:07 +0000 |
429 | +++ debian/changelog 2010-07-30 20:32:43 +0000 |
430 | @@ -1,3 +1,9 @@ |
431 | +magicicada (0.1.3-0ubuntu1) maverick; urgency=low |
432 | + |
433 | + * New upstream release. |
434 | + |
435 | + -- Facundo Batista <facundo@ubuntu.com> Thu, 29 Jul 2010 09:47:11 -0300 |
436 | + |
437 | magicicada (0.1.2-0ubuntu1) maverick; urgency=low |
438 | |
439 | * New upstream release. |
440 | |
441 | === modified file 'magicicada/__init__.py' |
442 | --- magicicada/__init__.py 2010-07-09 18:14:53 +0000 |
443 | +++ magicicada/__init__.py 2010-07-30 20:32:43 +0000 |
444 | @@ -49,9 +49,12 @@ |
445 | # set up the logging for all the project |
446 | logger_helper.set_up() |
447 | logger = logging.getLogger('magicicada.ui') |
448 | -console = logging.StreamHandler() |
449 | -console.setLevel(logging.DEBUG) |
450 | -#logger.addHandler(console) |
451 | + |
452 | +DEBUG = os.getenv('DEBUG') |
453 | +if DEBUG: |
454 | + console = logging.StreamHandler() |
455 | + console.setLevel(logging.DEBUG) |
456 | + logger.addHandler(console) |
457 | |
458 | |
459 | class MagicicadaUI(object): |
460 | @@ -63,6 +66,8 @@ |
461 | 'initial': _('Service is not started, click Start to continue.'), |
462 | } |
463 | |
464 | + _u1_root = UBUNTU_ONE_ROOT |
465 | + |
466 | def __init__(self, on_destroy=NO_OP, |
467 | syncdaemon_class=syncdaemon.SyncDaemon): |
468 | """Init.""" |
469 | @@ -87,11 +92,12 @@ |
470 | widgets = ( |
471 | 'start', 'stop', 'connect', 'disconnect', # toolbar buttons |
472 | 'folders', 'folders_dialog', # folders |
473 | - 'folders_store', 'folders_close', |
474 | + 'folders_view', 'folders_store', 'folders_close', |
475 | 'shares_to_me', 'shares_to_me_dialog', # shares_to_me |
476 | - 'shares_to_me_store', 'shares_to_me_close', |
477 | + 'shares_to_me_view', 'shares_to_me_store', 'shares_to_me_close', |
478 | 'shares_to_others', 'shares_to_others_dialog', # shares_to_others |
479 | - 'shares_to_others_store', 'shares_to_others_close', |
480 | + 'shares_to_others_view', 'shares_to_others_store', |
481 | + 'shares_to_others_close', |
482 | 'raw_metadata', # raw metadata |
483 | 'is_started', 'is_connected', 'is_online', # status bar images |
484 | 'status_label', 'status_icon', # status label and systray icon |
485 | @@ -106,6 +112,11 @@ |
486 | setattr(self, widget, obj) |
487 | assert obj is not None, '%s must not be None' % widget |
488 | |
489 | + self._sorting_order = {} |
490 | + self._make_view_sortable('folders') |
491 | + self._make_view_sortable('shares_to_me') |
492 | + self._make_view_sortable('shares_to_others') |
493 | + |
494 | self.raw_metadata_dialog = self._new_metadata_dialog() |
495 | self.volumes = (self.folders, self.shares_to_me, self.shares_to_others) |
496 | self.windows = (self.main_window, self.about_dialog, |
497 | @@ -135,10 +146,19 @@ |
498 | self.widget_is_visible = lambda w: w.get_property('visible') |
499 | self.widget_enabled = lambda w: self.widget_is_visible(w) and \ |
500 | w.is_sensitive() |
501 | - self.file_chooser.set_current_folder(UBUNTU_ONE_ROOT) |
502 | self.last_metadata_path = None |
503 | self.update() |
504 | |
505 | + def _make_view_sortable(self, view_name): |
506 | + """Set up view so columns are sortable.""" |
507 | + store = getattr(self, '%s_store' % view_name) |
508 | + view = getattr(self, '%s_view' % view_name) |
509 | + self._sorting_order[store] = {} |
510 | + for i, col in enumerate(view.get_columns()): |
511 | + col.set_clickable(True) |
512 | + col.connect('clicked', self.on_store_sort_column_changed, i, store) |
513 | + self._sorting_order[store][i] = gtk.SORT_ASCENDING |
514 | + |
515 | def _new_metadata_dialog(self): |
516 | """Return a new metadata dialog.""" |
517 | dialog = gtk.Dialog(title='Raw metadata', parent=self.main_window, |
518 | @@ -165,7 +185,7 @@ |
519 | dialog.get_child().add(text_view) |
520 | setattr(self, 'raw_metadata_view', text_view) |
521 | |
522 | - dialog.hide() # XXX to be fixed later |
523 | + dialog.hide() # XXX to be fixed later |
524 | return dialog |
525 | |
526 | # GTK callbacks |
527 | @@ -227,8 +247,8 @@ |
528 | |
529 | self.folders_store.clear() |
530 | for item in items: |
531 | - row = (item.node, item.path, item.suggested_path, |
532 | - item.subscribed, item.volume) |
533 | + row = (item.path, item.suggested_path, item.subscribed, |
534 | + item.node, item.volume) |
535 | self.folders_store.append(row) |
536 | |
537 | self.folders_dialog.run() |
538 | @@ -247,11 +267,13 @@ |
539 | store.clear() |
540 | for item in items: |
541 | free_bytes = item.free_bytes |
542 | - if isinstance(free_bytes, int): |
543 | - free_bytes = humanize_bytes(free_bytes, precision=2) |
544 | - row = (item.accepted, item.access_level, free_bytes, item.name, |
545 | - item.node_id, item.other_username, item.other_visible_name, |
546 | - item.path, item.volume_id) |
547 | + try: |
548 | + free_bytes = humanize_bytes(int(free_bytes), precision=2) |
549 | + except (ValueError, TypeError): |
550 | + logger.exception('Error while humanizing bytes') |
551 | + row = (item.name, item.other_visible_name, item.accepted, |
552 | + item.access_level, free_bytes, item.path, |
553 | + item.other_username, item.node_id, item.volume_id) |
554 | store.append(row) |
555 | |
556 | dialog.run() |
557 | @@ -277,6 +299,11 @@ |
558 | """Close the file_chooser dialog.""" |
559 | self.file_chooser.response(gtk.FILE_CHOOSER_ACTION_OPEN) |
560 | |
561 | + def on_file_chooser_show(self, widget, data=None): |
562 | + """Close the file_chooser dialog.""" |
563 | + if self.last_metadata_path is None: |
564 | + self.file_chooser.set_current_folder(self._u1_root) |
565 | + |
566 | def on_raw_metadata_close_clicked(self, widget, data=None): |
567 | """Close the raw_metadata dialog.""" |
568 | self.raw_metadata_dialog.hide() |
569 | @@ -302,6 +329,27 @@ |
570 | else: |
571 | self.main_window.show() |
572 | |
573 | + def on_store_sort_column_changed(self, column, col_index, store): |
574 | + """Store sort requested.""" |
575 | + order = self._sorting_order[store][col_index] |
576 | + last_col = self._sorting_order[store].get('last_col') |
577 | + if last_col is not None: |
578 | + last_col.set_sort_indicator(False) |
579 | + logger.debug('Sorting col index %s, named %s, with order %s', |
580 | + col_index, column.get_name(), order) |
581 | + |
582 | + store.set_sort_column_id(col_index, order) |
583 | + column.set_sort_indicator(True) |
584 | + column.set_sort_order(order) |
585 | + self._sorting_order[store]['last_col'] = column |
586 | + |
587 | + # change order |
588 | + if order == gtk.SORT_ASCENDING: |
589 | + order = gtk.SORT_DESCENDING |
590 | + else: |
591 | + order = gtk.SORT_ASCENDING |
592 | + self._sorting_order[store][col_index] = order |
593 | + |
594 | # SyncDaemon callbacks |
595 | |
596 | def on_started(self, *args, **kwargs): |
597 | |
598 | === modified file 'magicicada/syncdaemon.py' |
599 | --- magicicada/syncdaemon.py 2010-07-09 18:14:53 +0000 |
600 | +++ magicicada/syncdaemon.py 2010-07-30 20:32:43 +0000 |
601 | @@ -107,6 +107,7 @@ |
602 | self.on_shares_to_me_changed_callback = NO_OP |
603 | self.on_shares_to_others_changed_callback = NO_OP |
604 | self.on_metadata_ready_callback = None # mandatory |
605 | + self.on_initial_data_ready_callback = NO_OP |
606 | |
607 | # mq needs to be polled to know progress |
608 | self._mqcaller = None |
609 | @@ -147,6 +148,10 @@ |
610 | self.shares_to_me = yield self.dbus.get_shares_to_me() |
611 | self.shares_to_others = yield self.dbus.get_shares_to_others() |
612 | |
613 | + # let frontend know that we have all the initial data |
614 | + logger.info("All initial data is ready") |
615 | + self.on_initial_data_ready_callback() |
616 | + |
617 | @defer.inlineCallbacks |
618 | def on_sd_shares_changed(self): |
619 | """Shares changed, ask for new information.""" |
620 | |
621 | === modified file 'magicicada/tests/test_magicicada.py' |
622 | --- magicicada/tests/test_magicicada.py 2010-07-09 18:14:53 +0000 |
623 | +++ magicicada/tests/test_magicicada.py 2010-07-30 20:32:43 +0000 |
624 | @@ -19,6 +19,7 @@ |
625 | """Tests for magicicada.""" |
626 | |
627 | import logging |
628 | +import os |
629 | import sys |
630 | |
631 | from functools import wraps |
632 | @@ -111,12 +112,37 @@ |
633 | self.called = False |
634 | self.response = None |
635 | self.set_called = lambda *args, **kwargs: setattr(self, 'called', True) |
636 | + self._failed_test = False |
637 | |
638 | def tearDown(self): |
639 | """Cleanup.""" |
640 | self.ui.on_main_window_destroy(self.ui.main_window) |
641 | self.called = False |
642 | |
643 | + if self._failed_test: |
644 | + # no, I'm not raising a bool. pylint: disable-msg=E0702 |
645 | + raise self._failed_test |
646 | + |
647 | + def __getattribute__(self, name): |
648 | + """Overwrite the assert methods with safer ones. |
649 | + |
650 | + This way if a test called by gobject in the future fails, it |
651 | + makes the whole test suite fail. |
652 | + """ |
653 | + if name.startswith('assert') and hasattr(TestCase, name): |
654 | + |
655 | + def proxy(*args, **kwargs): |
656 | + """Function that will call the real assert.""" |
657 | + real_assert = getattr(TestCase, name) |
658 | + try: |
659 | + real_assert(self, *args, **kwargs) |
660 | + except Exception, e: |
661 | + self._failed_test = e |
662 | + raise |
663 | + return proxy |
664 | + else: |
665 | + return TestCase.__getattribute__(self, name) |
666 | + |
667 | def do_start(self): |
668 | """Simulate that start fully happened.""" |
669 | self.ui.on_start_clicked(self.ui.start) |
670 | @@ -137,7 +163,7 @@ |
671 | result.append(data_type(**kwargs)) |
672 | return result |
673 | |
674 | - def assert_store_correct(self, store, items, markup=None): |
675 | + def assert_store_correct(self, store, items, mapping, markup=None): |
676 | """Test that 'store' has 'items' as content.""" |
677 | msg = 'amount of rows for %s must be %s (got %s).' |
678 | self.assertEqual(len(store), len(items), |
679 | @@ -150,7 +176,7 @@ |
680 | msg = "column %i ('%s') must be '%s' (got '%s' instead)" |
681 | while tree_iter is not None: |
682 | head = tmp.pop() |
683 | - for i, field in enumerate(head._fields): |
684 | + for i, field in mapping: |
685 | actual, = store.get(tree_iter, i) |
686 | expected = getattr(head, field) |
687 | if store.get_column_type(i).name == 'gboolean': |
688 | @@ -426,7 +452,8 @@ |
689 | |
690 | def assert_store_correct(self, store, items): |
691 | """Test that 'store' has 'items' as content.""" |
692 | - args = (store, items, self.expected_markup) |
693 | + mapping = enumerate(['operation', 'path', 'share', 'node']) |
694 | + args = (store, items, mapping, self.expected_markup) |
695 | super(_MagicicadaUIQueueTestCase, self).assert_store_correct(*args) |
696 | |
697 | @skip_abstract_class |
698 | @@ -826,6 +853,7 @@ |
699 | |
700 | name = None |
701 | data_type = None |
702 | + mapping = [] |
703 | |
704 | def setUp(self): |
705 | """Init.""" |
706 | @@ -834,6 +862,7 @@ |
707 | return |
708 | self.volume = getattr(self.ui, self.name) |
709 | self.volume_store = getattr(self.ui, '%s_store' % self.name) |
710 | + self.volume_view = getattr(self.ui, '%s_view' % self.name) |
711 | self.volume_dialog_name = '%s_dialog' % self.name |
712 | self.volume_dialog = getattr(self.ui, self.volume_dialog_name) |
713 | self.on_volume_clicked = getattr(self.ui, 'on_%s_clicked' % self.name) |
714 | @@ -845,11 +874,48 @@ |
715 | r = super(_MagicicadaUIVolumeTestCase, self).build_some_data(**kwargs) |
716 | return r |
717 | |
718 | + def assert_store_correct(self, store, items): |
719 | + """Test that 'store' has 'items' as content.""" |
720 | + args = (store, items, self.mapping) |
721 | + super(_MagicicadaUIVolumeTestCase, self).assert_store_correct(*args) |
722 | + |
723 | def assert_widget_availability(self, enabled=True): |
724 | """Check volume availability according to 'enabled'.""" |
725 | s = super(_MagicicadaUIVolumeTestCase, self) |
726 | s.assert_widget_availability(self.name, enabled) |
727 | |
728 | + def assert_sort_order_correct(self, column, i, expected_order): |
729 | + """Check that sort order is correctly set.""" |
730 | + msg0 = 'Store sort id must be %r (got %r instead).' |
731 | + msg1 = 'Store sort order must be %r (got %r instead).' |
732 | + msg3 = 'Column sort order must be %r (got %r instead).' |
733 | + |
734 | + actual_id, actual_order = self.volume_store.get_sort_column_id() |
735 | + |
736 | + # store sort column id and order |
737 | + self.assertEqual(i, actual_id, msg0 % (i, actual_id)) |
738 | + self.assertEqual(expected_order, actual_order, |
739 | + msg1 % (expected_order, actual_order)) |
740 | + |
741 | + # column sort order |
742 | + actual_order = column.get_sort_order() |
743 | + self.assertEqual(expected_order, actual_order, |
744 | + msg3 % (expected_order, actual_order)) |
745 | + |
746 | + def assert_sort_indicator_correct(self, column): |
747 | + """Check that sort indicator is correctly set.""" |
748 | + msg = 'Column %s must have sort indicator %s.' |
749 | + colname = column.get_name() |
750 | + # column sort indicator |
751 | + self.assertTrue(column.get_sort_indicator(), msg % (colname, 'on')) |
752 | + |
753 | + # all the other columns must not have the sort indicator on |
754 | + for other_column in self.volume_view.get_columns(): |
755 | + if other_column.get_name() == colname: |
756 | + continue |
757 | + self.assertFalse(other_column.get_sort_indicator(), |
758 | + msg % (other_column.get_name(), 'off')) |
759 | + |
760 | @skip_abstract_class |
761 | def test_volume_are_disabled_until_started(self): |
762 | """Folders and shares are disabled until online.""" |
763 | @@ -955,33 +1021,72 @@ |
764 | self.assert_dialog_properties(dialog_name=self.volume_dialog_name, |
765 | title=title) |
766 | |
767 | + @skip_abstract_class |
768 | + def test_volume_columns_not_sorted_at_start(self): |
769 | + """Test volume columns are not sorted at start.""" |
770 | + msg = 'Column %s must not have the sort indicator on.' |
771 | + for col in self.volume_view.get_columns(): |
772 | + self.assertFalse(col.get_sort_indicator(), msg % col.get_name()) |
773 | + |
774 | + @skip_abstract_class |
775 | + def test_volume_columns_are_clickable(self): |
776 | + """Test volume columns are clickable.""" |
777 | + msg = 'Column %s must be clickable.' |
778 | + for col in self.volume_view.get_columns(): |
779 | + self.assertTrue(col.get_clickable(), msg % col.get_name()) |
780 | + |
781 | + @skip_abstract_class |
782 | + def test_volume_columns_clicked_signal(self): |
783 | + """Test volume columns clicks signal is properly connected.""" |
784 | + msg = 'Column %s must be connected to on_store_sort_column_changed.' |
785 | + for col in self.volume_view.get_columns(): |
786 | + self.assertTrue(col.get_clickable(), msg % col.get_name()) |
787 | + |
788 | + @skip_abstract_class |
789 | + def test_volume_sorting(self): |
790 | + """Test volume panel can be re-sorted.""" |
791 | + for i, col in enumerate(self.volume_view.get_columns()): |
792 | + col.clicked() # click on the column |
793 | + self.assert_sort_order_correct(col, i, gtk.SORT_ASCENDING) |
794 | + self.assert_sort_indicator_correct(col) |
795 | + |
796 | + col.clicked() # click on the column, sort order must change |
797 | + self.assert_sort_order_correct(col, i, gtk.SORT_DESCENDING) |
798 | + |
799 | + col.clicked() # click again, sort order must be the first one |
800 | + self.assert_sort_order_correct(col, i, gtk.SORT_ASCENDING) |
801 | + |
802 | |
803 | class MagicicadaUIFoldersTestCase(_MagicicadaUIVolumeTestCase): |
804 | """UI test cases for folders.""" |
805 | |
806 | name = 'folders' |
807 | - data_type = FolderData # node path suggested_path subscribed volume |
808 | + data_type = FolderData |
809 | + mapping = enumerate(['path', 'suggested_path', 'subscribed', |
810 | + 'node', 'volume']) |
811 | |
812 | |
813 | class _MagicicadaUISharesTestCase(_MagicicadaUIVolumeTestCase): |
814 | """UI test cases for shares_to_me.""" |
815 | |
816 | - data_type = ShareData # accepted access_level free_bytes name node_id |
817 | - # other_username other_visible_name path volume_id |
818 | + data_type = ShareData |
819 | + mapping = enumerate(['name', 'other_visible_name', 'accepted', |
820 | + 'access_level', 'free_bytes', 'path', |
821 | + 'other_username', 'node_id', 'volume_id']) |
822 | |
823 | - @skip_abstract_class |
824 | - def test_bytes_are_humanized(self): |
825 | + def assert_correct_free_bytes(self, free_bytes): |
826 | """Free bytes are shown humanized.""" |
827 | attrs = self.data_type._fields |
828 | kwargs = dict([(attr, str(attr)) for attr in attrs]) |
829 | - kwargs['free_bytes'] = 10000 |
830 | + kwargs['free_bytes'] = free_bytes |
831 | item = self.data_type(**kwargs) |
832 | setattr(self.ui.sd, self.name, [item]) |
833 | |
834 | def test(): |
835 | """Perform the test per se before closing the dialog.""" |
836 | - kwargs['free_bytes'] = humanize_bytes(kwargs['free_bytes'], |
837 | - precision=2) |
838 | + if kwargs['free_bytes'] is not None: |
839 | + i = int(kwargs['free_bytes']) |
840 | + kwargs['free_bytes'] = humanize_bytes(i, precision=2) |
841 | item = self.data_type(**kwargs) |
842 | self.assert_store_correct(self.volume_store, [item]) |
843 | |
844 | @@ -989,6 +1094,21 @@ |
845 | (self.volume_dialog, test)) |
846 | self.on_volume_clicked(self.volume) |
847 | |
848 | + @skip_abstract_class |
849 | + def test_bytes_are_humanized(self): |
850 | + """Free bytes are shown humanized.""" |
851 | + self.assert_correct_free_bytes(free_bytes=10000) |
852 | + |
853 | + @skip_abstract_class |
854 | + def test_bytes_are_humanized_even_when_string(self): |
855 | + """Free bytes are shown humanized even if they are string.""" |
856 | + self.assert_correct_free_bytes(free_bytes='10000') |
857 | + |
858 | + @skip_abstract_class |
859 | + def test_bytes_are_humanized_even_when_none(self): |
860 | + """Free bytes are shown humanized even if they are None.""" |
861 | + self.assert_correct_free_bytes(free_bytes=None) |
862 | + |
863 | |
864 | class MagicicadaUISharesToMeTestCase(_MagicicadaUISharesTestCase): |
865 | """UI test cases for shares_to_me.""" |
866 | @@ -1085,6 +1205,8 @@ |
867 | |
868 | def test_on_raw_metadata_clicked(self): |
869 | """Test on_raw_metadata_clicked.""" |
870 | + self.ui._u1_root = os.path.dirname(self.path) |
871 | + |
872 | self.assertFalse(self.ui.widget_is_visible( |
873 | self.ui.raw_metadata_dialog), |
874 | 'raw_metadata_dialog should not be visible.') |
875 | @@ -1127,6 +1249,19 @@ |
876 | self.ui.raw_metadata_dialog), |
877 | 'raw_metadata_dialog should not be visible.') |
878 | |
879 | + def test_file_chooser_folder_is_u1root_when_visible(self): |
880 | + """File chooser folder is ~/Ubuntu One only when visible.""" |
881 | + self.assertNotEqual(self.ui.file_chooser.get_current_folder(), |
882 | + UBUNTU_ONE_ROOT, |
883 | + "shouldn't have U1 folder before becoming visible") |
884 | + |
885 | + gobject.timeout_add(100, self.ui.file_chooser_open.clicked) |
886 | + self.ui.on_raw_metadata_clicked(self.ui.raw_metadata) |
887 | + |
888 | + self.assertEqual(self.ui.file_chooser.get_current_folder(), |
889 | + UBUNTU_ONE_ROOT, |
890 | + 'should have U1 folder after becoming visible') |
891 | + |
892 | def test_raw_metadata_dialog_properties(self): |
893 | """The raw_metadata dialog has correct properties.""" |
894 | title = self.name.replace('_', ' ').capitalize() |
895 | @@ -1148,14 +1283,6 @@ |
896 | self.assertFalse(self.ui.widget_is_visible(self.ui.file_chooser), |
897 | 'file_chooser must be hidden by default.') |
898 | |
899 | - def test_file_chooser_current_folder_is_ubuntu_one_root(self): |
900 | - """File chooser default folder is ~/Ubuntu One.""" |
901 | - process_gtk_pendings() # WOW! Needed to get proper value below |
902 | - actual = self.ui.file_chooser.get_current_folder() |
903 | - msg = 'file_chooser default folder must be %s (got %s instead).' |
904 | - self.assertEqual(actual, UBUNTU_ONE_ROOT, |
905 | - msg % (UBUNTU_ONE_ROOT, actual)) |
906 | - |
907 | def test_filename_is_used_only_if_open_clicked(self): |
908 | """Filename is used only if user clicked open.""" |
909 | self.patch(self.ui.sd, 'get_metadata', self.set_called) |
910 | @@ -1170,6 +1297,7 @@ |
911 | """Filename is stored as 'last_metadata_path' if user clicked open.""" |
912 | self.assertTrue(self.ui.last_metadata_path is None, |
913 | 'last_metadata_path must be None.') |
914 | + self.ui._u1_root = os.path.dirname(self.path) |
915 | self.ui.file_chooser.set_filename(self.path) |
916 | gobject.timeout_add(100, test_and_click, |
917 | (self.ui.file_chooser_open, NO_OP)) |
918 | |
919 | === modified file 'magicicada/tests/test_syncdaemon.py' |
920 | --- magicicada/tests/test_syncdaemon.py 2010-07-09 18:14:53 +0000 |
921 | +++ magicicada/tests/test_syncdaemon.py 2010-07-30 20:32:43 +0000 |
922 | @@ -700,6 +700,13 @@ |
923 | False, 'queues', 'connection') |
924 | self.assertTrue(self.called) |
925 | |
926 | + @defer.inlineCallbacks |
927 | + def test_on_initial_data_ready(self): |
928 | + """Called when SD gets all the initial data.""" |
929 | + self.flag_called(self.sd, 'on_initial_data_ready_callback') |
930 | + yield self.sd._get_initial_data() |
931 | + self.assertTrue(self.called) |
932 | + |
933 | |
934 | class TestLogs(unittest.TestCase): |
935 | """Test logging.""" |
936 | @@ -730,6 +737,7 @@ |
937 | """Log the initial filling.""" |
938 | yield self.sd._get_initial_data() |
939 | self.assertTrue(self.hdlr.check_info("Getting initial data")) |
940 | + self.assertTrue(self.hdlr.check_info("All initial data is ready")) |
941 | |
942 | def test_start(self): |
943 | """Log the call to start.""" |
944 | |
945 | === modified file 'setup.py' |
946 | --- setup.py 2010-07-09 18:14:53 +0000 |
947 | +++ setup.py 2010-07-30 20:32:43 +0000 |
948 | @@ -86,7 +86,7 @@ |
949 | |
950 | DistUtilsExtra.auto.setup( |
951 | name='magicicada', |
952 | - version='0.1.2', |
953 | + version='0.1.3', |
954 | license='GPL-3', |
955 | author='Natalia Bidart', |
956 | author_email='natalia.bidart@ubuntu.com', |
On Fri, 30 Jul 2010 20:32:43 -0000, Facundo Batista <email address hidden> wrote: 0.1.2.orig. tar.gz --version=0.1.2
> + * bzr get lp:ubuntu/magicicada
> + * cd magicicada
> + * uscan --verbose --rename (this gets the new upstream release from launchpad)
> + * bzr merge-package ../magicicada_
You mean merge-upstream I think?
Also, you can pass a URL and it will do the download and rename for you.
I will be adding uscan support so that those two steps are just
bzr merge-upstream
at some point.
Thanks,
James