From: <nc...@us...> - 2010-11-07 10:54:18
|
Revision: 679 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=679&view=rev Author: ncjones Date: 2010-11-07 10:54:11 +0000 (Sun, 07 Nov 2010) Log Message: ----------- Add prior usage to equipment and include it in total usage calculation. Modified Paths: -------------- pytrainer/trunk/glade/equipment.glade pytrainer/trunk/pytrainer/equipment.py pytrainer/trunk/pytrainer/gui/equipment.py pytrainer/trunk/test/pytrainer/equipment_test.py pytrainer/trunk/test/pytrainer/gui/equipment_test.py Modified: pytrainer/trunk/glade/equipment.glade =================================================================== --- pytrainer/trunk/glade/equipment.glade 2010-11-06 09:49:44 UTC (rev 678) +++ pytrainer/trunk/glade/equipment.glade 2010-11-07 10:54:11 UTC (rev 679) @@ -1,6 +1,6 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="UTF-8"?> <interface> - <!-- interface-requires gtk 2.6 --> + <!-- interface-requires gtk+ 2.6 --> <!-- interface-naming-policy project-wide --> <object class="GtkNotebook" id="notebookEquipment"> <property name="visible">True</property> @@ -134,7 +134,7 @@ <child> <object class="GtkTable" id="tableEquipmentAddDetails"> <property name="visible">True</property> - <property name="n_rows">4</property> + <property name="n_rows">5</property> <property name="n_columns">2</property> <property name="row_spacing">5</property> <child> @@ -172,7 +172,6 @@ <packing> <property name="top_attach">1</property> <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> @@ -199,6 +198,43 @@ </packing> </child> <child> + <object class="GtkLabel" id="labelEquipmentAddPriorUsage"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="yalign">0</property> + <property name="xpad">5</property> + <property name="ypad">5</property> + <property name="label" translatable="yes">Prior Usage</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkAlignment" id="alignment2"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xscale">0</property> + <child> + <object class="GtkEntry" id="entryEquipmentAddPriorUsage"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">•</property> + <property name="width_chars">8</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + <child> <object class="GtkCheckButton" id="checkbuttonEquipmentAddActive"> <property name="label" translatable="yes">Active</property> <property name="visible">True</property> @@ -209,8 +245,8 @@ <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> <property name="y_options"></property> </packing> </child> @@ -222,8 +258,8 @@ </child> </object> <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> <property name="y_options"></property> </packing> </child> @@ -237,8 +273,8 @@ <property name="label" translatable="yes">Notes</property> </object> <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> <property name="y_options">GTK_FILL</property> </packing> </child> @@ -258,8 +294,8 @@ <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> </packing> </child> </object> @@ -355,7 +391,7 @@ <child> <object class="GtkTable" id="tableEquipmentEditDetails"> <property name="visible">True</property> - <property name="n_rows">4</property> + <property name="n_rows">5</property> <property name="n_columns">2</property> <property name="row_spacing">5</property> <child> @@ -420,6 +456,41 @@ </packing> </child> <child> + <object class="GtkLabel" id="labelEquipmentEditPriorUsage"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="xpad">5</property> + <property name="label" translatable="yes">Prior Usage</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkAlignment" id="alignment4"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xscale">0</property> + <child> + <object class="GtkEntry" id="entryEquipmentEditPriorUsage"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">•</property> + <property name="width_chars">8</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + <child> <object class="GtkCheckButton" id="checkbuttonEquipmentEditActive"> <property name="label" translatable="yes">Active</property> <property name="visible">True</property> @@ -430,8 +501,8 @@ <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> <property name="y_options"></property> </packing> </child> @@ -443,8 +514,8 @@ </child> </object> <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> <property name="y_options"></property> </packing> </child> @@ -458,8 +529,8 @@ <property name="label" translatable="yes">Notes</property> </object> <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> <property name="y_options">GTK_FILL</property> </packing> </child> @@ -479,8 +550,8 @@ <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> </packing> </child> </object> Modified: pytrainer/trunk/pytrainer/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/equipment.py 2010-11-06 09:49:44 UTC (rev 678) +++ pytrainer/trunk/pytrainer/equipment.py 2010-11-07 10:54:11 UTC (rev 679) @@ -27,6 +27,7 @@ self.description = u"" self.active = True self.life_expectancy = 0 + self.prior_usage = 0 self.notes = u"" def _get_id(self): @@ -64,7 +65,15 @@ self._life_expectancy = int(life_expectancy) life_expectancy = property(_get_life_expectancy, _set_life_expectancy) + + def _get_prior_usage(self): + return self._prior_usage + def _set_prior_usage(self, prior_usage): + self._prior_usage = int(prior_usage) + + prior_usage = property(_get_prior_usage, _set_prior_usage) + def _get_notes(self): return self._notes @@ -89,7 +98,7 @@ _TABLE_NAME = "equipment" -_UPDATE_COLUMNS = "description,active,life_expectancy,notes" +_UPDATE_COLUMNS = "description,active,life_expectancy,prior_usage,notes" _ALL_COLUMNS = "id," + _UPDATE_COLUMNS @@ -97,6 +106,7 @@ return [equipment.description, 1 if equipment.active else 0, equipment.life_expectancy, + equipment.prior_usage, equipment.notes] class EquipmentServiceException(Exception): @@ -143,11 +153,12 @@ def _create_equipment_item(self, row): equipment = Equipment() - (id, description, active, life_expectancy, notes) = row + (id, description, active, life_expectancy, prior_usage, notes) = row equipment.id = id equipment.description = description equipment.active = bool(active) equipment.life_expectancy = life_expectancy + equipment.prior_usage = prior_usage equipment.notes = notes return equipment Modified: pytrainer/trunk/pytrainer/gui/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/gui/equipment.py 2010-11-06 09:49:44 UTC (rev 678) +++ pytrainer/trunk/pytrainer/gui/equipment.py 2010-11-07 10:54:11 UTC (rev 679) @@ -31,7 +31,7 @@ self.append(self._create_tuple(equipment)) def _create_tuple(self, equipment): - usage = self._equipment_service.get_equipment_usage(equipment) + usage = self._equipment_service.get_equipment_usage(equipment) + equipment.prior_usage return (equipment.id, equipment.description, self._calculate_usage_percent(usage, equipment.life_expectancy), @@ -113,6 +113,7 @@ def clear_add_equipment_fields(self): self._builder.get_object("entryEquipmentAddDescription").set_text("") self._builder.get_object("entryEquipmentAddLifeExpectancy").set_text("0") + self._builder.get_object("entryEquipmentAddPriorUsage").set_text("0") self._builder.get_object("checkbuttonEquipmentAddActive").set_active(True) self._builder.get_object("textviewEquipmentAddNotes").get_buffer().set_text("") @@ -140,6 +141,7 @@ #FIXME input validation for numeric fields description = self._builder.get_object("entryEquipmentAddDescription").get_text() life_expectancy = self._builder.get_object("entryEquipmentAddLifeExpectancy").get_text() + prior_usage = self._builder.get_object("entryEquipmentAddPriorUsage").get_text() active = self._builder.get_object("checkbuttonEquipmentAddActive").get_active() notes_buffer = self._builder.get_object("textviewEquipmentAddNotes").get_buffer() notes = notes_buffer.get_text(notes_buffer.get_start_iter(), notes_buffer.get_end_iter()) @@ -147,6 +149,7 @@ new_equipment.description = unicode(description) new_equipment.active = active new_equipment.life_expectancy = life_expectancy + new_equipment.prior_usage = prior_usage new_equipment.notes = unicode(notes) self._equipment_store.add_equipment(new_equipment) self.show_page_equipment_list() @@ -155,6 +158,7 @@ item = self._get_selected_equipment_item() self._builder.get_object("entryEquipmentEditDescription").set_text(item.description) self._builder.get_object("entryEquipmentEditLifeExpectancy").set_text(str(item.life_expectancy)) + self._builder.get_object("entryEquipmentEditPriorUsage").set_text(str(item.prior_usage)) self._builder.get_object("checkbuttonEquipmentEditActive").set_active(item.active) if item.notes != None: self._builder.get_object("textviewEquipmentEditNotes").get_buffer().set_text(item.notes) @@ -168,6 +172,7 @@ description_text = self._builder.get_object("entryEquipmentEditDescription").get_text() item.description = unicode(description_text) item.life_expectancy = self._builder.get_object("entryEquipmentEditLifeExpectancy").get_text() + item.prior_usage = self._builder.get_object("entryEquipmentEditPriorUsage").get_text() item.active = self._builder.get_object("checkbuttonEquipmentEditActive").get_active() notes_buffer = self._builder.get_object("textviewEquipmentEditNotes").get_buffer() notes_text = notes_buffer.get_text(notes_buffer.get_start_iter(), notes_buffer.get_end_iter()) Modified: pytrainer/trunk/test/pytrainer/equipment_test.py =================================================================== --- pytrainer/trunk/test/pytrainer/equipment_test.py 2010-11-06 09:49:44 UTC (rev 678) +++ pytrainer/trunk/test/pytrainer/equipment_test.py 2010-11-07 10:54:11 UTC (rev 679) @@ -120,7 +120,30 @@ pass else: self.fail("Should not be able to set life expectancy to non numeric value.") + + def test_prior_usage_defaults_to_zero(self): + equipment = Equipment() + self.assertEqual(0, equipment.prior_usage) + def test_prior_usage_set_to_integer(self): + equipment = Equipment() + equipment.prior_usage = 2 + self.assertEquals(2, equipment.prior_usage) + + def test_prior_usage_set_to_numeric_string(self): + equipment = Equipment() + equipment.prior_usage = "3" + self.assertEquals(3, equipment.prior_usage) + + def test_prior_usage_set_to_non_numeric_string(self): + equipment = Equipment() + try: + equipment.prior_usage = "test" + except(ValueError): + pass + else: + self.fail("Should not be able to set life expectancy to non numeric value.") + def test_notes_defaults_to_empty_string(self): equipment = Equipment() self.assertEquals(u"", equipment.notes) @@ -177,12 +200,13 @@ pass def test_get_equipment_item(self): - self.mock_ddbb.select.return_value = [(1, u"Test Description", True, 500, u"Test notes.")] + self.mock_ddbb.select.return_value = [(1, u"Test Description", True, 500, 200, u"Test notes.")] item = self.equipment_service.get_equipment_item(1) self.assertEquals(1, item.id) self.assertEquals("Test Description", item.description) self.assertTrue(item.active) self.assertEquals(500, item.life_expectancy) + self.assertEquals(200, item.prior_usage) self.assertEquals("Test notes.", item.notes) def test_get_equipment_item_non_existant(self): @@ -191,20 +215,22 @@ self.assertEquals(None, item) def test_get_all_equipment(self): - self.mock_ddbb.select.return_value = [(1, u"Test item 1", True, 500, u"Test notes 1."), - (2, u"Test item 2", False, 600, u"Test notes 2.")] + self.mock_ddbb.select.return_value = [(1, u"Test item 1", True, 500, 200, u"Test notes 1."), + (2, u"Test item 2", False, 600, 300, u"Test notes 2.")] items = self.equipment_service.get_all_equipment() item = items[0] self.assertEquals(1, item.id) self.assertEquals("Test item 1", item.description) self.assertTrue(item.active) self.assertEquals(500, item.life_expectancy) + self.assertEquals(200, item.prior_usage) self.assertEquals("Test notes 1.", item.notes) item = items[1] self.assertEquals(2, item.id) self.assertEquals("Test item 2", item.description) self.assertFalse(item.active) self.assertEquals(600, item.life_expectancy) + self.assertEquals(300, item.prior_usage) self.assertEquals("Test notes 2.", item.notes) def test_get_all_equipment_non_existant(self): @@ -213,20 +239,22 @@ self.assertEquals([], items) def test_get_active_equipment(self): - self.mock_ddbb.select.return_value = [(1, u"Test item 1", True, 500, u"Test notes 1."), - (2, u"Test item 2", True, 600, u"Test notes 2.")] + self.mock_ddbb.select.return_value = [(1, u"Test item 1", True, 500, 200, u"Test notes 1."), + (2, u"Test item 2", True, 600, 300, u"Test notes 2.")] items = self.equipment_service.get_active_equipment() item = items[0] self.assertEquals(1, item.id) self.assertEquals("Test item 1", item.description) self.assertTrue(item.active) self.assertEquals(500, item.life_expectancy) + self.assertEquals(200, item.prior_usage) self.assertEquals("Test notes 1.", item.notes) item = items[1] self.assertEquals(2, item.id) self.assertEquals("Test item 2", item.description) self.assertTrue(item.active) self.assertEquals(600, item.life_expectancy) + self.assertEquals(300, item.prior_usage) self.assertEquals("Test notes 2.", item.notes) def test_get_active_equipment_non_existant(self): @@ -234,6 +262,25 @@ items = self.equipment_service.get_active_equipment() self.assertEquals([], items) + def test_store_equipment(self): + equipment = Equipment() + equipment.description = u"test description" + equipment_ids = [] + def mock_select(table, columns, where): + if columns == "id": + return equipment_ids + else: + return [(2, u"", 1, 0, 0,u"")] + def update_equipment_ids(*args): + equipment_ids.append([1]) + self.mock_ddbb.select = mock.Mock(wraps=mock_select) + self.mock_ddbb.insert.side_effect = update_equipment_ids + stored_equipment = self.equipment_service.store_equipment(equipment) + self.mock_ddbb.insert.assert_called_with("equipment", + "description,active,life_expectancy,prior_usage,notes", + ["test description", 1, 0, 0,"" ]) + self.assertEquals(2, stored_equipment.id) + def test_store_equipment_duplicate_description(self): self.mock_ddbb.select.return_value = [(1,)] equipment = Equipment() @@ -244,6 +291,18 @@ except(EquipmentServiceException): pass + def test_update_equipment(self): + equipment = Equipment() + equipment.id = 1 + equipment.description = u"test description" + self.mock_ddbb.select.return_value = [(2, u"", 1, 0, 0,u"")] + stored_equipment = self.equipment_service.store_equipment(equipment) + self.mock_ddbb.update.assert_called_with("equipment", + "description,active,life_expectancy,prior_usage,notes", + ["test description", 1, 0, 0,"" ], + "id = 1") + self.assertEquals(2, stored_equipment.id) + def test_update_equipment_non_existant(self): self.mock_ddbb.select.return_value = [] equipment = Equipment() Modified: pytrainer/trunk/test/pytrainer/gui/equipment_test.py =================================================================== --- pytrainer/trunk/test/pytrainer/gui/equipment_test.py 2010-11-06 09:49:44 UTC (rev 678) +++ pytrainer/trunk/test/pytrainer/gui/equipment_test.py 2010-11-07 10:54:11 UTC (rev 679) @@ -56,6 +56,17 @@ iter = equipment_store.get_iter_first() self.assertEquals(50, equipment_store.get_value(iter, 2)) + def test_get_item_usage_percent_prior_usage(self): + equipment = Equipment() + equipment.id = 1 + equipment.life_expectancy = 200 + equipment.prior_usage = 50 + self.mock_equipment_service.get_all_equipment.return_value = [equipment] + self.mock_equipment_service.get_equipment_usage.return_value = 100 + equipment_store = EquipmentStore(self.mock_equipment_service) + iter = equipment_store.get_iter_first() + self.assertEquals(75, equipment_store.get_value(iter, 2)) + def test_get_item_usage_percent_zero_usage(self): equipment = Equipment() equipment.id = 1 @@ -86,6 +97,17 @@ iter = equipment_store.get_iter_first() self.assertEquals("101 / 200", equipment_store.get_value(iter, 3)) + def test_get_item_usage_text_prior_usage(self): + equipment = Equipment() + equipment.id = 1 + equipment.life_expectancy = 200 + equipment.prior_usage = 50 + self.mock_equipment_service.get_all_equipment.return_value = [equipment] + self.mock_equipment_service.get_equipment_usage.return_value = 100 + equipment_store = EquipmentStore(self.mock_equipment_service) + iter = equipment_store.get_iter_first() + self.assertEquals("150 / 200", equipment_store.get_value(iter, 3)) + def test_get_item_usage_text_zero_usage(self): equipment = Equipment() equipment.id = 1 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2010-11-09 10:03:17
|
Revision: 685 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=685&view=rev Author: ncjones Date: 2010-11-09 10:03:11 +0000 (Tue, 09 Nov 2010) Log Message: ----------- Handle equipment usage greater than 100%. Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/equipment.py pytrainer/trunk/test/pytrainer/gui/equipment_test.py Modified: pytrainer/trunk/pytrainer/gui/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/gui/equipment.py 2010-11-08 22:31:39 UTC (rev 684) +++ pytrainer/trunk/pytrainer/gui/equipment.py 2010-11-09 10:03:11 UTC (rev 685) @@ -42,7 +42,7 @@ if life_expectancy == 0: return 0 else: - return 100.0 * usage / life_expectancy + return min(100, 100.0 * usage / life_expectancy) def add_equipment(self, equipment): added_equipment = self._equipment_service.store_equipment(equipment) Modified: pytrainer/trunk/test/pytrainer/gui/equipment_test.py =================================================================== --- pytrainer/trunk/test/pytrainer/gui/equipment_test.py 2010-11-08 22:31:39 UTC (rev 684) +++ pytrainer/trunk/test/pytrainer/gui/equipment_test.py 2010-11-09 10:03:11 UTC (rev 685) @@ -77,6 +77,17 @@ iter = equipment_store.get_iter_first() self.assertEquals(0, equipment_store.get_value(iter, 2)) + def test_get_item_usage_percent_usage_exceeds_life_expectancy(self): + equipment = Equipment() + equipment.id = 1 + equipment.life_expectancy = 200 + self.mock_equipment_service.get_all_equipment.return_value = [equipment] + self.mock_equipment_service.get_equipment_usage.return_value = 300 + equipment_store = EquipmentStore(self.mock_equipment_service) + iter = equipment_store.get_iter_first() + self.assertEquals(100, equipment_store.get_value(iter, 2), "Progress bar cannot exceed 100%.") + + def test_get_item_usage_text(self): equipment = Equipment() equipment.id = 1 @@ -118,6 +129,16 @@ iter = equipment_store.get_iter_first() self.assertEquals("0 / 200", equipment_store.get_value(iter, 3)) + def test_get_item_usage_text_usage_exceeds_life_expectancy(self): + equipment = Equipment() + equipment.id = 1 + equipment.life_expectancy = 200 + self.mock_equipment_service.get_all_equipment.return_value = [equipment] + self.mock_equipment_service.get_equipment_usage.return_value = 300 + equipment_store = EquipmentStore(self.mock_equipment_service) + iter = equipment_store.get_iter_first() + self.assertEquals("300 / 200", equipment_store.get_value(iter, 3)) + def test_get_item_active(self): equipment = Equipment() equipment.id = 1 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-10 03:36:54
|
Revision: 688 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=688&view=rev Author: jblance Date: 2010-11-10 03:36:46 +0000 (Wed, 10 Nov 2010) Log Message: ----------- Initial GUI for CSV import - part of unified import GUI Modified Paths: -------------- pytrainer/trunk/glade/importdata.glade pytrainer/trunk/pytrainer/gui/windowimportdata.py Modified: pytrainer/trunk/glade/importdata.glade =================================================================== --- pytrainer/trunk/glade/importdata.glade 2010-11-10 02:32:48 UTC (rev 687) +++ pytrainer/trunk/glade/importdata.glade 2010-11-10 03:36:46 UTC (rev 688) @@ -1,4 +1,4 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="UTF-8"?> <glade-interface> <!-- interface-requires gtk+ 2.16 --> <!-- interface-naming-policy toplevel-contextual --> @@ -20,7 +20,6 @@ <child> <widget class="GtkVBox" id="vboxImportFromDevice"> <property name="visible">True</property> - <property name="orientation">vertical</property> <child> <widget class="GtkFrame" id="frameDeviceSelect"> <property name="visible">True</property> @@ -80,7 +79,6 @@ <child> <widget class="GtkVBox" id="vboxImportTools"> <property name="visible">True</property> - <property name="orientation">vertical</property> <child> <placeholder/> </child> @@ -180,7 +178,6 @@ <child> <widget class="GtkVBox" id="vboxImportFromFile"> <property name="visible">True</property> - <property name="orientation">vertical</property> <child> <widget class="GtkFrame" id="frameSelectFile"> <property name="visible">True</property> @@ -192,7 +189,6 @@ <child> <widget class="GtkVBox" id="vboxImportfromFileSelectFiles"> <property name="visible">True</property> - <property name="orientation">vertical</property> <child> <widget class="GtkScrolledWindow" id="scrolledwindowImportFiles"> <property name="visible">True</property> @@ -401,11 +397,9 @@ <child> <widget class="GtkVBox" id="vboxPluginsTab"> <property name="visible">True</property> - <property name="orientation">vertical</property> <child> <widget class="GtkVBox" id="vboxPlugins"> <property name="visible">True</property> - <property name="orientation">vertical</property> <child> <placeholder/> </child> @@ -481,7 +475,6 @@ <child> <widget class="GtkVBox" id="vboxOptions"> <property name="visible">True</property> - <property name="orientation">vertical</property> <child> <widget class="GtkFrame" id="frameDefaultTab"> <property name="visible">True</property> @@ -493,7 +486,6 @@ <child> <widget class="GtkHBox" id="hboxDefaultTab"> <property name="visible">True</property> - <property name="orientation">vertical</property> <child> <widget class="GtkRadioButton" id="radiobuttonTabGPSDevice"> <property name="label" translatable="yes">Import from GPS Device</property> @@ -685,6 +677,192 @@ <property name="type">tab</property> </packing> </child> + <child> + <widget class="GtkVBox" id="vboxCSVImport"> + <property name="visible">True</property> + <child> + <widget class="GtkFrame" id="frameSelectFile1"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <child> + <widget class="GtkAlignment" id="alignment6"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <widget class="GtkFileChooserButton" id="filechooserCSVImport"> + <property name="visible">True</property> + <signal name="file_set" handler="on_filechooserCSVImport_file_set"/> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="labelSelectFileFrame1"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Select file to import from</b></property> + <property name="use_markup">True</property> + <property name="single_line_mode">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">5</property> + <property name="position">1</property> + </packing> + </child> + <child> + <widget class="GtkFrame" id="frameSelectFile2"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <child> + <widget class="GtkAlignment" id="alignment7"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <widget class="GtkHBox" id="hbox3"> + <property name="visible">True</property> + <child> + <widget class="GtkRadioButton" id="rbCSVTab"> + <property name="label" translatable="yes">Tab</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="padding">5</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkRadioButton" id="rbCSVComma"> + <property name="label" translatable="yes">Comma</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="yalign">0.44999998807907104</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <property name="group">rbCSVTab</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="padding">5</property> + <property name="position">1</property> + </packing> + </child> + <child> + <widget class="GtkRadioButton" id="rbCSVOther"> + <property name="label" translatable="yes">Other</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <property name="group">rbCSVTab</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <widget class="GtkEntry" id="entryCSVOther"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="max_length">5</property> + <property name="invisible_char">•</property> + <property name="width_chars">5</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">3</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelSpace"> + <property name="visible">True</property> + </widget> + <packing> + <property name="position">4</property> + </packing> + </child> + <child> + <widget class="GtkButton" id="buttonCSVProcess"> + <property name="label" translatable="yes">Read File</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">5</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="labelCSVFileOptions"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>File delimiter</b></property> + <property name="use_markup">True</property> + <property name="single_line_mode">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">5</property> + <property name="position">2</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <widget class="GtkStatusbar" id="statusbarCSVImport"> + <property name="visible">True</property> + <property name="spacing">2</property> + <property name="has_resize_grip">False</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </widget> + <packing> + <property name="position">3</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVImportPage"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Import from CSV</b></property> + <property name="use_markup">True</property> + <property name="single_line_mode">True</property> + </widget> + <packing> + <property name="position">4</property> + <property name="tab_fill">False</property> + <property name="type">tab</property> + </packing> + </child> </widget> </child> </widget> Modified: pytrainer/trunk/pytrainer/gui/windowimportdata.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowimportdata.py 2010-11-10 02:32:48 UTC (rev 687) +++ pytrainer/trunk/pytrainer/gui/windowimportdata.py 2010-11-10 03:36:46 UTC (rev 688) @@ -29,716 +29,726 @@ from pytrainer.gui.dialogs import fileChooserDialog class WindowImportdata(SimpleGladeApp): - def __init__(self, data_path = None, parent=None, config=None, pytrainer_main=None): - self.data_path = data_path - self.glade_path=data_path+"glade/importdata.glade" - self.root = "win_importdata" - self.domain = None - self.parent = parent - self.pytrainer_main = pytrainer_main - self.configuration = config - self.activities_store = None - self.files_store = None - self.processClasses = [] - self.plugins = Plugins(data_path, self.parent.parent) - SimpleGladeApp.__init__(self, self.glade_path, self.root, self.domain) + def __init__(self, data_path = None, parent=None, config=None, pytrainer_main=None): + self.data_path = data_path + self.glade_path=data_path+"glade/importdata.glade" + self.root = "win_importdata" + self.domain = None + self.parent = parent + self.pytrainer_main = pytrainer_main + self.configuration = config + self.activities_store = None + self.files_store = None + self.processClasses = [] + self.plugins = Plugins(data_path, self.parent.parent) + SimpleGladeApp.__init__(self, self.glade_path, self.root, self.domain) - #def run(self): - # SimpleGladeApp.__init__(self, self.glade_path, self.root, self.domain) - - def new(self): - logging.debug(">>") - try: - self.defaulttab = self.configuration.getValue("pytraining","import_default_tab") - self.defaulttab = int(self.defaulttab) - except Exception as e: - logging.debug("Exception: %s", str(e)) - self.defaulttab = 0 - self.auto_launch = self.configuration.getValue("pytraining","auto_launch_file_selection") - if self.auto_launch == "True": - self.auto_launch = True - else: - self.auto_launch = False - logging.debug("Default tab: %s, Auto launch: %s" % (str(self.defaulttab), str(self.auto_launch))) - self.init_all_tabs() - self.notebookMainTabs.set_current_page(self.defaulttab) - self.init_tab(self.defaulttab, first=True) #TODO fix so dont need to re-call init_tab - logging.debug("<<") - - def init_all_tabs(self): - logging.debug(">>") - tabs = (0,1,2,3) - for tab in tabs: - self.init_tab(tab) + #def run(self): + # SimpleGladeApp.__init__(self, self.glade_path, self.root, self.domain) + + def new(self): + logging.debug(">>") + try: + self.defaulttab = self.configuration.getValue("pytraining","import_default_tab") + self.defaulttab = int(self.defaulttab) + except Exception as e: + logging.debug("Exception: %s", str(e)) + self.defaulttab = 0 + self.auto_launch = self.configuration.getValue("pytraining","auto_launch_file_selection") + if self.auto_launch == "True": + self.auto_launch = True + else: + self.auto_launch = False + logging.debug("Default tab: %s, Auto launch: %s" % (str(self.defaulttab), str(self.auto_launch))) + self.init_all_tabs() + self.notebookMainTabs.set_current_page(self.defaulttab) + self.init_tab(self.defaulttab, first=True) #TODO fix so dont need to re-call init_tab + logging.debug("<<") + + def init_all_tabs(self): + logging.debug(">>") + tabs = (0,1,2,3) + for tab in tabs: + self.init_tab(tab) - def init_tab(self, page, first=False): - ''' Initialise tab ''' - logging.debug(">>") - logging.debug("page: %d first: %s" % (page, first)) - if page == 0: - #'Import from GPS Device' tab - self.init_gpsdevice_tab() - elif page == 1: - #'Import from File' tab - self.init_file_tab(first) - elif page == 2: - #'Plugins' tab - self.init_plugins_tab() - elif page == 3: - #'Options' tab - self.init_options_tab() - else: - #unknown tab - logging.error("Unknown page %d passed to init_tab" % page) + def init_tab(self, page, first=False): + ''' Initialise tab ''' + logging.debug(">>") + logging.debug("page: %d first: %s" % (page, first)) + if page == 0: + #'Import from GPS Device' tab + self.init_gpsdevice_tab() + elif page == 1: + #'Import from File' tab + self.init_file_tab(first) + elif page == 2: + #'Plugins' tab + self.init_plugins_tab() + elif page == 3: + #'Options' tab + self.init_options_tab() + else: + #unknown tab + logging.error("Unknown page %d passed to init_tab" % page) - def updateStatusbar(self, statusbar, text, context_id = None): - ''' Help function to set the text of the statusbar ''' - logging.debug("Setting statusbar %s to %s" % (statusbar.get_name(), text) ) - if context_id is None: - context_id = statusbar.get_context_id(text) - statusbar.push(context_id, text) - return context_id + def updateStatusbar(self, statusbar, text, context_id = None): + ''' Help function to set the text of the statusbar ''' + logging.debug("Setting statusbar %s to %s" % (statusbar.get_name(), text) ) + if context_id is None: + context_id = statusbar.get_context_id(text) + statusbar.push(context_id, text) + return context_id - def init_gpsdevice_tab(self): - logging.debug(">>") - logging.error("GPS Device import not yet implemented") - logging.debug("<<") - return + def init_gpsdevice_tab(self): + logging.debug(">>") + logging.error("GPS Device import not yet implemented") + logging.debug("<<") + return - def init_file_tab(self, first=False): - logging.debug(">>") - self.updateStatusbar(self.statusbarImportFile, _("No file selected") ) - self.processClasses = [] - if self.activities_store is None: - self.activities_store = self.build_activities_tree_view() - else: - self.activities_store.clear() - if self.files_store is None: - self.files_store = self.build_files_tree_view() - else: - self.files_store.clear() - self.buttonRemoveSelectedFiles.set_sensitive(0) - self.buttonFileImport.set_sensitive(0) - if first and self.auto_launch: - while gtk.events_pending(): # This allows the GUI to update - gtk.main_iteration() # before completion of this entire action - logging.debug("autolaunch active") - self.buttonSelectFiles.clicked() - logging.debug(">>") - return + def init_file_tab(self, first=False): + logging.debug(">>") + self.updateStatusbar(self.statusbarImportFile, _("No file selected") ) + self.processClasses = [] + if self.activities_store is None: + self.activities_store = self.build_activities_tree_view() + else: + self.activities_store.clear() + if self.files_store is None: + self.files_store = self.build_files_tree_view() + else: + self.files_store.clear() + self.buttonRemoveSelectedFiles.set_sensitive(0) + self.buttonFileImport.set_sensitive(0) + if first and self.auto_launch: + while gtk.events_pending(): # This allows the GUI to update + gtk.main_iteration() # before completion of this entire action + logging.debug("autolaunch active") + self.buttonSelectFiles.clicked() + logging.debug(">>") + return - def init_plugins_tab(self): - logging.debug(">>") - #Remove components in vbox - in case of re-detection - for child in self.vboxPlugins.get_children(): - if isinstance(child, gtk.Table): - self.vboxPlugins.remove(child) - pluginList = self.plugins.getPluginsList() - logging.debug(pluginList) - for plugin in pluginList: - #Store plugin details - pluginClass = plugin[0] - pluginName = plugin[1] - pluginDescription = plugin[2] - #Build frame with name and description - pluginFrame = gtk.Frame(label="<b>"+pluginName+"</b>") - pluginFrameLabel = pluginFrame.get_label_widget() - pluginFrameLabel.set_use_markup(True) - description = gtk.Label("<small>"+pluginDescription+"</small>") - description.set_alignment(0,0) - description.set_use_markup(True) - description.set_line_wrap(True) - pluginFrame.add(description) - #Get plugin information - name,description,status = self.plugins.getPluginInfo(pluginClass) - #Create labels and buttons - configButton = gtk.Button(label=_("Configure")) - runButton = gtk.Button(label=_("Run")) - #Connect button handlers - configButton.connect('clicked', self.on_pluginsButton_Configure_clicked, pluginClass) - runButton.connect('clicked', self.on_pluginsButton_Run_clicked, pluginClass) - if status == 0 or status == "0": - #Plugin disabled - pluginFrame.set_sensitive(0) - runButton.set_sensitive(0) - statusLabel = gtk.Label(_("Disabled")) - else: - statusLabel = gtk.Label(_("Enabled")) + def init_plugins_tab(self): + logging.debug(">>") + #Remove components in vbox - in case of re-detection + for child in self.vboxPlugins.get_children(): + if isinstance(child, gtk.Table): + self.vboxPlugins.remove(child) + pluginList = self.plugins.getPluginsList() + logging.debug(pluginList) + for plugin in pluginList: + #Store plugin details + pluginClass = plugin[0] + pluginName = plugin[1] + pluginDescription = plugin[2] + #Build frame with name and description + pluginFrame = gtk.Frame(label="<b>"+pluginName+"</b>") + pluginFrameLabel = pluginFrame.get_label_widget() + pluginFrameLabel.set_use_markup(True) + description = gtk.Label("<small>"+pluginDescription+"</small>") + description.set_alignment(0,0) + description.set_use_markup(True) + description.set_line_wrap(True) + pluginFrame.add(description) + #Get plugin information + name,description,status = self.plugins.getPluginInfo(pluginClass) + #Create labels and buttons + configButton = gtk.Button(label=_("Configure")) + runButton = gtk.Button(label=_("Run")) + #Connect button handlers + configButton.connect('clicked', self.on_pluginsButton_Configure_clicked, pluginClass) + runButton.connect('clicked', self.on_pluginsButton_Run_clicked, pluginClass) + if status == 0 or status == "0": + #Plugin disabled + pluginFrame.set_sensitive(0) + runButton.set_sensitive(0) + statusLabel = gtk.Label(_("Disabled")) + else: + statusLabel = gtk.Label(_("Enabled")) - #Create a table for the frame and button - pluginTable = gtk.Table() - pluginTable.attach(pluginFrame, 0, 1, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5) - pluginTable.attach(statusLabel, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.SHRINK, xpadding=5, ypadding=5) - pluginTable.attach(configButton, 2, 3, 0, 1, xoptions=gtk.FILL, yoptions=gtk.SHRINK, xpadding=5, ypadding=5) - pluginTable.attach(runButton, 3, 4, 0, 1, xoptions=gtk.FILL, yoptions=gtk.SHRINK, xpadding=5, ypadding=5) - #Add frame to tab - self.vboxPlugins.pack_start(pluginTable, expand=False, fill=False, padding=5) - self.win_importdata.show_all() - logging.debug("<<") - return + #Create a table for the frame and button + pluginTable = gtk.Table() + pluginTable.attach(pluginFrame, 0, 1, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5) + pluginTable.attach(statusLabel, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.SHRINK, xpadding=5, ypadding=5) + pluginTable.attach(configButton, 2, 3, 0, 1, xoptions=gtk.FILL, yoptions=gtk.SHRINK, xpadding=5, ypadding=5) + pluginTable.attach(runButton, 3, 4, 0, 1, xoptions=gtk.FILL, yoptions=gtk.SHRINK, xpadding=5, ypadding=5) + #Add frame to tab + self.vboxPlugins.pack_start(pluginTable, expand=False, fill=False, padding=5) + self.win_importdata.show_all() + logging.debug("<<") + return - def init_options_tab(self): - logging.debug(">>") - logging.debug("Default tab %s" % str(self.defaulttab) ) - #Set correct radiobutton based on saved preference - if self.defaulttab == 1: - self.radiobuttonFile.set_active(1) - self.checkbuttonAutoLaunch.set_sensitive(1) - elif self.defaulttab == 2: - self.radiobuttonPlugins.set_active(1) - else: - self.radiobuttonTabGPSDevice.set_active(1) - if self.auto_launch: - self.checkbuttonAutoLaunch.set_active(1) - logging.debug("<<") - return - - def detect_tools(self): - ''' - Iterate through all tool files from import directory - Each file contains information on a particular tool - and knows how to determine if the tool is present on the system - and what configuration options are needed for the tool - - Currently displays the tool info and config grayed out if tool is not present - ''' - logging.debug('>>') - self.updateStatusbar(self.statusbarDevice, "Checking for tools") - #Remove all components in vbox - in case of re-detection - for child in self.vboxImportTools.get_children(): - self.vboxImportTools.remove(child) - #Get import tool_* files - fileList = glob.glob(self.data_path+"import/tool_*.py") - logging.debug("Tools filelist: %s" % fileList) - for toolFile in fileList: - index = fileList.index(toolFile) - directory, filename = os.path.split(toolFile) - filename = filename.rstrip('.py') - classname = filename.lstrip('tool_') - #Import module - sys.path.insert(0, self.data_path+"import") - module = __import__(filename) - toolMain = getattr(module, classname) - #Instantiate module - toolClass = toolMain(self.parent, self.data_path) - #Get info from class - toolName = toolClass.getName() - toolTable = gtk.Table() - toolFrame = gtk.Frame(label=toolName) - toolFrame.add(toolTable) - if toolClass.isPresent(): - version = gtk.Label("Version: " + toolClass.getVersion()) - version.set_alignment(0,0) - if toolClass.deviceExists(): - deviceExists = gtk.Label(_("GPS device found") ) - deviceExists.set_alignment(0,0) - else: - deviceExists = gtk.Label(_("GPS device <b>not</b> found")) - deviceExists.set_alignment(0,0) - deviceExists.set_use_markup(True) - toolTable.attach(version, 0, 1, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5) - toolTable.attach(deviceExists, 0, 1, 1, 2, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5) - toolFrame.set_sensitive(1) - else: - info = gtk.Label(_("This tool was not found on the system") ) - info.set_alignment(0,0.5) - location = gtk.LinkButton(toolClass.getSourceLocation(), toolName +_(" Homepage")) - info.set_sensitive(0) - toolTable.attach(info, 0, 1, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5) - toolTable.attach(location, 1, 2, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5) - #toolFrame.set_sensitive(0) - self.vboxImportTools.pack_start(toolFrame, expand=False, fill=False, padding=5) - self.win_importdata.show_all() - logging.debug('<<') + def init_options_tab(self): + logging.debug(">>") + logging.debug("Default tab %s" % str(self.defaulttab) ) + #Set correct radiobutton based on saved preference + if self.defaulttab == 1: + self.radiobuttonFile.set_active(1) + self.checkbuttonAutoLaunch.set_sensitive(1) + elif self.defaulttab == 2: + self.radiobuttonPlugins.set_active(1) + else: + self.radiobuttonTabGPSDevice.set_active(1) + if self.auto_launch: + self.checkbuttonAutoLaunch.set_active(1) + logging.debug("<<") + return + + def detect_tools(self): + ''' + Iterate through all tool files from import directory + Each file contains information on a particular tool + and knows how to determine if the tool is present on the system + and what configuration options are needed for the tool + + Currently displays the tool info and config grayed out if tool is not present + ''' + logging.debug('>>') + self.updateStatusbar(self.statusbarDevice, "Checking for tools") + #Remove all components in vbox - in case of re-detection + for child in self.vboxImportTools.get_children(): + self.vboxImportTools.remove(child) + #Get import tool_* files + fileList = glob.glob(self.data_path+"import/tool_*.py") + logging.debug("Tools filelist: %s" % fileList) + for toolFile in fileList: + index = fileList.index(toolFile) + directory, filename = os.path.split(toolFile) + filename = filename.rstrip('.py') + classname = filename.lstrip('tool_') + #Import module + sys.path.insert(0, self.data_path+"import") + module = __import__(filename) + toolMain = getattr(module, classname) + #Instantiate module + toolClass = toolMain(self.parent, self.data_path) + #Get info from class + toolName = toolClass.getName() + toolTable = gtk.Table() + toolFrame = gtk.Frame(label=toolName) + toolFrame.add(toolTable) + if toolClass.isPresent(): + version = gtk.Label("Version: " + toolClass.getVersion()) + version.set_alignment(0,0) + if toolClass.deviceExists(): + deviceExists = gtk.Label(_("GPS device found") ) + deviceExists.set_alignment(0,0) + else: + deviceExists = gtk.Label(_("GPS device <b>not</b> found")) + deviceExists.set_alignment(0,0) + deviceExists.set_use_markup(True) + toolTable.attach(version, 0, 1, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5) + toolTable.attach(deviceExists, 0, 1, 1, 2, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5) + toolFrame.set_sensitive(1) + else: + info = gtk.Label(_("This tool was not found on the system") ) + info.set_alignment(0,0.5) + location = gtk.LinkButton(toolClass.getSourceLocation(), toolName +_(" Homepage")) + info.set_sensitive(0) + toolTable.attach(info, 0, 1, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5) + toolTable.attach(location, 1, 2, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5) + #toolFrame.set_sensitive(0) + self.vboxImportTools.pack_start(toolFrame, expand=False, fill=False, padding=5) + self.win_importdata.show_all() + logging.debug('<<') - def validateFile(self, import_filename): - ''' - Iterate through all supported types of file by reading processing files from import directory - Each processing file understands one type of file + def validateFile(self, import_filename): + ''' + Iterate through all supported types of file by reading processing files from import directory + Each processing file understands one type of file - If a processing file is found that recognises the selected file: - returns the instantiated class - otherwise: - returns None - ''' - logging.debug('>>') - self.updateStatusbar(self.statusbarImportFile, "Checking file type for: " + import_filename) - #Get import files_* files - fileList = glob.glob(self.data_path+"import/file_*.py") - fileList.sort() - logging.debug("File filelist: %s" % fileList) - for processingFile in fileList: - directory, filename = os.path.split(processingFile) - filename = filename.rstrip('.py') - logging.debug("Trying: %s" % filename) - classname = filename.lstrip('file_') - #Import module - sys.path.insert(0, self.data_path+"import") - module = __import__(filename) - processMain = getattr(module, classname) - #Instantiate module - processClass = processMain(self.parent, self.data_path) - isValid = processClass.testFile(import_filename) - if isValid: - logging.debug('<<') - return processClass - else: - processClass = None - logging.debug('<<') - return processClass + If a processing file is found that recognises the selected file: + returns the instantiated class + otherwise: + returns None + ''' + logging.debug('>>') + self.updateStatusbar(self.statusbarImportFile, "Checking file type for: " + import_filename) + #Get import files_* files + fileList = glob.glob(self.data_path+"import/file_*.py") + fileList.sort() + logging.debug("File filelist: %s" % fileList) + for processingFile in fileList: + directory, filename = os.path.split(processingFile) + filename = filename.rstrip('.py') + logging.debug("Trying: %s" % filename) + classname = filename.lstrip('file_') + #Import module + sys.path.insert(0, self.data_path+"import") + module = __import__(filename) + processMain = getattr(module, classname) + #Instantiate module + processClass = processMain(self.parent, self.data_path) + isValid = processClass.testFile(import_filename) + if isValid: + logging.debug('<<') + return processClass + else: + processClass = None + logging.debug('<<') + return processClass - def build_files_tree_view(self): - ''' Build tree view to hold files from which the activities are read ''' - logging.debug('>>') - store = gtk.ListStore( gobject.TYPE_STRING, - gobject.TYPE_BOOLEAN, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, ) - column_names=["id", "", _("File"), _("Type"), _("Activities")] - for column_index, column_name in enumerate(column_names): - if column_index == 1: - #Add button column - self.renderer1 = gtk.CellRendererToggle() - self.renderer1.set_property('activatable', True) - self.renderer1.connect( 'toggled', self.treeviewImportFiles_toggled_checkbox, store ) - column = gtk.TreeViewColumn(column_name, self.renderer1 ) - column.add_attribute( self.renderer1, "active", column_index) - column.set_sort_column_id(-1) - #column.connect('clicked', self.treeviewImportFiles_header_checkbox, store) - else: - #Add other columns - column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) - column.set_sort_column_id(column_index) - if column_name == "id": - column.set_visible(False) - column.set_resizable(True) - self.treeviewImportFiles.append_column(column) - self.treeviewImportFiles.set_headers_clickable(True) - self.treeviewImportFiles.set_model(store) - logging.debug('<<') - return store - - def build_activities_tree_view(self): - ''' Build tree view to hold activities that can be selected for import ''' - logging.debug('>>') - store = gtk.ListStore( gobject.TYPE_STRING, - gobject.TYPE_BOOLEAN, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING ) - column_names=["id", "", _("Start Time"), _("Distance"),_("Duration"),_("Sport"), _("Notes"), "file_id"] - for column_index, column_name in enumerate(column_names): - if column_index == 1: - #Add checkbox column - self.renderer1 = gtk.CellRendererToggle() - self.renderer1.set_property('activatable', True) - self.renderer1.connect( 'toggled', self.treeviewImportEvents_toggled_checkbox, store ) - column = gtk.TreeViewColumn(column_name, self.renderer1 ) - column.add_attribute( self.renderer1, "active", column_index) - column.set_sort_column_id(-1) - column.connect('clicked', self.treeviewImportEvents_header_checkbox, store) - else: - #Add other columns - column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) - column.set_sort_column_id(column_index) - if column_name == "id" or column_name == "file_id": - column.set_visible(False) - column.set_resizable(True) - self.treeviewImportEvents.append_column(column) - self.treeviewImportEvents.set_headers_clickable(True) - self.treeviewImportEvents.set_model(store) - logging.debug('<<') - return store - - def checkTreestoreForSelection(self, store): - ''' - Function iterates over store checking if any items are selected - returns True if at least one item is selected, False otherwise - Checks item in position 1 only - ''' - for item in store: - if item[1]: - return True - return False + def build_files_tree_view(self): + ''' Build tree view to hold files from which the activities are read ''' + logging.debug('>>') + store = gtk.ListStore( gobject.TYPE_STRING, + gobject.TYPE_BOOLEAN, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, ) + column_names=["id", "", _("File"), _("Type"), _("Activities")] + for column_index, column_name in enumerate(column_names): + if column_index == 1: + #Add button column + self.renderer1 = gtk.CellRendererToggle() + self.renderer1.set_property('activatable', True) + self.renderer1.connect( 'toggled', self.treeviewImportFiles_toggled_checkbox, store ) + column = gtk.TreeViewColumn(column_name, self.renderer1 ) + column.add_attribute( self.renderer1, "active", column_index) + column.set_sort_column_id(-1) + #column.connect('clicked', self.treeviewImportFiles_header_checkbox, store) + else: + #Add other columns + column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) + column.set_sort_column_id(column_index) + if column_name == "id": + column.set_visible(False) + column.set_resizable(True) + self.treeviewImportFiles.append_column(column) + self.treeviewImportFiles.set_headers_clickable(True) + self.treeviewImportFiles.set_model(store) + logging.debug('<<') + return store + + def build_activities_tree_view(self): + ''' Build tree view to hold activities that can be selected for import ''' + logging.debug('>>') + store = gtk.ListStore( gobject.TYPE_STRING, + gobject.TYPE_BOOLEAN, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING ) + column_names=["id", "", _("Start Time"), _("Distance"),_("Duration"),_("Sport"), _("Notes"), "file_id"] + for column_index, column_name in enumerate(column_names): + if column_index == 1: + #Add checkbox column + self.renderer1 = gtk.CellRendererToggle() + self.renderer1.set_property('activatable', True) + self.renderer1.connect( 'toggled', self.treeviewImportEvents_toggled_checkbox, store ) + column = gtk.TreeViewColumn(column_name, self.renderer1 ) + column.add_attribute( self.renderer1, "active", column_index) + column.set_sort_column_id(-1) + column.connect('clicked', self.treeviewImportEvents_header_checkbox, store) + else: + #Add other columns + column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) + column.set_sort_column_id(column_index) + if column_name == "id" or column_name == "file_id": + column.set_visible(False) + column.set_resizable(True) + self.treeviewImportEvents.append_column(column) + self.treeviewImportEvents.set_headers_clickable(True) + self.treeviewImportEvents.set_model(store) + logging.debug('<<') + return store + + def checkTreestoreForSelection(self, store): + ''' + Function iterates over store checking if any items are selected + returns True if at least one item is selected, False otherwise + Checks item in position 1 only + ''' + for item in store: + if item[1]: + return True + return False - def treeviewImportFiles_toggled_checkbox(self, cell, path, store): - ''' - Sets the state of the checkbox to true or false. - ''' - store[path][1] = not store[path][1] - self.buttonRemoveSelectedFiles.set_sensitive(self.checkTreestoreForSelection(store)) - - def treeviewImportEvents_toggled_checkbox(self, cell, path, store): - ''' - Sets the state of the checkbox to true or false. - ''' - store[path][1] = not store[path][1] - self.buttonFileImport.set_sensitive(self.checkTreestoreForSelection(store)) + def treeviewImportFiles_toggled_checkbox(self, cell, path, store): + ''' + Sets the state of the checkbox to true or false. + ''' + store[path][1] = not store[path][1] + self.buttonRemoveSelectedFiles.set_sensitive(self.checkTreestoreForSelection(store)) + + def treeviewImportEvents_toggled_checkbox(self, cell, path, store): + ''' + Sets the state of the checkbox to true or false. + ''' + store[path][1] = not store[path][1] + self.buttonFileImport.set_sensitive(self.checkTreestoreForSelection(store)) - def treeviewImportEvents_setCheckboxes(self, state): - ''' - Sets or unsets all checkboxes - ''' - if self.activities_store is None or len(self.activities_store) == 0: - return - for item in self.activities_store: - item[1] = state - if state: - self.buttonFileImport.set_sensitive(1) - else: - self.buttonFileImport.set_sensitive(0) + def treeviewImportEvents_setCheckboxes(self, state): + ''' + Sets or unsets all checkboxes + ''' + if self.activities_store is None or len(self.activities_store) == 0: + return + for item in self.activities_store: + item[1] = state + if state: + self.buttonFileImport.set_sensitive(1) + else: + self.buttonFileImport.set_sensitive(0) - def saveOptions(self): - ''' - Save options selected in options tab - ''' - self.autoLaunchFileSelection = "False" - #Default tab option - if self.radiobuttonTabGPSDevice.get_active(): - self.defaulttab = "0" - elif self.radiobuttonFile.get_active(): - self.defaulttab = "1" - if self.checkbuttonAutoLaunch.get_active(): - self.autoLaunchFileSelection = "True" - elif self.radiobuttonPlugins.get_active(): - self.defaulttab = "2" - logging.debug("Saving default tab: %s, auto launch: %s" % (str(self.defaulttab), str(self.autoLaunchFileSelection))) - self.configuration.setValue("pytraining","import_default_tab",self.defaulttab) - self.configuration.setValue("pytraining","auto_launch_file_selection",self.autoLaunchFileSelection) - #option + def saveOptions(self): + ''' + Save options selected in options tab + ''' + self.autoLaunchFileSelection = "False" + #Default tab option + if self.radiobuttonTabGPSDevice.get_active(): + self.defaulttab = "0" + elif self.radiobuttonFile.get_active(): + self.defaulttab = "1" + if self.checkbuttonAutoLaunch.get_active(): + self.autoLaunchFileSelection = "True" + elif self.radiobuttonPlugins.get_active(): + self.defaulttab = "2" + logging.debug("Saving default tab: %s, auto launch: %s" % (str(self.defaulttab), str(self.autoLaunchFileSelection))) + self.configuration.setValue("pytraining","import_default_tab",self.defaulttab) + self.configuration.setValue("pytraining","auto_launch_file_selection",self.autoLaunchFileSelection) + #option - def removeSelectedFiles(self): - ''' - Function to determine which files are selected - * remove them from the list - * remove the associated activities from the list also - ''' - if self.files_store is None: - return - file_index = 0 - file_iters = [] - activity_iters = [] - for item in self.files_store: - if item[1] is True: #Checkbox is True, file for removal - file_id = item[0] - activity_index = 0 - for activity in self.activities_store: - if activity[7] == file_id: #Activity relates to file to be removed - activity_iters.append(self.activities_store.get_iter(activity_index)) - activity_index += 1 - file_iters.append( self.files_store.get_iter(file_index)) - file_index += 1 - logging.debug("Removing %d activities from activity tree view" % len(activity_iters) ) - for activity_iter in activity_iters: - self.activities_store.remove(activity_iter) - self.buttonFileImport.set_sensitive(self.checkTreestoreForSelection(self.activities_store)) #Set correct state for import button - logging.debug("Removing %d files from file tree view" % len(file_iters) ) - for file_iter in file_iters: - self.files_store.remove(file_iter) - - def getSelectedActivities(self): - """ - Function to determine which activities are selected - - Returns array of the ids of the selected activities - """ - selectedActivities = [] - if self.activities_store is None: - logging.debug("activities_store is empty") - return None - for item in self.activities_store: - if item[1] is True: #Checkbox is True - logging.debug("Added activity %s to selected list" % item) - file_id = int(item[7]) - activity_id = item[0] - start_time = item[2] - distance = item[3] - duration = item[4] - sport = item[5] - gpx_file = self.processClasses[file_id].getGPXFile(activity_id, file_id)[1] - selectedActivities.append((activity_id, start_time, distance, duration, sport, gpx_file, file_id)) - logging.debug( "Found %d selected activities to import" % len(selectedActivities) ) - return selectedActivities - - def importSelectedActivities(self, activities): - """ - Function to import selected activity - """ - - #selectedActivities.append((activity_id, start_time, distance, duration, sport, gpx_file)) - logging.debug( "Importing %d activities" % len(activities)) - list_sport = self.pytrainer_main.profile.getSportList() - result = self.pytrainer_main.record.newMultiRecord(activities, list_sport) - for activity in result: - if "db_id" in activity.keys() and type(activity["db_id"]) is types.IntType: - #Activity imported correctly - duration = "%0.0f:%0.0f:%02.0f" % (float(activity["rcd_time"][0]), float(activity["rcd_time"][1]), float(activity["rcd_time"][2])) - self.updateActivity(activity["activity_id"], activity["file_id"], - status = False, - notes = _("Imported into database"), - sport = activity["rcd_sport"], - distance = activity["rcd_distance"], - duration = duration) - #print "updating activity %s " % (str(activity)) + def removeSelectedFiles(self): + ''' + Function to determine which files are selected + * remove them from the list + * remove the associated activities from the list also + ''' + if self.files_store is None: + return + file_index = 0 + file_iters = [] + activity_iters = [] + for item in self.files_store: + if item[1] is True: #Checkbox is True, file for removal + file_id = item[0] + activity_index = 0 + for activity in self.activities_store: + if activity[7] == file_id: #Activity relates to file to be removed + activity_iters.append(self.activities_store.get_iter(activity_index)) + activity_index += 1 + file_iters.append( self.files_store.get_iter(file_index)) + file_index += 1 + logging.debug("Removing %d activities from activity tree view" % len(activity_iters) ) + for activity_iter in activity_iters: + self.activities_store.remove(activity_iter) + self.buttonFileImport.set_sensitive(self.checkTreestoreForSelection(self.activities_store)) #Set correct state for import button + logging.debug("Removing %d files from file tree view" % len(file_iters) ) + for file_iter in file_iters: + self.files_store.remove(file_iter) + + def getSelectedActivities(self): + """ + Function to determine which activities are selected + + Returns array of the ids of the selected activities + """ + selectedActivities = [] + if self.activities_store is None: + logging.debug("activities_store is empty") + return None + for item in self.activities_store: + if item[1] is True: #Checkbox is True + logging.debug("Added activity %s to selected list" % item) + file_id = int(item[7]) + activity_id = item[0] + start_time = item[2] + distance = item[3] + duration = item[4] + sport = item[5] + gpx_file = self.processClasses[file_id].getGPXFile(activity_id, file_id)[1] + selectedActivities.append((activity_id, start_time, distance, duration, sport, gpx_file, file_id)) + logging.debug( "Found %d selected activities to import" % len(selectedActivities) ) + return selectedActivities + + def importSelectedActivities(self, activities): + """ + Function to import selected activity + """ + + #selectedActivities.append((activity_id, start_time, distance, duration, sport, gpx_file)) + logging.debug( "Importing %d activities" % len(activities)) + list_sport = self.pytrainer_main.profile.getSportList() + result = self.pytrainer_main.record.newMultiRecord(activities, list_sport) + for activity in result: + if "db_id" in activity.keys() and type(activity["db_id"]) is types.IntType: + #Activity imported correctly + duration = "%0.0f:%0.0f:%02.0f" % (float(activity["rcd_time"][0]), float(activity["rcd_time"][1]), float(activity["rcd_time"][2])) + self.updateActivity(activity["activity_id"], activity["file_id"], + status = False, + notes = _("Imported into database"), + sport = activity["rcd_sport"], + distance = activity["rcd_distance"], + duration = duration) + #print "updating activity %s " % (str(activity)) - def updateActivity(self, activityID, file_id, status = None, notes = None, sport = None, distance = None, duration = None): - path = 0 - for item in self.activities_store: - if item[0] == activityID and item[7] == str(file_id): - if status is not None: - self.activities_store[path][1] = status - if notes is not None: - self.activities_store[path][6] = notes - if sport is not None: - self.activities_store[path][5] = sport - if distance is not None: - self.activities_store[path][3] = distance - if duration is not None: - self.activities_store[path][4] = duration - path +=1 + def updateActivity(self, activityID, file_id, status = None, notes = None, sport = None, distance = None, duration = None): + path = 0 + for item in self.activities_store: + if item[0] == activityID and item[7] == str(file_id): + if status is not None: + self.activities_store[path][1] = status + if notes is not None: + self.activities_store[path][6] = notes + if sport is not None: + self.activities_store[path][5] = sport + if distance is not None: + self.activities_store[path][3] = distance + if duration is not None: + self.activities_store[path][4] = duration + path +=1 - def close_window(self): - logging.debug('--') - self.win_importdata.hide() - #self.win_importdata.destroy() - self.quit() + def close_window(self): + logging.debug('--') + self.win_importdata.hide() + #self.win_importdata.destroy() + self.quit() - ############################ - ## Window signal handlers ## - ############################ + ############################ + ## Window signal handlers ## + ############################ - def on_radiobuttonFile_toggled(self, *args): - print "radio button toggled" - - def on_pluginsButton_Configure_clicked(self, button, pluginClass): - ''' - Handler for plugin Buttons - ''' - name,description,status = self.plugins.getPluginInfo(pluginClass) - prefs = self.plugins.getPluginConfParams(pluginClass) - - self.prefwindow = gtk.Window() - self.prefwindow.set_border_width(20) - self.prefwindow.set_title(_("%s settings" %name)) - - table = gtk.Table(1,2) - i=0 - self.entryList = [] - for pref in prefs: - label = gtk.Label("<b>%s</b>"%pref[0]) - label.set_use_markup(True) - if pref[0] != "status": - entry = gtk.Entry() - entry.set_text(pref[1]) - self.entryList.append(entry) - table.attach(entry,1,2,i,i+1) - else: - combobox = gtk.combo_box_new_text() - combobox.append_text(_("Disable")) - combobox.append_text(_("Enable")) - combobox.set_active(int(pref[1])) - table.attach(combobox,1,2,i,i+1) - self.entryList.append(combobox) - table.attach(label,0,1,i,i+1) - i+=1 - - button = gtk.Button(_("Ok")) - button.connect("clicked", self.on_pluginAcceptSettings_clicked, pluginClass) - table.attach(button,0,2,i,i+1) - self.prefwindow.add(table) - self.prefwindow.show_all() - - def on_pluginsButton_Run_clicked(self, button, pluginClass): - ''' - Handler for plugin Buttons - ''' - logging.debug('>>') - self.pytrainer_main.runPlugin(button,pluginClass) - logging.debug('<<') - - def on_pluginAcceptSettings_clicked(self, widget, pluginClass): - ''' - Duplicate of plugin settings accept handler - ''' - logging.debug('>>') - prefs = self.plugins.getPluginConfParams(pluginClass) - savedOptions = [] - i = 0 - for pref in prefs: - try: - savedOptions.append((pref[0],self.entryList[i].get_text())) - except: - combobox = self.entryList[i] - index = combobox.get_active() - savedOptions.append((pref[0],"%s" %index)) - i+=1 - self.prefwindow.hide() - self.prefwindow = None - self.plugins.setPluginConfParams(pluginClass,savedOptions) - self.init_plugins_tab() - logging.debug('<<') - - def treeviewImportEvents_header_checkbox(self, column, store): - ''' - Handler for click on checkbox column - ''' - logging.debug('--') - if store is None: - return - for item in store: - if item[1]: - self.treeviewImportEvents_setCheckboxes(False) - return - self.treeviewImportEvents_setCheckboxes(True) + def on_radiobuttonFile_toggled(self, *args): + print "radio button toggled" + + def on_pluginsButton_Configure_clicked(self, button, pluginClass): + ''' + Handler for plugin Buttons + ''' + name,description,status = self.plugins.getPluginInfo(pluginClass) + prefs = self.plugins.getPluginConfParams(pluginClass) + + self.prefwindow = gtk.Window() + self.prefwindow.set_border_width(20) + self.prefwindow.set_title(_("%s settings" %name)) + + table = gtk.Table(1,2) + i=0 + self.entryList = [] + for pref in prefs: + label = gtk.Label("<b>%s</b>"%pref[0]) + label.set_use_markup(True) + if pref[0] != "status": + entry = gtk.Entry() + entry.set_text(pref[1]) + self.entryList.append(entry) + table.attach(entry,1,2,i,i+1) + else: + combobox = gtk.combo_box_new_text() + combobox.append_text(_("Disable")) + combobox.append_text(_("Enable")) + combobox.set_active(int(pref[1])) + table.attach(combobox,1,2,i,i+1) + self.entryList.append(combobox) + table.attach(label,0,1,i,i+1) + i+=1 + + button = gtk.Button(_("Ok")) + button.connect("clicked", self.on_pluginAcceptSettings_clicked, pluginClass) + table.attach(button,0,2,i,i+1) + self.prefwindow.add(table) + self.prefwindow.show_all() + + def on_pluginsButton_Run_clicked(self, button, pluginClass): + ''' + Handler for plugin Buttons + ''' + logging.debug('>>') + self.pytrainer_main.runPlugin(button,pluginClass) + logging.debug('<<') + + def on_pluginAcceptSettings_clicked(self, widget, pluginClass): + ''' + Duplicate of plugin settings accept handler + ''' + logging.debug('>>') + prefs = self.plugins.getPluginConfParams(pluginClass) + savedOptions = [] + i = 0 + for pref in prefs: + try: + savedOptions.append((pref[0],self.entryList[i].get_text())) + except: + combobox = self.entryList[i] + index = combobox.get_active() + savedOptions.append((pref[0],"%s" %index)) + i+=1 + self.prefwindow.hide() + self.prefwindow = None + self.plugins.setPluginConfParams(pluginClass,savedOptions) + self.init_plugins_tab() + logging.debug('<<') + + def treeviewImportEvents_header_checkbox(self, column, store): + ''' + Handler for click on checkbox column + ''' + logging.debug('--') + if store is None: + return + for item in store: + if item[1]: + self.treeviewImportEvents_setCheckboxes(False) + return + self.treeviewImportEvents_setCheckboxes(True) - def on_wi... [truncated message content] |
From: <jb...@us...> - 2010-11-10 09:35:24
|
Revision: 689 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=689&view=rev Author: jblance Date: 2010-11-10 09:35:17 +0000 (Wed, 10 Nov 2010) Log Message: ----------- Slight progress on delimited import Modified Paths: -------------- pytrainer/trunk/glade/importdata.glade pytrainer/trunk/pytrainer/gui/windowimportdata.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/importdata.glade =================================================================== --- pytrainer/trunk/glade/importdata.glade 2010-11-10 03:36:46 UTC (rev 688) +++ pytrainer/trunk/glade/importdata.glade 2010-11-10 09:35:17 UTC (rev 689) @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0"?> <glade-interface> <!-- interface-requires gtk+ 2.16 --> <!-- interface-naming-policy toplevel-contextual --> @@ -778,7 +778,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">5</property> - <property name="invisible_char">•</property> + <property name="invisible_char">•</property> <property name="width_chars">5</property> </widget> <packing> @@ -798,8 +798,11 @@ <widget class="GtkButton" id="buttonCSVProcess"> <property name="label" translatable="yes">Read File</property> <property name="visible">True</property> + <property name="sensitive">False</property> <property name="can_focus">True</property> <property name="receives_default">True</property> + <property name="yalign">0.34000000357627869</property> + <signal name="clicked" handler="on_buttonCSVProcess_clicked"/> </widget> <packing> <property name="expand">False</property> Modified: pytrainer/trunk/pytrainer/gui/windowimportdata.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowimportdata.py 2010-11-10 03:36:46 UTC (rev 688) +++ pytrainer/trunk/pytrainer/gui/windowimportdata.py 2010-11-10 09:35:17 UTC (rev 689) @@ -24,6 +24,7 @@ import logging import types from lxml import etree +import csv from pytrainer.plugins import Plugins from pytrainer.gui.dialogs import fileChooserDialog @@ -45,7 +46,7 @@ #def run(self): # SimpleGladeApp.__init__(self, self.glade_path, self.root, self.domain) - + def new(self): logging.debug(">>") try: @@ -53,7 +54,7 @@ self.defaulttab = int(self.defaulttab) except Exception as e: logging.debug("Exception: %s", str(e)) - self.defaulttab = 0 + self.defaulttab = 0 self.auto_launch = self.configuration.getValue("pytraining","auto_launch_file_selection") if self.auto_launch == "True": self.auto_launch = True @@ -64,7 +65,7 @@ self.notebookMainTabs.set_current_page(self.defaulttab) self.init_tab(self.defaulttab, first=True) #TODO fix so dont need to re-call init_tab logging.debug("<<") - + def init_all_tabs(self): logging.debug(">>") tabs = (0,1,2,3) @@ -120,7 +121,7 @@ self.buttonRemoveSelectedFiles.set_sensitive(0) self.buttonFileImport.set_sensitive(0) if first and self.auto_launch: - while gtk.events_pending(): # This allows the GUI to update + while gtk.events_pending(): # This allows the GUI to update gtk.main_iteration() # before completion of this entire action logging.debug("autolaunch active") self.buttonSelectFiles.clicked() @@ -192,14 +193,14 @@ self.checkbuttonAutoLaunch.set_active(1) logging.debug("<<") return - + def detect_tools(self): ''' Iterate through all tool files from import directory - Each file contains information on a particular tool - and knows how to determine if the tool is present on the system + Each file contains information on a particular tool + and knows how to determine if the tool is present on the system and what configuration options are needed for the tool - + Currently displays the tool info and config grayed out if tool is not present ''' logging.debug('>>') @@ -213,7 +214,7 @@ for toolFile in fileList: index = fileList.index(toolFile) directory, filename = os.path.split(toolFile) - filename = filename.rstrip('.py') + filename = filename.rstrip('.py') classname = filename.lstrip('tool_') #Import module sys.path.insert(0, self.data_path+"import") @@ -227,7 +228,7 @@ toolFrame = gtk.Frame(label=toolName) toolFrame.add(toolTable) if toolClass.isPresent(): - version = gtk.Label("Version: " + toolClass.getVersion()) + version = gtk.Label("Version: " + toolClass.getVersion()) version.set_alignment(0,0) if toolClass.deviceExists(): deviceExists = gtk.Label(_("GPS device found") ) @@ -269,7 +270,7 @@ logging.debug("File filelist: %s" % fileList) for processingFile in fileList: directory, filename = os.path.split(processingFile) - filename = filename.rstrip('.py') + filename = filename.rstrip('.py') logging.debug("Trying: %s" % filename) classname = filename.lstrip('file_') #Import module @@ -278,7 +279,7 @@ processMain = getattr(module, classname) #Instantiate module processClass = processMain(self.parent, self.data_path) - isValid = processClass.testFile(import_filename) + isValid = processClass.testFile(import_filename) if isValid: logging.debug('<<') return processClass @@ -291,17 +292,17 @@ ''' Build tree view to hold files from which the activities are read ''' logging.debug('>>') store = gtk.ListStore( gobject.TYPE_STRING, - gobject.TYPE_BOOLEAN, + gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, ) column_names=["id", "", _("File"), _("Type"), _("Activities")] for column_index, column_name in enumerate(column_names): - if column_index == 1: + if column_index == 1: #Add button column self.renderer1 = gtk.CellRendererToggle() self.renderer1.set_property('activatable', True) - self.renderer1.connect( 'toggled', self.treeviewImportFiles_toggled_checkbox, store ) + self.renderer1.connect( 'toggled', self.treeviewImportFiles_toggled_checkbox, store ) column = gtk.TreeViewColumn(column_name, self.renderer1 ) column.add_attribute( self.renderer1, "active", column_index) column.set_sort_column_id(-1) @@ -318,25 +319,25 @@ self.treeviewImportFiles.set_model(store) logging.debug('<<') return store - + def build_activities_tree_view(self): ''' Build tree view to hold activities that can be selected for import ''' logging.debug('>>') store = gtk.ListStore( gobject.TYPE_STRING, - gobject.TYPE_BOOLEAN, + gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, gobject.TYPE_STRING ) column_names=["id", "", _("Start Time"), _("Distance"),_("Duration"),_("Sport"), _("Notes"), "file_id"] for column_index, column_name in enumerate(column_names): - if column_index == 1: + if column_index == 1: #Add checkbox column self.renderer1 = gtk.CellRendererToggle() self.renderer1.set_property('activatable', True) - self.renderer1.connect( 'toggled', self.treeviewImportEvents_toggled_checkbox, store ) + self.renderer1.connect( 'toggled', self.treeviewImportEvents_toggled_checkbox, store ) column = gtk.TreeViewColumn(column_name, self.renderer1 ) column.add_attribute( self.renderer1, "active", column_index) column.set_sort_column_id(-1) @@ -353,10 +354,10 @@ self.treeviewImportEvents.set_model(store) logging.debug('<<') return store - + def checkTreestoreForSelection(self, store): ''' - Function iterates over store checking if any items are selected + Function iterates over store checking if any items are selected returns True if at least one item is selected, False otherwise Checks item in position 1 only ''' @@ -371,7 +372,7 @@ ''' store[path][1] = not store[path][1] self.buttonRemoveSelectedFiles.set_sensitive(self.checkTreestoreForSelection(store)) - + def treeviewImportEvents_toggled_checkbox(self, cell, path, store): ''' Sets the state of the checkbox to true or false. @@ -390,7 +391,7 @@ if state: self.buttonFileImport.set_sensitive(1) else: - self.buttonFileImport.set_sensitive(0) + self.buttonFileImport.set_sensitive(0) def saveOptions(self): ''' @@ -407,13 +408,13 @@ elif self.radiobuttonPlugins.get_active(): self.defaulttab = "2" logging.debug("Saving default tab: %s, auto launch: %s" % (str(self.defaulttab), str(self.autoLaunchFileSelection))) - self.configuration.setValue("pytraining","import_default_tab",self.defaulttab) - self.configuration.setValue("pytraining","auto_launch_file_selection",self.autoLaunchFileSelection) + self.configuration.setValue("pytraining","import_default_tab",self.defaulttab) + self.configuration.setValue("pytraining","auto_launch_file_selection",self.autoLaunchFileSelection) #option def removeSelectedFiles(self): ''' - Function to determine which files are selected + Function to determine which files are selected * remove them from the list * remove the associated activities from the list also ''' @@ -439,11 +440,11 @@ logging.debug("Removing %d files from file tree view" % len(file_iters) ) for file_iter in file_iters: self.files_store.remove(file_iter) - + def getSelectedActivities(self): """ Function to determine which activities are selected - + Returns array of the ids of the selected activities """ selectedActivities = [] @@ -463,12 +464,12 @@ selectedActivities.append((activity_id, start_time, distance, duration, sport, gpx_file, file_id)) logging.debug( "Found %d selected activities to import" % len(selectedActivities) ) return selectedActivities - + def importSelectedActivities(self, activities): """ Function to import selected activity """ - + #selectedActivities.append((activity_id, start_time, distance, duration, sport, gpx_file)) logging.debug( "Importing %d activities" % len(activities)) list_sport = self.pytrainer_main.profile.getSportList() @@ -478,10 +479,10 @@ #Activity imported correctly duration = "%0.0f:%0.0f:%02.0f" % (float(activity["rcd_time"][0]), float(activity["rcd_time"][1]), float(activity["rcd_time"][2])) self.updateActivity(activity["activity_id"], activity["file_id"], - status = False, + status = False, notes = _("Imported into database"), - sport = activity["rcd_sport"], - distance = activity["rcd_distance"], + sport = activity["rcd_sport"], + distance = activity["rcd_distance"], duration = duration) #print "updating activity %s " % (str(activity)) @@ -513,18 +514,18 @@ def on_radiobuttonFile_toggled(self, *args): print "radio button toggled" - + def on_pluginsButton_Configure_clicked(self, button, pluginClass): ''' Handler for plugin Buttons ''' name,description,status = self.plugins.getPluginInfo(pluginClass) prefs = self.plugins.getPluginConfParams(pluginClass) - + self.prefwindow = gtk.Window() self.prefwindow.set_border_width(20) self.prefwindow.set_title(_("%s settings" %name)) - + table = gtk.Table(1,2) i=0 self.entryList = [] @@ -534,24 +535,24 @@ if pref[0] != "status": entry = gtk.Entry() entry.set_text(pref[1]) - self.entryList.append(entry) + self.entryList.append(entry) table.attach(entry,1,2,i,i+1) else: combobox = gtk.combo_box_new_text() - combobox.append_text(_("Disable")) - combobox.append_text(_("Enable")) + combobox.append_text(_("Disable")) + combobox.append_text(_("Enable")) combobox.set_active(int(pref[1])) table.attach(combobox,1,2,i,i+1) - self.entryList.append(combobox) + self.entryList.append(combobox) table.attach(label,0,1,i,i+1) i+=1 - + button = gtk.Button(_("Ok")) button.connect("clicked", self.on_pluginAcceptSettings_clicked, pluginClass) table.attach(button,0,2,i,i+1) self.prefwindow.add(table) self.prefwindow.show_all() - + def on_pluginsButton_Run_clicked(self, button, pluginClass): ''' Handler for plugin Buttons @@ -559,7 +560,7 @@ logging.debug('>>') self.pytrainer_main.runPlugin(button,pluginClass) logging.debug('<<') - + def on_pluginAcceptSettings_clicked(self, widget, pluginClass): ''' Duplicate of plugin settings accept handler @@ -581,7 +582,7 @@ self.plugins.setPluginConfParams(pluginClass,savedOptions) self.init_plugins_tab() logging.debug('<<') - + def treeviewImportEvents_header_checkbox(self, column, store): ''' Handler for click on checkbox column @@ -599,7 +600,7 @@ ''' Window closed ''' logging.debug('--') self.close_window() - + def on_notebookMainTabs_switch_page(self, notebook, page, new_page): logging.debug('--') #self.init_tab(new_page) @@ -625,7 +626,7 @@ logging.debug('>>') self.removeSelectedFiles() logging.debug('<<') - + def on_buttonFileImport_clicked(self, widget): ''' Import selected activities ''' logging.debug('>>') @@ -640,7 +641,7 @@ msgImported = _("Imported %d activities" % selectedCount) self.updateStatusbar(self.statusbarImportFile, msgImporting) logging.debug(msgImporting) - while gtk.events_pending(): # This allows the GUI to update + while gtk.events_pending(): # This allows the GUI to update gtk.main_iteration() # before completion of this entire action #for activity in selectedActivities: self.importSelectedActivities(selectedActivities) @@ -653,11 +654,11 @@ #md.destroy() self.buttonFileImport.set_sensitive(0) #Disable import button logging.debug('<<') - + def on_buttonSelectFiles_clicked(self, widget): logging.debug('>>') selectedFiles = fileChooserDialog(title=_("Choose a file (or files) to import activities from"), multiple=True).getFiles() - while gtk.events_pending(): # This allows the GUI to update + while gtk.events_pending(): # This allows the GUI to update gtk.main_iteration() # before completion of this entire action if selectedFiles is None or len(selectedFiles) == 0: #Nothing selected @@ -730,7 +731,7 @@ def on_buttonOptionsClose_clicked(self, widget): logging.debug('--') self.close_window() - + def on_buttonPluginsClose_clicked(self, widget): logging.debug('--') self.close_window() @@ -742,7 +743,7 @@ def on_comboboxDevice_changed(self, widget): logging.debug('--') self.detect_tools() - + def on_filechooserCSVImport_file_set(self, widget): logging.debug('--') filename = widget.get_filename() @@ -750,5 +751,28 @@ return self.updateStatusbar(self.statusbarCSVImport, "Got file: " + filename) #Enable buttons - - + self.buttonCSVProcess.set_sensitive(True) + + def on_buttonCSVProcess_clicked(self, widget): + #Get selected file + filename = self.filechooserCSVImport.get_filename() + if not os.path.isfile(filename): + return + #Determine delimiter + if self.rbCSVTab.get_active(): + delimiter = "\t" + elif self.rbCSVComma.get_active(): + delimiter = "," + elif self.rbCSVOther.get_active(): + delimiter = self.entryCSVOther.get_text() + else: + delimiter = " " + + #Read as delimited file + csvfile = open(filename, 'rb') + reader = csv.DictReader(csvfile, delimiter=delimiter) + for row in reader: + pass + #print reader.fieldnames + + Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-10 03:36:46 UTC (rev 688) +++ pytrainer/trunk/pytrainer/main.py 2010-11-10 09:35:17 UTC (rev 689) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#687" + self.version ="1.7.2_svn#689" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-10 21:59:06
|
Revision: 690 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=690&view=rev Author: jblance Date: 2010-11-10 21:59:00 +0000 (Wed, 10 Nov 2010) Log Message: ----------- CSV Import changes Modified Paths: -------------- pytrainer/trunk/glade/importdata.glade pytrainer/trunk/pytrainer/gui/windowimportdata.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/importdata.glade =================================================================== --- pytrainer/trunk/glade/importdata.glade 2010-11-10 09:35:17 UTC (rev 689) +++ pytrainer/trunk/glade/importdata.glade 2010-11-10 21:59:00 UTC (rev 690) @@ -1,4 +1,4 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="UTF-8"?> <glade-interface> <!-- interface-requires gtk+ 2.16 --> <!-- interface-naming-policy toplevel-contextual --> @@ -778,7 +778,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">5</property> - <property name="invisible_char">•</property> + <property name="invisible_char">•</property> <property name="width_chars">5</property> </widget> <packing> @@ -834,9 +834,198 @@ </packing> </child> <child> - <placeholder/> + <widget class="GtkFrame" id="frame1"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <child> + <widget class="GtkAlignment" id="alignment8"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <widget class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="n_rows">5</property> + <property name="n_columns">3</property> + <child> + <widget class="GtkLabel" id="labelCSVDate"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Date</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVDate"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVDistance"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Distance</property> + </widget> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVDuration"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Duration</property> + </widget> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVDistance"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVDuration"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVDataField"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>PyTrainer Field</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVFileCol"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>File Column</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="labelCSVColumns"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Map Columns</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">5</property> + <property name="position">3</property> + </packing> </child> <child> + <widget class="GtkHBox" id="hbox4"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <widget class="GtkButton" id="buttonCSVImport"> + <property name="label" translatable="yes">Import Data</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">4</property> + </packing> + </child> + <child> <widget class="GtkStatusbar" id="statusbarCSVImport"> <property name="visible">True</property> <property name="spacing">2</property> Modified: pytrainer/trunk/pytrainer/gui/windowimportdata.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowimportdata.py 2010-11-10 09:35:17 UTC (rev 689) +++ pytrainer/trunk/pytrainer/gui/windowimportdata.py 2010-11-10 21:59:00 UTC (rev 690) @@ -752,6 +752,7 @@ self.updateStatusbar(self.statusbarCSVImport, "Got file: " + filename) #Enable buttons self.buttonCSVProcess.set_sensitive(True) + self.buttonCSVImport.set_sensitive(True) def on_buttonCSVProcess_clicked(self, widget): #Get selected file @@ -770,9 +771,29 @@ #Read as delimited file csvfile = open(filename, 'rb') + #See if file has header row + has_header = csv.Sniffer().has_header(csvfile.read(1024)) + csvfile.seek(0) reader = csv.DictReader(csvfile, delimiter=delimiter) + #Read file to determine fields (must be a better way of doing this) for row in reader: pass - #print reader.fieldnames + #Build array of column names + if has_header: + #If the file has a header row, use the actual column names + columns = reader.fieldnames + else: + #Otherwise just label them with numbers + print len(reader.fieldnames) + columns = [_("Column %d") % x for x in range(0, len(reader.fieldnames))] + #print columns + + for column in columns: + self.cbCSVDate.append_text(column) + self.cbCSVDistance.append_text(column) + self.cbCSVDuration.append_text(column) + self.cbCSVDate.set_active(0) + self.cbCSVDistance.set_active(0) + self.cbCSVDuration.set_active(0) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-10 09:35:17 UTC (rev 689) +++ pytrainer/trunk/pytrainer/main.py 2010-11-10 21:59:00 UTC (rev 690) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#689" + self.version ="1.7.2_svn#690" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-11 02:26:16
|
Revision: 692 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=692&view=rev Author: jblance Date: 2010-11-11 02:26:09 +0000 (Thu, 11 Nov 2010) Log Message: ----------- Add delimited file import to unified import Modified Paths: -------------- pytrainer/trunk/glade/importdata.glade pytrainer/trunk/pytrainer/gui/windowimportdata.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/importdata.glade =================================================================== --- pytrainer/trunk/glade/importdata.glade 2010-11-10 22:01:21 UTC (rev 691) +++ pytrainer/trunk/glade/importdata.glade 2010-11-11 02:26:09 UTC (rev 692) @@ -842,139 +842,548 @@ <property name="visible">True</property> <property name="left_padding">12</property> <child> - <widget class="GtkTable" id="table1"> + <widget class="GtkScrolledWindow" id="scrolledwindow1"> <property name="visible">True</property> - <property name="n_rows">5</property> - <property name="n_columns">3</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">never</property> + <property name="vscrollbar_policy">automatic</property> <child> - <widget class="GtkLabel" id="labelCSVDate"> + <widget class="GtkViewport" id="viewport1"> <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label" translatable="yes">Date</property> + <property name="resize_mode">queue</property> + <property name="shadow_type">none</property> + <child> + <widget class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="n_rows">16</property> + <property name="n_columns">3</property> + <child> + <widget class="GtkLabel" id="labelCSVDate"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Date</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVDate"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVDistance"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Distance (km)</property> + </widget> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVDuration"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Duration (sec)</property> + </widget> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVDistance"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVDuration"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVDataField"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>PyTrainer Field</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVFileCol"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>File Column</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVTitle"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Title</property> + </widget> + <packing> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVDescent"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Descent (m)</property> + </widget> + <packing> + <property name="top_attach">10</property> + <property name="bottom_attach">11</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVAccent"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Accent (m)</property> + </widget> + <packing> + <property name="top_attach">9</property> + <property name="bottom_attach">10</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVCalories"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Calories (kcal)</property> + </widget> + <packing> + <property name="top_attach">8</property> + <property name="bottom_attach">9</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVMaxSpeed"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Max Speed (km/h)</property> + </widget> + <packing> + <property name="top_attach">7</property> + <property name="bottom_attach">8</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVAvgSpeed"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Average Speed (km/h)</property> + </widget> + <packing> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVSport"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Sport</property> + </widget> + <packing> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVHR"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Average Heartrate (bpm)</property> + </widget> + <packing> + <property name="top_attach">11</property> + <property name="bottom_attach">12</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVMaxHR"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Max Heartrate (bpm)</property> + </widget> + <packing> + <property name="top_attach">12</property> + <property name="bottom_attach">13</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVPace"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Pace (min/km)</property> + </widget> + <packing> + <property name="top_attach">13</property> + <property name="bottom_attach">14</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVMaxPace"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Max Pace (min/km)</property> + </widget> + <packing> + <property name="top_attach">14</property> + <property name="bottom_attach">15</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelCSVComments"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Comments</property> + </widget> + <packing> + <property name="top_attach">15</property> + <property name="bottom_attach">16</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVTitle"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVSport"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVAvgSpeed"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVMaxSpeed"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">7</property> + <property name="bottom_attach">8</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVCal"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">8</property> + <property name="bottom_attach">9</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVAccent"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">9</property> + <property name="bottom_attach">10</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVDescent"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">10</property> + <property name="bottom_attach">11</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVHR"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">11</property> + <property name="bottom_attach">12</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVMaxHR"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">12</property> + <property name="bottom_attach">13</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVPace"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">13</property> + <property name="bottom_attach">14</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVMaxPace"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">14</property> + <property name="bottom_attach">15</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cbCSVComments"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">Exclude</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">15</property> + <property name="bottom_attach">16</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkHBox" id="hbox5"> + <property name="visible">True</property> + <child> + <widget class="GtkCheckButton" id="checkbCSVForceSport"> + <property name="label" translatable="yes">Force sport to:</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="comboCSVForceSport"> + <property name="visible">True</property> + <property name="items" translatable="yes"> </property> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </widget> + </child> </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> </child> - <child> - <widget class="GtkComboBox" id="cbCSVDate"> - <property name="visible">True</property> - <property name="active">0</property> - <property name="items" translatable="yes">Exclude</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options"></property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelCSVDistance"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label" translatable="yes">Distance</property> - </widget> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelCSVDuration"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label" translatable="yes">Duration</property> - </widget> - <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkComboBox" id="cbCSVDistance"> - <property name="visible">True</property> - <property name="active">0</property> - <property name="items" translatable="yes">Exclude</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options"></property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkComboBox" id="cbCSVDuration"> - <property name="visible">True</property> - <property name="active">0</property> - <property name="items" translatable="yes">Exclude</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options"></property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelCSVDataField"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>PyTrainer Field</b></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelCSVFileCol"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>File Column</b></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> </widget> </child> </widget> @@ -999,18 +1408,28 @@ <widget class="GtkHBox" id="hbox4"> <property name="visible">True</property> <child> - <placeholder/> + <widget class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes"><small>This is an experiemental import for delimited files +1) Select a file +2) Click 'Read File' to analyse the file +3) Map columns in the file to pytrainer data elements (Date is required) +4) Click 'Import Data'</small></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="position">0</property> + </packing> </child> <child> - <placeholder/> - </child> - <child> <widget class="GtkButton" id="buttonCSVImport"> <property name="label" translatable="yes">Import Data</property> <property name="visible">True</property> <property name="sensitive">False</property> <property name="can_focus">True</property> <property name="receives_default">True</property> + <signal name="clicked" handler="on_buttonCSVImport_clicked"/> </widget> <packing> <property name="expand">False</property> Modified: pytrainer/trunk/pytrainer/gui/windowimportdata.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowimportdata.py 2010-11-10 22:01:21 UTC (rev 691) +++ pytrainer/trunk/pytrainer/gui/windowimportdata.py 2010-11-11 02:26:09 UTC (rev 692) @@ -25,9 +25,11 @@ import types from lxml import etree import csv +import locale from pytrainer.plugins import Plugins from pytrainer.gui.dialogs import fileChooserDialog +from pytrainer.lib.date import Date class WindowImportdata(SimpleGladeApp): def __init__(self, data_path = None, parent=None, config=None, pytrainer_main=None): @@ -68,7 +70,7 @@ def init_all_tabs(self): logging.debug(">>") - tabs = (0,1,2,3) + tabs = (0,1,2,3,4) for tab in tabs: self.init_tab(tab) @@ -88,6 +90,9 @@ elif page == 3: #'Options' tab self.init_options_tab() + elif page == 4: + #'CSV Import' tab + self.init_csvimport_tab() else: #unknown tab logging.error("Unknown page %d passed to init_tab" % page) @@ -193,6 +198,19 @@ self.checkbuttonAutoLaunch.set_active(1) logging.debug("<<") return + + def init_csvimport_tab(self): + logging.debug(">>") + #Populate Force Sport to combobox + sport_list = self.pytrainer_main.profile.getSportList() + #Remove placeholder item (needed to ensure correct model for combobox) + self.comboCSVForceSport.remove_text(0) + for sport in sport_list: + logging.debug('Adding sport: %s' % sport[0]) + self.comboCSVForceSport.append_text(sport[0]) + self.comboCSVForceSport.set_active(0) + logging.debug("<<") + return def detect_tools(self): ''' @@ -755,31 +773,32 @@ self.buttonCSVImport.set_sensitive(True) def on_buttonCSVProcess_clicked(self, widget): + logging.debug('>>') #Get selected file - filename = self.filechooserCSVImport.get_filename() - if not os.path.isfile(filename): + self.CSVfilename = self.filechooserCSVImport.get_filename() + if not os.path.isfile(self.CSVfilename): return #Determine delimiter if self.rbCSVTab.get_active(): - delimiter = "\t" + self.delimiter = "\t" elif self.rbCSVComma.get_active(): - delimiter = "," + self.delimiter = "," elif self.rbCSVOther.get_active(): - delimiter = self.entryCSVOther.get_text() + self.delimiter = self.entryCSVOther.get_text() else: - delimiter = " " + self.delimiter = " " #Read as delimited file - csvfile = open(filename, 'rb') + csvfile = open(self.CSVfilename, 'rb') #See if file has header row - has_header = csv.Sniffer().has_header(csvfile.read(1024)) + self.has_header = csv.Sniffer().has_header(csvfile.read(1024)) csvfile.seek(0) - reader = csv.DictReader(csvfile, delimiter=delimiter) + reader = csv.DictReader(csvfile, delimiter=self.delimiter) #Read file to determine fields (must be a better way of doing this) for row in reader: pass #Build array of column names - if has_header: + if self.has_header: #If the file has a header row, use the actual column names columns = reader.fieldnames else: @@ -792,8 +811,182 @@ self.cbCSVDate.append_text(column) self.cbCSVDistance.append_text(column) self.cbCSVDuration.append_text(column) + self.cbCSVTitle.append_text(column) + self.cbCSVSport.append_text(column) + self.cbCSVAvgSpeed.append_text(column) + self.cbCSVMaxSpeed.append_text(column) + self.cbCSVCal.append_text(column) + self.cbCSVAccent.append_text(column) + self.cbCSVDescent.append_text(column) + self.cbCSVHR.append_text(column) + self.cbCSVMaxHR.append_text(column) + self.cbCSVPace.append_text(column) + self.cbCSVMaxPace.append_text(column) + self.cbCSVComments.append_text(column) self.cbCSVDate.set_active(0) self.cbCSVDistance.set_active(0) self.cbCSVDuration.set_active(0) + self.cbCSVTitle.set_active(0) + self.cbCSVSport.set_active(0) + self.cbCSVAvgSpeed.set_active(0) + self.cbCSVMaxSpeed.set_active(0) + self.cbCSVCal.set_active(0) + self.cbCSVAccent.set_active(0) + self.cbCSVDescent.set_active(0) + self.cbCSVHR.set_active(0) + self.cbCSVMaxHR.set_active(0) + self.cbCSVPace.set_active(0) + self.cbCSVMaxPace.set_active(0) + self.cbCSVComments.set_active(0) + logging.debug('<<') + def on_buttonCSVImport_clicked(self, widget): + logging.debug('>>') + #Determine values + dateCol = self.cbCSVDate.get_active() + distanceCol = self.cbCSVDistance.get_active() + durationCol = self.cbCSVDuration.get_active() + titleCol = self.cbCSVTitle.get_active() + sportCol = self.cbCSVSport.get_active() + avgspeedCol = self.cbCSVAvgSpeed.get_active() + maxspeedCol = self.cbCSVMaxSpeed.get_active() + calCol = self.cbCSVCal.get_active() + accCol = self.cbCSVAccent.get_active() + desCol = self.cbCSVDescent.get_active() + hrCol = self.cbCSVHR.get_active() + maxHRCol = self.cbCSVMaxHR.get_active() + paceCol = self.cbCSVPace.get_active() + maxPaceCol = self.cbCSVMaxPace.get_active() + commentsCol = self.cbCSVComments.get_active() + + #print dateCol, distanceCol, durationCol, titleCol, sportCol, avgspeedCol, maxspeedCol, calCol, accCol, desCol, hrCol, maxHRCol, paceCol, maxPaceCol, commentsCol + + if dateCol == 0: + #Error need to have at least a date + self.updateStatusbar(self.statusbarCSVImport, "ERROR: Must define at least a date column") + return + + #Import... + #Get selected file + if not os.path.isfile(self.CSVfilename): + return + #Read as delimited file + csvfile = open(self.CSVfilename, 'rb') + reader = csv.reader(csvfile, delimiter=self.delimiter) + #Process File + + for i, row in enumerate(reader): + if self.has_header and i==0: + #Ignore first row + continue + data = {} + #Determine dates + _date = Date().getDateTime(row[dateCol-1]) + #year, month, day = date.split("-") + date = _date[1].strftime("%Y-%m-%d") + zuluDateTime = _date[0].strftime("%Y-%m-%dT%H:%M:%SZ") + localDateTime = str(_date[1]) + data['date'] = date + data['date_time_utc'] = zuluDateTime + data['date_time_local'] = localDateTime + if distanceCol: + try: + data['distance'] = locale.atof(row[distanceCol-1]) + except: + pass + if durationCol: + #calculate duration in sec... + _duration = row[durationCol-1] + if _duration.count(':') == 2: + #Have 00:00:00 duration + h, m, s = _duration.split(':') + try: + durationSec = int(h)*3600 + int(m)*60 + int(s) + except: + logging.debug("Error calculating duration for '%s'" % _duration) + print("Error calculating duration for '%s'" % _duration) + durationSec = None + else: + try: + durationSec = locale.atoi(_duration) + except: + #Unknown duration + logging.debug("Could not determine duration for '%s'" % _duration) + print("Could not determine duration for '%s'" % _duration) + durationSec = None + if durationSec is not None: + data['duration'] = durationSec + data['time'] = str(durationSec) + if titleCol: + data['title'] = row[titleCol-1] + if self.checkbCSVForceSport.get_active(): + sport_id = self.pytrainer_main.record.getSportId(self.comboCSVForceSport.get_active_text(),add=True) + data['sport'] = sport_id + elif sportCol: + #retrieving sport id (adding sport if it doesn't exist yet) + sport_id = self.pytrainer_main.record.getSportId(row[sportCol-1],add=True) + data['sport'] = sport_id + else: + self.comboCSVForceSport.set_active(0) + sport_id = self.pytrainer_main.record.getSportId(self.comboCSVForceSport.get_active_text(),add=True) + data['sport'] = sport_id + + if avgspeedCol: + # + try: + data['average'] = locale.atof(row[avgspeedCol-1]) + except: + pass + if maxspeedCol: + try: + data['maxspeed'] = locale.atof(row[maxspeedCol-1]) + except: + pass + if calCol: + try: + data['calories'] = locale.atoi(row[calCol-1]) + except: + pass + if accCol: + try: + data['upostive'] = locale.atof(row[accCol-1]) + except: + pass + if desCol: + try: + data['unegative'] = locale.atof(row[desCol-1]) + except: + pass + if hrCol: + try: + data['beats'] = locale.atof(row[hrCol-1]) + except: + pass + if maxHRCol: + try: + data['maxbeats'] = locale.atof(row[maxHRCol-1]) + except: + pass + if paceCol: + try: + data['pace'] = locale.atof(row[paceCol-1]) + except: + pass + if maxPaceCol: + try: + data['maxpace'] = locale.atof(row[maxPaceCol-1]) + except: + pass + if commentsCol: + data['comments'] = row[commentsCol-1] + + #Insert into DB + print "Data", data + self.pytrainer_main.ddbb.insert_dict('records', data) + #Display message.... + self.updateStatusbar(self.statusbarCSVImport, "Import completed. %d rows processed" % i) + #Disable import button + self.buttonCSVImport.set_sensitive(0) + + logging.debug('<<') Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-10 22:01:21 UTC (rev 691) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-11 02:26:09 UTC (rev 692) @@ -971,7 +971,10 @@ gobject.TYPE_INT, object) for i in record_list: - hour,min,sec = date.second2time(int(i[6])) + try: + hour,min,sec = date.second2time(int(i[6])) + except (ValueError, TypeError): + hour,min,sec = (0,0,0) _time = "%2d:%02d:%02d" %(hour,min,sec) #original # experimental only if hour >0: @@ -987,11 +990,20 @@ continue _title = str(i[3]) _date = str(i[0]) - _distance = float(i[1]) + try: + _distance = float(i[1]) + except (ValueError, TypeError): + _distance = 0 _sport = str(i[4]) - _average = float(i[2]) - _calories = int(i[8]) try: + _average = float(i[2]) + except (ValueError, TypeError): + _average = 0 + try: + _calories = int(i[8]) + except (ValueError, TypeError): + _calories = 0 + try: _beats = round(float(i[7])) except (ValueError, TypeError) as e: logging.debug("Unable to parse beats for %s" % str(i[7]) ) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-10 22:01:21 UTC (rev 691) +++ pytrainer/trunk/pytrainer/main.py 2010-11-11 02:26:09 UTC (rev 692) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#690" + self.version ="1.7.2_svn#692" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2010-11-11 11:09:18
|
Revision: 698 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=698&view=rev Author: ncjones Date: 2010-11-11 11:09:12 +0000 (Thu, 11 Nov 2010) Log Message: ----------- Display message when no equipment items are active. Modified Paths: -------------- pytrainer/trunk/glade/newrecord.glade pytrainer/trunk/pytrainer/gui/windowrecord.py Modified: pytrainer/trunk/glade/newrecord.glade =================================================================== --- pytrainer/trunk/glade/newrecord.glade 2010-11-11 09:36:29 UTC (rev 697) +++ pytrainer/trunk/glade/newrecord.glade 2010-11-11 11:09:12 UTC (rev 698) @@ -1107,32 +1107,79 @@ <property name="label_xalign">0</property> <property name="shadow_type">none</property> <child> - <widget class="GtkAlignment" id="alignmentRecordEquipment"> + <widget class="GtkVBox" id="vbox1"> <property name="visible">True</property> - <property name="left_padding">12</property> <child> - <widget class="GtkTable" id="table1"> + <widget class="GtkAlignment" id="noActiveEquipmentMessageContainer"> + <property name="left_padding">12</property> + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="border_width">5</property> + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="xpad">5</property> + <property name="ypad">5</property> + <property name="stock">gtk-info</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label10"> + <property name="visible">True</property> + <property name="label" translatable="yes"><i>There are no active equipment items.</i></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + </widget> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkAlignment" id="alignmentRecordEquipment"> <property name="visible">True</property> - <property name="border_width">5</property> + <property name="left_padding">12</property> <child> - <widget class="GtkScrolledWindow" id="scrolledwindow1"> + <widget class="GtkTable" id="table1"> <property name="visible">True</property> - <property name="can_focus">True</property> <property name="border_width">5</property> - <property name="hscrollbar_policy">automatic</property> - <property name="vscrollbar_policy">automatic</property> - <property name="shadow_type">in</property> <child> - <widget class="GtkTreeView" id="treeviewRecordEquipment"> + <widget class="GtkScrolledWindow" id="scrolledwindow1"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="headers_visible">False</property> - <property name="headers_clickable">False</property> + <property name="border_width">5</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <widget class="GtkTreeView" id="treeviewRecordEquipment"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + </widget> + </child> </widget> </child> </widget> </child> </widget> + <packing> + <property name="position">1</property> + </packing> </child> </widget> </child> Modified: pytrainer/trunk/pytrainer/gui/windowrecord.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-11-11 09:36:29 UTC (rev 697) +++ pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-11-11 11:09:12 UTC (rev 698) @@ -101,8 +101,11 @@ def _init_equipment(self, selected_equipment, equipment_service): equipment = {} - for item in equipment_service.get_active_equipment(): + active_equipment = equipment_service.get_active_equipment() + for item in active_equipment: equipment[item] = False + if len(active_equipment) == 0: + self.noActiveEquipmentMessageContainer.set_visible(True) for item in selected_equipment: equipment[item] = True list_store = gtk.ListStore(int, str, bool) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2010-11-11 11:32:53
|
Revision: 699 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=699&view=rev Author: ncjones Date: 2010-11-11 11:32:47 +0000 (Thu, 11 Nov 2010) Log Message: ----------- Edit equipment when double clicked. Modified Paths: -------------- pytrainer/trunk/glade/equipment.glade pytrainer/trunk/pytrainer/gui/equipment.py Modified: pytrainer/trunk/glade/equipment.glade =================================================================== --- pytrainer/trunk/glade/equipment.glade 2010-11-11 11:09:12 UTC (rev 698) +++ pytrainer/trunk/glade/equipment.glade 2010-11-11 11:32:47 UTC (rev 699) @@ -30,6 +30,7 @@ <object class="GtkTreeView" id="treeviewEquipmentList"> <property name="visible">True</property> <property name="can_focus">True</property> + <signal name="row_activated" handler="equipment_row_activated"/> </object> </child> </object> Modified: pytrainer/trunk/pytrainer/gui/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/gui/equipment.py 2010-11-11 11:09:12 UTC (rev 698) +++ pytrainer/trunk/pytrainer/gui/equipment.py 2010-11-11 11:32:47 UTC (rev 699) @@ -97,6 +97,7 @@ "cancel_add_equipment_clicked": self._cancel_add_equipment_clicked, "confirm_add_equipment_clicked": self._confirm_add_equipment_clicked, "edit_equipment_clicked": self._edit_equipment_clicked, + "equipment_row_activated": self._edit_equipment_clicked, "cancel_edit_equipment_clicked": self._cancel_edit_equipment_clicked, "confirm_edit_equipment_clicked": self._confirm_edit_equipment_clicked, "delete_equipment_clicked": self._delete_equipment_clicked, @@ -154,7 +155,7 @@ self._equipment_store.add_equipment(new_equipment) self.show_page_equipment_list() - def _edit_equipment_clicked(self, widget): + def _edit_equipment_clicked(self, widget, *args): item = self._get_selected_equipment_item() self._builder.get_object("entryEquipmentEditDescription").set_text(item.description) self._builder.get_object("entryEquipmentEditLifeExpectancy").set_text(str(item.life_expectancy)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <aza...@us...> - 2010-11-12 14:57:10
|
Revision: 704 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=704&view=rev Author: azapletal Date: 2010-11-12 14:56:56 +0000 (Fri, 12 Nov 2010) Log Message: ----------- Applied uc to windowrecord (WIP) Modified Paths: -------------- pytrainer/trunk/glade/newrecord.glade pytrainer/trunk/pytrainer/gui/windowrecord.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/newrecord.glade =================================================================== --- pytrainer/trunk/glade/newrecord.glade 2010-11-12 07:27:52 UTC (rev 703) +++ pytrainer/trunk/glade/newrecord.glade 2010-11-12 14:56:56 UTC (rev 704) @@ -216,7 +216,7 @@ <property name="column_spacing">5</property> <property name="row_spacing">5</property> <child> - <widget class="GtkLabel" id="label8"> + <widget class="GtkLabel" id="label_rcd_distance"> <property name="width_request">120</property> <property name="visible">True</property> <property name="xalign">0</property> @@ -517,7 +517,7 @@ <property name="column_spacing">5</property> <property name="row_spacing">5</property> <child> - <widget class="GtkLabel" id="label134"> + <widget class="GtkLabel" id="label_rcd_maxvel"> <property name="width_request">120</property> <property name="visible">True</property> <property name="xalign">0</property> @@ -543,7 +543,7 @@ </packing> </child> <child> - <widget class="GtkLabel" id="label133"> + <widget class="GtkLabel" id="label_rcd_average"> <property name="visible">True</property> <property name="xalign">0</property> <property name="label" translatable="yes">Average (km/h)</property> @@ -640,7 +640,7 @@ <property name="column_spacing">5</property> <property name="row_spacing">5</property> <child> - <widget class="GtkLabel" id="label138"> + <widget class="GtkLabel" id="label_rcd_maxpace"> <property name="width_request">110</property> <property name="visible">True</property> <property name="xalign">0</property> @@ -666,7 +666,7 @@ </packing> </child> <child> - <widget class="GtkLabel" id="label137"> + <widget class="GtkLabel" id="label_rcd_pace"> <property name="width_request">110</property> <property name="visible">True</property> <property name="xalign">0</property> @@ -748,7 +748,7 @@ <property name="column_spacing">5</property> <property name="row_spacing">5</property> <child> - <widget class="GtkLabel" id="label139"> + <widget class="GtkLabel" id="label_rcd_upositive"> <property name="width_request">110</property> <property name="visible">True</property> <property name="xalign">0</property> @@ -774,7 +774,7 @@ </packing> </child> <child> - <widget class="GtkLabel" id="label140"> + <widget class="GtkLabel" id="label_rcd_unegative"> <property name="width_request">110</property> <property name="visible">True</property> <property name="xalign">0</property> @@ -1273,3 +1273,5 @@ </child> </widget> </glade-interface> + + Modified: pytrainer/trunk/pytrainer/gui/windowrecord.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-11-12 07:27:52 UTC (rev 703) +++ pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-11-12 14:56:56 UTC (rev 704) @@ -35,9 +35,9 @@ logging.debug(">>") self.parent = parent self.pytrainer_main = parent.pytrainer_main - self.us = self.pytrainer_main.profile.prf_us_system + #self.us = self.pytrainer_main.profile.prf_us_system #DEPRECATED self.uc = UC() - logging.debug("Using US system: "+ str(self.us)) + logging.debug("Using US system: "+ str(self.uc.us)) self.data_path = data_path glade_path="glade/newrecord.glade" root = "newrecord" @@ -80,24 +80,28 @@ self.rcd_title.set_text(title) if distance != None: #self.rcd_distance.set_text(distance) - myset_text(rcd_distance, 'distance', distance, us=self.us, round=2) + #myset_text(rcd_distance, 'distance', distance, us=self.us, round=2) + self.rcd_distance.set_text(self.uc.distance(distance)) if time != None: self.setTime(time) if distance!=None and time!=None: self.on_calcaverage_clicked(None) if upositive != None: - self.rcd_upositive.set_text(upositive) + self.rcd_upositive.set_text(self.uc.height(upositive)) if unegative != None: - self.rcd_unegative.set_text(unegative) + self.rcd_unegative.set_text(self.uc.height(unegative)) if calories != None: self.rcd_calories.set_text(calories) - #populate labels with units - # test only - #if self.us: - # self.label8.set_text('Distance (mi)') - #else: - # self.label8.set_text('Distance (km)') - self.label8.set_text('Distance [%s]' %self.uc.unit_distance) + + #populate labels with units + self.label_rcd_distance.set_text('Distance (%s)' %self.uc.unit_distance) + self.label_rcd_maxvel.set_text('Max (%s)' %self.uc.unit_speed) + self.label_rcd_average.set_text('Average (%s)' %self.uc.unit_speed) + self.label_rcd_maxpace.set_text('Max (%s)' %self.uc.unit_pace) + self.label_rcd_pace.set_text('Pace (%s)' %self.uc.unit_pace) + self.label_rcd_upositive.set_text('Ascent (%s)' %self.uc.unit_height) + self.label_rcd_unegative.set_text('Descent (%s)' %self.uc.unit_height) + self._init_equipment(equipment, equipment_service) logging.debug("<<") @@ -252,18 +256,25 @@ trackSummary = {} list_options["rcd_date"] = self.rcd_date.get_text() list_options["rcd_sport"] = self.rcd_sport.get_active_text() - list_options["rcd_distance"] = self.rcd_distance.get_text() + list_options["rcd_distance"] = self.uc.usr2sys('distance', self.rcd_distance.get_text()) list_options["rcd_beats"] = self.rcd_beats.get_text() - list_options["rcd_average"] = self.rcd_average.get_text() + list_options["rcd_average"] = self.uc.usr2sys('speed', self.rcd_average.get_text()) list_options["rcd_calories"] = self.rcd_calories.get_text() list_options["rcd_title"] = self.rcd_title.get_text().replace("\"","'") list_options["rcd_gpxfile"] = self.rcd_gpxfile.get_text() - list_options["rcd_upositive"] = self.rcd_upositive.get_text() - list_options["rcd_unegative"] = self.rcd_unegative.get_text() + list_options["rcd_upositive"] = self.uc.usr2sys('height', self.rcd_upositive.get_text()) + list_options["rcd_unegative"] = self.uc.usr2sys('height', self.rcd_unegative.get_text()) list_options["rcd_maxbeats"] = self.rcd_maxbeats.get_text() - list_options["rcd_pace"] = self.rcd_pace.get_text() - list_options["rcd_maxpace"] = self.rcd_maxpace.get_text() - list_options["rcd_maxvel"] = self.rcd_maxvel.get_text() + + # tricky for uc as rcd_pace is in min:sec + _p1 = self.parent.pace_to_float(self.rcd_pace.get_text()) + _p2 = self.parent.pace_from_float(self.uc.pace(_p1)) + list_options["rcd_pace"] = _p2 #self.rcd_pace.get_text() + _p1 = self.parent.pace_to_float(self.rcd_maxpace.get_text()) + _p2 = self.parent.pace_from_float(self.uc.pace(_p1)) + list_options["rcd_maxpace"] = _p2#self.rcd_maxpace.get_text() + + list_options["rcd_maxvel"] = self.uc.usr2sys('speed', self.rcd_maxvel.get_text()) list_options["rcd_time"] = [self.rcd_hour.get_value_as_int(),self.rcd_min.get_value_as_int(),self.rcd_second.get_value_as_int()] buffer = self.rcd_comments.get_buffer() start,end = buffer.get_bounds() @@ -340,16 +351,18 @@ self.rcd_min.set_value(m) self.rcd_second.set_value(s) self.rcd_date.set_text(activity.date) + #self.rcd_distance.set_text("%.2f"%activity.distance) - myset_text(self.rcd_distance, 'distance', activity.distance, us=self.us, round=2) - self.rcd_average.set_text("%.2f"%activity.average) + #myset_text(self.rcd_distance, 'distance', activity.distance, us=self.us, round=2) + self.rcd_distance.set_text("%.2f" %self.uc.distance(activity.distance)) + self.rcd_average.set_text("%.2f" %self.uc.speed(activity.average)) self.rcd_calories.set_text("%s"%activity.calories) self.rcd_beats.set_text("%s"%activity.beats) - self.rcd_upositive.set_text("%.2f"%activity.upositive) - self.rcd_unegative.set_text("%.2f"%activity.unegative) - self.rcd_maxvel.set_text("%.2f"%activity.maxspeed) - self.rcd_maxpace.set_text("%s"%self.parent.pace_from_float(activity.maxpace)) - self.rcd_pace.set_text("%s"%self.parent.pace_from_float(activity.pace)) + self.rcd_upositive.set_text("%.2f" %self.uc.height(activity.upositive)) + self.rcd_unegative.set_text("%.2f" %self.uc.height(activity.unegative)) + self.rcd_maxvel.set_text("%.2f" %self.uc.speed(activity.maxspeed)) + self.rcd_maxpace.set_text("%s" %self.parent.pace_from_float(self.uc.pace(activity.maxpace))) + self.rcd_pace.set_text("%s" %self.parent.pace_from_float(self.uc.pace(activity.pace))) self.rcd_maxbeats.set_text("%s"%activity.maxbeats) self.rcd_title.set_text(activity.title) @@ -361,9 +374,9 @@ start,end = buffer.get_bounds() buffer.set_text(activity.comments) if activity.gpx_file is not None: - self.rcd_gpxfile.set_text(activity.gpx_file) - self.frameGeneral.set_sensitive(0) #Currently record values not changed if a GPX file is present - self.frameVelocity.set_sensitive(0) #Greying out options to indicate this to user + self.rcd_gpxfile.set_text(activity.gpx_file) + self.frameGeneral.set_sensitive(0) #Currently record values not changed if a GPX file is present + self.frameVelocity.set_sensitive(0) #Greying out options to indicate this to user logging.debug("<<") def setValues(self,values): @@ -660,9 +673,9 @@ pass def set_distance(self,distance): - #self.rcd_distance.set_text("%0.2f" %distance) - myset_text(rcd_distance, 'distance', distance, us=self.us, round=2) - + self.rcd_distance.set_text("%0.2f" %distance) + #myset_text(rcd_distance, 'distance', distance, us=self.us, round=2) + def set_maxspeed(self,vel): self.rcd_maxvel.set_text("%0.2f" %vel) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-12 07:27:52 UTC (rev 703) +++ pytrainer/trunk/pytrainer/main.py 2010-11-12 14:56:56 UTC (rev 704) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#703" + self.version ="1.7.2_svn#704" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2010-11-14 03:42:59
|
Revision: 706 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=706&view=rev Author: ncjones Date: 2010-11-14 03:42:46 +0000 (Sun, 14 Nov 2010) Log Message: ----------- Tolerate non-unicode strings returned from DB. This is necessary for MySql support. Modified Paths: -------------- pytrainer/trunk/pytrainer/equipment.py pytrainer/trunk/test/pytrainer/equipment_test.py Modified: pytrainer/trunk/pytrainer/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/equipment.py 2010-11-12 21:33:27 UTC (rev 705) +++ pytrainer/trunk/pytrainer/equipment.py 2010-11-14 03:42:46 UTC (rev 706) @@ -155,11 +155,11 @@ equipment = Equipment() (id, description, active, life_expectancy, prior_usage, notes) = row equipment.id = id - equipment.description = description + equipment.description = unicode(description) equipment.active = bool(active) equipment.life_expectancy = life_expectancy equipment.prior_usage = prior_usage - equipment.notes = notes + equipment.notes = unicode(notes) return equipment def store_equipment(self, equipment): Modified: pytrainer/trunk/test/pytrainer/equipment_test.py =================================================================== --- pytrainer/trunk/test/pytrainer/equipment_test.py 2010-11-12 21:33:27 UTC (rev 705) +++ pytrainer/trunk/test/pytrainer/equipment_test.py 2010-11-14 03:42:46 UTC (rev 706) @@ -209,6 +209,12 @@ self.assertEquals(200, item.prior_usage) self.assertEquals("Test notes.", item.notes) + def test_get_equipment_item_non_unicode(self): + self.mock_ddbb.select.return_value = [(1, "Test Description", True, 500, 200, "Test notes.")] + item = self.equipment_service.get_equipment_item(1) + self.assertEquals("Test Description", item.description) + self.assertEquals("Test notes.", item.notes) + def test_get_equipment_item_non_existant(self): self.mock_ddbb.select.return_value = [] item = self.equipment_service.get_equipment_item(1) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2010-11-14 07:49:13
|
Revision: 707 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=707&view=rev Author: ncjones Date: 2010-11-14 07:49:02 +0000 (Sun, 14 Nov 2010) Log Message: ----------- Remove "--equip" start up parameter. Modified Paths: -------------- pytrainer/trunk/glade/profile.glade pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/profile.glade =================================================================== --- pytrainer/trunk/glade/profile.glade 2010-11-14 03:42:46 UTC (rev 706) +++ pytrainer/trunk/glade/profile.glade 2010-11-14 07:49:02 UTC (rev 707) @@ -1738,7 +1738,7 @@ <child> <widget class="GtkTable" id="table1"> <property name="visible">True</property> - <property name="n_rows">7</property> + <property name="n_rows">6</property> <property name="n_columns">3</property> <child> <widget class="GtkLabel" id="labelLogLevel"> @@ -1872,12 +1872,12 @@ </packing> </child> <child> - <widget class="GtkLabel" id="labelEquip"> + <widget class="GtkLabel" id="labelNewGraph"> <property name="visible">True</property> <property name="xalign">0</property> <property name="xpad">5</property> <property name="ypad">5</property> - <property name="label" translatable="yes">Equipment handling</property> + <property name="label" translatable="yes">New Graph</property> </widget> <packing> <property name="top_attach">5</property> @@ -1885,51 +1885,6 @@ </packing> </child> <child> - <widget class="GtkCheckButton" id="checkbuttonEquip"> - <property name="label">--equip</property> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">False</property> - <property name="receives_default">False</property> - <property name="draw_indicator">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="x_padding">10</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelEquipDescription"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="label" translatable="yes"><small>Want to track equipment?</small></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelNewGraph"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="ypad">5</property> - <property name="label" translatable="yes">New Graph</property> - </widget> - <packing> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - </packing> - </child> - <child> <widget class="GtkCheckButton" id="checkbuttonNewGraph"> <property name="label">--newgraph</property> <property name="visible">True</property> @@ -1941,8 +1896,8 @@ <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> <property name="x_padding">10</property> </packing> </child> @@ -1957,8 +1912,8 @@ <packing> <property name="left_attach">2</property> <property name="right_attach">3</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> </packing> </child> <child> Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-14 03:42:46 UTC (rev 706) +++ pytrainer/trunk/pytrainer/main.py 2010-11-14 07:49:02 UTC (rev 707) @@ -121,7 +121,6 @@ parser.add_option("-w", "--warn", action="store_const", const=logging.WARNING, dest="log_level", help="enable logging at warning level") parser.add_option("--valid", action="store_true", dest="validate", help="enable validation of files imported by plugins (details at info or debug logging level) - note plugin must support validation") parser.add_option("--check", action="store_true", dest="check", help="triggers database (only sqlite based) and configuration file sanity checks, adding fields if necessary. Backup of database is done before any change. Details at info or debug logging level") - parser.add_option("--equip", action="store_false", dest="equip", help="EXPERIMENTAL: enable equipment management") parser.add_option("--newgraph", action="store_true", dest="newgraph", help="EXPERIMENTAL: new graphing approach") (options, args) = parser.parse_args() return options This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2010-11-14 08:24:24
|
Revision: 708 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=708&view=rev Author: ncjones Date: 2010-11-14 08:24:12 +0000 (Sun, 14 Nov 2010) Log Message: ----------- Remove unused equipment graphing tab. Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-14 07:49:02 UTC (rev 707) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-14 08:24:12 UTC (rev 708) @@ -5111,86 +5111,6 @@ </packing> </child> <child> - <widget class="GtkVBox" id="equipview"> - <property name="visible">True</property> - <child> - <widget class="GtkHBox" id="hbox6"> - <property name="visible">True</property> - <property name="border_width">5</property> - <property name="spacing">8</property> - <child> - <widget class="GtkLabel" id="label19"> - <property name="visible">True</property> - <property name="label" translatable="yes">Category:</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <widget class="GtkComboBoxEntry" id="record_combovalue1"> - <property name="visible">True</property> - <property name="items" translatable="yes">Running shoes -GPS watch -T-shirts -Tyres -Socks</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <placeholder/> - </child> - <child> - <widget class="GtkButton" id="button3"> - <property name="label" translatable="yes">New equipment</property> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="image_position">right</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">3</property> - </packing> - </child> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - </widget> - <packing> - <property name="position">5</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label15"> - <property name="visible">True</property> - <property name="label" translatable="yes">Equipment</property> - </widget> - <packing> - <property name="position">5</property> - <property name="tab_fill">False</property> - <property name="type">tab</property> - </packing> - </child> - <child> <widget class="GtkHBox" id="athletearea"> <property name="visible">True</property> <child> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-14 07:49:02 UTC (rev 707) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-14 08:24:12 UTC (rev 708) @@ -1442,8 +1442,6 @@ self.selected_view="month" elif page == 4: self.selected_view="year" - elif page == 5: - self.selected_view="equipment" elif page == 6: self.selected_view="athlete" else: Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-14 07:49:02 UTC (rev 707) +++ pytrainer/trunk/pytrainer/main.py 2010-11-14 08:24:12 UTC (rev 708) @@ -259,9 +259,6 @@ elif view=="listview": logging.debug('list view') self.refreshListView() - elif view=="equipment": - logging.debug('equipment view') - print('TODO equipment view') elif view=="athlete": logging.debug('athlete view') self.windowmain.on_athleteview_activate() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2010-11-14 11:13:39
|
Revision: 709 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=709&view=rev Author: ncjones Date: 2010-11-14 11:13:26 +0000 (Sun, 14 Nov 2010) Log Message: ----------- Add program argument for specifying config directory. Modified Paths: -------------- pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/profile.py Added Paths: ----------- pytrainer/trunk/pytrainer/environment.py pytrainer/trunk/pytrainer/platform.py pytrainer/trunk/test/pytrainer/environment_test.py Added: pytrainer/trunk/pytrainer/environment.py =================================================================== --- pytrainer/trunk/pytrainer/environment.py (rev 0) +++ pytrainer/trunk/pytrainer/environment.py 2010-11-14 11:13:26 UTC (rev 709) @@ -0,0 +1,64 @@ +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#This program is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public License +#as published by the Free Software Foundation; either version 2 +#of the License, or (at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import os +import logging + +class Environment(object): + + """Describes the location of the program's configuration directories and files.""" + + def __init__(self, platform, conf_dir): + """Initialise an environment. + + Arguments: + platform -- the current system platform. + conf_dir -- the directory where program configuration should be stored. If None, then the default for the platform is used. + + """ + self.conf_dir = conf_dir if conf_dir is not None else platform.get_default_conf_dir() + self.conf_file = self.conf_dir + "/conf.xml" + self.log_file = self.conf_dir + "/log.out" + self.temp_dir = self.conf_dir + "/tmp" + self.gpx_dir = self.conf_dir + "/gpx" + self.extension_dir = self.conf_dir + "/extensions" + self.plugin_dir = self.conf_dir + "/plugins" + + def clear_temp_dir(self): + """Remove all files from the tmp directory.""" + logging.debug("clearing tmp directory %s" % self.temp_dir) + if not os.path.isdir(self.temp_dir): + return + else: + files = os.listdir(self.temp_dir) + for name in files: + fullname = (os.path.join(self.temp_dir, name)) + if os.path.isfile(fullname): + os.remove(os.path.join(self.temp_dir, name)) + + def create_directories(self): + """Create all required directories if they do not already exist.""" + self._create_dir(self.conf_dir) + self._create_dir(self.temp_dir) + self._create_dir(self.extension_dir) + self._create_dir(self.plugin_dir) + self._create_dir(self.gpx_dir) + + def _create_dir(self, dir_name): + if not os.path.isdir(dir_name): + os.mkdir(dir_name) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-14 08:24:12 UTC (rev 708) +++ pytrainer/trunk/pytrainer/main.py 2010-11-14 11:13:26 UTC (rev 709) @@ -32,6 +32,8 @@ from os import path +from pytrainer import platform +from environment import Environment from record import Record from waypoint import Waypoint from extension import Extension @@ -55,6 +57,8 @@ self.DB_version = 6 #Process command line options self.startup_options = self.get_options() + self.environment = Environment(platform.get_platform(), self.startup_options.conf_dir) + self.environment.create_directories() #Setup logging self.set_logging(self.startup_options.log_level) logging.debug('>>') @@ -64,7 +68,7 @@ self.ddbb = None # Checking profile logging.debug('Checking configuration and profile...') - self.profile = Profile(self.data_path,self) + self.profile = Profile(self.environment, self.data_path,self) self.uc = UC() self.windowmain = None self.ddbb = DDBB(self.profile, self) @@ -115,23 +119,20 @@ For more help on valid options try: %prog -h ''' parser = OptionParser(usage=usage) - parser.set_defaults(log_level=logging.ERROR, validate=False, equip=False, newgraph=False) + parser.set_defaults(log_level=logging.ERROR, validate=False, equip=False, newgraph=False, conf_dir=None) parser.add_option("-d", "--debug", action="store_const", const=logging.DEBUG, dest="log_level", help="enable logging at debug level") parser.add_option("-i", "--info", action="store_const", const=logging.INFO, dest="log_level", help="enable logging at info level") parser.add_option("-w", "--warn", action="store_const", const=logging.WARNING, dest="log_level", help="enable logging at warning level") parser.add_option("--valid", action="store_true", dest="validate", help="enable validation of files imported by plugins (details at info or debug logging level) - note plugin must support validation") parser.add_option("--check", action="store_true", dest="check", help="triggers database (only sqlite based) and configuration file sanity checks, adding fields if necessary. Backup of database is done before any change. Details at info or debug logging level") parser.add_option("--newgraph", action="store_true", dest="newgraph", help="EXPERIMENTAL: new graphing approach") + parser.add_option("--confdir", dest="conf_dir", help="Specify the directory where application configuration will be stored.") (options, args) = parser.parse_args() return options def set_logging(self,level): '''Setup rotating log file with customized format''' - PATH = os.environ['HOME']+"/.pytrainer" - if not os.path.exists(PATH): - os.mkdir(PATH) - LOG_FILENAME = PATH + "/log.out" - rotHandler = logging.handlers.RotatingFileHandler(LOG_FILENAME, maxBytes=100000, backupCount=5) + rotHandler = logging.handlers.RotatingFileHandler(self.environment.log_file, maxBytes=100000, backupCount=5) formatter = logging.Formatter('%(asctime)s|%(levelname)s|%(module)s|%(funcName)s|%(message)s') rotHandler.setFormatter(formatter) logging.getLogger('').addHandler(rotHandler) Added: pytrainer/trunk/pytrainer/platform.py =================================================================== --- pytrainer/trunk/pytrainer/platform.py (rev 0) +++ pytrainer/trunk/pytrainer/platform.py 2010-11-14 11:13:26 UTC (rev 709) @@ -0,0 +1,47 @@ +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#This program is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public License +#as published by the Free Software Foundation; either version 2 +#of the License, or (at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import os +import sys + +def get_platform(): + if sys.platform == "linux2": + return _Linux() + elif sys.platform == "win32": + return _Windows() + else: + print "Unsupported sys.platform: %s." % sys.platform + sys.exit(1) + +class _Platform(object): + + def get_default_conf_dir(self): + """Get the path to the default configuration directory for the platform.""" + return self._home_dir + "/" + self._conf_dir_name + +class _Linux(_Platform): + + def __init__(self): + self._home_dir = os.environ['HOME'] + self._conf_dir_name = ".pytrainer" + +class _Windows(_Platform): + + def __init__(self): + self._home_dir = os.environ['USERPROFILE'] + self._conf_dir_name = "pytrainer" Modified: pytrainer/trunk/pytrainer/profile.py =================================================================== --- pytrainer/trunk/pytrainer/profile.py 2010-11-14 08:24:12 UTC (rev 708) +++ pytrainer/trunk/pytrainer/profile.py 2010-11-14 11:13:26 UTC (rev 709) @@ -17,7 +17,7 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -import os, sys, stat +import os, stat import logging from StringIO import StringIO @@ -26,31 +26,22 @@ from lib.uc import UC class Profile: - def __init__(self, data_path = None, parent = None): + def __init__(self, environment, data_path = None, parent = None): logging.debug(">>") + self.environment = environment self.pytrainer_main = parent self.data_path = data_path self.xml_tree = None - self.home = None - self.tmpdir = None - self.confdir = None - self.conffile = None - self.gpxdir = None - self.extensiondir = None - self.plugindir = None + self.tmpdir = environment.temp_dir + self.confdir = environment.conf_dir + self.conffile = environment.conf_file + self.gpxdir = environment.gpx_dir + self.extensiondir = environment.extension_dir + self.plugindir = environment.plugin_dir self.uc = UC() - #Set configuration parameters - self._setHome() - self._setConfFiles() - self._setTempDir() - self._setExtensionDir() - self._setPluginDir() - self._setGpxDir() + + environment.clear_temp_dir() - #Clear temp dir - logging.debug("clearing tmp directory %s" % self.tmpdir) - self._clearTempDir() - #Profile Options and Defaults self.profile_options = { "prf_name":"default", @@ -77,7 +68,7 @@ } #Parse pytrainer configuration file - self.config_file = self.conffile + self.config_file = environment.conf_file self.configuration = self._parse_config_file(self.config_file) logging.debug("Configuration retrieved: "+str(self.configuration)) #self.pytrainer_main.ddbb = DDBB(self, pytrainer_main=self.pytrainer_main) @@ -85,61 +76,6 @@ self._setZones() logging.debug("<<") - def _setHome(self): - if sys.platform == "linux2": - variable = 'HOME' - elif sys.platform == "win32": - variable = 'USERPROFILE' - else: - print "Unsupported sys.platform: %s." % sys.platform - sys.exit(1) - self.home = os.environ[variable] - - def _setTempDir(self): - self.tmpdir = self.confdir+"/tmp" - if not os.path.isdir(self.tmpdir): - os.mkdir(self.tmpdir) - - def _clearTempDir(self): - """Function to clear out the tmp directory that pytrainer uses - will only remove files - """ - if not os.path.isdir(self.tmpdir): - return - else: - files = os.listdir(self.tmpdir) - for name in files: - fullname = (os.path.join(self.tmpdir, name)) - if os.path.isfile(fullname): - os.remove(os.path.join(self.tmpdir, name)) - - def _setConfFiles(self): - if sys.platform == "win32": - self.confdir = self.home+"/pytrainer" - elif sys.platform == "linux2": - self.confdir = self.home+"/.pytrainer" - else: - print "Unsupported sys.platform: %s." % sys.platform - sys.exit(1) - self.conffile = self.confdir+"/conf.xml" - if not os.path.isdir(self.confdir): - os.mkdir(self.confdir) - - def _setGpxDir(self): - self.gpxdir = self.confdir+"/gpx" - if not os.path.isdir(self.gpxdir): - os.mkdir(self.gpxdir) - - def _setExtensionDir(self): - self.extensiondir = self.confdir+"/extensions" - if not os.path.isdir(self.extensiondir): - os.mkdir(self.extensiondir) - - def _setPluginDir(self): - self.plugindir = self.confdir+"/plugins" - if not os.path.isdir(self.plugindir): - os.mkdir(self.plugindir) - def _setZones(self): #maxhr = self.getValue("pytraining","prf_maxhr") #resthr = self.getValue("pytraining","prf_minhr") Added: pytrainer/trunk/test/pytrainer/environment_test.py =================================================================== --- pytrainer/trunk/test/pytrainer/environment_test.py (rev 0) +++ pytrainer/trunk/test/pytrainer/environment_test.py 2010-11-14 11:13:26 UTC (rev 709) @@ -0,0 +1,75 @@ +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#This program is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public License +#as published by the Free Software Foundation; either version 2 +#of the License, or (at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import unittest + +from mock import Mock + +import pytrainer.platform +from pytrainer.environment import Environment + +TEST_DIR_NAME = "/test/.pytrainer_test" + +PLATFORM = pytrainer.platform.get_platform() + +class Test(unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_get_conf_dir(self): + environment = Environment(PLATFORM, TEST_DIR_NAME) + self.assertEquals(TEST_DIR_NAME, environment.conf_dir) + + def test_get_conf_dir_default(self): + test_platform = Mock(spec=pytrainer.platform.get_platform()) + test_platform.get_default_conf_dir.return_value = "/test/.pytrainer_test" + environment = Environment(test_platform, None) + self.assertEquals("/test/.pytrainer_test", environment.conf_dir) + + def test_get_conf_file(self): + environment = Environment(PLATFORM, TEST_DIR_NAME) + self.assertEquals(TEST_DIR_NAME + "/conf.xml", environment.conf_file) + + def test_get_log_file(self): + environment = Environment(PLATFORM, TEST_DIR_NAME) + self.assertEquals(TEST_DIR_NAME + "/log.out", environment.log_file) + + def test_get_temp_dir(self): + environment = Environment(PLATFORM, TEST_DIR_NAME) + self.assertEquals(TEST_DIR_NAME + "/tmp", environment.temp_dir) + + def test_get_gpx_dir(self): + environment = Environment(PLATFORM, TEST_DIR_NAME) + self.assertEquals(TEST_DIR_NAME + "/gpx", environment.gpx_dir) + + def test_get_extension_dir(self): + environment = Environment(PLATFORM, TEST_DIR_NAME) + self.assertEquals(TEST_DIR_NAME + "/extensions", environment.extension_dir) + + def test_get_plugin_dir(self): + environment = Environment(PLATFORM, TEST_DIR_NAME) + self.assertEquals(TEST_DIR_NAME + "/plugins", environment.plugin_dir) + + +if __name__ == "__main__": + #import sys;sys.argv = ['', 'Test.testName'] + unittest.main() \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2010-11-16 09:51:01
|
Revision: 711 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=711&view=rev Author: ncjones Date: 2010-11-16 09:50:54 +0000 (Tue, 16 Nov 2010) Log Message: ----------- Disallow changing equipment description to non-unique value. Modified Paths: -------------- pytrainer/trunk/pytrainer/equipment.py pytrainer/trunk/test/pytrainer/equipment_test.py Modified: pytrainer/trunk/pytrainer/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/equipment.py 2010-11-14 13:36:37 UTC (rev 710) +++ pytrainer/trunk/pytrainer/equipment.py 2010-11-16 09:50:54 UTC (rev 711) @@ -177,6 +177,7 @@ def _update_equipment(self, equipment): logging.debug("Updating existing equipment item.") self._assert_exists(equipment) + self._assert_unique(equipment) self._ddbb.update(_TABLE_NAME, _UPDATE_COLUMNS, _create_row(equipment), "id = {0}".format(equipment.id)) return equipment.id @@ -194,7 +195,9 @@ def _assert_unique(self, equipment): result = self._ddbb.select(_TABLE_NAME, "id", "description = \"{0}\"".format(equipment.description)) if len(result) > 0: - raise EquipmentServiceException("An equipment item already exists with description '{0}'".format(equipment.description)) + id = result[0][0] + if id != equipment.id: + raise EquipmentServiceException("An equipment item already exists with description '{0}'".format(equipment.description)) logging.debug("Asserted description is unique: '{0}'.".format(equipment.description)) def remove_equipment(self, equipment): Modified: pytrainer/trunk/test/pytrainer/equipment_test.py =================================================================== --- pytrainer/trunk/test/pytrainer/equipment_test.py 2010-11-14 13:36:37 UTC (rev 710) +++ pytrainer/trunk/test/pytrainer/equipment_test.py 2010-11-16 09:50:54 UTC (rev 711) @@ -300,14 +300,13 @@ def test_update_equipment(self): equipment = Equipment() equipment.id = 1 - equipment.description = u"test description" - self.mock_ddbb.select.return_value = [(2, u"", 1, 0, 0,u"")] - stored_equipment = self.equipment_service.store_equipment(equipment) + equipment.description = u"new description" + self.mock_ddbb.select.return_value = [(1, u"old description", 1, 0, 0,u"")] + self.equipment_service.store_equipment(equipment) self.mock_ddbb.update.assert_called_with("equipment", "description,active,life_expectancy,prior_usage,notes", - ["test description", 1, 0, 0,"" ], + ["new description", 1, 0, 0,"" ], "id = 1") - self.assertEquals(2, stored_equipment.id) def test_update_equipment_non_existant(self): self.mock_ddbb.select.return_value = [] @@ -319,6 +318,17 @@ except(EquipmentServiceException): pass + def test_update_equipment_duplicate_description(self): + self.mock_ddbb.select.return_value = [(1, u"test item", True, 500, 200, u"Test notes.")] + equipment = Equipment() + equipment.id = 2 + equipment.description = u"test item" + try: + self.equipment_service.store_equipment(equipment) + self.fail("Should not be able to change item description to non-unique value.") + except(EquipmentServiceException): + pass + def test_get_equipment_usage(self): self.mock_ddbb.select.return_value = [(250,)] equipment = Equipment() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dg...@us...> - 2010-11-16 16:42:33
|
Revision: 713 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=713&view=rev Author: dgranda Date: 2010-11-16 16:42:27 +0000 (Tue, 16 Nov 2010) Log Message: ----------- Added alternative paths to start from sources - thx to Martin. Updated revision Modified Paths: -------------- pytrainer/trunk/bin/pytrainer pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/bin/pytrainer =================================================================== --- pytrainer/trunk/bin/pytrainer 2010-11-16 16:39:39 UTC (rev 712) +++ pytrainer/trunk/bin/pytrainer 2010-11-16 16:42:27 UTC (rev 713) @@ -17,12 +17,10 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -import locale import gettext import sys import pygtk pygtk.require('2.0') -import gtk import gtk.glade import os import glob @@ -66,19 +64,29 @@ bin_path = os.path.realpath(os.path.dirname(__file__)) # directory that the pytrainer script executes from e.g. /usr/bin or /usr/local/bin base_path = os.path.dirname(bin_path) -data_path = base_path + "/share/pytrainer/" -site_path = base_path + "/lib/python2.6/site-packages" -DIR = base_path + "/share/locale" +if (os.path.exists(base_path + "/INSTALL") + and os.path.exists(base_path + "/setup.py") + and os.path.exists(base_path + "/pytrainer/main.py") + and os.path.exists(base_path + "/locale")): + print("running pytrainer from source path") + data_path = base_path + "/" + site_path = base_path + gettext_path = base_path + "/locale" +else: + print("running pytrainer from egg installation") + data_path = base_path + "/share/pytrainer/" + site_path = base_path + "/lib/python2.6/site-packages" + gettext_path = base_path + "/share/locale" print "data_path: " + data_path -print "DIR: " + DIR +print "gettext_path: " + gettext_path print "site_path: " + site_path -gettext.bindtextdomain("pytrainer", DIR) -gtk.glade.bindtextdomain("pytrainer", DIR) +gettext.bindtextdomain("pytrainer", gettext_path) +gtk.glade.bindtextdomain("pytrainer", gettext_path) gtk.glade.textdomain("pytrainer") gettext.textdomain("pytrainer") -gettext.install("pytrainer",DIR,unicode=1) +gettext.install("pytrainer", gettext_path, unicode=1) #ensure pytrainer directory is included in import path sys.path.insert(0, site_path) @@ -101,10 +109,11 @@ xul_env = max_version print "Using xulrunner dir: %s" % xul_env -os.environ['MOZILLA_FIVE_HOME']=xul_env +os.environ['MOZILLA_FIVE_HOME'] = xul_env -def main(argv): +def main(): pytrainer = pyTrainer(None, data_path) if __name__ == "__main__": - main(sys.argv[1:]) + main() + Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-16 16:39:39 UTC (rev 712) +++ pytrainer/trunk/pytrainer/main.py 2010-11-16 16:42:27 UTC (rev 713) @@ -53,7 +53,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#705" + self.version ="1.7.2_svn#713" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2010-11-20 22:15:50
|
Revision: 718 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=718&view=rev Author: ncjones Date: 2010-11-20 22:15:41 +0000 (Sat, 20 Nov 2010) Log Message: ----------- Prevent delete/edit when no equipment selected. ticket:12 Modified Paths: -------------- pytrainer/trunk/glade/equipment.glade pytrainer/trunk/pytrainer/gui/equipment.py Modified: pytrainer/trunk/glade/equipment.glade =================================================================== --- pytrainer/trunk/glade/equipment.glade 2010-11-20 21:08:03 UTC (rev 717) +++ pytrainer/trunk/glade/equipment.glade 2010-11-20 22:15:41 UTC (rev 718) @@ -30,6 +30,7 @@ <object class="GtkTreeView" id="treeviewEquipmentList"> <property name="visible">True</property> <property name="can_focus">True</property> + <signal name="cursor_changed" handler="equipment_cursor_changed"/> <signal name="row_activated" handler="equipment_row_activated"/> </object> </child> @@ -60,6 +61,7 @@ <child> <object class="GtkButton" id="buttonEquipmentEdit"> <property name="label">gtk-edit</property> + <property name="sensitive">False</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> @@ -76,6 +78,7 @@ <child> <object class="GtkButton" id="buttonEquipmentDelete"> <property name="label">gtk-delete</property> + <property name="sensitive">False</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> Modified: pytrainer/trunk/pytrainer/gui/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/gui/equipment.py 2010-11-20 21:08:03 UTC (rev 717) +++ pytrainer/trunk/pytrainer/gui/equipment.py 2010-11-20 22:15:41 UTC (rev 718) @@ -49,8 +49,11 @@ self._append_row(added_equipment) def get_equipment_item(self, item_path): - item_id = self.get_value(self.get_iter(item_path), 0) - return self._equipment_service.get_equipment_item(item_id) + item = None + if item_path is not None: + item_id = self.get_value(self.get_iter(item_path), 0) + item = self._equipment_service.get_equipment_item(item_id) + return item def edit_equipment(self, item_path, equipment): updated_item = self._equipment_service.store_equipment(equipment) @@ -96,6 +99,7 @@ "add_equipment_clicked": self._add_equipment_clicked, "cancel_add_equipment_clicked": self._cancel_add_equipment_clicked, "confirm_add_equipment_clicked": self._confirm_add_equipment_clicked, + "equipment_cursor_changed": self._equipment_cursor_changed, "edit_equipment_clicked": self._edit_equipment_clicked, "equipment_row_activated": self._edit_equipment_clicked, "cancel_edit_equipment_clicked": self._cancel_edit_equipment_clicked, @@ -154,6 +158,11 @@ new_equipment.notes = unicode(notes) self._equipment_store.add_equipment(new_equipment) self.show_page_equipment_list() + + def _equipment_cursor_changed(self, widget, *args): + item_selected = self._get_selected_equipment_item() != None + self._builder.get_object("buttonEquipmentEdit").set_sensitive(item_selected) + self._builder.get_object("buttonEquipmentDelete").set_sensitive(item_selected) def _edit_equipment_clicked(self, widget, *args): item = self._get_selected_equipment_item() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-22 22:32:50
|
Revision: 727 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=727&view=rev Author: jblance Date: 2010-11-22 22:32:44 +0000 (Mon, 22 Nov 2010) Log Message: ----------- Add scrolling to graph options Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-22 22:13:43 UTC (rev 726) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-22 22:32:44 UTC (rev 727) @@ -848,7 +848,6 @@ <property name="visible">True</property> <property name="xalign">0</property> <property name="yalign">0</property> - <property name="label" translatable="yes"></property> <property name="use_markup">True</property> <property name="wrap">True</property> </widget> @@ -860,7 +859,16 @@ </packing> </child> <child> - <placeholder/> + <widget class="GtkLabel" id="record_duration"> + <property name="visible">True</property> + <property name="xalign">1</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> </child> <child> <placeholder/> @@ -926,16 +934,7 @@ <placeholder/> </child> <child> - <widget class="GtkLabel" id="record_duration"> - <property name="visible">True</property> - <property name="xalign">1</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - </packing> + <placeholder/> </child> </widget> <packing> @@ -1153,18 +1152,45 @@ </packing> </child> <child> - <widget class="GtkHBox" id="graph_data_hbox"> + <widget class="GtkHBox" id="hboxGraphOptions"> <property name="visible">True</property> <child> - <placeholder/> + <widget class="GtkScrolledWindow" id="scrolledwindowGraphOptions"> + <property name="height_request">200</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <widget class="GtkViewport" id="viewportGraphOptions"> + <property name="visible">True</property> + <property name="resize_mode">queue</property> + <property name="vadjustment">0 0 198 19.800000000000001 178.20000000000002 198</property> + <child> + <widget class="GtkHBox" id="graph_data_hbox"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="position">0</property> + </packing> </child> <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> <widget class="GtkVBox" id="vbox2"> <property name="visible">True</property> <child> @@ -1208,13 +1234,12 @@ <packing> <property name="expand">False</property> <property name="pack_type">end</property> - <property name="position">0</property> + <property name="position">1</property> </packing> </child> </widget> <packing> <property name="expand">False</property> - <property name="fill">False</property> <property name="position">1</property> </packing> </child> @@ -5295,7 +5320,7 @@ </widget> </child> <child> - <widget class="GtkLabel" id="label26"> + <widget class="GtkLabel" id="label14"> <property name="visible">True</property> <property name="label" translatable="yes"><b>History</b></property> <property name="use_markup">True</property> @@ -5821,7 +5846,7 @@ </widget> </child> <child> - <widget class="GtkLabel" id="label14"> + <widget class="GtkLabel" id="label15"> <property name="visible">True</property> <property name="label">label162</property> </widget> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-22 22:13:43 UTC (rev 726) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-22 22:32:44 UTC (rev 727) @@ -1350,18 +1350,20 @@ def on_buttonGraphHideOptions_clicked(self, widget): logging.debug('on_buttonGraphHideOptions_clicked') self.buttonGraphHideOptions.hide() - for child in self.graph_data_hbox.get_children(): - if isinstance(child, gtk.Frame): - child.hide() + self.scrolledwindowGraphOptions.hide() + #for child in self.graph_data_hbox.get_children(): + # if isinstance(child, gtk.Frame): + # child.hide() self.buttonGraphShowOptions.show() def on_buttonGraphShowOptions_clicked(self, widget): logging.debug('on_buttonGraphShowOptions_clicked') self.buttonGraphShowOptions.hide() - for child in self.graph_data_hbox.get_children(): - if isinstance(child, gtk.Frame): - child.show() + #for child in self.graph_data_hbox.get_children(): + # if isinstance(child, gtk.Frame): + # child.show() + self.scrolledwindowGraphOptions.show() self.buttonGraphHideOptions.show() def on_buttonRedrawMap_clicked(self, widget): Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-22 22:13:43 UTC (rev 726) +++ pytrainer/trunk/pytrainer/main.py 2010-11-22 22:32:44 UTC (rev 727) @@ -53,7 +53,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#726" + self.version ="1.7.2_svn#727" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-23 20:34:34
|
Revision: 730 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=730&view=rev Author: jblance Date: 2010-11-23 20:34:28 +0000 (Tue, 23 Nov 2010) Log Message: ----------- Reduce size of graph options, fix bug where graph controls disappear after viewing map Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-23 01:51:18 UTC (rev 729) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-23 20:34:28 UTC (rev 730) @@ -1156,7 +1156,7 @@ <property name="visible">True</property> <child> <widget class="GtkScrolledWindow" id="scrolledwindowGraphOptions"> - <property name="height_request">200</property> + <property name="height_request">100</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="hscrollbar_policy">automatic</property> @@ -1165,7 +1165,7 @@ <widget class="GtkViewport" id="viewportGraphOptions"> <property name="visible">True</property> <property name="resize_mode">queue</property> - <property name="vadjustment">0 0 198 19.800000000000001 178.20000000000002 198</property> + <property name="vadjustment">0 0 1 0.10000000000000001 0.90000000000000002 1</property> <child> <widget class="GtkHBox" id="graph_data_hbox"> <property name="visible">True</property> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-23 01:51:18 UTC (rev 729) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-23 20:34:28 UTC (rev 730) @@ -370,7 +370,6 @@ logging.debug("Using the new TEST graphing approach") #Hide current drop down boxes self.hbox30.hide() - #Show new graph details self.graph_data_hbox.hide() #Enable graph self.record_vbox.set_sensitive(1) @@ -547,6 +546,11 @@ if y2min is not None and y2max is not None: y2minlabel.set_text(str(y2min)) y2maxlabel.set_text(str(y2max)) + + #Default to showing options + self.buttonGraphShowOptions.hide() + self.scrolledwindowGraphOptions.show() + self.buttonGraphHideOptions.show() else: logging.debug("Activity has no GPX data") #Show drop down boxes Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-23 01:51:18 UTC (rev 729) +++ pytrainer/trunk/pytrainer/main.py 2010-11-23 20:34:28 UTC (rev 730) @@ -53,7 +53,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#729" + self.version ="1.7.2_svn#730" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-24 02:57:31
|
Revision: 737 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=737&view=rev Author: jblance Date: 2010-11-24 02:57:23 +0000 (Wed, 24 Nov 2010) Log Message: ----------- French localizations from Pierre Modified Paths: -------------- pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer.mo pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer_fr.po pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer.mo =================================================================== (Binary files differ) Modified: pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer_fr.po =================================================================== --- pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer_fr.po 2010-11-24 02:51:29 UTC (rev 736) +++ pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer_fr.po 2010-11-24 02:57:23 UTC (rev 737) @@ -9,10 +9,11 @@ msgstr "" "Project-Id-Version: pytrainer_fr\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-04-12 08:56+0200\n" -"PO-Revision-Date: 2010-04-12 08:57+0100\n" +"POT-Creation-Date: 2010-11-23 21:42+0100\n" +"PO-Revision-Date: 2010-11-23 21:43+0100\n" "Last-Translator: Pierre Gaigé <pg...@fr...>\n" "Language-Team: <fr...@li...>\n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -25,8 +26,54 @@ msgid "Calendar" msgstr "Calendrier" +#: glade/equipment.glade:109 +msgid "<b>Equipment List</b>" +msgstr "<b>Liste d'équipements</b>" + +#: glade/equipment.glade:149 +#: glade/equipment.glade:406 +msgid "Description" +msgstr "Description" + +#: glade/equipment.glade:174 +#: glade/equipment.glade:431 +msgid "Life Expectancy" +msgstr "Durée de vie" + +#: glade/equipment.glade:211 +#: glade/equipment.glade:467 +msgid "Prior Usage" +msgstr "Utilisation précédente" + +#: glade/equipment.glade:243 +#: glade/equipment.glade:499 +msgid "Active" +msgstr "Actif" + +#: glade/equipment.glade:277 +#: glade/equipment.glade:533 +#: pytrainer/gui/windowimportdata.py:352 +msgid "Notes" +msgstr "Notes" + +#: glade/equipment.glade:366 +msgid "<b>Add New Equipment</b>" +msgstr "<b>Ajouter un équipement</b>" + +#: glade/equipment.glade:622 +msgid "<b>Edit Equipment</b>" +msgstr "<b>Éditer un équipement</b>" + +#: glade/equipment.glade:651 +msgid "Really delete the equipment item?" +msgstr "Voulez vous vraiment détruire cet équipement?" + +#: glade/equipment.glade:704 +msgid "<b>Delete Equipment</b>" +msgstr "<b>Supprimer un équipement</b>" + #: glade/extensions.glade:9 -#: glade/pytrainer.glade:162 +#: glade/pytrainer.glade:163 msgid "Extensions" msgstr "Extensions" @@ -40,7 +87,8 @@ #: glade/extensions.glade:82 #: glade/plugins.glade:144 -#: glade/profile.glade:744 +#: glade/profile.glade:727 +#: glade/pytrainer.glade:5161 msgid "Name:" msgstr "Nom:" @@ -51,7 +99,7 @@ #: glade/extensions.glade:110 #: glade/plugins.glade:86 -#: glade/pytrainer.glade:4728 +#: glade/pytrainer.glade:5690 msgid "Description:" msgstr "Description:" @@ -66,110 +114,288 @@ msgstr "Description:" #: glade/importdata.glade:7 -#: glade/importdata.glade:329 +#: glade/importdata.glade:325 msgid "Import" msgstr "Importer" -#: glade/importdata.glade:37 +#: glade/importdata.glade:36 msgid "" "Test 1\n" "Test 2" msgstr "" -#: glade/importdata.glade:47 +#: glade/importdata.glade:46 msgid "<b>Select your GPS device</b>" msgstr "<b>Sélectionnez votre périphérique GPS</b>" -#: glade/importdata.glade:65 +#: glade/importdata.glade:64 msgid "Import from GPS Device is not yet implemented" -msgstr "Import à partir du périphérique GPS pas encore implémenté" +msgstr "L'importation à partir du périphérique GPS n'est pas encore implémenté" -#: glade/importdata.glade:94 +#: glade/importdata.glade:92 msgid "<b>Tools</b>" msgstr "<b>Outils:</b>" -#: glade/importdata.glade:113 +#: glade/importdata.glade:111 msgid "Rescan" msgstr "Re-scan" -#: glade/importdata.glade:117 +#: glade/importdata.glade:115 msgid "Rescan system for available tools" msgstr "Re-scan le système pour trouver les outils disponibles" -#: glade/importdata.glade:170 +#: glade/importdata.glade:168 msgid "<b>Import from GPS Device</b>" msgstr "<b>Importer à partir du périphérique GPS</b>" -#: glade/importdata.glade:225 +#: glade/importdata.glade:221 msgid "Remove selected files and the associated activities" msgstr "Supprimer les fichiers et les activités associées" -#: glade/importdata.glade:243 +#: glade/importdata.glade:239 msgid "Add files to import activities from" msgstr "Ajouter des fichiers pour récupérer les activités" -#: glade/importdata.glade:268 +#: glade/importdata.glade:264 msgid "<b>Add file(s) to import activities from</b>" msgstr "<b>Ajouter des fichiers pour récupérer les activités</b>" -#: glade/importdata.glade:311 +#: glade/importdata.glade:307 msgid "<b>Select activities to import</b>" -msgstr "<b>Sélectionnez une activité à importer</b>" +msgstr "<b>Sélectionnez les activités à importer</b>" -#: glade/importdata.glade:334 +#: glade/importdata.glade:330 msgid "Import selected activities" -msgstr "Importer les activités selectionnées" +msgstr "Importer les activités sélectionnées" -#: glade/importdata.glade:351 +#: glade/importdata.glade:347 msgid "Close Import dialog" -msgstr "Fermer la fenêtre d'import" +msgstr "Fermer la fenêtre d'importation" -#: glade/importdata.glade:391 +#: glade/importdata.glade:387 msgid "<b>Import from File</b>" msgstr "<b>Importer à partir d'un fichier</b>" -#: glade/importdata.glade:470 +#: glade/importdata.glade:464 msgid "<b>Plugins</b>" msgstr "<b>Plugins</b>" -#: glade/importdata.glade:499 +#: glade/importdata.glade:491 msgid "Import from GPS Device" msgstr "Importer à partir du périphérique GPS" -#: glade/importdata.glade:518 +#: glade/importdata.glade:510 msgid "Import from File" msgstr "Importer à partir d'un fichier" -#: glade/importdata.glade:533 +#: glade/importdata.glade:525 msgid "Launch 'File Select' on start" msgstr "Lancer 'Fichier ouvrir' au démarrage" -#: glade/importdata.glade:538 +#: glade/importdata.glade:530 msgid "Automatically start the file selection dialog" msgstr "Démarre automatiquement le sélecteur de fichiers" -#: glade/importdata.glade:554 +#: glade/importdata.glade:546 #: glade/plugins.glade:9 msgid "Plugins" msgstr "Plugins" -#: glade/importdata.glade:580 +#: glade/importdata.glade:572 msgid "<b>Default to Tab</b>" msgstr "<b>Onglet par défaut</b>" -#: glade/importdata.glade:603 +#: glade/importdata.glade:595 msgid "Reset" msgstr "Réinitialiser" -#: glade/importdata.glade:619 +#: glade/importdata.glade:611 msgid "Save" msgstr "Sauvegarder" -#: glade/importdata.glade:678 +#: glade/importdata.glade:670 msgid "<b>Options</b>" msgstr "<b>Options</b>" +#: glade/importdata.glade:702 +msgid "<b>Select file to import from</b>" +msgstr "<b>Sélectionnez un fichier à partir duquel importer</b>" + +#: glade/importdata.glade:731 +msgid "Tab" +msgstr "Tabulation" + +#: glade/importdata.glade:746 +msgid "Comma" +msgstr "Virgule" + +#: glade/importdata.glade:763 +msgid "Other" +msgstr "Autre" + +#: glade/importdata.glade:799 +msgid "Read File" +msgstr "Lire le fichier" + +#: glade/importdata.glade:820 +msgid "<b>File delimiter</b>" +msgstr "<b>Délimiteur de champs</b>" + +#: glade/importdata.glade:864 +#: pytrainer/gui/windowmain.py:109 +#: pytrainer/gui/windowmain.py:124 +#: pytrainer/gui/windowmain.py:1132 +#: pytrainer/gui/dialogselecttrack.py:40 +msgid "Date" +msgstr "Date" + +#: glade/importdata.glade:877 +#: glade/importdata.glade:918 +#: glade/importdata.glade:933 +#: glade/importdata.glade:1128 +#: glade/importdata.glade:1143 +#: glade/importdata.glade:1158 +#: glade/importdata.glade:1173 +#: glade/importdata.glade:1188 +#: glade/importdata.glade:1203 +#: glade/importdata.glade:1218 +#: glade/importdata.glade:1233 +#: glade/importdata.glade:1248 +#: glade/importdata.glade:1263 +#: glade/importdata.glade:1278 +#: glade/importdata.glade:1293 +msgid "Exclude" +msgstr "Exclure" + +#: glade/importdata.glade:892 +#: pytrainer/monthgraph.py:70 +#: pytrainer/heartrategraph.py:36 +#: pytrainer/recordgraph.py:134 +#: pytrainer/recordgraph.py:136 +#: pytrainer/recordgraph.py:138 +#: pytrainer/recordgraph.py:140 +#: pytrainer/recordgraph.py:142 +#: pytrainer/recordgraph.py:144 +#: pytrainer/recordgraph.py:146 +#: pytrainer/weekgraph.py:115 +#: pytrainer/yeargraph.py:70 +#: pytrainer/daygraph.py:52 +#: pytrainer/daygraph.py:54 +#: pytrainer/daygraph.py:56 +msgid "Distance (km)" +msgstr "Distance (km) " + +#: glade/importdata.glade:905 +msgid "Duration (sec)" +msgstr "Durée (s)" + +#: glade/importdata.glade:947 +msgid "<b>PyTrainer Field</b>" +msgstr "<b>Champs pytrainer</b>" + +#: glade/importdata.glade:958 +msgid "<b>File Column</b>" +msgstr "<b>Colonne du fichier</b>" + +#: glade/importdata.glade:972 +#: pytrainer/gui/windowmain.py:108 +#: pytrainer/gui/windowmain.py:1131 +msgid "Title" +msgstr "Titre" + +#: glade/importdata.glade:985 +msgid "Descent (m)" +msgstr "Dénivelé Négatif (m)" + +#: glade/importdata.glade:998 +msgid "Accent (m)" +msgstr "Dénivelé Positif (m)" + +#: glade/importdata.glade:1011 +msgid "Calories (kcal)" +msgstr "Calories (kcal)" + +#: glade/importdata.glade:1024 +msgid "Max Speed (km/h)" +msgstr "Vitesse Max (km/h)" + +#: glade/importdata.glade:1037 +#: pytrainer/monthgraph.py:76 +#: pytrainer/weekgraph.py:121 +#: pytrainer/yeargraph.py:76 +msgid "Average Speed (km/h)" +msgstr "Vitesse moyenne (km/h)" + +#: glade/importdata.glade:1050 +#: glade/pytrainer.glade:277 +#: pytrainer/gui/windowmain.py:103 +#: pytrainer/gui/windowmain.py:111 +#: pytrainer/gui/windowmain.py:1134 +#: pytrainer/gui/windowimportdata.py:352 +#: pytrainer/gui/windowprofile.py:59 +#: pytrainer/gui/windowrecord.py:210 +msgid "Sport" +msgstr "Sport" + +#: glade/importdata.glade:1063 +msgid "Average Heartrate (bpm)" +msgstr "FC moyenne (bpm)" + +#: glade/importdata.glade:1076 +msgid "Max Heartrate (bpm)" +msgstr "FC Max (bpm)" + +#: glade/importdata.glade:1089 +#: pytrainer/recordgraph.py:138 +msgid "Pace (min/km)" +msgstr "Cadence (min/km)" + +#: glade/importdata.glade:1102 +msgid "Max Pace (min/km)" +msgstr "Cadence Max (min/km)" + +#: glade/importdata.glade:1115 +#: glade/newrecord.glade:1095 +msgid "Comments" +msgstr "Commentaires" + +#: glade/importdata.glade:1309 +msgid "Force sport to:" +msgstr "Forcer le sport à:" + +#: glade/importdata.glade:1323 +#: glade/newrecord.glade:406 +msgid " " +msgstr " " + +#: glade/importdata.glade:1394 +msgid "<b>Map Columns</b>" +msgstr "<b>Associer les colonnes</b>" + +#: glade/importdata.glade:1414 +msgid "" +"<small>This is an experiemental import for delimited files\n" +"1) Select a file\n" +"2) Click 'Read File' to analyse the file\n" +"3) Map columns in the file to pytrainer data elements (Date is required)\n" +"4) Click 'Import Data'</small>" +msgstr "" +"<small>Ceci est un essai pour l'importation de fichiers CSV\n" +"1) Sélectionnez un fichier\n" +"2) Cliquez sur 'Lire le fichier' pour l'analyser\n" +"3) Associez les colonnes du fichier aux données de Pytrainer (La date est nécessaire)\n" +"4) Cliquez sur 'Importer les données'</small>" + +#: glade/importdata.glade:1427 +msgid "Import Data" +msgstr "Importer les données" + +#: glade/importdata.glade:1467 +msgid "<b>Import from CSV</b>" +msgstr "<b>Importer à partir d'un fichier CSV</b>" + #: glade/newrecord.glade:7 +#: pytrainer/gui/windowmain.py:1744 msgid "New Entry" msgstr "Nouvelle entrée" @@ -202,7 +428,7 @@ #: glade/newrecord.glade:560 #: glade/newrecord.glade:698 #: glade/newrecord.glade:959 -#: glade/profile.glade:1404 +#: glade/profile.glade:1462 msgid "Calculate" msgstr "Calculer" @@ -212,16 +438,6 @@ #: glade/newrecord.glade:281 #: glade/newrecord.glade:308 -#: glade/pytrainer.glade:833 -#: glade/pytrainer.glade:855 -#: glade/pytrainer.glade:2038 -#: glade/pytrainer.glade:2060 -#: glade/pytrainer.glade:2651 -#: glade/pytrainer.glade:2673 -#: glade/pytrainer.glade:3276 -#: glade/pytrainer.glade:3298 -#: glade/pytrainer.glade:3976 -#: glade/pytrainer.glade:3998 msgid ":" msgstr ":" @@ -229,12 +445,6 @@ msgid "Date:" msgstr "Date:" -#: glade/newrecord.glade:406 -#: glade/pytrainer.glade:2843 -#: glade/pytrainer.glade:3468 -msgid " " -msgstr " " - #: glade/newrecord.glade:447 msgid "Start Time:" msgstr "Début:" @@ -244,7 +454,7 @@ msgstr "" #: glade/newrecord.glade:488 -#: glade/profile.glade:1442 +#: glade/profile.glade:1500 msgid "<b>General</b>" msgstr "<b>Général:</b>" @@ -297,9 +507,10 @@ msgstr "Fréquence Cardiaque:" #: glade/newrecord.glade:903 -#: pytrainer/gui/windowmain.py:755 -#: pytrainer/monthgraph.py:77 +#: pytrainer/monthgraph.py:78 #: pytrainer/weekgraph.py:123 +#: pytrainer/gui/windowmain.py:115 +#: pytrainer/gui/windowmain.py:1138 #: pytrainer/yeargraph.py:78 msgid "Calories" msgstr "Calories" @@ -320,10 +531,19 @@ msgid "<b>Comments</b>" msgstr "<b>Commentaires</b>" -#: glade/newrecord.glade:1095 -msgid "Comments" -msgstr "Commentaires" +#: glade/newrecord.glade:1135 +msgid "<i>There are no active equipment items.</i>" +msgstr "<i>Il n'y a aucun article d'équipement actif.</i>" +#: glade/newrecord.glade:1189 +msgid "<b>Associated Equipment</b>" +msgstr "<b>Équipement associé</b>" + +#: glade/newrecord.glade:1204 +#: glade/profile.glade:1360 +msgid "Equipment" +msgstr "Équipement" + #: glade/plugins.glade:53 msgid "<b>Plugin Details</b>" msgstr "<b>Détail du plugin</b>" @@ -341,116 +561,126 @@ msgid "Preferences" msgstr "Préférences" -#: glade/profile.glade:43 +#: glade/profile.glade:37 msgid "Metric system" msgstr "Système Métrique" -#: glade/profile.glade:57 +#: glade/profile.glade:53 msgid "U.S. customary units" msgstr "Unités U.S." -#: glade/profile.glade:79 +#: glade/profile.glade:74 msgid "<b>System of Measurement</b>" msgstr "<b>Système de Mesure</b>" -#: glade/profile.glade:115 +#: glade/profile.glade:103 +#: glade/pytrainer.glade:2023 +msgid "Google" +msgstr "" + +#: glade/profile.glade:118 +#: glade/pytrainer.glade:2006 +msgid "Open Street Map" +msgstr "Open Street Map" + +#: glade/profile.glade:140 +msgid "<b>Default Map Viewer</b>" +msgstr "<b>Visualiseur de cartes par défaut</b>" + +#: glade/profile.glade:176 msgid "Database type:" msgstr "Type de Base de Données:" -#: glade/profile.glade:126 +#: glade/profile.glade:187 msgid "Database host:" msgstr "Hôte de la Base de Données:" -#: glade/profile.glade:152 +#: glade/profile.glade:213 msgid "Database name:" msgstr "Nom de la Base de Données:" -#: glade/profile.glade:191 +#: glade/profile.glade:252 msgid "Database user:" msgstr "Utilisateur de la Base de Données:" -#: glade/profile.glade:206 +#: glade/profile.glade:267 msgid "Database pass:" msgstr "Mot de passe de la Base de Données:" -#: glade/profile.glade:257 +#: glade/profile.glade:318 msgid "<b>Database</b>" msgstr "<b>Base de données</b>" -#: glade/profile.glade:293 -msgid "Use this port for internal connections: " -msgstr "Utiliser ce port pour les connexions internes:" - -#: glade/profile.glade:318 -msgid "<small><b>Note:</b> Change this only if you know what you are doing</small>" -msgstr "<small><b>Note:</b> Changez cette valeur uniquement si vous savez ce que vous faites</small>" - -#: glade/profile.glade:336 -msgid "<b>Port Connnection</b>" -msgstr "<b>Port de Connexion:</b>" - -#: glade/profile.glade:355 +#: glade/profile.glade:340 msgid "General" msgstr "Général" -#: glade/profile.glade:384 +#: glade/profile.glade:369 msgid "User name:" msgstr "Nom d'Utilisateur:" -#: glade/profile.glade:395 +#: glade/profile.glade:380 msgid "Gender:" msgstr "Sexe:" -#: glade/profile.glade:422 +#: glade/profile.glade:407 +#: glade/pytrainer.glade:5186 msgid "Height:" msgstr "Taille:" -#: glade/profile.glade:462 +#: glade/profile.glade:447 +#: glade/pytrainer.glade:5173 msgid "Date of birth:" msgstr "Date de Naissance:" -#: glade/profile.glade:535 +#: glade/profile.glade:520 msgid "Weight:" msgstr "Poids:" -#: glade/profile.glade:557 +#: glade/profile.glade:542 +#: glade/pytrainer.glade:5248 msgid "<b>Athlete Details</b>" msgstr "<b>Détail de l'Athlète</b>" -#: glade/profile.glade:572 +#: glade/profile.glade:557 +#: glade/pytrainer.glade:5351 msgid "Athlete" msgstr "Athlète" -#: glade/profile.glade:687 +#: glade/profile.glade:671 msgid "<b>Sport List</b>" msgstr "<b>Liste des Sports</b>" -#: glade/profile.glade:699 +#: glade/profile.glade:683 msgid "llist" msgstr "" -#: glade/profile.glade:755 +#: glade/profile.glade:738 msgid "M.E.T.:" msgstr "M.E.T.:" -#: glade/profile.glade:782 +#: glade/profile.glade:765 msgid "Extra Weight:" msgstr "Poids Additionnel:" -#: glade/profile.glade:818 -#: glade/profile.glade:1171 +#: glade/profile.glade:801 +#: glade/profile.glade:1181 msgid "More information on determining yor M.E.T sport coefficient on Wikipedia" msgstr "Plus d'information pour déterminer le coefficient M.E.T du sport sur Wikipedia" -#: glade/profile.glade:900 +#: glade/profile.glade:821 +msgid "Maximum Pace:" +msgstr "Cadence Max:" + +#: glade/profile.glade:913 msgid "<b>Add New Sport</b>" msgstr "<b>Ajouter un Sport</b>" -#: glade/profile.glade:915 +#: glade/profile.glade:928 msgid "new" msgstr "nouveau" -#: glade/profile.glade:948 +#: glade/profile.glade:959 msgid "" "Deleting a sport removes associated records.\n" "Continue?" @@ -458,94 +688,96 @@ "Détruire un sport supprime les enregistrements associés.\n" "Continuer?" -#: glade/profile.glade:1030 +#: glade/profile.glade:1041 msgid "<b>Delete Sport</b>" msgstr "<b>Supprimer un Sport</b>" -#: glade/profile.glade:1041 -#: glade/pytrainer.glade:1884 -#: glade/pytrainer.glade:4857 -msgid "label-2147483648" -msgstr "label-2147483648" - -#: glade/profile.glade:1062 +#: glade/profile.glade:1073 msgid "delete" msgstr "supprimer" -#: glade/profile.glade:1096 +#: glade/profile.glade:1106 msgid "Name" msgstr "Nom" -#: glade/profile.glade:1119 +#: glade/profile.glade:1129 msgid "M.E.T." msgstr "M.E.T." -#: glade/profile.glade:1146 -#: pytrainer/gui/windowprofile.py:71 +#: glade/profile.glade:1156 +#: pytrainer/gui/windowprofile.py:59 msgid "Extra Weight" msgstr "Poids Additionnel" -#: glade/profile.glade:1252 +#: glade/profile.glade:1201 +msgid "Maxiumum Pace" +msgstr "Cadence Max" + +#: glade/profile.glade:1289 msgid "<b>Edit Sport</b>" msgstr "<b>Éditer un sport</b>" -#: glade/profile.glade:1263 +#: glade/profile.glade:1300 msgid "<b>lalaal</b>" msgstr "<b>Base de données</b>" -#: glade/profile.glade:1285 +#: glade/profile.glade:1322 msgid "edit" msgstr "édition" -#: glade/profile.glade:1301 +#: glade/profile.glade:1338 msgid "Sports" msgstr "Sports" -#: glade/profile.glade:1335 +#: glade/profile.glade:1393 msgid "Maximum heart rate:" msgstr "Fréquence Cardiaque Maximale:" -#: glade/profile.glade:1346 +#: glade/profile.glade:1404 msgid "Resting heart rate:" msgstr "Fréquence Cardiaque au Repos:" -#: glade/profile.glade:1391 +#: glade/profile.glade:1449 msgid "<small><b>Note:</b> Maximum heart rate is calculated by subtracting the number 220 minus your age. </small>" msgstr "<small><b>Note:</b> Le calcul de votre fréquence cardiaque maximale est effectué grâce à la formule 220 moins votre âge. </small>" -#: glade/profile.glade:1478 +#: glade/profile.glade:1536 msgid "<small><b>NOTE:</b> in order to use the Karvonen method you must cover the Resting hr field.</small>" msgstr "<small><b>Note:</b> Afin d'utiliser la méthode de Karvonen vous devez obligatoirement renseigner le champ «Fréquence Cardiaque au Repos».</small>" -#: glade/profile.glade:1491 +#: glade/profile.glade:1549 msgid "Percentages based method" msgstr "Méthode basée sur des pourcentages" -#: glade/profile.glade:1507 -#: pytrainer/gui/windowmain.py:308 +#: glade/profile.glade:1565 +#: pytrainer/gui/windowmain.py:599 msgid "Karvonen method" msgstr "Méthode de Karvonen" -#: glade/profile.glade:1528 +#: glade/profile.glade:1586 msgid "Select how to calculate your heart rate zones." msgstr "Sélectionnez la méthode appropriée pour définir les zones cardiaque." -#: glade/profile.glade:1567 +#: glade/profile.glade:1625 msgid "<b>Heart Rate Zones</b>" msgstr "<b>Zones Cardiaque:</b>" -#: glade/profile.glade:1589 +#: glade/profile.glade:1647 +#: pytrainer/heartrategraph.py:36 +#: pytrainer/recordgraph.py:140 #: pytrainer/daygraph.py:56 -#: pytrainer/recordgraph.py:120 -#: pytrainer/heartrategraph.py:38 +#: pytrainer/lib/activity.py:430 +#: pytrainer/lib/activity.py:432 +#: pytrainer/lib/activity.py:442 +#: pytrainer/lib/activity.py:512 msgid "Heart Rate" msgstr "Fréquence Cardiaque" -#: glade/profile.glade:1616 +#: glade/profile.glade:1673 msgid "Log Level" msgstr "Niveau de Log" -#: glade/profile.glade:1624 +#: glade/profile.glade:1681 msgid "" "Error\n" "Warning\n" @@ -557,300 +789,235 @@ "Info\n" "Debug" -#: glade/profile.glade:1642 +#: glade/profile.glade:1699 msgid "<small>What level of detail is written to the log?</small>" msgstr "<small>Niveau de détail du fichier log?</small>" -#: glade/profile.glade:1656 +#: glade/profile.glade:1713 msgid "Validate" msgstr "Valider" -#: glade/profile.glade:1665 -msgid "--valid" -msgstr "" - -#: glade/profile.glade:1686 +#: glade/profile.glade:1743 msgid "<small>Do the plugins attempt to validate the input file before processing?</small>" msgstr "<small>Le plugin doit-il essayer de valider le fichier d'entrée avant d'effectuer le traitement?</small>" -#: glade/profile.glade:1702 +#: glade/profile.glade:1759 msgid "Check" msgstr "Vérifier" -#: glade/profile.glade:1711 -msgid "--check" -msgstr "" - -#: glade/profile.glade:1731 +#: glade/profile.glade:1788 msgid "<small>Was a configuration and database check requested?</small>" msgstr "<small>La vérification de la configuration et de la base de données est-elle activée?</small>" -#: glade/profile.glade:1747 -msgid "Googlemaps v3" -msgstr "" - -#: glade/profile.glade:1757 -msgid "--gmaps2*" -msgstr "" - -#: glade/profile.glade:1779 -msgid "<small>Is the Googlemaps API version 3 in use?</small>" -msgstr "<small>Googlemaps utilise t-il l'API version 3?</small>" - -#: glade/profile.glade:1795 -msgid "Unified Import" -msgstr "Import unifié" - #: glade/profile.glade:1804 -msgid "--testimport" -msgstr "" +msgid "New Graph" +msgstr "Nouveau Graphe" -#: glade/profile.glade:1825 -msgid "<small>Is the Unified Importer active?</small>" -msgstr "<small>L'import unifié est-il activé?</small>" +#: glade/profile.glade:1833 +msgid "<small>Want to use experimental new approach to graphing?</small>" +msgstr "<small>Voulez vous expérimenter un nouveau mode pour les graphes?</small>" -#: glade/profile.glade:1850 +#: glade/profile.glade:1876 msgid "<small>This screen shows the state of command line configurable options for pytrainer. These options can be changed here which will affect the current instance of pytrainer, they will not be remembered next time though</small>" msgstr "<small>Cet écran montre l'état des options configurables de la ligne de commande de pytrainer. Ces options peuvent être changées ici pour la session en cours, elles ne seront toutefois pas conservées au prochain démarrage.</small>" -#: glade/profile.glade:1866 -msgid "<small>* Note Googlemaps API version 3 is on by default, use --gmaps2 to switch it off</small>" -msgstr "<small>* Notez que l'API version 3 de Googlemaps est activée par défaut, utilisez --gmaps2 pour la déactiver</small>" - -#: glade/profile.glade:1882 +#: glade/profile.glade:1897 msgid "Startup Parameters" msgstr "Paramètres de démarrage" -#: glade/pytrainer.glade:7 -msgid "window1" -msgstr "fenêtre1" - #: glade/pytrainer.glade:24 msgid "_File" msgstr "_Fichier" -#: glade/pytrainer.glade:93 +#: glade/pytrainer.glade:39 +#, fuzzy +msgid "_Import" +msgstr "Importer" + +#: glade/pytrainer.glade:60 +msgid "_Export as Text Separated by Commas" +msgstr "_Exporter un Fichier Texte séparé par des virgules" + +#: glade/pytrainer.glade:94 msgid "_Edit" msgstr "_Édition" -#: glade/pytrainer.glade:113 +#: glade/pytrainer.glade:114 msgid "_View" msgstr "_Vue" -#: glade/pytrainer.glade:120 +#: glade/pytrainer.glade:121 msgid " _Classic View" msgstr "_Vue classique" -#: glade/pytrainer.glade:130 +#: glade/pytrainer.glade:131 msgid " _List View" msgstr "_Vue en liste" -#: glade/pytrainer.glade:140 +#: glade/pytrainer.glade:141 msgid " _Waypoints Editor" msgstr "_Vue d'édition des Points de Localisation" -#: glade/pytrainer.glade:154 +#: glade/pytrainer.glade:155 msgid "Tools" msgstr "Outils" -#: glade/pytrainer.glade:171 +#: glade/pytrainer.glade:172 msgid "GPS Device Plugins" msgstr "Plugins pour les Périphériques GPS" -#: glade/pytrainer.glade:184 +#: glade/pytrainer.glade:185 msgid "_Help" msgstr "_Aide" -#: glade/pytrainer.glade:276 -#: pytrainer/gui/windowprofile.py:71 -#: pytrainer/gui/windowmain.py:65 -#: pytrainer/gui/windowmain.py:68 -#: pytrainer/gui/windowmain.py:751 -#: pytrainer/gui/windowrecord.py:147 -#: pytrainer/gui/windowimportdata.py:333 -msgid "Sport" -msgstr "Sport" - -#: glade/pytrainer.glade:288 +#: glade/pytrainer.glade:290 +#: glade/pytrainer.glade:5467 msgid "All Sports" msgstr "Tous les Sports" -#: glade/pytrainer.glade:395 +#: glade/pytrainer.glade:396 msgid "<b>Sport:</b>" msgstr "<b>Sport:</b>" -#: glade/pytrainer.glade:407 -#: glade/pytrainer.glade:2013 -#: glade/pytrainer.glade:2626 -#: glade/pytrainer.glade:3251 -#: glade/pytrainer.glade:3952 +#: glade/pytrainer.glade:408 +#: glade/pytrainer.glade:2726 +#: glade/pytrainer.glade:3337 +#: glade/pytrainer.glade:3960 +#: glade/pytrainer.glade:4659 msgid "<b>Duration:</b>" msgstr "<b>Durée:</b>" -#: glade/pytrainer.glade:422 -#: glade/pytrainer.glade:2103 -#: glade/pytrainer.glade:2705 -#: glade/pytrainer.glade:3330 -#: glade/pytrainer.glade:4054 +#: glade/pytrainer.glade:423 +#: glade/pytrainer.glade:2816 +#: glade/pytrainer.glade:3416 +#: glade/pytrainer.glade:4039 +#: glade/pytrainer.glade:4761 msgid "<b>Speed:</b>" msgstr "<b>Vitesse:</b>" -#: glade/pytrainer.glade:436 -#: glade/pytrainer.glade:2271 -#: glade/pytrainer.glade:2900 -#: glade/pytrainer.glade:3525 -#: glade/pytrainer.glade:4149 +#: glade/pytrainer.glade:437 +#: glade/pytrainer.glade:2984 +#: glade/pytrainer.glade:3611 +#: glade/pytrainer.glade:4234 +#: glade/pytrainer.glade:4856 msgid "<b>Pace:</b>" msgstr "<b>Cadence:</b>" -#: glade/pytrainer.glade:450 +#: glade/pytrainer.glade:451 msgid "<b>Ascent:</b>" msgstr "<b>Dénivelé Pos.:</b>" -#: glade/pytrainer.glade:464 +#: glade/pytrainer.glade:465 msgid "<b>Calories:</b>" msgstr "<b>Calories:</b>" -#: glade/pytrainer.glade:478 +#: glade/pytrainer.glade:479 msgid "<b>Comments:</b>" msgstr "<b>Commentaires:</b>" -#: glade/pytrainer.glade:493 -#: glade/pytrainer.glade:890 -#: glade/pytrainer.glade:2133 -#: glade/pytrainer.glade:2166 -#: glade/pytrainer.glade:2735 -#: glade/pytrainer.glade:2828 -#: glade/pytrainer.glade:3360 -#: glade/pytrainer.glade:3453 -#: glade/pytrainer.glade:4084 -#: glade/pytrainer.glade:4100 -#: pytrainer/gui/windowmain.py:192 -#: pytrainer/gui/windowmain.py:193 -#: pytrainer/gui/windowmain.py:328 -#: pytrainer/gui/windowmain.py:329 -#: pytrainer/gui/windowmain.py:432 -#: pytrainer/gui/windowmain.py:433 -#: pytrainer/gui/windowmain.py:510 -#: pytrainer/gui/windowmain.py:511 -msgid "km/h" -msgstr "km/h" - -#: glade/pytrainer.glade:509 -#: glade/pytrainer.glade:721 -#: glade/pytrainer.glade:2286 -#: glade/pytrainer.glade:2318 -#: glade/pytrainer.glade:2931 -#: glade/pytrainer.glade:2947 -#: glade/pytrainer.glade:3556 -#: glade/pytrainer.glade:3572 -#: glade/pytrainer.glade:4181 -#: glade/pytrainer.glade:4197 -#: pytrainer/gui/windowmain.py:194 -#: pytrainer/gui/windowmain.py:195 -#: pytrainer/gui/windowmain.py:330 -#: pytrainer/gui/windowmain.py:331 -#: pytrainer/gui/windowmain.py:434 -#: pytrainer/gui/windowmain.py:435 -#: pytrainer/gui/windowmain.py:512 -#: pytrainer/gui/windowmain.py:513 -msgid "min/km" -msgstr "min/km" - -#: glade/pytrainer.glade:525 -#: glade/pytrainer.glade:752 -#: pytrainer/gui/windowmain.py:196 -#: pytrainer/gui/windowmain.py:197 -#: pytrainer/gui/windowmain.py:1047 -#: pytrainer/gui/windowmain.py:1049 -msgid "m" -msgstr "m" - -#: glade/pytrainer.glade:613 +#: glade/pytrainer.glade:614 msgid "<b>Date:</b>" msgstr "<b>Date:</b>" -#: glade/pytrainer.glade:627 -#: glade/pytrainer.glade:1999 -#: glade/pytrainer.glade:2612 -#: glade/pytrainer.glade:3237 -#: glade/pytrainer.glade:3938 +#: glade/pytrainer.glade:628 +#: glade/pytrainer.glade:2712 +#: glade/pytrainer.glade:3323 +#: glade/pytrainer.glade:3946 +#: glade/pytrainer.glade:4645 msgid "<b>Distance:</b>" msgstr "<b>Distance:</b>" -#: glade/pytrainer.glade:644 +#: glade/pytrainer.glade:645 msgid "<b>Max Speed</b>" msgstr "<b>Vit. Max:</b>" -#: glade/pytrainer.glade:660 -#: glade/pytrainer.glade:2301 -#: glade/pytrainer.glade:2914 -#: glade/pytrainer.glade:3539 -#: glade/pytrainer.glade:4164 +#: glade/pytrainer.glade:661 +#: glade/pytrainer.glade:3014 +#: glade/pytrainer.glade:3625 +#: glade/pytrainer.glade:4248 +#: glade/pytrainer.glade:4871 msgid "<b>Max Pace:</b>" msgstr "<b>Cad. Max:</b>" -#: glade/pytrainer.glade:676 +#: glade/pytrainer.glade:677 msgid "<b>Descent:</b>" msgstr "<b>Dénivelé Nég.:</b>" -#: glade/pytrainer.glade:768 -#: glade/pytrainer.glade:2211 -#: glade/pytrainer.glade:2780 -#: glade/pytrainer.glade:3405 -#: glade/pytrainer.glade:3864 +#: glade/pytrainer.glade:769 +#: glade/pytrainer.glade:2924 +#: glade/pytrainer.glade:3491 +#: glade/pytrainer.glade:4114 +#: glade/pytrainer.glade:4571 msgid "Cal" msgstr "Cal" -#: glade/pytrainer.glade:807 -#: glade/pytrainer.glade:1973 -#: glade/pytrainer.glade:2586 -#: glade/pytrainer.glade:3211 -#: glade/pytrainer.glade:4041 +#: glade/pytrainer.glade:808 +#: glade/pytrainer.glade:2686 +#: glade/pytrainer.glade:3297 +#: glade/pytrainer.glade:3920 +#: glade/pytrainer.glade:4748 +#: pytrainer/gui/windowmain.py:102 msgid "Km" msgstr "km" -#: glade/pytrainer.glade:824 -#: glade/pytrainer.glade:844 -#: glade/pytrainer.glade:867 -#: glade/pytrainer.glade:2028 -#: glade/pytrainer.glade:2049 -#: glade/pytrainer.glade:2071 -#: glade/pytrainer.glade:2662 -#: glade/pytrainer.glade:2684 -#: glade/pytrainer.glade:3287 -#: glade/pytrainer.glade:3309 -#: glade/pytrainer.glade:3987 -#: glade/pytrainer.glade:4009 -msgid "00" -msgstr "" +#: glade/pytrainer.glade:823 +#: glade/pytrainer.glade:2846 +#: glade/pytrainer.glade:2879 +#: glade/pytrainer.glade:3446 +#: glade/pytrainer.glade:3539 +#: glade/pytrainer.glade:4069 +#: glade/pytrainer.glade:4162 +#: glade/pytrainer.glade:4791 +#: glade/pytrainer.glade:4807 +#: pytrainer/gui/windowmain.py:616 +#: pytrainer/gui/windowmain.py:617 +#: pytrainer/gui/windowmain.py:739 +#: pytrainer/gui/windowmain.py:740 +#: pytrainer/gui/windowmain.py:817 +#: pytrainer/gui/windowmain.py:818 +#: pytrainer/lib/activity.py:199 +msgid "km/h" +msgstr "km/h" -#: glade/pytrainer.glade:1041 +#: glade/pytrainer.glade:838 +msgid "<b>Equipment:</b>" +msgstr "<b>Équipement:</b>" + +#: glade/pytrainer.glade:1014 msgid " <b>Title:</b>" msgstr " <b>Titre:</b>" -#: glade/pytrainer.glade:1098 +#: glade/pytrainer.glade:1064 +#: pytrainer/gui/windowmain.py:1350 +msgid "Show graph display options" +msgstr "Montrer les réglages du graphe" + +#: glade/pytrainer.glade:1082 msgid "" "Profile\n" "Speed\n" "Pace\n" "Heart Rate\n" -"Cadence" +"Cadence\n" +"Percentage\n" +"Zone" msgstr "" "Profil\n" "Vitesse\n" "Cadence\n" "Fréquence Cardiaque\n" -"Rythme" +"Rythme\n" +"Pourcentage\n" +"Zone" -#: glade/pytrainer.glade:1113 -#: glade/pytrainer.glade:3121 -#: glade/pytrainer.glade:3746 -#: glade/pytrainer.glade:4370 +#: glade/pytrainer.glade:1099 +#: glade/pytrainer.glade:3831 +#: glade/pytrainer.glade:4454 +#: glade/pytrainer.glade:5076 msgid "Versus" -msgstr "" +msgstr "Versus" -#: glade/pytrainer.glade:1124 +#: glade/pytrainer.glade:1110 msgid "" "None\n" "Profile\n" @@ -866,131 +1033,199 @@ "Fréquence Cardiaque\n" "Rythme\n" -#: glade/pytrainer.glade:1141 +#: glade/pytrainer.glade:1257 +msgid "<small>Graph Display Options</small>" +msgstr "<small>Options d'affichage des graphiques</small>" + +#: glade/pytrainer.glade:1282 +#: glade/pytrainer.glade:1497 +#: glade/pytrainer.glade:1717 +msgid "<small>Limits</small>" +msgstr "<small>Limites</small>" + +#: glade/pytrainer.glade:1294 +#: glade/pytrainer.glade:1509 +#: glade/pytrainer.glade:1763 +msgid "<small>Min</small>" +msgstr "<small>Min</small>" + +#: glade/pytrainer.glade:1306 +#: glade/pytrainer.glade:1521 +#: glade/pytrainer.glade:1775 +msgid "<small>Max</small>" +msgstr "<small>Max</small>" + +#: glade/pytrainer.glade:1355 +#: glade/pytrainer.glade:1577 +msgid "<small>Color</small>" +msgstr "<small>Couleur</small>" + +#: glade/pytrainer.glade:1386 +#: glade/pytrainer.glade:1590 +msgid "<small>Weight</small>" +msgstr "<small>Poids</small>" + +#: glade/pytrainer.glade:1416 +msgid "Y1" +msgstr "" + +#: glade/pytrainer.glade:1427 +#: glade/pytrainer.glade:1638 +msgid "<small>Smoothing</small>" +msgstr "<small>Lissage</small>" + +#: glade/pytrainer.glade:1567 +msgid "Y2" +msgstr "" + +#: glade/pytrainer.glade:1707 +msgid "X" +msgstr "" + +#: glade/pytrainer.glade:1788 +msgid "<small>Distance</small>" +msgstr "<small>Distance</small>" + +#: glade/pytrainer.glade:1817 +msgid "<small>Time</small>" +msgstr "<small>Temps</small>" + +#: glade/pytrainer.glade:1878 msgid "Show Laps" msgstr "Montrer les tours" -#: glade/pytrainer.glade:1199 -msgid "<small>Y Axis</small>" -msgstr "<small>Axe Y</small>" - -#: glade/pytrainer.glade:1248 -msgid "<small>Graph Display Options</small>" -msgstr "<small>Options d'affichage des graphiques</small>" - -#: glade/pytrainer.glade:1258 +#: glade/pytrainer.glade:1917 msgid "Reset Graph" msgstr "Réinitialiser le Graphe" -#: glade/pytrainer.glade:1262 -msgid "Reset Graph display to original settings" -msgstr "Revenir aux réglages initiaux pour l'affichage du graphe " +#: glade/pytrainer.glade:1979 +msgid "Redraw Map" +msgstr "Redessiner la carte" -#: glade/pytrainer.glade:1381 +#: glade/pytrainer.glade:1995 +msgid "<small>Display map using:</small>" +msgstr "<small>Afficher la carte avec:</small>" + +#: glade/pytrainer.glade:2097 msgid "<b>Beats:</b>" msgstr "<b>FC Moy:</b>" -#: glade/pytrainer.glade:1393 -#: glade/pytrainer.glade:2181 -#: glade/pytrainer.glade:2750 -#: glade/pytrainer.glade:3375 -#: glade/pytrainer.glade:3834 +#: glade/pytrainer.glade:2109 +#: glade/pytrainer.glade:2894 +#: glade/pytrainer.glade:3461 +#: glade/pytrainer.glade:4084 +#: glade/pytrainer.glade:4541 msgid "<b>Calories: </b>" msgstr "<b>Calories:</b>" -#: glade/pytrainer.glade:1407 -#: glade/pytrainer.glade:2333 -#: glade/pytrainer.glade:2978 -#: glade/pytrainer.glade:3603 -#: glade/pytrainer.glade:4212 +#: glade/pytrainer.glade:2123 +#: glade/pytrainer.glade:3046 +#: glade/pytrainer.glade:3689 +#: glade/pytrainer.glade:4312 +#: glade/pytrainer.glade:4919 msgid "<b>Max Beats:</b>" msgstr "<b>FC Max:</b>" -#: glade/pytrainer.glade:1421 +#: glade/pytrainer.glade:2137 msgid "<b>HR Zones Method:</b>" msgstr "<b>Calcul des zones de FC :</b>" -#: glade/pytrainer.glade:1436 +#: glade/pytrainer.glade:2152 msgid "<b>HR Zone5:</b>" msgstr "<b>Zone FC5:</b>" -#: glade/pytrainer.glade:1451 -#: glade/pytrainer.glade:1650 +#: glade/pytrainer.glade:2167 +#: glade/pytrainer.glade:2366 msgid " bpm" msgstr " bpm" -#: glade/pytrainer.glade:1467 +#: glade/pytrainer.glade:2183 msgid " Cal" msgstr " Cal" -#: glade/pytrainer.glade:1525 +#: glade/pytrainer.glade:2241 msgid "<b>HR Zone4:</b>" msgstr "<b>Zone FC4:</b>" -#: glade/pytrainer.glade:1541 +#: glade/pytrainer.glade:2257 msgid "<b>HR Zone3:</b>" msgstr "<b>Zone FC3:</b>" -#: glade/pytrainer.glade:1557 +#: glade/pytrainer.glade:2273 msgid "<b>HR Zone2:</b>" msgstr "<b>Zone FC2:</b>" -#: glade/pytrainer.glade:1573 +#: glade/pytrainer.glade:2289 msgid "<b>HR Zone1:</b>" msgstr "<b>Zone FC1:</b>" -#: glade/pytrainer.glade:1675 -#: glade/pytrainer.glade:1687 -#: glade/pytrainer.glade:1702 -#: glade/pytrainer.glade:1717 -#: glade/pytrainer.glade:1732 -#: glade/pytrainer.glade:2256 -#: glade/pytrainer.glade:2350 -#: glade/pytrainer.glade:2885 -#: glade/pytrainer.glade:2963 -#: glade/pytrainer.glade:3510 -#: glade/pytrainer.glade:3588 -#: glade/pytrainer.glade:3909 -#: glade/pytrainer.glade:4116 +#: glade/pytrainer.glade:2391 +#: glade/pytrainer.glade:2403 +#: glade/pytrainer.glade:2418 +#: glade/pytrainer.glade:2433 +#: glade/pytrainer.glade:2448 +#: glade/pytrainer.glade:2969 +#: glade/pytrainer.glade:3063 +#: glade/pytrainer.glade:3596 +#: glade/pytrainer.glade:3674 +#: glade/pytrainer.glade:4219 +#: glade/pytrainer.glade:4297 +#: glade/pytrainer.glade:4616 +#: glade/pytrainer.glade:4823 +#: pytrainer/lib/activity.py:432 +#: pytrainer/lib/activity.py:512 msgid "bpm" msgstr "bpm" -#: glade/pytrainer.glade:1777 +#: glade/pytrainer.glade:2493 msgid " <b>Heart Rate:</b>" msgstr " <b>Fréquence Cardiaque:</b>" -#: glade/pytrainer.glade:1905 -#, fuzzy -msgid "label-2147483647" -msgstr "label-2147483648" - -#: glade/pytrainer.glade:1939 +#: glade/pytrainer.glade:2653 msgid "Record" msgstr "Enregistrement" -#: glade/pytrainer.glade:2149 -#: glade/pytrainer.glade:2796 -#: glade/pytrainer.glade:3421 -#: glade/pytrainer.glade:4132 +#: glade/pytrainer.glade:2862 +#: glade/pytrainer.glade:3507 +#: glade/pytrainer.glade:4130 +#: glade/pytrainer.glade:4839 msgid "<b>Max Speed:</b>" msgstr "<b>Vit. Max:</b>" -#: glade/pytrainer.glade:2226 -#: glade/pytrainer.glade:2855 -#: glade/pytrainer.glade:3480 -#: glade/pytrainer.glade:3879 +#: glade/pytrainer.glade:2939 +#: glade/pytrainer.glade:3566 +#: glade/pytrainer.glade:4189 +#: glade/pytrainer.glade:4586 msgid "<b>Beats avg:</b>" msgstr "<b>FC Moy:</b>" -#: glade/pytrainer.glade:2440 +#: glade/pytrainer.glade:2999 +#: glade/pytrainer.glade:3031 +#: glade/pytrainer.glade:3642 +#: glade/pytrainer.glade:3658 +#: glade/pytrainer.glade:4265 +#: glade/pytrainer.glade:4281 +#: glade/pytrainer.glade:4888 +#: glade/pytrainer.glade:4904 +#: pytrainer/gui/windowmain.py:618 +#: pytrainer/gui/windowmain.py:619 +#: pytrainer/gui/windowmain.py:741 +#: pytrainer/gui/windowmain.py:742 +#: pytrainer/gui/windowmain.py:819 +#: pytrainer/gui/windowmain.py:820 +#: pytrainer/lib/activity.py:200 +msgid "min/km" +msgstr "min/km" + +#: glade/pytrainer.glade:3153 msgid " <b>Date:</b>" msgstr " <b>Date:</b>" -#: glade/pytrainer.glade:2484 +#: glade/pytrainer.glade:3196 msgid "Value" msgstr "Valeur" -#: glade/pytrainer.glade:2495 +#: glade/pytrainer.glade:3207 msgid "" "Stage Profile\n" "Stage Velocity\n" @@ -1000,23 +1235,17 @@ "Vitesse de la sortie\n" "Profil de la sortie/Vitesse" -#: glade/pytrainer.glade:2551 +#: glade/pytrainer.glade:3263 msgid "Day" msgstr "Jour" -#: glade/pytrainer.glade:2641 -#: glade/pytrainer.glade:3266 -#: glade/pytrainer.glade:3966 -msgid "000" -msgstr "" - -#: glade/pytrainer.glade:3054 +#: glade/pytrainer.glade:3765 msgid " <b>Week:</b>" msgstr "<b>Semaine:</b>" -#: glade/pytrainer.glade:3106 -#: glade/pytrainer.glade:3731 -#: glade/pytrainer.glade:4355 +#: glade/pytrainer.glade:3816 +#: glade/pytrainer.glade:4439 +#: glade/pytrainer.glade:5061 msgid "" "Distance\n" "Time\n" @@ -1030,9 +1259,9 @@ "Vitesse moyenne\n" "Calories" -#: glade/pytrainer.glade:3132 -#: glade/pytrainer.glade:3757 -#: glade/pytrainer.glade:4381 +#: glade/pytrainer.glade:3842 +#: glade/pytrainer.glade:4465 +#: glade/pytrainer.glade:5087 msgid "" "None\n" "Distance\n" @@ -1048,51 +1277,71 @@ "Vitesse moyenne\n" "Calories" -#: glade/pytrainer.glade:3176 +#: glade/pytrainer.glade:3886 msgid "Week" msgstr "Semaine" -#: glade/pytrainer.glade:3679 +#: glade/pytrainer.glade:4388 msgid " <b>Month:</b>" msgstr " <b>Mois:</b>" -#: glade/pytrainer.glade:3800 +#: glade/pytrainer.glade:4508 msgid "Month" msgstr "Mois" -#: glade/pytrainer.glade:4303 +#: glade/pytrainer.glade:5010 msgid " <b>Year:</b>" msgstr " <b>Année:</b>" -#: glade/pytrainer.glade:4424 +#: glade/pytrainer.glade:5130 msgid "Year" msgstr "Année" -#: glade/pytrainer.glade:4447 -msgid "label154" -msgstr "label154" +#: glade/pytrainer.glade:5284 +msgid "<b>Graph</b>" +msgstr "<b>Graphe:</b>" -#: glade/pytrainer.glade:4467 +#: glade/pytrainer.glade:5325 +msgid "<b>History</b>" +msgstr "<b>Historique</b>" + +#: glade/pytrainer.glade:5389 msgid "<b>Title:</b>" msgstr "<b>Titre:</b>" -#: glade/pytrainer.glade:4490 +#: glade/pytrainer.glade:5412 msgid "Search" msgstr "Rechercher" -#: glade/pytrainer.glade:4517 +#: glade/pytrainer.glade:5436 +msgid "All Distances" +msgstr "Toutes les distances" + +#: glade/pytrainer.glade:5445 +msgid "All Durations" +msgstr "Toutes les durées" + +#: glade/pytrainer.glade:5455 +msgid "" +"All time\n" +"Last 4 weeks\n" +"Last 6 months\n" +"Last 12 months" +msgstr "" +"Toutes les dates\n" +"Les 4 dernières semaines\n" +"Les 6 derniers mois\n" +"Les 12 derniers moiss" + +#: glade/pytrainer.glade:5492 msgid "Columns" msgstr "Colonnes" -#: glade/pytrainer.glade:4573 -msgid "label155" -msgstr "label155" - -#: glade/pytrainer.glade:4657 +#: glade/pytrainer.glade:5619 msgid "Type:" msgstr "Type:" -#: glade/pytrainer.glade:4670 +#: glade/pytrainer.glade:5632 msgid "" "Font\n" "Restaurant\n" @@ -1104,30 +1353,34 @@ "Vue Panoramique\n" "Sommet" -#: glade/pytrainer.glade:4686 +#: glade/pytrainer.glade:5648 msgid "Latitude: " msgstr "Latitude:" -#: glade/pytrainer.glade:4700 +#: glade/pytrainer.glade:5662 msgid " Name:" msgstr "Nom:" -#: glade/pytrainer.glade:4712 +#: glade/pytrainer.glade:5674 msgid "Longitude:" msgstr " Longitude:" -#: glade/pytrainer.glade:4804 +#: glade/pytrainer.glade:5766 msgid "<b> Waypoint: </b>" msgstr "<b> Point de localisation:</b>" -#: glade/pytrainer.glade:4885 -msgid "label162" -msgstr "label162" +#: glade/pytrainer.glade:5950 +msgid "Edit Record" +msgstr "Éditer un enregistrement" -#: glade/pytrainer.glade:4972 -msgid "label163" -msgstr "label163" +#: glade/pytrainer.glade:5964 +msgid "Show graph in classic view" +msgstr "Montrer le graphe dans la vue classique" +#: glade/pytrainer.glade:5978 +msgid "Merge tracks" +msgstr "Fusionner les traces" + #: glade/selecttrackdialog.glade:7 msgid "Select track record" msgstr "Sélectionnez un Circuit" @@ -1137,15 +1390,51 @@ msgid "Warning" msgstr "Attention" -#: extensions/openstreetmap/openstreetmap.py:27 +#: import/file_kml20.py:47 +msgid "Geodistance kml version 2.0 file" +msgstr "Fichier Geodistance kml version 2.0" + +#: import/file_gpxplus.py:41 +msgid "GPS eXchange file" +msgstr "Fichier de type GPX" + +#: import/tool_gpsbabel.py:37 +msgid "GPSBabel" +msgstr "GPSBabel" + +#: import/tool_garmintools.py:37 +msgid "Garmintools" +msgstr "Garmintools" + +#: import/file_garmintcxv1.py:45 +msgid "Garmin training center database file version 1" +msgstr "Fichier de base de données Garmin training center version 1" + +#: import/file_gpxplusNokia.py:41 +msgid "Nokia Export - GPS eXchange file" +msgstr "Export Nokia- GPS eXchange file" + +#: import/tool_gant.py:37 +msgid "Gant" +msgstr "Gant" + +#: import/file_garmintools.py:44 +msgid "Garmin tools dump file" +msgstr "Fichier de dump Garmin tools" + +#: import/file_garmintcxv2.py:43 +msgid "Garmin training center database file version 2" +msgstr "Fichier de base de données Garmin training center version 2" + +#: extensions/openstreetmap/openstreetmap.py:30 msgid "Must have username and password configured" msgstr "Un nom d'utilisateur et un mot de passe doivent être configurés" -#: extensions/openstreetmap/openstreetmap.py:29 +#: extensions/openstreetmap/openstreetmap.py:32 msgid "Openstreetmap Extension Error" msgstr "Erreur d'extension Openstreetmap" -#: extensions/openstreetmap/openstreetmap.py:66 +#: extensions/openstreetmap/openstreetmap.py:79 msgid "" "Posting GPX trace to Openstreetmap\n" "\n" @@ -1155,353 +1444,555 @@ "\n" "Merci d'attendre la fin du processus qui peut prendre quelques minutes" -#: extensions/openstreetmap/openstreetmap.py:68 +#: extensions/openstreetmap/openstreetmap.py:81 msgid "Openstreetmap Extension Processing" msgstr "Traitement de l'extension Openstreetmap" -#: extensions/openstreetmap/openstreetmap.py:86 +#: extensions/openstreetmap/openstreetmap.py:99 msgid "Openstreetmap Extension Upload Complete" msgstr "Chargement sur Openstreetmap effectué" -#: extensions/openstreetmap/openstreetmap.py:96 +#: extensions/openstreetmap/openstreetmap.py:109 msgid "Please add any additional information for this upload" msgstr "Merci de Compléter les informations pour ce chargement" -#: pytrainer/gui/windowprofile.py:53 -msgid "Male" -msgstr "Homme" +#: extensions/fixelevation/fixelevation.py:94 +msgid "Elevation Correction Complete" +msgstr "Correction d'élévation terminée" -#: pytrainer/gui/windowprofile.py:54 -msgid "Female" -msgstr "Femme" +#: extensions/wordpress/wordpress.py:46 +msgid "Posting to Wordpress blog" +msgstr "Poster sur le blog Wordpress" -#: pytrainer/gui/windowprofile.py:71 -msgid "MET" -msgstr "MET" +#: extensions/wordpress/wordpress.py:48 +msgid "Wordpress Extension Processing" +msgstr "Traitement de l'extension Wordpress" -#: pytrainer/gui/windowplugins.py:69 -#: pytrainer/gui/windowplugins.py:96 -#: pytrainer/gui/windowextensions.py:72 -#: pytrainer/gui/windowimportdata.py:542 -msgid "Enable" -msgstr "Activé" +#: extensions/wordpress/wordpress.py:144 +msgid "Wordpress Extension Upload Complete" +msgstr "Chargement sur Wordpress effectué" -#: pytrainer/gui/windowplugins.py:71 -#: pytrainer/gui/windowplugins.py:95 -#: pytrainer/gui/windowextensions.py:70 -#: pytrainer/gui/windowimportdata.py:541 -msgid "Disable" -msgstr "Désactivé" +#: pytrainer/record.py:63 +#: pytrainer/gui/windowmain.py:1740 +msgid "Edit Entry" +msgstr "Entrée Rapide" -#: pytrainer/gui/windowplugins.py:80 -#: pytrainer/gui/windowextensions.py:81 -#: pytrainer/gui/windowimportdata.py:526 -#, python-format -msgid "%s settings" -msgstr "" +#: pytrainer/record.py:513 +msgid "pyTrainer can't import data from your gpx file" +msgstr "pyTrainer ne peut pas importer de données depuis le fichier GPX" -#: pytrainer/gui/windowplugins.py:103 -#: pytrainer/gui/windowimportdata.py:549 -msgid "Ok" -msgstr "Ok" +#: pytrainer/monthgraph.py:70 +#: pytrainer/monthgraph.py:72 +#: pytrainer/monthgraph.py:74 +#: pytrainer/monthgraph.py:76 +#: pytrainer/monthgraph.py:78 +msgid "day" +msgstr "jour" -#: pytrainer/gui/windowmain.py:65 -#: pytrainer/gui/windowmain.py:68 -#: pytrainer/gui/windowmain.py:72 -msgid "id" -msgstr "id" +#: pytrainer/monthgraph.py:70 +#: pytrainer/weekgraph.py:115 +msgid "Daily Distance" +msgstr "Distance Journalière" -#: pytrainer/gui/windowmain.py:65 -msgid "Start" -msgstr "Début" +#: pytrainer/monthgraph.py:72 +#: pytrainer/weekgraph.py:117 +#: pytrainer/yeargraph.py:72 +msgid "Time (hours)" +msgstr "Durée (Heures)" -#: pytrainer/gui/windowmain.py:65 -msgid "Kilometer" -msgstr "Kilomètres" +#: pytrainer/monthgraph.py:72 +#: pytrainer/weekgraph.py:117 +msgid "Daily Time" +msgstr "Durée Journalière" -#: pytrainer/gui/windowmain.py:68 -#: pytrainer/gui/windowmain.py:748 -msgid "Title" -msgstr "Titre" +#: pytrainer/monthgraph.py:74 +#: pytrainer/weekgraph.py:119 +#: pytrainer/yeargraph.py:74 +msgid "Average Heart Rate (bpm)" +msgstr "FC moyenne (bpm):" -#: pytrainer/gui/windowmain.py:68 -#: pytrainer/gui/windowmain.py:749 -#: pytrainer/gui/dialogselecttrack.py:40 -msgid "Date" -msgstr "Date" +#: pytrainer/monthgraph.py:74 +#: pytrainer/weekgraph.py:119 +msgid "Daily Average Heart Rate" +msgstr "FC moyenne Journalière" -#: pytrainer/gui/windowmain.py:68 -#: pytrainer/gui/windowmain.py:750 -#: pytrainer/gui/windowrecord.py:147 -#: pytrainer/gui/windowimportdata.py:333 -#: pytrainer/extensions/googlemaps.py:93 -msgid "Distance" -msgstr "Distance" +#: pytrainer/monthgraph.py:76 +#: pytrainer/weekgraph.py:121 +msgid "Daily Average Speed" +msgstr "Vitesse moyenne Journalière" -#: pytrainer/gui/windowmain.py:68 -#: pytrainer/gui/windowmain.py:752 -#: pytrainer/extensions/googlemaps.py:93 -msgid "Time" -msgstr "Temps" +#: pytrainer/monthgraph.py:78 +#: pytrainer/weekgraph.py:123 +msgid "Daily Calories" +msgstr "Calories Journalière" -#: pytrainer/gui/windowmain.py:68 -#: pytrainer/gui/windowmain.py:753 +#: pytrainer/heartrategraph.py:36 +#: pytrainer/recordgraph.py:140 +#: pytrainer/daygraph.py:56 +msgid "Beats (bpm)" +msgstr "Pulsations (bpm)" + +#: pytrainer/recordgraph.py:134 +#: pytrainer/daygraph.py:52 +msgid "Height (m)" +msgstr "Altitude (m)" + +#: pytrainer/recordgraph.py:134 +#: pytrainer/daygraph.py:52 +msgid "Stage Profile" +msgstr "Profil de la sortie" + +#: pytrainer/recordgraph.py:136 +msgid "Speed (Km/h)" +msgstr "Vitesse (km/h)" + +#: pytrainer/recordgraph.py:136 +#: pytrainer/lib/activity.py:322 +#: pytrainer/lib/activity.py:412 +#: pytrainer/lib/activity.py:414 +msgid "Speed" +msgstr "Vitesse" + +#: pytrainer/recordgraph.py:138 +#: pytrainer/lib/activity.py:311 +#: pytrainer/lib/activity.py:421 +#: pytrainer/lib/activity.py:423 +msgid "Pace" +msgstr "Cadence" + +#: pytrainer/recordgraph.py:142 +msgid "Cadence (rpm)" +msgstr "Rythme (rpm) " + +#: pytrainer/recordgraph.py:142 +#: pytrainer/lib/activity.py:449 +#: pytrainer/lib/activity.py:451 +msgid "Cadence" +msgstr "Rythme" + +#: pytrainer/recordgraph.py:144 +msgid "Beats (%)" +msgstr "Pulsations (%)" + +#: pytrainer/recordgraph.py:144 +#: pytrainer/gui/windowmain.py:1136 msgid "Beats" msgstr "Pulsations" -#: pytrainer/gui/windowmain.py:68 -#: pytrainer/gui/windowmain.py:754 -msgid "Average" -msgstr "Moyenne" +#: pytrainer/recordgraph.py:146 +msgid "Zone" +msgstr "Zone" -#: pytrainer/gui/windowmain.py:72 +#: pytrainer/waypoint.py:87 +msgid "The gpx file seems to be a several days records. Perhaps you will need to edit your gpx file" +msgstr "Ce fichier GPX semble contenir plusieurs jours d'enregistrements. Vous devrez peut-être au préalable éditer celui-ci." + +#: pytrainer/extensions/googlemaps.py:69 +#: pytrainer/extensions/osm.py:48 +#: pytrainer/gui/windowmain.py:1654 +#: pytrainer/gui/drawArea.py:165 +msgid "h" +msgstr "h" + +#: pytrainer/extensions/googlemaps.py:69 +#: pytrainer/extensions/osm.py:48 +#: pytrainer/gui/drawArea.py:166 +msgid "min" +msgstr "min" + +#: pytrainer/extensions/googlemaps.py:71 +#: pytrainer/extensions/osm.py:50 +#: pytrainer/gui/windowmain.py:112 +#: pytrainer/gui/windowmain.py:393 +#: pytrainer/gui/windowmain.py:1135 +msgid "Time" +msgstr "Temps" + +#: pytrainer/extensions/googlemaps.py:71 +#: pytrainer/extensions/osm.py:50 +#: pytrainer/gui/windowmain.py:110 +#: pytrainer/gui/windowmain.py:392 +#: pytrainer/gui/windowmain.py:1133 +#: pytrainer/gui/windowimportdata.py:352 +#: pytrainer/gui/windowrecord.py:210 +#: pytrainer/lib/activity.py:310 +#: pytrainer/lib/activity.py:321 +#: pytrainer/lib/activity.py:393 +#: pytrainer/lib/activity.py:404 +#: pytrainer/lib/activity.py:413 +#: pytrainer/lib/activity.py:422 +#: pytrainer/lib/activity.py:431 +#: pytrainer/lib/activity.py:441 +#: pytrainer/lib/activity.py:450 +#: pytrainer/lib/activity.py:511 +msgid "Distance" +msgstr "Distance" + +#: pytrainer/gui/drawGraph.py:164 +msgid "Athlete Data" +msgstr "Données de l'athlète" + +#: pytrainer/gui/windowmain.py:100 +msgid "Miles" +msgstr "Miles" + +#: pytrainer/gui/windowmain.py:103 +#: pytrainer/gui/windowmain.py:107 +#: pytrainer/gui/windowmain.py:120 +#: pytrainer/gui/windowmain.py:123 +msgid "id" +msgstr "id" + +#: pytrainer/gui/windowmain.py:103 +msgid "Start" +msgstr "Début" + +#: pytrainer/gui/windowmain.py:113 +msgid "⌀ HR" +msgstr "FC" + +#: pytrainer/gui/windowmain.py:114 +msgid "⌀ Speed" +msgstr "Vitesse" + +#: pytrainer/gui/windowmain.py:120 msgid "Waypoint" msgstr "Point de Localisation" -#: pytrainer/gui/windowmain.py:183 -#: pytrainer/gui/windowmain.py:321 -#: pytrainer/gui/windowmain.py:425 -#: pytrainer/gui/windowmain.py:503 +#: pytrainer/gui/windowmain.py:125 +msgid "Weight" +msgstr "Poids" + +#: pytrainer/gui/windowmain.py:126 +msgid "Body Fat %" +msgstr "% de Masse Grasse" + +#: pytrainer/gui/windowmain.py:127 +msgid "Resting HR" +msgstr "Fréquence de repos" + +#: pytrainer/gui/windowmain.py:128 +msgid "Max HR" +msgstr "FC Max" + +#: pytrainer/gui/windowmain.py:394 +msgid "Laps" +msgstr "Tours" + +#: pytrainer/gui/windowmain.py:446 +msgid "Reset Limits" +msgstr "Réinitialiser les limites" + +#: pytrainer/gui/windowmain.py:448 +msgid "Set Limits" +msgstr "Fixer les limites" + +#: pytrainer/gui/windowmain.py:601 +msgid "Percentages method" +msgstr "Méthode basée sur des pourcentages" + +#: pytrainer/gui/windowmain.py:609 +#: pytrainer/gui/windowmain.py:732 +#: pytrainer/gui/windowmain.py:810 +#: pytrainer/lib/activity.py:193 msgid "miles" msgstr "miles" -#: pytrainer/gui/windowmain.py:184 -#: pytrainer/gui/windowmain.py:185 -#: pytrainer/gui/windowmain.py:322 -#: pytrainer/gui/windowmain.py:323 -#: pytrainer/gui/windowmain.py:426 -#: pytrainer/gui/windowmain.py:427 -#: pytrainer/gui/windowmain.py:504 -#: pytrainer/gui/windowmain.py:505 +#: pytrainer/gui/windowmain.py:610 +#: pytrainer/gui/windowmain.py:611 +#: pytrainer/gui/windowmain.py:733 +#: pytrainer/gui/windowmain.py:734 +#: pytrainer/gui/windowmain.py:811 +#: pytrainer/gui/windowmain.py:812 +#: pytrainer/lib/activity.py:194 msgid "miles/h" -msgstr "" +msgstr "miles/h" -#: pytrainer/gui/windowmain.py:186 -#: pytrainer/gui/windowmain.py:187 -#: pytrainer/gui/windowmain.py:324 -#: pytrainer/gui/windowmain.py:325 -#: pytrainer/gui/windowmain.py:428 -#: pytrainer/gui/windowmain.py:429 -#: pytrainer/gui/windowmain.py:506 -#: pytrainer/gui/windowmain.py:507 +#: pytrainer/gui/windowmain.py:612 +#: pytrainer/gui/windowmain.py:613 +#: pytrainer/gui/windowmain.py:735 +#: pytrainer/gui/windowmain.py:736 +#: pytrainer/gui/windowmain.py:813 +#: pytrainer/gui/windowmain.py:814 +#: pytrainer/lib/activity.py:195 msgid "min/mile" msgstr "min/mile" -#: pytrainer/gui/windowmain.py:188 -#: pytrainer/gui/windowmain.py:189 -msgid "feet" -msgstr "pieds" - -#: pytrainer/gui/windowmain.py:191 -#: pytrainer/gui/windowmain.py:327 -#: pytrainer/gui/windowmain.py:431 -#: pytrainer/gui/windowmain.py:509 -#: pytrainer/extensions/googlemaps.py:93 +#: pytrainer/gui/windowmain.py:615 +#: pytrainer/gui/windowmain.py:738 +#: pytrainer/gui/windowmain.py:816 +#: pytrainer/lib/activity.py:198 msgid "km" msgstr "km" -#: pytrainer/gui/windowmain.py:310 -msgid "Percentages method" -msgstr "Méthode basée sur des pourcentages" +#: pytrainer/gui/windowmain.py:1137 +msgid "Average" +msgstr "Moyenne" -#: pytrainer/gui/windowmain.py:1041 +#: pytrainer/gui/windowmain.py:1346 +msgid "Hide graph display options" +msgstr "Cacher les réglages du graphe " + +#: pytrainer/gui/windowmain.py:1644 msgid "lap" msgstr "tour " -#: pytrainer/gui/windowmain.py:1047 -#: pytrainer/gui/drawArea.py:143 -#: pytrainer/extensions/googlemaps.py:91 -msgid "h" -msgstr "" +#: pytrainer/gui/windowmain.py:1654 +#: pytrainer/gui/windowmain.py:1656 +#: pytrainer/lib/activity.py:201 +msgid "m" +msgstr "m" -#: pytrainer/gui/windowmain.py:1047 -#: pytrainer/gui/windowmain.py:1049 +#: pytrainer/gui/windowmain.py:1654 +#: pytrainer/gui/windowmain.py:1656 msgid "s" -msgstr "" +msgstr "s" -#: pytrainer/gui/dialogselecttrack.py:40 -msgid "Track Name" -msgstr "Nom du Circuit" +#: pytrainer/gui/windowmain.py:1751 +msgid "Delete Entry" +msgstr "Détruire l'entrée" -#: pytrainer/gui/drawArea.py:144 -#: pytrainer/extensions/googlemaps.py:91 -msgid "min" -msgstr "min" +#: pytrainer/gui/windowmain.py:1775 +msgid "Create Athlete Entry" +msgstr "Créer une entrée Athlète" -#: pytrainer/gui/windowrecord.py:147 -#: pytrainer/gui/windowimportdata.py:333 -msgid "Start Time" -msgstr "Heure de début" +#: pytrainer/gui/windowmain.py:1779 +msgid "Edit Athlete Entry" +msgstr "Éditer les données de l'athlète" -#: pytrainer/gui/windowrecord.py:147 -#: pytrainer/gui/windowimportdata.py:333 -msgid "Duration" -msgstr "Durée" +#: pytrainer/gui/windowmain.py:1860 +#: pytrainer/main.py:433 +msgid "Delete this database entry?" +msgstr "Supprimer cette entrée de la Base de Données?" -#: pytrainer/gui/windowrecord.py:147 -msgid "GPX File" -msgstr "Fichier GPX" +#: pytrainer/gui/windowmain.py:1862 +msgid "Are you sure?" +msgstr "Êtes vous sûr?" +#: pytrainer/gui/windowextensions.py:70 +#: pytrainer/gui/windowimportdata.py:560 +#: pytrainer/gui/windowplugins.py:71 +#: pytrainer/gui/windowplugins.py:95 +msgid "Disable" +msgstr "Désactivé" + +#: pytrainer/gui/windowextensions.py:72 +#: pytrainer/gui/windowimportdata.py:561 +#: pytrainer/gui/windowplugins.py:69 +#: pytrainer/gui/windowplugins.py:96 +msgid "Enable" +msgstr "Activé" + +#: pytrainer/gui/windowextensions.py:81 +#: pytrainer/gui/windowimportdata.py:545 +#: pytrainer/gui/windowplugins.py:80 +#, python-format +msgid "%s settings" +msgstr "" + #: pytrainer/gui/windowextensions.py:112 #: pytrainer/gui/windowextensions.py:125 msgid "OK" msgstr "OK" -#: pytrainer/gui/windowimportdata.py:110 +#: pytrainer/gui/windowimportdata.py:116 msgid "No file selected" msgstr "Pas de fichier sélectionné" -#: pytrainer/gui/windowimportdata.py:155 +#: pytrainer/gui/windowimportdata.py:161 msgid "Configure" msgstr "Configurer" -#: pytrainer/gui/windowimportdata.py:156 +#: pytrainer/gui/windowimportdata.py:162 msgid "Run" msgstr "" -#: pytrainer/gui/windowimportdata.py:164 +#: pytrainer/gui/windowimportdata.py:170 msgid "Disabled" msgstr "Désactivé" -#: pytrainer/gui/windowimportdata.py:166 +#: pytrainer/gui/windowimportdata.py:172 msgid "Enabled" msgstr "Activé" -#: pytrainer/gui/windowimportdata.py:233 +#: pytrainer/gui/windowimportdata.py:252 msgid "GPS device found" msgstr "Périphérique GPS trouvé" -#: pytrainer/gui/windowimportdata.py:236 +#: pytrainer/gui/windowimportdata.py:255 msgid "GPS device <b>not</b> found" msgstr "Périphérique GPS <b>non</b> trouvé" -#: pytrainer/gui/windowimportdata.py:243 +#: pytrainer/gui/windowimportdata.py:262 msgid "This tool was not found on the system" msgstr "Cet outil n'est pas installé sur votre système" -#: pytrainer/gui/windowimportdata.py:245 +#: pytrainer/gui/windowimportdata.py:264 msgid " Homepage" msgstr "Page d'accueil" -#: pytrainer/gui/windowimportdata.py:298 +#: pytrainer/gui/windowimportdata.py:317 msgid "File" msgstr "Fichier" -#: pytrainer/gui/windowimportdata.py:298 +#: pytrainer/gui/windowimportdata.py:317 msgid "Type" msgstr "Type" -#: pytrainer/gui/windowimportdata.py:298 +#: pytrainer/gui/windowimportdata.py:317 msgid "Activities" msgstr "Activités" -#: pytrainer/gui/windowimportdata.py:333 -msgid "Notes" -msgstr "" +#: pytrainer/gui/windowimportdata.py:352 +#: pytrainer/gui/windowrecord.py:210 +msgid "Start Time" +msgstr "Heure de début" -#: pytrainer/gui/windowimportdata.py:482 +#: pytrainer/gui/windowimportdata.py:352 +#: pytrainer/gui/windowrecord.py:210 +msgid "Duration" +msgstr "Durée" + +#: pytrainer/gui/windowimportdata.py:501 msgid "Imported into database" msgstr "Importé dans la base" -#: pytrainer/gui/windowimportdata.py:609 +#: pytrainer/gui/windowimportdata.py:568 +#: pytrainer/gui/windowplugins.py:103 +msgid "Ok" +msgstr "Ok" + +#: pytrainer/gui/windowimportdata.py:628 msgid "Saving options" msgstr "Sauvegarde des options" -#: pytrainer/gui/windowimportdata.py:611 +#: pytrainer/gui/windowimportdata.py:630 msgid "Options saved" msgstr "Options sauvegardées" -#: pytrainer/gui/windowimportdata.py:636 +#: pytrainer/gui/windowimportdata.py:655 msgid "Importing one activity" msgstr "Importation d'une activité" -#: pytrainer/gui/windowimportdata.py:637 +#: pytrainer/gui/windowimportdata.py:656 msgid "Imported one activity" msgstr "Une activité importée" -#: pytrainer/gui/windowimportdata.py:639 +#: pytrainer/gui/windowimportdata.py:658 #, python-format msgid "Importing %d activities" -msgstr "Import de %d activités" +msgstr "Importation de %d activités" -#: pytrainer/gui/windowimportdata.py:640 +#: pytrainer/gui/windowimportdata.py:659 #, python-format msgid "Imported %d activities" msgstr "%d activités importées" -#: pytrainer/gui/windowimportdata.py:659 +#: pytrainer/gui/windowimportdata.py:678 msgid "Choose a file (or files) to import activities from" -msgstr "Choisir un fichier pour importer vos activitées" +msgstr "Choisir un fichier pour importer vos activités" -#: pytrainer/gui/windowimp... [truncated message content] |
From: <jb...@us...> - 2010-11-25 22:38:10
|
Revision: 746 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=746&view=rev Author: jblance Date: 2010-11-25 22:38:03 +0000 (Thu, 25 Nov 2010) Log Message: ----------- Separate popup menu handler for listview and recordview and fix bug introduced in 745 Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-25 22:17:14 UTC (rev 745) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-25 22:38:03 UTC (rev 746) @@ -246,7 +246,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="rubber_banding">True</property> - <signal name="button_press_event" handler="on_allRecordTreeView_button_press"/> + <signal name="button_press_event" handler="on_recordTreeView_button_press_event"/> <signal name="row_activated" handler="on_recordTree_clicked"/> </widget> </child> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-25 22:17:14 UTC (rev 745) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-25 22:38:03 UTC (rev 746) @@ -1600,10 +1600,35 @@ self.parent.editGpsPlugins() #hasta aqui revisado + def on_recordTreeView_button_press_event(self, treeview, event): + ''' Handler for clicks on recordTreeview list (all records for a day) + event.button = mouse button pressed (i.e. 1 = left, 3 = right) + ''' + logging.debug(">>") + x = int(event.x) + y = int(event.y) + time = event.time + pthinfo = treeview.get_path_at_pos(x, y) + if pthinfo is not None: + path, col, cellx, celly = pthinfo + treeview.grab_focus() + treeview.set_cursor(path, col, 0) + if event.button == 3: + selected,iter = treeview.get_selection().get_selected() + #Por si hay un registro (malo) sin fecha, pa poder borrarlo + try: + date = self.parent.date.getDate() + except: + date = None + self.popup.show(selected.get_value(iter,0), event.button, time, date) + elif event.button == 1: + self.notebook.set_current_page(0) + self.parent.refreshGraphView("record") + logging.debug("<<") + return False + def on_allRecordTreeView_button_press(self, treeview, event): - ''' - Handler for clicks on recordview list (list of activities for the day) - + ''' Handler for clicks on listview list event.button = mouse button pressed (i.e. 1 = left, 3 = right) ''' logging.debug(">>") @@ -1619,7 +1644,7 @@ selected,iter = treeview.get_selection().get_selected() #Por si hay un registro (malo) sin fecha, pa poder borrarlo try: - date = self.parent.date.getDate(selected.get_value(iter,2)) + date = self.parent.date.getDate() except: pass self.popup.show(selected.get_value(iter,0), event.button, time, selected.get_value(iter,2)) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-25 22:17:14 UTC (rev 745) +++ pytrainer/trunk/pytrainer/main.py 2010-11-25 22:38:03 UTC (rev 746) @@ -53,7 +53,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#745" + self.version ="1.7.2_svn#746" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-25 22:41:26
|
Revision: 747 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=747&view=rev Author: jblance Date: 2010-11-25 22:41:20 +0000 (Thu, 25 Nov 2010) Log Message: ----------- Updated French localization from Pierre Modified Paths: -------------- pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer.mo pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer_fr.po pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer.mo =================================================================== (Binary files differ) Modified: pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer_fr.po =================================================================== --- pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer_fr.po 2010-11-25 22:38:03 UTC (rev 746) +++ pytrainer/trunk/locale/fr/LC_MESSAGES/pytrainer_fr.po 2010-11-25 22:41:20 UTC (rev 747) @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: pytrainer_fr\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-11-23 21:42+0100\n" -"PO-Revision-Date: 2010-11-23 21:43+0100\n" +"POT-Creation-Date: 2010-11-25 22:45+0100\n" +"PO-Revision-Date: \n" "Last-Translator: Pierre Gaigé <pg...@fr...>\n" "Language-Team: <fr...@li...>\n" "Language: \n" @@ -244,7 +244,7 @@ #: glade/importdata.glade:864 #: pytrainer/gui/windowmain.py:109 #: pytrainer/gui/windowmain.py:124 -#: pytrainer/gui/windowmain.py:1132 +#: pytrainer/gui/windowmain.py:1147 #: pytrainer/gui/dialogselecttrack.py:40 msgid "Date" msgstr "Date" @@ -299,7 +299,7 @@ #: glade/importdata.glade:972 #: pytrainer/gui/windowmain.py:108 -#: pytrainer/gui/windowmain.py:1131 +#: pytrainer/gui/windowmain.py:1146 msgid "Title" msgstr "Titre" @@ -330,7 +330,7 @@ #: glade/pytrainer.glade:277 #: pytrainer/gui/windowmain.py:103 #: pytrainer/gui/windowmain.py:111 -#: pytrainer/gui/windowmain.py:1134 +#: pytrainer/gui/windowmain.py:1149 #: pytrainer/gui/windowimportdata.py:352 #: pytrainer/gui/windowprofile.py:59 #: pytrainer/gui/windowrecord.py:210 @@ -348,14 +348,14 @@ #: glade/importdata.glade:1089 #: pytrainer/recordgraph.py:138 msgid "Pace (min/km)" -msgstr "Cadence (min/km)" +msgstr "Allure (min/km)" #: glade/importdata.glade:1102 msgid "Max Pace (min/km)" -msgstr "Cadence Max (min/km)" +msgstr "Allure Max (min/km)" #: glade/importdata.glade:1115 -#: glade/newrecord.glade:1095 +#: glade/newrecord.glade:1094 msgid "Comments" msgstr "Commentaires" @@ -364,7 +364,7 @@ msgstr "Forcer le sport à:" #: glade/importdata.glade:1323 -#: glade/newrecord.glade:406 +#: glade/newrecord.glade:404 msgid " " msgstr " " @@ -395,151 +395,151 @@ msgstr "<b>Importer à partir d'un fichier CSV</b>" #: glade/newrecord.glade:7 -#: pytrainer/gui/windowmain.py:1744 +#: pytrainer/gui/windowmain.py:1769 msgid "New Entry" msgstr "Nouvelle entrée" -#: glade/newrecord.glade:63 +#: glade/newrecord.glade:61 msgid "Title:" msgstr "Titre:" -#: glade/newrecord.glade:87 +#: glade/newrecord.glade:85 msgid "GPX File:" msgstr "Fichier GPX:" -#: glade/newrecord.glade:131 +#: glade/newrecord.glade:129 msgid "Calculate Values" msgstr "Calculer les Valeurs" -#: glade/newrecord.glade:151 +#: glade/newrecord.glade:149 msgid "Sport:" msgstr "Sport:" -#: glade/newrecord.glade:186 +#: glade/newrecord.glade:184 msgid "<b>Main</b>" msgstr "<b>Principal:</b>" -#: glade/newrecord.glade:223 +#: glade/newrecord.glade:221 msgid "Distance (Km):" msgstr "Distance (km):" -#: glade/newrecord.glade:232 -#: glade/newrecord.glade:357 -#: glade/newrecord.glade:560 -#: glade/newrecord.glade:698 -#: glade/newrecord.glade:959 +#: glade/newrecord.glade:230 +#: glade/newrecord.glade:355 +#: glade/newrecord.glade:558 +#: glade/newrecord.glade:697 +#: glade/newrecord.glade:958 #: glade/profile.glade:1462 msgid "Calculate" msgstr "Calculer" -#: glade/newrecord.glade:250 +#: glade/newrecord.glade:248 msgid "Duration:" msgstr "Durée" -#: glade/newrecord.glade:281 -#: glade/newrecord.glade:308 +#: glade/newrecord.glade:279 +#: glade/newrecord.glade:306 msgid ":" msgstr ":" -#: glade/newrecord.glade:378 +#: glade/newrecord.glade:376 msgid "Date:" msgstr "Date:" -#: glade/newrecord.glade:447 +#: glade/newrecord.glade:445 msgid "Start Time:" msgstr "Début:" -#: glade/newrecord.glade:463 +#: glade/newrecord.glade:461 msgid "12:00:00" msgstr "" -#: glade/newrecord.glade:488 +#: glade/newrecord.glade:486 #: glade/profile.glade:1500 msgid "<b>General</b>" msgstr "<b>Général:</b>" -#: glade/newrecord.glade:524 +#: glade/newrecord.glade:522 msgid "Max (km/h):" msgstr "Max (km/h):" -#: glade/newrecord.glade:549 +#: glade/newrecord.glade:547 msgid "Average (km/h)" msgstr "Vitesse moy. (km/h)" -#: glade/newrecord.glade:595 +#: glade/newrecord.glade:593 msgid "<b>Speed</b>" msgstr "<b>Vitesse:</b>" -#: glade/newrecord.glade:614 +#: glade/newrecord.glade:612 msgid "Quick Entry" msgstr "Entrée Rapide" -#: glade/newrecord.glade:647 +#: glade/newrecord.glade:644 msgid "Max (min/km):" msgstr "Max (min/km)" -#: glade/newrecord.glade:673 +#: glade/newrecord.glade:671 msgid "Pace (min/km):" -msgstr "Cadence (min/km)" +msgstr "Allure (min/km)" -#: glade/newrecord.glade:719 +#: glade/newrecord.glade:718 msgid "<b>Pace</b>" -msgstr "<b>Cadence:</b>" +msgstr "<b>Allure</b>" -#: glade/newrecord.glade:755 +#: glade/newrecord.glade:754 msgid "Ascent:" -msgstr "Dénivelé Pos.:" +msgstr "Dénivelé Positif:" -#: glade/newrecord.glade:781 +#: glade/newrecord.glade:780 msgid "Descent:" -msgstr "Dénivelé Nég.:" +msgstr "Dénivelé Négatif:" -#: glade/newrecord.glade:814 +#: glade/newrecord.glade:813 msgid "<b>Accumulated Altitude Change</b>" msgstr " <b>Dénivelé Cumulé:</b> " -#: glade/newrecord.glade:851 +#: glade/newrecord.glade:850 msgid "Max (bpm):" msgstr "Max (bpm):" -#: glade/newrecord.glade:863 +#: glade/newrecord.glade:862 msgid "Heart rate:" msgstr "Fréquence Cardiaque:" -#: glade/newrecord.glade:903 +#: glade/newrecord.glade:902 #: pytrainer/monthgraph.py:78 #: pytrainer/weekgraph.py:123 #: pytrainer/gui/windowmain.py:115 -#: pytrainer/gui/windowmain.py:1138 +#: pytrainer/gui/windowmain.py:1153 #: pytrainer/yeargraph.py:78 msgid "Calories" msgstr "Calories" -#: glade/newrecord.glade:932 +#: glade/newrecord.glade:931 msgid "<small><b>Note:</b> In order to calculate the calories you must set the sport MET (in Preferences->Sport) </small>" msgstr "<small><b>Note:</b> Afin de calculer les calories vous devez renseigner le coefficient M.E.T. pour votre sport (menu Préférences->Sport) </small>" -#: glade/newrecord.glade:1006 +#: glade/newrecord.glade:1005 msgid "<b>Heart Rate</b>" msgstr "<b>Fréquence Cardiaque:</b>" -#: glade/newrecord.glade:1028 +#: glade/newrecord.glade:1027 msgid "Advanced" msgstr "Avancé" -#: glade/newrecord.glade:1080 +#: glade/newrecord.glade:1079 msgid "<b>Comments</b>" msgstr "<b>Commentaires</b>" -#: glade/newrecord.glade:1135 +#: glade/newrecord.glade:1134 msgid "<i>There are no active equipment items.</i>" msgstr "<i>Il n'y a aucun article d'équipement actif.</i>" -#: glade/newrecord.glade:1189 +#: glade/newrecord.glade:1188 msgid "<b>Associated Equipment</b>" msgstr "<b>Équipement associé</b>" -#: glade/newrecord.glade:1204 +#: glade/newrecord.glade:1203 #: glade/profile.glade:1360 msgid "Equipment" msgstr "Équipement" @@ -670,7 +670,7 @@ #: glade/profile.glade:821 msgid "Maximum Pace:" -msgstr "Cadence Max:" +msgstr "Allure Max:" #: glade/profile.glade:913 msgid "<b>Add New Sport</b>" @@ -711,7 +711,7 @@ #: glade/profile.glade:1201 msgid "Maxiumum Pace" -msgstr "Cadence Max" +msgstr "Allure Max" #: glade/profile.glade:1289 msgid "<b>Edit Sport</b>" @@ -750,7 +750,7 @@ msgstr "Méthode basée sur des pourcentages" #: glade/profile.glade:1565 -#: pytrainer/gui/windowmain.py:599 +#: pytrainer/gui/windowmain.py:614 msgid "Karvonen method" msgstr "Méthode de Karvonen" @@ -766,10 +766,10 @@ #: pytrainer/heartrategraph.py:36 #: pytrainer/recordgraph.py:140 #: pytrainer/daygraph.py:56 -#: pytrainer/lib/activity.py:430 -#: pytrainer/lib/activity.py:432 -#: pytrainer/lib/activity.py:442 -#: pytrainer/lib/activity.py:512 +#: pytrainer/lib/activity.py:433 +#: pytrainer/lib/activity.py:435 +#: pytrainer/lib/activity.py:445 +#: pytrainer/lib/activity.py:515 msgid "Heart Rate" msgstr "Fréquence Cardiaque" @@ -901,11 +901,11 @@ #: glade/pytrainer.glade:4234 #: glade/pytrainer.glade:4856 msgid "<b>Pace:</b>" -msgstr "<b>Cadence:</b>" +msgstr "<b>Allure:</b>" #: glade/pytrainer.glade:451 msgid "<b>Ascent:</b>" -msgstr "<b>Dénivelé Pos.:</b>" +msgstr "<b>Dénivelé Positif:</b>" #: glade/pytrainer.glade:465 msgid "<b>Calories:</b>" @@ -929,7 +929,7 @@ #: glade/pytrainer.glade:645 msgid "<b>Max Speed</b>" -msgstr "<b>Vit. Max:</b>" +msgstr "<b>Vitesse Max:</b>" #: glade/pytrainer.glade:661 #: glade/pytrainer.glade:3014 @@ -937,11 +937,11 @@ #: glade/pytrainer.glade:4248 #: glade/pytrainer.glade:4871 msgid "<b>Max Pace:</b>" -msgstr "<b>Cad. Max:</b>" +msgstr "<b>Allure Max:</b>" #: glade/pytrainer.glade:677 msgid "<b>Descent:</b>" -msgstr "<b>Dénivelé Nég.:</b>" +msgstr "<b>Dénivelé Négatif:</b>" #: glade/pytrainer.glade:769 #: glade/pytrainer.glade:2924 @@ -969,13 +969,13 @@ #: glade/pytrainer.glade:4162 #: glade/pytrainer.glade:4791 #: glade/pytrainer.glade:4807 -#: pytrainer/gui/windowmain.py:616 -#: pytrainer/gui/windowmain.py:617 -#: pytrainer/gui/windowmain.py:739 -#: pytrainer/gui/windowmain.py:740 -#: pytrainer/gui/windowmain.py:817 -#: pytrainer/gui/windowmain.py:818 -#: pytrainer/lib/activity.py:199 +#: pytrainer/gui/windowmain.py:631 +#: pytrainer/gui/windowmain.py:632 +#: pytrainer/gui/windowmain.py:754 +#: pytrainer/gui/windowmain.py:755 +#: pytrainer/gui/windowmain.py:832 +#: pytrainer/gui/windowmain.py:833 +#: pytrainer/lib/activity.py:202 msgid "km/h" msgstr "km/h" @@ -988,7 +988,7 @@ msgstr " <b>Titre:</b>" #: glade/pytrainer.glade:1064 -#: pytrainer/gui/windowmain.py:1350 +#: pytrainer/gui/windowmain.py:1375 msgid "Show graph display options" msgstr "Montrer les réglages du graphe" @@ -1004,7 +1004,7 @@ msgstr "" "Profil\n" "Vitesse\n" -"Cadence\n" +"Allure\n" "Fréquence Cardiaque\n" "Rythme\n" "Pourcentage\n" @@ -1029,7 +1029,7 @@ "Null\n" "Profil\n" "Vitesse\n" -"Cadence\n" +"Allure\n" "Fréquence Cardiaque\n" "Rythme\n" @@ -1172,8 +1172,8 @@ #: glade/pytrainer.glade:4297 #: glade/pytrainer.glade:4616 #: glade/pytrainer.glade:4823 -#: pytrainer/lib/activity.py:432 -#: pytrainer/lib/activity.py:512 +#: pytrainer/lib/activity.py:435 +#: pytrainer/lib/activity.py:515 msgid "bpm" msgstr "bpm" @@ -1207,13 +1207,13 @@ #: glade/pytrainer.glade:4281 #: glade/pytrainer.glade:4888 #: glade/pytrainer.glade:4904 -#: pytrainer/gui/windowmain.py:618 -#: pytrainer/gui/windowmain.py:619 -#: pytrainer/gui/windowmain.py:741 -#: pytrainer/gui/windowmain.py:742 -#: pytrainer/gui/windowmain.py:819 -#: pytrainer/gui/windowmain.py:820 -#: pytrainer/lib/activity.py:200 +#: pytrainer/gui/windowmain.py:633 +#: pytrainer/gui/windowmain.py:634 +#: pytrainer/gui/windowmain.py:756 +#: pytrainer/gui/windowmain.py:757 +#: pytrainer/gui/windowmain.py:834 +#: pytrainer/gui/windowmain.py:835 +#: pytrainer/lib/activity.py:203 msgid "min/km" msgstr "min/km" @@ -1473,7 +1473,7 @@ msgstr "Chargement sur Wordpress effectué" #: pytrainer/record.py:63 -#: pytrainer/gui/windowmain.py:1740 +#: pytrainer/gui/windowmain.py:1765 msgid "Edit Entry" msgstr "Entrée Rapide" @@ -1547,26 +1547,26 @@ msgstr "Vitesse (km/h)" #: pytrainer/recordgraph.py:136 -#: pytrainer/lib/activity.py:322 -#: pytrainer/lib/activity.py:412 -#: pytrainer/lib/activity.py:414 +#: pytrainer/lib/activity.py:325 +#: pytrainer/lib/activity.py:415 +#: pytrainer/lib/activity.py:417 msgid "Speed" msgstr "Vitesse" #: pytrainer/recordgraph.py:138 -#: pytrainer/lib/activity.py:311 -#: pytrainer/lib/activity.py:421 -#: pytrainer/lib/activity.py:423 +#: pytrainer/lib/activity.py:314 +#: pytrainer/lib/activity.py:424 +#: pytrainer/lib/activity.py:426 msgid "Pace" -msgstr "Cadence" +msgstr "Allure" #: pytrainer/recordgraph.py:142 msgid "Cadence (rpm)" -msgstr "Rythme (rpm) " +msgstr "Rythme (tpm) " #: pytrainer/recordgraph.py:142 -#: pytrainer/lib/activity.py:449 -#: pytrainer/lib/activity.py:451 +#: pytrainer/lib/activity.py:452 +#: pytrainer/lib/activity.py:454 msgid "Cadence" msgstr "Rythme" @@ -1575,7 +1575,7 @@ msgstr "Pulsations (%)" #: pytrainer/recordgraph.py:144 -#: pytrainer/gui/windowmain.py:1136 +#: pytrainer/gui/windowmain.py:1151 msgid "Beats" msgstr "Pulsations" @@ -1589,7 +1589,7 @@ #: pytrainer/extensions/googlemaps.py:69 #: pytrainer/extensions/osm.py:48 -#: pytrainer/gui/windowmain.py:1654 +#: pytrainer/gui/windowmain.py:1679 #: pytrainer/gui/drawArea.py:165 msgid "h" msgstr "h" @@ -1603,32 +1603,32 @@ #: pytrainer/extensions/googlemaps.py:71 #: pytrainer/extensions/osm.py:50 #: pytrainer/gui/windowmain.py:112 -#: pytrainer/gui/windowmain.py:393 -#: pytrainer/gui/windowmain.py:1135 +#: pytrainer/gui/windowmain.py:394 +#: pytrainer/gui/windowmain.py:1150 msgid "Time" msgstr "Temps" #: pytrainer/extensions/googlemaps.py:71 #: pytrainer/extensions/osm.py:50 #: pytrainer/gui/windowmain.py:110 -#: pytrainer/gui/windowmain.py:392 -#: pytrainer/gui/windowmain.py:1133 +#: pytrainer/gui/windowmain.py:393 +#: pytrainer/gui/windowmain.py:1148 #: pytrainer/gui/windowimportdata.py:352 #: pytrainer/gui/windowrecord.py:210 -#: pytrainer/lib/activity.py:310 -#: pytrainer/lib/activity.py:321 -#: pytrainer/lib/activity.py:393 -#: pytrainer/lib/activity.py:404 -#: pytrainer/lib/activity.py:413 -#: pytrainer/lib/activity.py:422 -#: pytrainer/lib/activity.py:431 -#: pytrainer/lib/activity.py:441 -#: pytrainer/lib/activity.py:450 -#: pytrainer/lib/activity.py:511 +#: pytrainer/lib/activity.py:313 +#: pytrainer/lib/activity.py:324 +#: pytrainer/lib/activity.py:396 +#: pytrainer/lib/activity.py:407 +#: pytrainer/lib/activity.py:416 +#: pytrainer/lib/activity.py:425 +#: pytrainer/lib/activity.py:434 +#: pytrainer/lib/activity.py:444 +#: pytrainer/lib/activity.py:453 +#: pytrainer/lib/activity.py:514 msgid "Distance" msgstr "Distance" -#: pytrainer/gui/drawGraph.py:164 +#: pytrainer/gui/drawGraph.py:170 msgid "Athlete Data" msgstr "Données de l'athlète" @@ -1675,97 +1675,109 @@ msgid "Max HR" msgstr "FC Max" -#: pytrainer/gui/windowmain.py:394 +#: pytrainer/gui/windowmain.py:395 msgid "Laps" msgstr "Tours" -#: pytrainer/gui/windowmain.py:446 +#: pytrainer/gui/windowmain.py:396 +msgid "Left Axis Grid" +msgstr "Grille d'axe Gauche" + +#: pytrainer/gui/windowmain.py:397 +msgid "Right Axis Grid" +msgstr "Grille d'axe Droite" + +#: pytrainer/gui/windowmain.py:398 +msgid "X Axis Grid" +msgstr "Grille d'axe X" + +#: pytrainer/gui/windowmain.py:459 msgid "Reset Limits" msgstr "Réinitialiser les limites" -#: pytrainer/gui/windowmain.py:448 +#: pytrainer/gui/windowmain.py:461 msgid "Set Limits" msgstr "Fixer les limites" -#: pytrainer/gui/windowmain.py:601 +#: pytrainer/gui/windowmain.py:616 msgid "Percentages method" msgstr "Méthode basée sur des pourcentages" -#: pytrainer/gui/windowmain.py:609 -#: pytrainer/gui/windowmain.py:732 -#: pytrainer/gui/windowmain.py:810 -#: pytrainer/lib/activity.py:193 +#: pytrainer/gui/windowmain.py:624 +#: pytrainer/gui/windowmain.py:747 +#: pytrainer/gui/windowmain.py:825 +#: pytrainer/lib/activity.py:196 msgid "miles" msgstr "miles" -#: pytrainer/gui/windowmain.py:610 -#: pytrainer/gui/windowmain.py:611 -#: pytrainer/gui/windowmain.py:733 -#: pytrainer/gui/windowmain.py:734 -#: pytrainer/gui/windowmain.py:811 -#: pytrainer/gui/windowmain.py:812 -#: pytrainer/lib/activity.py:194 +#: pytrainer/gui/windowmain.py:625 +#: pytrainer/gui/windowmain.py:626 +#: pytrainer/gui/windowmain.py:748 +#: pytrainer/gui/windowmain.py:749 +#: pytrainer/gui/windowmain.py:826 +#: pytrainer/gui/windowmain.py:827 +#: pytrainer/lib/activity.py:197 msgid "miles/h" msgstr "miles/h" -#: pytrainer/gui/windowmain.py:612 -#: pytrainer/gui/windowmain.py:613 -#: pytrainer/gui/windowmain.py:735 -#: pytrainer/gui/windowmain.py:736 -#: pytrainer/gui/windowmain.py:813 -#: pytrainer/gui/windowmain.py:814 -#: pytrainer/lib/activity.py:195 +#: pytrainer/gui/windowmain.py:627 +#: pytrainer/gui/windowmain.py:628 +#: pytrainer/gui/windowmain.py:750 +#: pytrainer/gui/windowmain.py:751 +#: pytrainer/gui/windowmain.py:828 +#: pytrainer/gui/windowmain.py:829 +#: pytrainer/lib/activity.py:198 msgid "min/mile" msgstr "min/mile" -#: pytrainer/gui/windowmain.py:615 -#: pytrainer/gui/windowmain.py:738 -#: pytrainer/gui/windowmain.py:816 -#: pytrainer/lib/activity.py:198 +#: pytrainer/gui/windowmain.py:630 +#: pytrainer/gui/windowmain.py:753 +#: pytrainer/gui/windowmain.py:831 +#: pytrainer/lib/activity.py:201 msgid "km" msgstr "km" -#: pytrainer/gui/windowmain.py:1137 +#: pytrainer/gui/windowmain.py:1152 msgid "Average" msgstr "Moyenne" -#: pytrainer/gui/windowmain.py:1346 +#: pytrainer/gui/windowmain.py:1371 msgid "Hide graph display options" msgstr "Cacher les réglages du graphe " -#: pytrainer/gui/windowmain.py:1644 +#: pytrainer/gui/windowmain.py:1669 msgid "lap" msgstr "tour " -#: pytrainer/gui/windowmain.py:1654 -#: pytrainer/gui/windowmain.py:1656 -#: pytrainer/lib/activity.py:201 +#: pytrainer/gui/windowmain.py:1679 +#: pytrainer/gui/windowmain.py:1681 +#: pytrainer/lib/activity.py:204 msgid "m" msgstr "m" -#: pytrainer/gui/windowmain.py:1654 -#: pytrainer/gui/windowmain.py:1656 +#: pytrainer/gui/windowmain.py:1679 +#: pytrainer/gui/windowmain.py:1681 msgid "s" msgstr "s" -#: pytrainer/gui/windowmain.py:1751 +#: pytrainer/gui/windowmain.py:1776 msgid "Delete Entry" msgstr "Détruire l'entrée" -#: pytrainer/gui/windowmain.py:1775 +#: pytrainer/gui/windowmain.py:1800 msgid "Create Athlete Entry" msgstr "Créer une entrée Athlète" -#: pytrainer/gui/windowmain.py:1779 +#: pytrainer/gui/windowmain.py:1804 msgid "Edit Athlete Entry" msgstr "Éditer les données de l'athlète" -#: pytrainer/gui/windowmain.py:1860 +#: pytrainer/gui/windowmain.py:1885 #: pytrainer/main.py:433 msgid "Delete this database entry?" msgstr "Supprimer cette entrée de la Base de Données?" -#: pytrainer/gui/windowmain.py:1862 +#: pytrainer/gui/windowmain.py:1887 msgid "Are you sure?" msgstr "Êtes vous sûr?" @@ -1927,7 +1939,7 @@ #: pytrainer/gui/windowprofile.py:59 msgid "Maximum Pace" -msgstr "Cadence Maximale" +msgstr "Allure Maximale" #: pytrainer/gui/drawArea.py:399 msgid "rest" @@ -2009,55 +2021,55 @@ msgid "kg" msgstr "kg" -#: pytrainer/lib/activity.py:196 +#: pytrainer/lib/activity.py:199 msgid "feet" msgstr "pieds" -#: pytrainer/lib/activity.py:309 +#: pytrainer/lib/activity.py:312 msgid "Pace by Lap" -msgstr "Cadence au tour" +msgstr "Allure au tour" -#: pytrainer/lib/activity.py:315 -#: pytrainer/lib/activity.py:326 -#: pytrainer/lib/activity.py:398 -#: pytrainer/lib/activity.py:408 -#: pytrainer/lib/activity.py:417 -#: pytrainer/lib/activity.py:426 -#: pytrainer/lib/activity.py:435 -#: pytrainer/lib/activity.py:445 -#: pytrainer/lib/activity.py:454 -#: pytrainer/lib/activity.py:516 +#: pytrainer/lib/activity.py:318 +#: pytrainer/lib/activity.py:329 +#: pytrainer/lib/activity.py:401 +#: pytrainer/lib/activity.py:411 +#: pytrainer/lib/activity.py:420 +#: pytrainer/lib/activity.py:429 +#: pytrainer/lib/activity.py:438 +#: pytrainer/lib/activity.py:448 +#: pytrainer/lib/activity.py:457 +#: pytrainer/lib/activity.py:519 msgid "Time (seconds)" msgstr "Durée (s)" -#: pytrainer/lib/activity.py:320 +#: pytrainer/lib/activity.py:323 msgid "Speed by Lap" msgstr "Vitesse au tour" -#: pytrainer/lib/activity.py:392 -#: pytrainer/lib/activity.py:394 +#: pytrainer/lib/activity.py:395 +#: pytrainer/lib/activity.py:397 msgid "Elevation" msgstr "Altitude" -#: pytrainer/lib/activity.py:403 -#: pytrainer/lib/activity.py:405 +#: pytrainer/lib/activity.py:406 +#: pytrainer/lib/activity.py:408 msgid "Corrected Elevation" msgstr "Altitude corrigée" -#: pytrainer/lib/activity.py:440 +#: pytrainer/lib/activity.py:443 #, python-format msgid "Heart Rate (% of max)" msgstr "Fréquence Cardiaque (% du max)" -#: pytrainer/lib/activity.py:442 +#: pytrainer/lib/activity.py:445 msgid "%" msgstr "%" -#: pytrainer/lib/activity.py:451 +#: pytrainer/lib/activity.py:454 msgid "rpm" msgstr "tpm" -#: pytrainer/lib/activity.py:510 +#: pytrainer/lib/activity.py:513 msgid "Heart Rate zone" msgstr "Zone de Fréquence Cardiaque" Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-25 22:38:03 UTC (rev 746) +++ pytrainer/trunk/pytrainer/main.py 2010-11-25 22:41:20 UTC (rev 747) @@ -53,7 +53,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#746" + self.version ="1.7.2_svn#747" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dg...@us...> - 2010-11-29 23:23:26
|
Revision: 751 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=751&view=rev Author: dgranda Date: 2010-11-29 22:39:36 +0000 (Mon, 29 Nov 2010) Log Message: ----------- Updating info for version 1.8.0 Modified Paths: -------------- pytrainer/trunk/CHANGES pytrainer/trunk/pytrainer/gui/aboutdialog.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/setup.py Modified: pytrainer/trunk/CHANGES =================================================================== --- pytrainer/trunk/CHANGES 2010-11-27 14:21:55 UTC (rev 750) +++ pytrainer/trunk/CHANGES 2010-11-29 22:39:36 UTC (rev 751) @@ -1,5 +1,70 @@ See the pytrainer roadmap for more information http://sourceforge.net/apps/trac/pytrainer/roadmap +- PyTrainer changes for 1.8.0: + +* New functionality + - Equipment management (thx to Nathan) [571] [572] [573] [598] [678] [679] [680] [685] [698] [699] [707] [708] [711] [717] [718] #12 + - OpenStreetMap added as route map viewer (user selectable) - thanks to Druzee [578] [585] [590] + - Anonymous data for OSM, cancel button (thx to Druzee, Arnd) [608] [611] [626] + - Changes to graphing to allow user to change limits, color, line width etc [563] [567] [579] [599] + - Remember size of main screen [581] + - Function to merge tracks (work in progress) [597] + - New Activity and ActivityPool classes to hold all info about an activity [582] [583] [584] [587] [589] [591] [677] [694] + - Management of athlete data [605] [609] [649] [651] [653] [655] [656] [665] [668] [731] #13 + - New graphic approach [616] [617] [622] [624] [628] [638] [639] [640] [642] [644] [646] [648] [674] [675] [721] [726] [727] [730] [733] + - Added support for Nokia exported GPX files [673] + - Added support for new formats (csv, delimited file) in unified import [688] [689] [690] [692] [693] [695] [697] [701] + +* Fixes + - Variables and configuration refactored to be 'global' (reused and not re-instantiated by each class) [561] [562] [564] [565] [566] [568] #28 + - Config file accepting non ascii characters [574] [575] [576] + - Config file handling fixed to not fail with empty or missing file [586] #48 + - Fix list view to update after edit, delete, import. Added filters and improvements (tnx Arnd) [569] [650] [652] [658] [661] [663] [664] [735] [742] [745] [746] + - Localization updates (thanks to Pierre, David) [570] [588] [595] [715] [737] [744] [747] + - Fix wordpress extension to work with newer wordpress codebase and support US measurement [577] [601] [602] #45 #51 + - Update plugins to write UTF8 not ASCII GPX files [580] #47 + - Fix googlemaps lap data display [592] [632] [633] + - Fix calories display in heartrate tab [593] + - Fix html in map generation (thanks to Druzee) [594] + - Change default graph colors [596] + - Improve handling of US units [600] [669] [672] [683] [687] [696] [700] [702] [703] [704] [705] [710] [738] [739] + - Fix bug in plugins where ESC during file open dialog causes error [603] + - Fix to garmintools_full plugin to make progress bar work (thanks to Druzee) [604] + - Avoid exiting when parsing problem is found, entry skipped [607] # + - Activites without GPX data don't break application [610] [615] + - Improvements (show and calculation) to pace and elevation as suggested by Arnd [612] [618] [619] [623] [627] [741] + - Better troubleshooting for graphics issues and minor fixes [625] [629] [636] + - Fixes to csv export (thx Arnd) [630] + - Fixes to startup script to better handling different environments [631] [637] [713] [714] + - Updates to wordpress extension - removed separate googlemaps [634] + - Allowing zero calories entries [641] + - Fixes to edit record [643] [647] + - Fixing confusion with dates (start day of the week, week number) [654] [655] [657] [670] [750] #57 + - Fix for GPX files with no lap info [660] + - Correction to date handling to work for mysql and sqlite [667] + - Improving logging output [671] [748] [749] + - Fix for HR percent graph so does not error in hr is None - thanks to Arnd [676] + - Bug fixes for sports filtering from Patrick [681] + - Updates for heartrate pie chart from Patrick [682] + - Fixes in lap generation (divide by zero, empty laps) - thanks to Arnd [684] [686] + - Fixes for record filtering from Patrick [691] + - Tolerate non-unicode strings returned from DB for better MySQL support [706] + - Add program argument for specifying config directory [709] #67 + - Better handling of floats and division. Thx to Martin [712] + - Retrieving a real list with DB tables, comparison was failing [716] + - Remove redundant Port option in preferences [719] #80 + - Fix to display blank sport properties correctly (not as None) [720] #78 + - Fix mysql code to match changes to sqlite tablelist handling [722] + - Stop preferences sport list edit button disabling dialog buttons if no sport is selected [723] #75 + - Fix to stop crash on editing record with empty distance [724] #73 + - Update record summary after edit [725] #79 + - Fix sport filtering to work with non consecutive sport_ids [728] + - Fix summary screens to update correctly with record add and deletes [729] + - Make pace read only [732] + - Display heartrate as integer in day, week, month and year views [734] + - Update DB check to ensure time == duration [736] + - Updating credits [740] [743] + - PyTrainer changes for 1.7.2: * Lap DB table created and code changed to populate and use the table [507] [508] [509] @@ -26,31 +91,31 @@ * Minor cosmetic changes [552] [553] [554] * Added check for early detection of empty local configuration file [555] * EXPERIMENTAL Unified Import GUI modifications (disabled by default, enabled on startup with --testimport) [526] - o file import supports multiple files at once [510] [511] - o option to have file import window automatically start with a file selection dialog [519] - o activities can be edited before import [514] [517] [521] [522] [534] [537] [538] - o kml file import support [523] [525] - o plugins tab added - provides alternative way of viewing and running import plugins [512] - o device import NOT functional + - file import supports multiple files at once [510] [511] + - option to have file import window automatically start with a file selection dialog [519] + - activities can be edited before import [514] [517] [521] [522] [534] [537] [538] + - kml file import support [523] [525] + - plugins tab added - provides alternative way of viewing and running import plugins [512] + - device import NOT functional - PyTrainer changes for 1.7.1: * New import plugin - Garmintools - svn [430], [431], [436], [452], [453], [459], [460], [461], [463], [464], [486], [487], [488] - o both file (dump file) and device import implemented - o smart import from device to cater for different start times compared to GPSBabel (to reduce duplicated activities) + - both file (dump file) and device import implemented + - smart import from device to cater for different start times compared to GPSBabel (to reduce duplicated activities) * Move to Google maps API version 3 - svn [477] * Add lap functionality - svn [433], [447], [448], [451], [454], [455] - o display individual laps under activity on treeview - o visually display lap duration on record graphs (user selectable) - o display lap markers on route map + - display individual laps under activity on treeview + - visually display lap duration on record graphs (user selectable) + - display lap markers on route map * Improve check functionality - svn [437], [438], [439], [475], [478], [479], [480], [482] - o Can be initiated by command line option --check - o Will be initiated if DB version in code is newer than user's DB version - o DB migration checks refactored and improved + - Can be initiated by command line option --check + - Will be initiated if DB version in code is newer than user's DB version + - DB migration checks refactored and improved * Timezone support - svn [434], [440], [442], [483] - o DB updated with new field date_time_local - o field populated on import (or when DB check is run) - o field used in preference to UTC if present for display + - DB updated with new field date_time_local + - field populated on import (or when DB check is run) + - field used in preference to UTC if present for display * Cadence / RPM support and graph added (tcx v2 file import only) - svn [432] * Improved install process and remove unneeded files - svn [445], [446], [462], [467], [472], [473] * Bug fix to TCX v2 to cater for multiple activities per file - svn [435] @@ -61,10 +126,10 @@ * Updated localizations (es, fr) - svn [494], [495], [497] * Separate some GUI elements into separate files to ease development - svn [443], [457], [465] * EXPERIMENTAL Unified Import GUI begun (for testing/feedback only) - svn [458], [466], [468], [469], [470], [471], [476], [481], [489] - o disabled by default - o enabled on startup with --testimport - o file import functional - o device import NOT functional + - disabled by default + - enabled on startup with --testimport + - file import functional + - device import NOT functional - PyTrainer changes for 1.7.0: Modified: pytrainer/trunk/pytrainer/gui/aboutdialog.py =================================================================== --- pytrainer/trunk/pytrainer/gui/aboutdialog.py 2010-11-27 14:21:55 UTC (rev 750) +++ pytrainer/trunk/pytrainer/gui/aboutdialog.py 2010-11-29 22:39:36 UTC (rev 751) @@ -39,7 +39,7 @@ about_dialog.set_destroy_with_parent(True) about_dialog.set_name("pyTrainer") about_dialog.set_version(self.version) - about_dialog.set_copyright("Copyright \xc2\xa9 2005-10 Fiz Vázquez") + about_dialog.set_copyright("Copyright \xc2\xa9 2005-09 Fiz Vázquez") about_dialog.set_website("http://sourceforge.net/projects/pytrainer") about_dialog.set_website_label("http://sourceforge.net/projects/pytrainer") about_dialog.set_comments("The free sport tracking center") Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-27 14:21:55 UTC (rev 750) +++ pytrainer/trunk/pytrainer/main.py 2010-11-29 22:39:36 UTC (rev 751) @@ -53,7 +53,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#750" + self.version ="1.8.0" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() Modified: pytrainer/trunk/setup.py =================================================================== --- pytrainer/trunk/setup.py 2010-11-27 14:21:55 UTC (rev 750) +++ pytrainer/trunk/setup.py 2010-11-29 22:39:36 UTC (rev 751) @@ -15,10 +15,10 @@ return "share/pytrainer/extensions/%s"%extension_name, glob("extensions/%s/*"%extension_name) setup( name="pytrainer", - version="1.7.2", + version="1.8.0", description="The free sport tracking center", long_description="Pytrainer is a tool to log all your sport excursion coming from GPS devices (with a focus on ForeRunner 205, 305 and 405) or GPX (http://www.topografix.com) files. Pytrainer supports GPS track files and displays it in graphs, maps... ", - author="Fiz Vazquez, John Blance, David Garcia Granda", + author="Fiz Vazquez, John Blance, David Garcia Granda, Arnd Zapletal, Nathan Jones", maintainer_email="pyt...@li...", url="http://sourceforge.net/projects/pytrainer/", license="GNU General Public License (GPL)", This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sig...@us...> - 2011-03-11 00:41:01
|
Revision: 766 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=766&view=rev Author: siggipals Date: 2011-03-11 00:40:53 +0000 (Fri, 11 Mar 2011) Log Message: ----------- Totals tab, stacked graphs and refactoring, colored map selection - a new "Totals" tab, along the lines of that suggested in ticket #60, with a table of aggregate info for each sport, ordered by descending duration. It also includes a graph with a bar for each year. - extension of the stacked/colored graph of the Week view to Day, Month, Year and Totals. - refactoring of day/week/month/year(/totals) graph code, introducing a base class "TimeGraph", eliminating some pretty severe code duplication - I had also done speed coloring on the Google maps, but Jonathan's implementation is better than mine, so I scrapped the latter. I am contributing an extension of the coloring to HR and cadence*, and a combobox to select None/Speed/HR/Cadence. * (The cadence coloring is untested, as I don't have a cadence sensor or footpod. Can someone try it out?) Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/daygraph.py pytrainer/trunk/pytrainer/extensions/googlemaps.py pytrainer/trunk/pytrainer/extensions/osm.py pytrainer/trunk/pytrainer/gui/drawArea.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/monthgraph.py pytrainer/trunk/pytrainer/weekgraph.py pytrainer/trunk/pytrainer/yeargraph.py Added Paths: ----------- pytrainer/trunk/pytrainer/stats.py pytrainer/trunk/pytrainer/timegraph.py pytrainer/trunk/pytrainer/totalgraph.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2011-03-05 19:01:19 UTC (rev 765) +++ pytrainer/trunk/glade/pytrainer.glade 2011-03-11 00:40:53 UTC (rev 766) @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0"?> <glade-interface> <!-- interface-requires gtk+ 2.6 --> <!-- interface-naming-policy toplevel-contextual --> @@ -1316,7 +1316,7 @@ <widget class="GtkSpinButton" id="spinbuttonY1Min"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> <signal name="value_changed" handler="on_spinbuttonY1_value_changed"/> @@ -1334,7 +1334,7 @@ <widget class="GtkSpinButton" id="spinbuttonY1Max"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> <signal name="value_changed" handler="on_spinbuttonY1_value_changed"/> @@ -1397,7 +1397,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 1 10 1 1 0</property> <signal name="value_changed" handler="on_spinbuttonY1LineWeight_value_changed"/> </widget> @@ -1439,7 +1439,7 @@ <property name="sensitive">False</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1531,7 +1531,7 @@ <widget class="GtkSpinButton" id="spinbuttonY2Min"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -1548,7 +1548,7 @@ <widget class="GtkSpinButton" id="spinbuttonY2Max"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">1 -500 1000 1 10 0</property> </widget> @@ -1618,7 +1618,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1650,7 +1650,7 @@ <property name="sensitive">False</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1727,7 +1727,7 @@ <widget class="GtkSpinButton" id="spinbuttonXMin"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -1744,7 +1744,7 @@ <widget class="GtkSpinButton" id="spinbuttonXMax"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -1985,6 +1985,32 @@ <packing> <property name="expand">False</property> <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelMapLineType"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes"><small>Show:</small></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="padding">5</property> + <property name="position">2</property> + </packing> + </child> + <child> + <widget class="GtkComboBoxEntry" id="comboMapLineType"> + <property name="visible">True</property> + <property name="items" translatable="yes">None +Speed +Heart rate +Cadence</property> + <signal name="changed" handler="on_comboMapLineType_changed"/> + </widget> + <packing> + <property name="expand">False</property> <property name="position">3</property> </packing> </child> @@ -1997,8 +2023,7 @@ </widget> <packing> <property name="padding">5</property> - <property name="pack_type">end</property> - <property name="position">2</property> + <property name="position">4</property> </packing> </child> <child> @@ -2015,7 +2040,7 @@ <property name="expand">False</property> <property name="fill">False</property> <property name="pack_type">end</property> - <property name="position">1</property> + <property name="position">5</property> </packing> </child> <child> @@ -5356,6 +5381,297 @@ <property name="type">tab</property> </packing> </child> + <child> + <widget class="GtkHBox" id="statsarea"> + <property name="visible">True</property> + <child> + <widget class="GtkVBox" id="vbox3"> + <property name="visible">True</property> + <child> + <widget class="GtkFrame" id="frame9"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <child> + <widget class="GtkAlignment" id="alignment10"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <widget class="GtkTreeView" id="statsTreeView"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <signal name="button_press_event" handler="on_sportstatsTreeView_button_press"/> + </widget> + <packing> + </packing> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label27"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Sports</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="padding">6</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkFrame" id="frame1123"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <child> + <widget class="GtkAlignment" id="alignment101"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <widget class="GtkHBox" id="total_vbox"> + <property name="height_request">650</property> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="spacing">8</property> + <child> + <widget class="GtkVBox" id="vbox123"> + <property name="visible">True</property> + <child> + <widget class="GtkComboBoxEntry" id="total_combovalue"> + <property name="visible">True</property> + <property name="items" translatable="yes">Distance +Time +Average Heart Rate +Average Speed +Calories</property> + <signal name="changed" handler="on_total_combovalue_changed"/> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label-37"> + <property name="visible">True</property> + <property name="label" translatable="yes">Versus</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <widget class="GtkComboBoxEntry" id="total_combovalue2"> + <property name="visible">True</property> + <property name="items" translatable="yes">None +Distance +Time +Average Heart Rate +Average Speed +Calories</property> + <signal name="changed" handler="on_total_combovalue_changed"/> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <widget class="GtkTable" id="table3"> + <property name="visible">True</property> + <property name="n_rows">4</property> + <property name="n_columns">2</property> + <child> + <widget class="GtkLabel" id="label15"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="yalign">0</property> + <property name="label" translatable="yes">Total distance:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">10</property> + <property name="y_padding">10</property> + <property name="y_options">GTK_SHRINK</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label19"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="yalign">0</property> + <property name="label" translatable="yes">Total duration:</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">10</property> + <property name="y_padding">10</property> + <property name="y_options">GTK_SHRINK</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelTotalDistance"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="xpad">5</property> + </widget> + <packing> + <property name="top_attach">0</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">10</property> + <property name="y_padding">10</property> + <property name="y_options">GTK_SHRINK</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelTotalDuration"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="xpad">5</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">10</property> + <property name="y_padding">10</property> + <property name="y_options">GTK_SHRINK</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label21a"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="yalign">0</property> + <property name="label" translatable="yes">Start date:</property> + </widget> + <packing> + <property name="top_attach">3</property> + <property name="left_attach">0</property> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">10</property> + <property name="y_padding">10</property> + <property name="y_options">GTK_SHRINK</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label22a"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="yalign">0</property> + <property name="label" translatable="yes">End date:</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">4</property> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">10</property> + <property name="y_padding">10</property> + <property name="y_options">GTK_SHRINK</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelStartDate"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="xpad">5</property> + </widget> + <packing> + <property name="top_attach">3</property> + <property name="left_attach">1</property> + <property name="right_attach">4</property> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">10</property> + <property name="y_padding">10</property> + <property name="y_options">GTK_SHRINK</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelEndDate"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="xpad">5</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">4</property> + <property name="top_attach">4</property> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">10</property> + <property name="y_padding">10</property> + <property name="y_options">GTK_SHRINK</property> + </packing> + </child> + </widget> + </child> + + + </widget> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + </widget> + <packing> + </packing> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label271"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>All</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="padding">6</property> + <property name="position">3</property> + </packing> + </child> + </widget> + <packing> + <property name="position">0</property> + </packing> + </child> + </widget> + <packing> + <property name="position">6</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label28"> + <property name="visible">True</property> + <property name="label" translatable="yes">Totals</property> + </widget> + <packing> + <property name="position">7</property> + <property name="tab_fill">False</property> + <property name="type">tab</property> + </packing> + </child> </widget> <packing> <property name="position">1</property> @@ -5399,7 +5715,7 @@ <widget class="GtkEntry" id="lsa_searchvalue"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="expand">False</property> @@ -5545,13 +5861,13 @@ <widget class="GtkVBox" id="waypointarea"> <property name="visible">True</property> <child> - <widget class="GtkFrame" id="frame10"> + <widget class="GtkFrame" id="frame12"> <property name="visible">True</property> <property name="border_width">9</property> <property name="label_xalign">0</property> <property name="shadow_type">in</property> <child> - <widget class="GtkAlignment" id="alignment10"> + <widget class="GtkAlignment" id="alignment15"> <property name="visible">True</property> <property name="left_padding">12</property> <child> @@ -5701,7 +6017,7 @@ <widget class="GtkEntry" id="waypoint_longitude"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">3</property> @@ -5716,7 +6032,7 @@ <widget class="GtkEntry" id="waypoint_description"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -5731,7 +6047,7 @@ <widget class="GtkEntry" id="waypoint_latitude"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">3</property> @@ -5744,7 +6060,7 @@ <widget class="GtkEntry" id="waypoint_name"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -5846,7 +6162,7 @@ </widget> </child> <child> - <widget class="GtkLabel" id="label15"> + <widget class="GtkLabel" id="label29"> <property name="visible">True</property> <property name="label">label162</property> </widget> Modified: pytrainer/trunk/pytrainer/daygraph.py =================================================================== --- pytrainer/trunk/pytrainer/daygraph.py 2011-03-05 19:01:19 UTC (rev 765) +++ pytrainer/trunk/pytrainer/daygraph.py 2011-03-11 00:40:53 UTC (rev 766) @@ -16,11 +16,11 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from gui.drawArea import DrawArea +from timegraph import TimeGraph -class DayGraph: +class DayGraph(TimeGraph): def __init__(self, vbox = None, combovalue = None): - self.drawarea = DrawArea(vbox) + TimeGraph.__init__(self, vbox=vbox, window=window) self.combovalue = combovalue def drawgraph(self,values): @@ -67,10 +67,4 @@ if value_selected==2: yvalue.append(value[5]) return xvalue,yvalue - - def getFloatValue(self, value): - try: - return float(value) - except: - return float(0) Modified: pytrainer/trunk/pytrainer/extensions/googlemaps.py =================================================================== --- pytrainer/trunk/pytrainer/extensions/googlemaps.py 2011-03-05 19:01:19 UTC (rev 765) +++ pytrainer/trunk/pytrainer/extensions/googlemaps.py 2011-03-11 00:40:53 UTC (rev 766) @@ -62,7 +62,7 @@ i[2] = '#%02x%02x%02x' % rgb_tuple - def drawMap(self,activity): + def drawMap(self,activity, linetype): '''Draw google map create html file using Google API version3 render using embedded Mozilla @@ -85,15 +85,21 @@ av_sum = 0 variance_sum = 0 n = 0 - for i in list_values: - if pre: - speed = (i[0]-pre[0])/((i[2]-pre[2])/3600) + if linetype==1: + if pre: + val = (i[0]-pre[0])/((i[2]-pre[2])/3600) + else: + val = (list_values[1][0]-list_values[0][0])/((list_values[1][2]-list_values[0][2])/3600) + elif linetype==2: + val = i[6] if i[6] else 0 + elif linetype==3: + val =i[7] if i[7]!=None else 1 else: - speed = (list_values[1][0]-list_values[0][0])/((list_values[1][2]-list_values[0][2])/3600) + val = 1 - variance_sum += (speed)**2 - av_sum += speed + variance_sum += (val)**2 + av_sum += val n += 1 lat, lon = float(i[4]), float(i[5]) @@ -102,7 +108,7 @@ minlon = min(minlon, lon) maxlon = max(maxlon, lon) pointlist.append((lat,lon)) - polyline.append(["new google.maps.LatLng(%s, %s)" % (lat, lon), speed, ""]) + polyline.append(["new google.maps.LatLng(%s, %s)" % (lat, lon), val, ""]) pre = i av_speed = av_sum / float(n) @@ -125,13 +131,13 @@ finishinfo = "<div class='info_content'>%s: %s<br>%s: %s%s</div>" % (_("Time"), time, _("Distance"), activity.distance, activity.distance_unit) startinfo = startinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html finishinfo = finishinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html - self.createHtml_api3(polyline, minlat, minlon, maxlat, maxlon, startinfo, finishinfo, laps) + self.createHtml_api3(polyline, minlat, minlon, maxlat, maxlon, startinfo, finishinfo, laps, linetype) else: self.createErrorHtml() return self.htmlfile logging.debug("<<") - def createHtml_api3(self,polyline, minlat, minlon, maxlat, maxlon, startinfo, finishinfo, laps): + def createHtml_api3(self,polyline, minlat, minlon, maxlat, maxlon, startinfo, finishinfo, laps, linetype): ''' Generate a Google maps html file using the v3 api documentation at http://code.google.com/apis/maps/documentation/v3 @@ -270,15 +276,22 @@ });\n polyline.setMap(map);\n''' % point[2] + contenttemplate = [ + "%s", + "Speed: %0.1f km/h", + "HR: %d bpm", + "Cadence: %d", + ] + content += ''' google.maps.event.addListener(polyline, 'click', function(event) { var marker = new google.maps.InfoWindow({ position: event.latLng, - content: "Speed: %0.1f km/h" + content: "%s" }); marker.setMap(map); }); - ''' % point[1] + ''' % contenttemplate[linetype] % point[1] pre = point content += ''' Modified: pytrainer/trunk/pytrainer/extensions/osm.py =================================================================== --- pytrainer/trunk/pytrainer/extensions/osm.py 2011-03-05 19:01:19 UTC (rev 765) +++ pytrainer/trunk/pytrainer/extensions/osm.py 2011-03-11 00:40:53 UTC (rev 766) @@ -21,7 +21,7 @@ self.htmlfile = "%s/osm.html" % (self.pytrainer_main.profile.tmpdir) logging.debug("<<") - def drawMap(self,activity): + def drawMap(self, activity, linetype): '''Draw osm map create html file using Open Layers and Open Street Map render using embedded Mozilla @@ -33,6 +33,7 @@ levels = [] pointlist = [] polyline = [] + attrlist = [] list_values = activity.tracks if list_values is not None and list_values != [] and len(list_values) > 0: @@ -40,6 +41,7 @@ lat, lon = float(i[4]), float(i[5]) pointlist.append((lat,lon)) polyline.append("[%s, %s]" % (lon, lat)) + attrlist.append((i[3],i[6])) # (Speed, HR) points,levels = Points.encodePoints(pointlist) points = points.replace("\\","\\\\") laps = activity.laps @@ -51,13 +53,13 @@ startinfo = startinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html finishinfo = finishinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html - self.createHtml_osm(polyline, startinfo, finishinfo, laps) + self.createHtml_osm(polyline, startinfo, finishinfo, laps, attrlist, linetype) else: self.createErrorHtml() return self.htmlfile logging.debug("<<") - def createHtml_osm(self, polyline, startinfo, finishinfo, laps): + def createHtml_osm(self, polyline, startinfo, finishinfo, laps, attrlist, linetype): ''' Generate OSM map html file using MapLayers ''' Modified: pytrainer/trunk/pytrainer/gui/drawArea.py =================================================================== --- pytrainer/trunk/pytrainer/gui/drawArea.py 2011-03-05 19:01:19 UTC (rev 765) +++ pytrainer/trunk/pytrainer/gui/drawArea.py 2011-03-11 00:40:53 UTC (rev 766) @@ -212,6 +212,7 @@ self.showGraph=False #Display first axis + xticks = [] for key in keys: logging.debug("Day of the week: %s", str(key)) for ind in inds: @@ -237,6 +238,8 @@ if len(xvalues) == 1: plt.title(title[0]) axis.legend(loc=0) + + axis.set_xlim(0,numCols) logging.debug("X values first axis: %s", str(xvals)) logging.debug("Y values first axis: %s", str(yheights)) @@ -276,6 +279,7 @@ ax2.bar(xvals, [0]*numCols, bottom=[0]*numCols, width=barWidth, color=color, align='edge', label=key) pass ax2.set_xticklabels('' * len(xvalues[1])) + ax2.set_xlim(0,numCols) ax2.set_ylabel(ylabel[1]) ax2.legend(loc=0) plt.title("%s vs %s" %(title[0],title[1])) Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2011-03-05 19:01:19 UTC (rev 765) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2011-03-11 00:40:53 UTC (rev 766) @@ -41,6 +41,7 @@ from pytrainer.weekgraph import WeekGraph from pytrainer.monthgraph import MonthGraph from pytrainer.yeargraph import YearGraph +from pytrainer.totalgraph import TotalGraph from pytrainer.heartrategraph import HeartRateGraph from pytrainer.extensions.mapviewer import MapViewer from pytrainer.extensions.waypointeditor import WaypointEditor @@ -130,6 +131,19 @@ {'name':_("Max HR"), 'xalign':1.0} ] self.create_treeview(self.athleteTreeView,columns) + #create the columns for the stats treeview + columns=[ {'name':_("id"), 'visible':False}, + {'name':_("Sport")}, + {'name':_("Total duration"), 'xalign':1.0, 'format_duration':True}, + {'name':_("Total distance"), 'xalign':1.0, 'format_float':'%.1f', 'quantity':'distance'}, + {'name':_("Avg speed"), 'format_float':'%.2f', 'quantity':'maxspeed'}, + {'name':_("Max speed"), 'format_float':'%.2f', 'quantity':'maxspeed'}, + {'name':_("Max HR"), 'xalign':1.0}, + {'name':_("Max duration"), 'xalign':1.0, 'format_duration':True}, + {'name':_("Max distance"), 'xalign':1.0, 'format_float':'%.1f', 'quantity':'distance'}, + ] + self.create_treeview(self.statsTreeView,columns) + self.fileconf = self.pytrainer_main.profile.confdir+"/listviewmenu.xml" if not os.path.isfile(self.fileconf): self._createXmlListView(self.fileconf) @@ -142,9 +156,8 @@ self.radiobuttonOSM.set_active(1) else: self.radiobuttonGMap.set_active(1) + self.comboMapLineType.set_active(0) - - def _float_or(self, value, default): '''Function to parse and return a float, or the default if the parsing fails''' try: @@ -156,7 +169,7 @@ return result def setup(self): - self.createGraphs(RecordGraph,DayGraph,WeekGraph, MonthGraph,YearGraph,HeartRateGraph) + self.createGraphs() self.createMap(MapViewer,self.pytrainer_main.waypoint) self.createWaypointEditor(WaypointEditor,self.pytrainer_main.waypoint, parent=self.pytrainer_main) page = self.notebook.get_current_page() @@ -211,7 +224,7 @@ id = selected.get_value(iter,0) self.parent.runExtension(extension,id) - def createGraphs(self,RecordGraph,DayGraph,WeekGraph, MonthGraph,YearGraph,HeartRateGraph): + def createGraphs(self): self.drawarearecord = RecordGraph(self.record_graph_vbox, self.window1, self.record_combovalue, self.record_combovalue2, self.btnShowLaps, self.tableConfigY1, pytrainer_main=self.pytrainer_main) self.drawareaheartrate = HeartRateGraph(self.heartrate_vbox, self.window1, self.heartrate_vbox2, pytrainer_main=self.pytrainer_main) #self.drawareaday = DayGraph(self.day_vbox, self.day_combovalue) @@ -219,11 +232,13 @@ self.drawareaweek = WeekGraph(self.weekview, self.window1, self.week_combovalue, self.week_combovalue2) self.drawareamonth = MonthGraph(self.month_vbox, self.window1, self.month_combovalue,self.month_combovalue2) self.drawareayear = YearGraph(self.year_vbox, self.window1, self.year_combovalue,self.year_combovalue2) + self.drawareatotal = TotalGraph(self.total_vbox, self.window1, self.total_combovalue,self.total_combovalue2) def createMap(self,MapViewer,waypoint): self.waypoint = waypoint - self.mapviewer = MapViewer(self.data_path, pytrainer_main=self.parent, box=self.map_vbox) - self.mapviewer_fs = MapViewer(self.data_path, pytrainer_main=self.parent, box=self.map_vbox_old) + if not getattr(self, 'mapviewer', None): + self.mapviewer = MapViewer(self.data_path, pytrainer_main=self.parent, box=self.map_vbox) + self.mapviewer_fs = MapViewer(self.data_path, pytrainer_main=self.parent, box=self.map_vbox_old) #self.googlemaps = Googlemaps(self.data_path, self.map_vbox,waypoint, pytrainer_main=self.parent) #self.osm = Osm(self.data_path, self.map_vbox,waypoint, pytrainer_main=self.parent) #self.googlemaps_old = Googlemaps(self.data_path, self.map_vbox_old,waypoint, pytrainer_main=self.parent) @@ -245,7 +260,11 @@ def render_duration(self, column, cell, model, iter): orig = cell.get_property('text') - new = orig + if not ':' in orig: + h,m,s = self.parent.date.second2time(int(orig)) + new = '%d:%02d:%02d' % (h,m,s) + else: + new = orig if orig[:4] == ' 0:0': new = orig[4:] elif orig[:3] == ' 0:': @@ -347,6 +366,13 @@ self.label_record_equipment.set_text(equipment_text) else: self.label_record_equipment.set_markup("<i>None</i>") + + for lap in activity.laps: +# print lap + t = float(lap['elapsed_time']) + m = lap['distance'] + s = m / t * 3.6 +# print t,m,s, lap['calories'] else: self.recordview.set_current_page(0) @@ -712,11 +738,11 @@ if self.radiobuttonOSM.get_active(): #Use OSM to draw map logging.debug("Using OSM to draw map....") - htmlfile = Osm(data_path=self.data_path, waypoint=self.waypoint, pytrainer_main=self.parent).drawMap(activity) + htmlfile = Osm(data_path=self.data_path, waypoint=self.waypoint, pytrainer_main=self.parent).drawMap(activity, self.comboMapLineType.get_active()) elif self.radiobuttonGMap.get_active(): #Use Google to draw map logging.debug("Using Google to draw map") - htmlfile = Googlemaps(data_path=self.data_path, waypoint=self.waypoint, pytrainer_main=self.parent).drawMap(activity) + htmlfile = Googlemaps(data_path=self.data_path, waypoint=self.waypoint, pytrainer_main=self.parent).drawMap(activity, self.comboMapLineType.get_active()) else: #Unknown map type... logging.error("Unknown map viewer requested") @@ -809,7 +835,7 @@ self.weekview.set_sensitive(1) else: self.weekview.set_sensitive(0) - self.drawareaweek.drawgraph(record_list, date_ini, date_end) + self.drawareaweek.drawgraph(record_list, date_ini) logging.debug("<<") def actualize_monthview(self,record_list, nameMonth): @@ -991,6 +1017,51 @@ self.grapher.drawAthleteGraph(athlete=athlete, box=self.boxAthleteGraph) logging.debug("<<") + def actualize_statsview(self, stats, record_list): + logging.debug(">>") + self.labelTotalDistance.set_text(str(stats.data['total_distance']) + " km") + self.labelTotalDuration.set_text(str(stats.data['total_duration'] / 3600) + " hours") + self.labelStartDate.set_text(stats.data['start_date'].strftime('%Y-%m-%d')) + self.labelEndDate.set_text(stats.data['end_date'].strftime('%Y-%m-%d')) + + data = self.parent.stats.data + + store = gtk.ListStore( + gobject.TYPE_INT, + gobject.TYPE_STRING, + gobject.TYPE_INT, + gobject.TYPE_FLOAT, + gobject.TYPE_FLOAT, + gobject.TYPE_FLOAT, + gobject.TYPE_INT, + gobject.TYPE_INT, + gobject.TYPE_FLOAT + ) + for s in data['sports'].values(): + iter = store.append() + + c = 0 + store.set (iter, c, c) + c += 1 + store.set (iter, c, s['name']) + for f in data['fields'][2:]: + c += 1 + store.set (iter, c, s['total_'+f]) + c += 1 + store.set (iter, c, s['total_distance'] / s['total_duration'] * 3600.) + for f in data['fields']: + c += 1 + store.set (iter, c, s[f]) + + self.statsTreeView.set_model(store) + self.statsTreeView.set_rules_hint(True) + + store.set_sort_column_id(2, gtk.SORT_DESCENDING) + + self.drawareatotal.drawgraph(record_list) + + logging.debug("<<") + def actualize_listview(self,record_list): logging.debug(">>") #recod list tiene: @@ -1403,6 +1474,10 @@ logging.debug( 'on_radiobuttonMap_toggled '+ widget.get_name()+ ' activated') self.parent.refreshMapView() + def on_comboMapLineType_changed(self, widget): + logging.debug( 'on_comboMapLineType_changed '+ widget.get_name()+ ' = ' + str(+ widget.get_active())) + self.parent.refreshMapView() + def on_hpaned1_move_handle(self, widget): print "Handler" print widget @@ -1486,6 +1561,8 @@ self.selected_view="year" elif page == 5: self.selected_view="athlete" + elif page == 6: + self.selected_view="stats" else: self.selected_view="record" self.parent.refreshGraphView(self.selected_view) @@ -1530,6 +1607,10 @@ logging.debug("--") self.parent.refreshGraphView(self.selected_view) + def on_total_combovalue_changed(self,widget): + logging.debug("--") + self.parent.refreshGraphView(self.selected_view) + def on_calendar_selected(self,widget): logging.debug("--") if self.block: @@ -1580,6 +1661,9 @@ self.parent.refreshAthleteView() #self.athletearea.show() + def on_statsview_activate(self,widget=None): + self.parent.refreshStatsView() + def on_waypointsview_activate(self,widget): self.listarea.hide() self.classicarea.hide() Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2011-03-05 19:01:19 UTC (rev 765) +++ pytrainer/trunk/pytrainer/main.py 2011-03-11 00:40:53 UTC (rev 766) @@ -41,6 +41,7 @@ from plugins import Plugins from profile import Profile from athlete import Athlete +from stats import Stats from gui.windowimportdata import WindowImportdata from gui.windowmain import Main @@ -92,6 +93,7 @@ logging.info('No sanity check requested') self.record = Record(data_path,self) self.athlete = Athlete(data_path,self) + self.stats = Stats(data_path,self) pool_size = self.profile.getIntValue("pytraining","activitypool_size", default=1) self.activitypool = ActivityPool(self, size=pool_size) #preparamos la ventana principal @@ -255,7 +257,8 @@ date_ini, date_end = self.date.getMonthInterval(date_selected) sport = self.windowmain.activeSport sport_id = self.record.getSportId(sport) - record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport_id) +# record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport_id) + record_list = self.record.getrecordPeriod(date_ini, date_end, sport_id) nameMonth, daysInMonth = self.date.getNameMonth(date_selected) self.windowmain.actualize_monthview(record_list, nameMonth) self.windowmain.actualize_monthgraph(record_list, daysInMonth) @@ -265,7 +268,8 @@ sport = self.windowmain.activeSport sport_id = self.record.getSportId(sport) year = self.date.getYear(date_selected) - record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport_id) +# record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport_id) + record_list = self.record.getrecordPeriod(date_ini, date_end, sport_id) self.windowmain.actualize_yearview(record_list, year) self.windowmain.actualize_yeargraph(record_list) elif view=="listview": @@ -274,6 +278,9 @@ elif view=="athlete": logging.debug('athlete view') self.windowmain.on_athleteview_activate() + elif view=="stats": + logging.debug('stats view') + self.windowmain.on_statsview_activate() else: print "Unknown view %s" % view logging.debug('<<') @@ -343,6 +350,12 @@ self.windowmain.actualize_athleteview(self.athlete) logging.debug('<<') + def refreshStatsView(self): + logging.debug('>>') + self.stats.refresh() + self.windowmain.actualize_statsview(self.stats, self.record.getAllRecordList()) + logging.debug('<<') + def refreshListView(self,condition=None): logging.debug('>>') record_list = self.record.getRecordListByCondition(condition) Modified: pytrainer/trunk/pytrainer/monthgraph.py =================================================================== --- pytrainer/trunk/pytrainer/monthgraph.py 2011-03-05 19:01:19 UTC (rev 765) +++ pytrainer/trunk/pytrainer/monthgraph.py 2011-03-11 00:40:53 UTC (rev 766) @@ -16,68 +16,30 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from gui.drawArea import DrawArea import dateutil +import datetime +from timegraph import TimeGraph -class MonthGraph: +class MonthGraph(TimeGraph): + + value_params = [ + (_("day"),_("Distance (km)"),_("Daily Distance"),"y"), + (_("day"),_("Time (hours)"), _("Daily Time"),"b"), + (_("day"),_("Average Heart Rate (bpm)"), _("Daily Average Heart Rate"),"r"), + (_("day"),_("Average Speed (km/h)"), _("Daily Average Speed"),"g"), + (_("day"),_("Calories"), _("Daily Calories"),"b"), + ] + def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None): - ... [truncated message content] |
From: <sig...@us...> - 2011-03-12 00:11:07
|
Revision: 768 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=768&view=rev Author: siggipals Date: 2011-03-12 00:11:01 +0000 (Sat, 12 Mar 2011) Log Message: ----------- #109 - Added laps data to record view Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2011-03-11 09:18:39 UTC (rev 767) +++ pytrainer/trunk/glade/pytrainer.glade 2011-03-12 00:11:01 UTC (rev 768) @@ -952,6 +952,48 @@ <property name="position">1</property> </packing> </child> + <child> + <widget class="GtkFrame" id="frame_laps"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <child> + <widget class="GtkAlignment" id="alignment12l"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <property name="right_padding">12</property> + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow2l"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="height_request">300</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <widget class="GtkTreeView" id="lapsTreeView"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label14"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Laps</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">5</property> + <property name="position">2</property> + </packing> + </child> <child> <widget class="GtkHBox" id="recordbuttons_hbox"> <property name="visible">True</property> @@ -996,9 +1038,9 @@ </child> </widget> <packing> - <property name="expand">False</property> + <property name="expand">True</property> <property name="fill">False</property> - <property name="position">2</property> + <property name="position">3</property> </packing> </child> </widget> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2011-03-11 09:18:39 UTC (rev 767) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2011-03-12 00:11:01 UTC (rev 768) @@ -143,6 +143,17 @@ {'name':_("Max distance"), 'xalign':1.0, 'format_float':'%.1f', 'quantity':'distance'}, ] self.create_treeview(self.statsTreeView,columns) + + #create the columns for the laps treeview + columns=[ + {'name':_("Lap")}, + {'name':_("Distance"), 'xalign':1.0, 'format_float':'%.1f', 'quantity':'distance'}, + {'name':_("Time"), 'xalign':1.0, 'format_duration':True}, + {'name':_("Avg speed"), 'format_float':'%.2f', 'quantity':'speed'}, + {'name':_("Avg pace"), 'format_float':'%.2f', 'quantity':'pace'}, + {'name':_("Calories"), 'xalign':1.0}, + ] + self.create_treeview(self.lapsTreeView,columns) self.fileconf = self.pytrainer_main.profile.confdir+"/listviewmenu.xml" if not os.path.isfile(self.fileconf): @@ -317,6 +328,7 @@ self.record_calories.set_text("") self.record_title.set_text("") self.label_record_equipment.set_text("") + self.frame_laps.hide() com_buffer = self.record_comments.get_buffer() start,end = com_buffer.get_bounds() com_buffer.set_text("") @@ -367,12 +379,26 @@ else: self.label_record_equipment.set_markup("<i>None</i>") - for lap in activity.laps: -# print lap - t = float(lap['elapsed_time']) - m = lap['distance'] - s = m / t * 3.6 -# print t,m,s, lap['calories'] + if len(activity.laps)>1: + store = gtk.ListStore( + gobject.TYPE_INT, + gobject.TYPE_FLOAT, + gobject.TYPE_STRING, + gobject.TYPE_FLOAT, + gobject.TYPE_FLOAT, + gobject.TYPE_INT, + ) + for lap in activity.laps: + t = lap['elapsed_time'] + m = lap['distance'] + s = m / float(t) * 3.6 + iter = store.append() + store.set(iter, 0, lap['lap_number']+1, 1, m/1000, 2, str(int(float(t))), 3, s, 4, 60/s, 5, lap['calories']) + self.lapsTreeView.set_model(store) + self.lapsTreeView.set_rules_hint(True) + self.frame_laps.show() + else: + self.frame_laps.hide() else: self.recordview.set_current_page(0) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sig...@us...> - 2011-03-19 00:16:21
|
Revision: 772 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=772&view=rev Author: siggipals Date: 2011-03-19 00:16:14 +0000 (Sat, 19 Mar 2011) Log Message: ----------- Store more lap info in DB, and show in record view Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/lib/gpx.py pytrainer/trunk/pytrainer/lib/sqliteUtils.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py Added Paths: ----------- pytrainer/trunk/glade/trigger_distance.png pytrainer/trunk/glade/trigger_hr.png pytrainer/trunk/glade/trigger_location.png pytrainer/trunk/glade/trigger_manual.png pytrainer/trunk/glade/trigger_time.png Added: pytrainer/trunk/glade/trigger_distance.png =================================================================== (Binary files differ) Property changes on: pytrainer/trunk/glade/trigger_distance.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: pytrainer/trunk/glade/trigger_hr.png =================================================================== (Binary files differ) Property changes on: pytrainer/trunk/glade/trigger_hr.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: pytrainer/trunk/glade/trigger_location.png =================================================================== (Binary files differ) Property changes on: pytrainer/trunk/glade/trigger_location.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: pytrainer/trunk/glade/trigger_manual.png =================================================================== (Binary files differ) Property changes on: pytrainer/trunk/glade/trigger_manual.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: pytrainer/trunk/glade/trigger_time.png =================================================================== (Binary files differ) Property changes on: pytrainer/trunk/glade/trigger_time.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2011-03-16 23:43:51 UTC (rev 771) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2011-03-19 00:16:14 UTC (rev 772) @@ -147,11 +147,17 @@ #create the columns for the laps treeview columns=[ {'name':_("Lap")}, + {'name':_(""), 'xalign':0, 'pixbuf':True}, {'name':_("Distance"), 'xalign':1.0, 'format_float':'%.2f', 'quantity':'distance'}, {'name':_("Time"), 'xalign':1.0, 'format_duration':True}, {'name':_("Avg speed"), 'format_float':'%.2f', 'quantity':'speed'}, + {'name':_("Max speed"), 'format_float':'%.2f', 'quantity':'speed'}, {'name':_("Avg pace"), 'xalign':1.0, 'quantity':'pace'}, + {'name':_("Max pace"), 'xalign':1.0, 'quantity':'pace'}, + {'name':_("Avg HR"), 'xalign':1.0}, + {'name':_("Max HR"), 'xalign':1.0}, {'name':_("Calories"), 'xalign':1.0}, + {'name':_("Intensity"), 'visible':False}, ] self.create_treeview(self.lapsTreeView,columns) @@ -291,10 +297,16 @@ def create_treeview(self,treeview,columns): for column_index, column_dict in enumerate(columns): + if 'pixbuf' in column_dict: + renderer = gtk.CellRendererPixbuf() + else: + renderer = gtk.CellRendererText() column = gtk.TreeViewColumn(column_dict['name']) - renderer = gtk.CellRendererText() column.pack_start(renderer, expand=False) - column.add_attribute(renderer, 'text', column_index) + if 'pixbuf' in column_dict: + column.add_attribute(renderer, 'pixbuf', column_index) + else: + column.add_attribute(renderer, 'text', column_index) column.set_resizable(True) column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) if 'xalign' in column_dict: @@ -382,11 +394,17 @@ if len(activity.laps)>1: store = gtk.ListStore( gobject.TYPE_INT, + gtk.gdk.Pixbuf, gobject.TYPE_FLOAT, gobject.TYPE_STRING, gobject.TYPE_FLOAT, + gobject.TYPE_FLOAT, gobject.TYPE_STRING, + gobject.TYPE_STRING, gobject.TYPE_INT, + gobject.TYPE_INT, + gobject.TYPE_INT, + gobject.TYPE_STRING, ) for lap in activity.laps: t = lap['elapsed_time'] @@ -396,12 +414,29 @@ m = km2miles(m) s = m / float(t) * 3.6 + max_speed = lap['max_speed'] * 3.6 if s > 0: pace = "%d:%02d" %((3600/s)/60,(3600/s)%60) + max_pace = "%d:%02d" %((3600/max_speed)/60,(3600/max_speed)%60) + + color = { + 'active' : '#000000', + 'rest' : '#808080', + } + + pic = gtk.gdk.pixbuf_new_from_file(self.data_path+"glade/trigger_%s.png" % lap['trigger']) + iter = store.append() - store.set(iter, 0, lap['lap_number']+1, 1, m/1000, 2, str(int(float(t))), 3, s, 4, pace, 5, lap['calories']) + store.set(iter, 0, lap['lap_number']+1, 1, pic, 2, m/1000, 3, str(int(float(t))), 4, s, 5, max_speed, 6, pace, 7, max_pace, 8, lap['avg_hr'], 9, lap['max_hr'], 10, lap['calories'], 11, color[lap['intensity']]) self.lapsTreeView.set_model(store) self.lapsTreeView.set_rules_hint(True) + + # Use grey color for "rest" laps + for c in self.lapsTreeView.get_columns()[:-1]: + for cr in c.get_cell_renderers(): + if type(cr)==gtk.CellRendererText: + c.add_attribute(cr, 'foreground', 11) + self.frame_laps.show() else: self.frame_laps.hide() Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2011-03-16 23:43:51 UTC (rev 771) +++ pytrainer/trunk/pytrainer/lib/activity.py 2011-03-19 00:16:14 UTC (rev 772) @@ -285,7 +285,7 @@ raise Exception( "Error - multiple results from DB for id: %s" % self.id ) #Get lap information laps = self.pytrainer_main.ddbb.select_dict("laps", - ("id_lap", "record", "elapsed_time", "distance", "start_lat", "start_lon", "end_lat", "end_lon", "calories", "lap_number"), + ("id_lap", "record", "elapsed_time", "distance", "start_lat", "start_lon", "end_lat", "end_lon", "calories", "lap_number", "intensity", "avg_hr", "max_hr", "max_speed", "trigger"), "record=\"%s\"" % self.id) if laps is None or laps == [] or len(laps) < 1: #No laps found logging.debug("No laps in DB for record %d" % self.id) Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2011-03-16 23:43:51 UTC (rev 771) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2011-03-19 00:16:14 UTC (rev 772) @@ -23,6 +23,7 @@ import traceback import commands, os import dateutil +import gpx from pytrainer.lib.date import Date #Define the tables and their columns that should be in the database @@ -73,6 +74,11 @@ "end_lat": "float", "end_lon": "float", "calories": "int", + "intensity": "varchar(7)", + "trigger": "varchar(9)", + "max_speed": "float", + "avg_hr": "int", + "max_hr": "int", }, "athletestats": { "id_athletestat": "integer primary key autoincrement", @@ -348,6 +354,7 @@ #These functions _must_ be safe to run at any time (i.e. not be version specfic or only safe to run once) self.populate_date_time_local() self.populate_duration_from_time() + self.add_lap_metadata() logging.debug('<<') def checkDBDataValues(self): @@ -442,3 +449,21 @@ print e logging.debug("Error updating record: " + str(record)) logging.debug(str(e)) + + def add_lap_metadata(self): + logging.debug('--') + record_ids = set([r[0] for r in self.select("laps","record")]) + for record in record_ids: + try: + laps = self.select("laps","id_lap, intensity, avg_hr, max_hr, max_speed, trigger", "record = %s" % record) + gpxfile = self.configuration.gpxdir+"/%s.gpx"%(record) + if not laps[0][1] and os.path.isfile(gpxfile) : #GPX file exists for this record - probably not a manual record + gpxrecord = gpx.Gpx(filename=gpxfile) + for lap, gpxlap in zip(laps, gpxrecord.getLaps()): + self.ddbbObject.update("laps", "intensity, avg_hr, max_hr, max_speed, trigger", (gpxlap[7], gpxlap[8], gpxlap[9], gpxlap[10], "%s" % gpxlap[11]), "id_lap = %d" % lap[0]) + except Exception as e: + print "Error updating record: " + str(record) + print e + logging.debug("Error updating record: " + str(record)) + logging.debug(str(e)) + Modified: pytrainer/trunk/pytrainer/lib/gpx.py =================================================================== --- pytrainer/trunk/pytrainer/lib/gpx.py 2011-03-16 23:43:51 UTC (rev 771) +++ pytrainer/trunk/pytrainer/lib/gpx.py 2011-03-19 00:16:14 UTC (rev 772) @@ -47,6 +47,9 @@ startPointTag = gpxdataNS.substitute(tag="startPoint") elapsedTimeTag = gpxdataNS.substitute(tag="elapsedTime") distanceTag = gpxdataNS.substitute(tag="distance") +intensityTag = gpxdataNS.substitute(tag="intensity") +triggerTag = gpxdataNS.substitute(tag="trigger") +summaryTag = gpxdataNS.substitute(tag="summary") pytrainerNS = string.Template(".//{http://sourceforge.net.project/pytrainer/GPX/0/1}$tag") pyt_eleTag = pytrainerNS.substitute(tag="ele") @@ -99,6 +102,7 @@ trackSegTag = mainNS.substitute(tag="trkseg") elevationTag = mainNS.substitute(tag="ele") nameTag = mainNS.substitute(tag="name") + intensityTag = mainNS.substitute(tag="intensity") logging.debug("getting values...") self.Values = self._getValues() @@ -161,7 +165,7 @@ lat = self.trkpoints[-1]['lat'] lon = self.trkpoints[-1]['lon'] #print ((self.total_time, lat, lon, self.calories, self.total_dist, stLat, stLon)) - lapInfo.append((self.total_time, lat, lon, self.calories, self.total_dist*1000, stLat, stLon)) + lapInfo.append((self.total_time, lat, lon, self.calories, self.total_dist*1000, stLat, stLon, "active", self.hr_average, self.maxhr, self.maxvel, "manual")) else: for lap in laps: endPoint = lap.find(endPointTag) @@ -180,8 +184,14 @@ #print elapsedTime calories = lap.findtext(calorieTag) distance = lap.findtext(distanceTag) + intensity = lap.findtext(intensityTag) + trigger = lap.findtext(triggerTag) + summary = lap.find(summaryTag) + max_speed = summary.findtext(mainNS.substitute(tag="MaximumSpeed")) + avg_hr = summary.findtext(mainNS.substitute(tag="AverageHeartRateBpm")) + max_hr = summary.findtext(mainNS.substitute(tag="MaximumHeartRateBpm")) logging.debug("Found time: %s, lat: %s lon: %s cal: %s dist: %s " % (elapsedTime, lat, lon, calories, distance)) - lapInfo.append((elapsedTime, lat, lon, calories, distance, stLat, stLon)) + lapInfo.append((elapsedTime, lat, lon, calories, distance, stLat, stLon, intensity, avg_hr, max_hr, max_speed, trigger)) logging.debug("<<") return lapInfo Modified: pytrainer/trunk/pytrainer/lib/sqliteUtils.py =================================================================== --- pytrainer/trunk/pytrainer/lib/sqliteUtils.py 2011-03-16 23:43:51 UTC (rev 771) +++ pytrainer/trunk/pytrainer/lib/sqliteUtils.py 2011-03-19 00:16:14 UTC (rev 772) @@ -116,7 +116,7 @@ for val in values: if count>0: string+="," - string += """%s="%s" """ %(cells[count],values[count]) + string += """%s=%s """ %(cells[count],values[count] if type(values[count]) not in [str, unicode] else "'%s'" % values[count]) count = count+1 string +=" where %s" %condition Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2011-03-16 23:43:51 UTC (rev 771) +++ pytrainer/trunk/pytrainer/main.py 2011-03-19 00:16:14 UTC (rev 772) @@ -55,7 +55,7 @@ def __init__(self,filename = None, data_path = None): #Version constants self.version ="1.8.0-svn#753" - self.DB_version = 6 + self.DB_version = 7 #Process command line options self.startup_options = self.get_options() self.environment = Environment(platform.get_platform(), self.startup_options.conf_dir) Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2011-03-16 23:43:51 UTC (rev 771) +++ pytrainer/trunk/pytrainer/record.py 2011-03-19 00:16:14 UTC (rev 772) @@ -237,6 +237,11 @@ tmp_lap['end_lat'] = lap[1] tmp_lap['end_lon'] = lap[2] tmp_lap['calories'] = lap[3] + tmp_lap['intensity'] = lap[7] + tmp_lap['avg_hr'] = lap[8] + tmp_lap['max_hr'] = lap[9] + tmp_lap['max_speed'] = lap[10] + tmp_lap['trigger'] = lap[11] laps.append(tmp_lap) logging.debug('<<') return laps @@ -346,7 +351,7 @@ def getLaps(self, id_record): logging.debug('--') laps = self.pytrainer_main.ddbb.select("laps", - "id_lap, record, elapsed_time, distance, start_lat, start_lon, end_lat, end_lon, calories, lap_number", + "id_lap, record, elapsed_time, distance, start_lat, start_lon, end_lat, end_lon, calories, lap_number, intensity, max_speed, avg_hr, max_hr, trigger", "record=\"%s\"" % id_record) if laps is None or laps == []: #No laps stored - update DB logging.debug("No laps in DB for record %d" % id_record) @@ -363,7 +368,7 @@ self.insertLaps(lap_keys,lap.values()) #Try to get lap info again #TODO? refactor laps = self.pytrainer_main.ddbb.select("laps", - "id_lap, record, elapsed_time, distance, start_lat, start_lon, end_lat, end_lon, calories, lap_number", + "id_lap, record, elapsed_time, distance, start_lat, start_lon, end_lat, end_lon, calories, lap_number, intensity, max_speed, avg_hr, max_hr, trigger", "record=\"%s\"" % id_record) return laps This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |