You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2009 |
Jan
|
Feb
(1) |
Mar
(15) |
Apr
(20) |
May
(2) |
Jun
(9) |
Jul
(3) |
Aug
(2) |
Sep
(17) |
Oct
(16) |
Nov
(38) |
Dec
(40) |
2010 |
Jan
(51) |
Feb
(11) |
Mar
(24) |
Apr
(31) |
May
(24) |
Jun
(3) |
Jul
(9) |
Aug
(1) |
Sep
(29) |
Oct
(33) |
Nov
(81) |
Dec
(6) |
2011 |
Jan
(2) |
Feb
(4) |
Mar
(13) |
Apr
(4) |
May
(24) |
Jun
(4) |
Jul
(19) |
Aug
(46) |
Sep
(10) |
Oct
(28) |
Nov
(31) |
Dec
|
From: <jb...@us...> - 2010-11-11 02:30:26
|
Revision: 693 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=693&view=rev Author: jblance Date: 2010-11-11 02:30:18 +0000 (Thu, 11 Nov 2010) Log Message: ----------- Bug fix to delimited import Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowimportdata.py Modified: pytrainer/trunk/pytrainer/gui/windowimportdata.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowimportdata.py 2010-11-11 02:26:09 UTC (rev 692) +++ pytrainer/trunk/pytrainer/gui/windowimportdata.py 2010-11-11 02:30:18 UTC (rev 693) @@ -880,6 +880,8 @@ if self.has_header and i==0: #Ignore first row continue + if not row: + continue data = {} #Determine dates _date = Date().getDateTime(row[dateCol-1]) @@ -905,7 +907,7 @@ 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) + #print("Error calculating duration for '%s'" % _duration) durationSec = None else: try: @@ -913,7 +915,7 @@ except: #Unknown duration logging.debug("Could not determine duration for '%s'" % _duration) - print("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 @@ -982,7 +984,7 @@ data['comments'] = row[commentsCol-1] #Insert into DB - print "Data", data + logging.debug("Data", data) self.pytrainer_main.ddbb.insert_dict('records', data) #Display message.... self.updateStatusbar(self.statusbarCSVImport, "Import completed. %d rows processed" % i) 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: <jb...@us...> - 2010-11-10 22:01:27
|
Revision: 691 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=691&view=rev Author: jblance Date: 2010-11-10 22:01:21 +0000 (Wed, 10 Nov 2010) Log Message: ----------- Fixes for record filtering from Patrick Modified Paths: -------------- pytrainer/trunk/pytrainer/record.py Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2010-11-10 21:59:00 UTC (rev 690) +++ pytrainer/trunk/pytrainer/record.py 2010-11-10 22:01:21 UTC (rev 691) @@ -395,7 +395,7 @@ if not sport: condition = "date>=\"%s\" and date<=\"%s\" and records.sport=sports.id_sports" %(date_ini,date_end) else: - condition = "date>=\"%s\" and date<=\"%s\" and records.sport=sports.id_sports and sports.name=\"%s\"" %(date_ini,date_end, sport) + condition = "date>=\"%s\" and date<=\"%s\" and records.sport=sports.id_sports and sports.id_sports=\"%s\"" %(date_ini,date_end, sport) return self.pytrainer_main.ddbb.select(tables,"date,distance,time,beats,comments,average,calories,maxspeed,maxbeats, sports.name", condition) @@ -405,7 +405,7 @@ condition = "date>\"%s\" and date<\"%s\"" %(date_ini,date_end) else : tables = "records,sports" - condition = "date>\"%s\" and date<\"%s\" and records.sport=sports.id_sports and sports.name=\"%s\"" %(date_ini,date_end,sport) + condition = "date>\"%s\" and date<\"%s\" and records.sport=sports.id_sports and sports.id_sports=\"%s\"" %(date_ini,date_end,sport) return self.pytrainer_main.ddbb.select(tables, "date,distance,time,beats,comments,average,calories,maxspeed,maxbeats", 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-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 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 02:32:55
|
Revision: 687 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=687&view=rev Author: jblance Date: 2010-11-10 02:32:48 +0000 (Wed, 10 Nov 2010) Log Message: ----------- Adding new metric/imperial conversion utility Modified Paths: -------------- pytrainer/trunk/pytrainer/main.py Added Paths: ----------- pytrainer/trunk/pytrainer/lib/singleton.py pytrainer/trunk/pytrainer/lib/uc.py Added: pytrainer/trunk/pytrainer/lib/singleton.py =================================================================== --- pytrainer/trunk/pytrainer/lib/singleton.py (rev 0) +++ pytrainer/trunk/pytrainer/lib/singleton.py 2010-11-10 02:32:48 UTC (rev 687) @@ -0,0 +1,21 @@ +# -*- coding: iso-8859-1 -*- + +#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. + +class Singleton (object): + def __new__(cls, *args, **kwargs): + if not hasattr(cls, 'self'): + cls.self = object.__new__(cls) + return cls.self Added: pytrainer/trunk/pytrainer/lib/uc.py =================================================================== --- pytrainer/trunk/pytrainer/lib/uc.py (rev 0) +++ pytrainer/trunk/pytrainer/lib/uc.py 2010-11-10 02:32:48 UTC (rev 687) @@ -0,0 +1,77 @@ +# -*- coding: iso-8859-1 -*- + +#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. + +from pytrainer.lib.singleton import Singleton + +""" Units of physical quantities [metric, imperial] """ +uc_units = {'distance' : ['km','mi'] , 'speed' : ['km/h', 'mph'], + 'pace' : ['min/km','min/mi'], 'height' : ['m', 'ft'], + 'weight': ['kg', 'lb']} + +""" Conversion factors from metric to imperial, units as in uc_units """ +uc_factors = {'distance' : 0.621371192, 'speed': 0.621371192, 'pace':1.609344, + 'height': 3.2808399, 'weight': 2.204624} + +class UC(Singleton): + """ + When instantiated first time us is assigned, otherwise not. + Can be called with or w/o argument. + us = False; metric system + us = True ; imperial system + """ + def __init__(self, *args): + _us = False + if args: + if args[0] in [True, False]: + _us = args[0] + if not hasattr(self, 'us'): + self.us = _us + + def __str__(self): + if self.us: + return 'imperial' + else: + return 'metric' + + def set_us(self, us): + self.us = us + + def get_unit(self, quantity): + if self.us: + return uc_units[quantity][1] + else: + return uc_units[quantity][0] + + unit_distance = property(lambda self: self.get_unit('distance') ) + unit_speed = property( lambda self: self.get_unit('speed') ) + unit_pace = property( lambda self: self.get_unit('pace') ) + unit_height = property( lambda self: self.get_unit('height') ) + unit_weight = property( lambda self: self.get_unit('weight') ) + + def sys2usr(self, quantity, value): + """gives value of physical quantity (metric) in users system""" + if self.us: + return value * uc_factors[quantity] + else: + return value + + def usr2sys(self, quantity, value): + """takes value (users system) and convert to metric (sys)""" + if self.us: + return value / uc_factors[quantity] + else: + return value + Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-10 02:21:52 UTC (rev 686) +++ pytrainer/trunk/pytrainer/main.py 2010-11-10 02:32:48 UTC (rev 687) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#683" + self.version ="1.7.2_svn#687" 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 02:21:58
|
Revision: 686 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=686&view=rev Author: jblance Date: 2010-11-10 02:21:52 +0000 (Wed, 10 Nov 2010) Log Message: ----------- Fix for empty laps from Arnd Modified Paths: -------------- pytrainer/trunk/extensions/openstreetmap/openstreetmap.py Modified: pytrainer/trunk/extensions/openstreetmap/openstreetmap.py =================================================================== --- pytrainer/trunk/extensions/openstreetmap/openstreetmap.py 2010-11-09 10:03:11 UTC (rev 685) +++ pytrainer/trunk/extensions/openstreetmap/openstreetmap.py 2010-11-10 02:21:52 UTC (rev 686) @@ -240,10 +240,13 @@ lat = endPoint.get("lat") lon = endPoint.get("lon") # Create waypt if not in home box - if not ((SW_LAT < float(lat) < NE_LAT) and (SW_LON < float(lon) < NE_LON)): - etree.SubElement(myroot, 'wpt', attrib= {'lat':lat, 'lon':lon}) + try: + if not ((SW_LAT < float(lat) < NE_LAT) and (SW_LON < float(lon) < NE_LON)): + etree.SubElement(myroot, 'wpt', attrib= {'lat':lat, 'lon':lon}) + except: + pass etree.strip_attributes(myroot, 'creator') - + # Wipe out home box for trkpt in tree.findall(_trkpt_path): lat = float(trkpt.attrib['lat']) 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-08 22:31:45
|
Revision: 684 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=684&view=rev Author: jblance Date: 2010-11-08 22:31:39 +0000 (Mon, 08 Nov 2010) Log Message: ----------- Fix for divide by zero error in lap generation - thanks to Arnd Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/activity.py Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-11-07 21:40:39 UTC (rev 683) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-11-08 22:31:39 UTC (rev 684) @@ -315,10 +315,13 @@ for lap in self.laps: time = float( lap['elapsed_time'].decode('utf-8') ) # time in sql is a unicode string dist = lap['distance']/1000 #distance in km - pace = time/(60*dist) #min/km + try: + pace = time/(60*dist) #min/km + except ZeroDivisionError: + pace = 0.0 if self.pace_limit is not None and pace > self.pace_limit: logging.debug("Pace (%s) exceeds limit (%s). Setting to 0" % (str(pace), str(self.pace_limit))) - pace = 0 + pace = 0.0 logging.debug("Time: %f, Dist: %f, Pace: %f" % (time, dist, pace) ) self.lap_time.addBars(x=time, y=10) if self.us_system: @@ -497,7 +500,7 @@ ''' Function to return a value formated as a string - takes into account US/metric - also appends units if required - ''' + ''' value = self.get_value(param) if not value: #Return blank string if value is None or 0 @@ -511,7 +514,7 @@ result += self.units[param] #print "activity: 509", result return result - + def get_value(self, param): ''' Function to get the value of various params in this activity instance Automatically returns values converted to imperial if needed This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-07 21:40:46
|
Revision: 683 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=683&view=rev Author: jblance Date: 2010-11-07 21:40:39 +0000 (Sun, 07 Nov 2010) Log Message: ----------- New units/conversion helper functions from Arnd - WIP Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowrecord.py pytrainer/trunk/pytrainer/lib/unitsconversor.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/gui/windowrecord.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-11-07 21:14:30 UTC (rev 682) +++ pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-11-07 21:40:39 UTC (rev 683) @@ -24,6 +24,7 @@ from filechooser import FileChooser from pytrainer.lib.date import Date +from pytrainer.lib.unitsconversor import * import pytrainer.record import dateutil.parser from dateutil.tz import * # for tzutc() @@ -33,6 +34,8 @@ logging.debug(">>") self.parent = parent self.pytrainer_main = parent.pytrainer_main + self.us = self.pytrainer_main.profile.prf_us_system + logging.debug("Using US system: "+ str(self.us)) self.data_path = data_path glade_path="glade/newrecord.glade" root = "newrecord" @@ -74,7 +77,8 @@ if title != None: self.rcd_title.set_text(title) if distance != None: - self.rcd_distance.set_text(distance) + #self.rcd_distance.set_text(distance) + myset_text(rcd_distance, 'distance', distance, us=self.us, round=2) if time != None: self.setTime(time) if distance!=None and time!=None: @@ -85,6 +89,13 @@ self.rcd_unegative.set_text(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._init_equipment(equipment, equipment_service) logging.debug("<<") @@ -324,7 +335,8 @@ 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) + #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) self.rcd_calories.set_text("%s"%activity.calories) self.rcd_beats.set_text("%s"%activity.beats) @@ -643,7 +655,8 @@ pass def set_distance(self,distance): - self.rcd_distance.set_text("%0.2f" %distance) + #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/lib/unitsconversor.py =================================================================== --- pytrainer/trunk/pytrainer/lib/unitsconversor.py 2010-11-07 21:14:30 UTC (rev 682) +++ pytrainer/trunk/pytrainer/lib/unitsconversor.py 2010-11-07 21:40:39 UTC (rev 683) @@ -16,6 +16,19 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +'''def _set_units(self): + if self.us_system: + self.distance_unit = _("miles") + self.speed_unit = _("miles/h") + self.pace_unit = _("min/mile") + self.height_unit = _("feet") + else: + self.distance_unit = _("km") + self.speed_unit = _("km/h") + self.pace_unit = _("min/km") + self.height_unit = _("m") + self.units = { 'distance': self.distance_unit, 'average': self.speed_unit, 'upositive': self.height_unit, 'unegative': self.height_unit, 'maxspeed': self.speed_unit, 'pace': self.pace_unit, 'maxpace': self.pace_unit }''' + def km2miles(kilometers): try: km = float(kilometers) @@ -71,3 +84,98 @@ return m/2.20462262 except Exception as e: return 0.0 + +def myset_text(gtkentry, quantity, value, **kwargs): + _us = False + _round = False + _value = value + + if kwargs.has_key('us'): + if kwargs['us'] == True: + _us = True + if kwargs.has_key('units'): + if kwargs['units']: + _units = True + if kwargs.has_key('round'): + _round = True + _round_digits = kwargs['round'] + + print 'set_text via myset_text()' + print quantity, _value + # quantity=physical quantitiy like 'distance' or 'speed' + # here we should call the universal 'conversion prepare for output' filter + # need the same for get_text + _value = filter_inout(quantity, _value, 'out', us=_us, round=_round_digits) + _value = str(_value) + gtkentry.set_text(_value) + +def myget_text(gtkentry, quantity, **kwargs): + _us = False + _round = False + _value = gtkentry.get_text() + + if kwargs.has_key('us'): + if kwargs['us'] == True: + _us = True + if kwargs.has_key('units'): + if kwargs['units']: + _units = True + if kwargs.has_key('round'): + _round = True + _round_digits = kwargs['round'] + + _value = float(_value) + _value = filter_inout(quantity, _value, 'in', us=_us) + return float(_value) + +def filter_inout(param, values, direction,**kwargs): + """ """ + units = {'distance' : ['km','mi'] , 'speed' : ['km/h', 'mph'], + 'pace' : ['min/km','min/mi'], 'height' : ['m', 'ft']} + + if direction == 'out': #all comes from metric + myexp = 1 + else: + myexp = -1 + if not type(values) == list: + _list = False + values_return = [values] + else: + _list = True + values_return = values + _units = False + _round = False + _round_digits = 99 + #print kwargs + _us = False + if kwargs.has_key('us'): + if kwargs['us'] == True: + _us = True + if kwargs.has_key('units'): + if kwargs['units']: + _units = True + if kwargs.has_key('round'): + _round = True + _round_digits = kwargs['round'] + + if _us: #if us: + if param in ['distance', 'speed']: + values_return = [x * (0.6213711**myexp) for x in values_return] + elif param in ['pace']: + values_return = [x * (1.609344**myexp) for x in values_return] + elif param in ['height']: + values_return = [x * (3.2808399**myexp) for x in values_return] + + if _round: + values_return = [round(x, _round_digits) for x in values_return] + + if _units: + if _us: + values_return = [str(x) + ' ' + units[param][1] for x in values_return] + else: + values_return = [str(x) + ' ' + units[param][0] for x in values_return] + + if not _list: + return values_return[0] + else: + return values_return Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-07 21:14:30 UTC (rev 682) +++ pytrainer/trunk/pytrainer/main.py 2010-11-07 21:40:39 UTC (rev 683) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#682" + self.version ="1.7.2_svn#683" 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-07 21:14:36
|
Revision: 682 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=682&view=rev Author: jblance Date: 2010-11-07 21:14:30 +0000 (Sun, 07 Nov 2010) Log Message: ----------- Updates for heartrate pie chart from Patrick Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/drawArea.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/gui/drawArea.py =================================================================== --- pytrainer/trunk/pytrainer/gui/drawArea.py 2010-11-07 20:59:28 UTC (rev 681) +++ pytrainer/trunk/pytrainer/gui/drawArea.py 2010-11-07 21:14:30 UTC (rev 682) @@ -384,8 +384,8 @@ logging.debug("Figure: %s" % str(figure) ) axis = figure.add_subplot(111) - labels = ["rest"] - colors = ["#ffffff"] + labels = [] + colors = [] frac0 = 0 frac1 = 0 frac2 = 0 @@ -393,25 +393,69 @@ frac4 = 0 frac5 = 0 for zone in zones: - labels.append(zone[3]) - colors.append(zone[2]) + labels.insert(0,zone[3]) + colors.insert(0,zone[2]) + labels.insert(0,_("rest")) + colors.insert(0,"#ffffff") + for value in yvalues[0]: - if value < zones[4][0]: + if value <= zones[4][0]: frac0+=1 - elif value > zones[4][0] and value < zones[4][1]: + elif value > zones[4][0] and value <= zones[4][1]: frac1+=1 - elif value > zones[3][0] and value < zones[3][1]: + elif value > zones[3][0] and value <= zones[3][1]: frac2+=1 - elif value > zones[2][0] and value < zones[2][1]: + elif value > zones[2][0] and value <= zones[2][1]: frac3+=1 - elif value > zones[1][0] and value < zones[1][1]: + elif value > zones[1][0] and value <= zones[1][1]: frac4+=1 - elif value > zones[0][0] and value < zones[0][1]: + elif value > zones[0][0] and value <= zones[0][1]: frac5+=1 - fracs = [frac0,frac1,frac2,frac3,frac4, frac5] - explode=(0, 0, 0, 0,0,0) + fracs = [] + explode=[] + if frac5 == 0: + labels.pop(5) + colors.pop(5) + else: + fracs.insert(0, frac5) + explode.insert(0, 0) + + if frac4 == 0: + labels.pop(4) + colors.pop(4) + else: + fracs.insert(0, frac4) + explode.insert(0, 0) + + if frac3 == 0: + labels.pop(3) + colors.pop(3) + else: + fracs.insert(0, frac3) + explode.insert(0, 0) + + if frac2 == 0: + labels.pop(2) + colors.pop(2) + else: + fracs.insert(0, frac2) + explode.insert(0, 0) + + if frac1 == 0: + labels.pop(1) + colors.pop(1) + else: + fracs.insert(0, frac1) + explode.insert(0, 0) + + if frac0 == 0: + labels.pop(0) + colors.pop(0) + else: + fracs.insert(0, frac0) + explode.insert(0, 0) axis.pie(fracs, explode=explode, labels=labels, colors=colors, autopct='%1.1f%%', shadow=True) canvas = FigureCanvasGTK(figure) # a gtk.DrawingArea Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-07 20:59:28 UTC (rev 681) +++ pytrainer/trunk/pytrainer/main.py 2010-11-07 21:14:30 UTC (rev 682) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#681" + self.version ="1.7.2_svn#682" 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-07 20:59:34
|
Revision: 681 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=681&view=rev Author: jblance Date: 2010-11-07 20:59:28 +0000 (Sun, 07 Nov 2010) Log Message: ----------- Bug fixes for sports filtering from Patrick Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-07 10:59:44 UTC (rev 680) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-07 20:59:28 UTC (rev 681) @@ -1410,6 +1410,7 @@ logging.debug("--") if self.sportlist.get_active() != self.activeSport: self.activeSport = self.sportlist.get_active() + self.parent.refreshListRecords() self.parent.refreshGraphView(self.selected_view) else: logging.debug("on_sportlist_changed called with no change") Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-07 10:59:44 UTC (rev 680) +++ pytrainer/trunk/pytrainer/main.py 2010-11-07 20:59:28 UTC (rev 681) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#678" + self.version ="1.7.2_svn#681" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2010-11-07 10:59:44 UTC (rev 680) +++ pytrainer/trunk/pytrainer/record.py 2010-11-07 20:59:28 UTC (rev 681) @@ -487,7 +487,7 @@ if not id_sport: records = self.pytrainer_main.ddbb.select("records","date","date LIKE '"+year+"-"+month+"-%'") else: - records = self.ddbb.select("records","date","date LIKE \"%s-%s-%%\" and sport=\"%s\"" %(year,month,id_sport)) + records = self.pytrainer_main.ddbb.select("records","date","date LIKE \"%s-%s-%%\" and sport=\"%s\"" %(year,month,id_sport)) logging.debug('Found '+str(len(records))+' entries') day_list = [] for i in records: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2010-11-07 10:59:52
|
Revision: 680 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=680&view=rev Author: ncjones Date: 2010-11-07 10:59:44 +0000 (Sun, 07 Nov 2010) Log Message: ----------- Remove unused purchase_price column from equipment table. Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/ddbb.py Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-11-07 10:54:11 UTC (rev 679) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-11-07 10:59:44 UTC (rev 680) @@ -85,7 +85,6 @@ "id": "integer primary key autoincrement" , "description": "varchar (200)", "active": "boolean", - "purchase_price": "int", "life_expectancy": "int", "prior_usage": "int", "notes": "text", This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
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: <dg...@us...> - 2010-11-06 09:49:52
|
Revision: 678 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=678&view=rev Author: dgranda Date: 2010-11-06 09:49:44 +0000 (Sat, 06 Nov 2010) Log Message: ----------- Basic equipment management - thx to ncjones Modified Paths: -------------- pytrainer/trunk/glade/newrecord.glade pytrainer/trunk/glade/profile.glade pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/gui/windowprofile.py pytrainer/trunk/pytrainer/gui/windowrecord.py pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py Added Paths: ----------- pytrainer/trunk/glade/equipment.glade pytrainer/trunk/pytrainer/equipment.py pytrainer/trunk/pytrainer/gui/equipment.py pytrainer/trunk/test/ pytrainer/trunk/test/pytrainer/ pytrainer/trunk/test/pytrainer/equipment_test.py pytrainer/trunk/test/pytrainer/gui/ pytrainer/trunk/test/pytrainer/gui/equipment_test.py Added: pytrainer/trunk/glade/equipment.glade =================================================================== --- pytrainer/trunk/glade/equipment.glade (rev 0) +++ pytrainer/trunk/glade/equipment.glade 2010-11-06 09:49:44 UTC (rev 678) @@ -0,0 +1,642 @@ +<?xml version="1.0"?> +<interface> + <!-- interface-requires gtk 2.6 --> + <!-- interface-naming-policy project-wide --> + <object class="GtkNotebook" id="notebookEquipment"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="show_tabs">False</property> + <property name="show_border">False</property> + <child> + <object class="GtkFrame" id="frameEquipmentList"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignmentEquipmentList"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <object class="GtkVBox" id="vboxEquipmentList"> + <property name="visible">True</property> + <property name="border_width">5</property> + <child> + <object class="GtkScrolledWindow" id="scrolledwindowEquipmentList"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="treeviewEquipmentList"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hboxEquipmentListButtons"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="buttonEquipmentDelete"> + <property name="label">gtk-delete</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="delete_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="buttonEquipmentEdit"> + <property name="label">gtk-edit</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="edit_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="buttonEquipmentAdd"> + <property name="label">gtk-add</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="add_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="labelEquipmentList"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Equipment List</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="tab_expand">True</property> + </packing> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <object class="GtkFrame" id="frameEquipmentAdd"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignmentEquipmentAdd"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <object class="GtkVBox" id="vboxEquipmentAdd"> + <property name="visible">True</property> + <property name="border_width">5</property> + <child> + <object class="GtkHBox" id="hboxEquipmentAddDetails"> + <property name="visible">True</property> + <child> + <object class="GtkTable" id="tableEquipmentAddDetails"> + <property name="visible">True</property> + <property name="n_rows">4</property> + <property name="n_columns">2</property> + <property name="row_spacing">5</property> + <child> + <object class="GtkLabel" id="labelEquipmentAddDescription"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="xpad">5</property> + <property name="label" translatable="yes">Description</property> + </object> + <packing> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entryEquipmentAddDescription"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + <property name="width_chars">35</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkLabel" id="labelEquipmentAddLifeExpectancy"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="xpad">5</property> + <property name="label" translatable="yes">Life Expectancy</property> + </object> + <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> + <child> + <object class="GtkAlignment" id="alignment3"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xscale">0</property> + <child> + <object class="GtkEntry" id="entryEquipmentAddLifeExpectancy"> + <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">1</property> + <property name="bottom_attach">2</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> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="draw_indicator">True</property> + </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="GtkAlignment" id="alignment6"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkLabel" id="labelEquipmentAddNotes"> + <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">Notes</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTextView" id="textviewEquipmentAddNotes"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + </child> + </object> + <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> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hboxEquipmentAddButtons"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="buttonEquipmentAddCancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="cancel_add_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="buttonEquipmentAddConfirm"> + <property name="label">gtk-add</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="confirm_add_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="labelEquipmentAdd"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Add New Equipment</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <object class="GtkFrame" id="frameEquipmentEdit"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignmentEquipmentEdit"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <object class="GtkVBox" id="vboxEquipmentEdit"> + <property name="visible">True</property> + <property name="border_width">5</property> + <child> + <object class="GtkHBox" id="hboxEquipmentEditDetails"> + <property name="visible">True</property> + <child> + <object class="GtkTable" id="tableEquipmentEditDetails"> + <property name="visible">True</property> + <property name="n_rows">4</property> + <property name="n_columns">2</property> + <property name="row_spacing">5</property> + <child> + <object class="GtkLabel" id="labelEquipmentEditDescription"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="xpad">5</property> + <property name="label" translatable="yes">Description</property> + </object> + <packing> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entryEquipmentEditDescription"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + <property name="width_chars">35</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkLabel" id="labelEquipmentEditLifeExpectancy"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="xpad">5</property> + <property name="label" translatable="yes">Life Expectancy</property> + </object> + <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> + <child> + <object class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xscale">0</property> + <child> + <object class="GtkEntry" id="entryEquipmentEditLifeExpectancy"> + <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">1</property> + <property name="bottom_attach">2</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> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="draw_indicator">True</property> + </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="GtkAlignment" id="alignment8"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkLabel" id="labelEquipmentEditNotes"> + <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">Notes</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTextView" id="textviewEquipmentEditNotes"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + </child> + </object> + <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> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hboxEquipmentEditButtons"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="buttonEquipmentEditCancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="cancel_edit_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="buttonEquipmentEditConfirm"> + <property name="label">gtk-save</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="confirm_edit_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="labelEquipmentEdit"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Edit Equipment</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <object class="GtkFrame" id="frameEquipmentDelete"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignmentEquipmentDelete"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <object class="GtkVBox" id="vboxEquipmentDelete"> + <property name="visible">True</property> + <property name="border_width">5</property> + <child> + <object class="GtkLabel" id="labelEquipmentDeleteConfirm"> + <property name="visible">True</property> + <property name="label" translatable="yes">Really delete the equipment item?</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonboxEquipmentDeleteButtons"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="buttonEquipmentDeleteCancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="cancel_delete_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="buttonEquipmentDeleteConfirm"> + <property name="label">gtk-ok</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="confirm_delete_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="labelEquipmentDelete"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Delete Equipment</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="position">3</property> + </packing> + </child> + <child type="tab"> + <placeholder/> + </child> + </object> +</interface> Modified: pytrainer/trunk/glade/newrecord.glade =================================================================== --- pytrainer/trunk/glade/newrecord.glade 2010-11-04 01:46:37 UTC (rev 677) +++ pytrainer/trunk/glade/newrecord.glade 2010-11-06 09:49:44 UTC (rev 678) @@ -1100,6 +1100,68 @@ <property name="type">tab</property> </packing> </child> + <child> + <widget class="GtkFrame" id="frameRecordEquipment"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <widget class="GtkAlignment" id="alignmentRecordEquipment"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <widget class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="border_width">5</property> + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1"> + <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"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + <property name="headers_clickable">False</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Associated Equipment</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="position">3</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="record_equipment_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Equipment</property> + </widget> + <packing> + <property name="position">3</property> + <property name="tab_fill">False</property> + <property name="type">tab</property> + </packing> + </child> </widget> <packing> <property name="expand">False</property> Modified: pytrainer/trunk/glade/profile.glade =================================================================== --- pytrainer/trunk/glade/profile.glade 2010-11-04 01:46:37 UTC (rev 677) +++ pytrainer/trunk/glade/profile.glade 2010-11-06 09:49:44 UTC (rev 678) @@ -1420,6 +1420,28 @@ </packing> </child> <child> + <widget class="GtkAlignment" id="equipment_container"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="position">5</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelEquipment"> + <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="GtkVBox" id="vbox25"> <property name="visible">True</property> <child> Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-04 01:46:37 UTC (rev 677) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-06 09:49:44 UTC (rev 678) @@ -57,7 +57,7 @@ </child> <child> <widget class="GtkImageMenuItem" id="export_csv"> - <property name="label">_Export as Text Separated by Commas</property> + <property name="label" translatable="yes">_Export as Text Separated by Commas</property> <property name="visible">True</property> <property name="use_underline">True</property> <property name="use_stock">False</property> @@ -342,7 +342,7 @@ <child> <widget class="GtkTable" id="table13"> <property name="visible">True</property> - <property name="n_rows">10</property> + <property name="n_rows">11</property> <property name="n_columns">6</property> <property name="column_spacing">3</property> <property name="row_spacing">6</property> @@ -480,8 +480,8 @@ <property name="use_markup">True</property> </widget> <packing> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> + <property name="top_attach">7</property> + <property name="bottom_attach">8</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> @@ -796,8 +796,8 @@ </widget> <packing> <property name="right_attach">6</property> - <property name="top_attach">7</property> - <property name="bottom_attach">8</property> + <property name="top_attach">8</property> + <property name="bottom_attach">9</property> </packing> </child> <child> @@ -831,6 +831,35 @@ </packing> </child> <child> + <widget class="GtkLabel" id="label26"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="label" translatable="yes"><b>Equipment:</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_record_equipment"> + <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> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">6</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + </packing> + </child> + <child> <placeholder/> </child> <child> @@ -5973,7 +6002,7 @@ <widget class="GtkMenu" id="popup"> <child> <widget class="GtkImageMenuItem" id="edit_record1"> - <property name="label">Edit Record</property> + <property name="label" translatable="yes">Edit Record</property> <property name="visible">True</property> <property name="use_stock">False</property> <signal name="activate" handler="on_editrecord_activate"/> Added: pytrainer/trunk/pytrainer/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/equipment.py (rev 0) +++ pytrainer/trunk/pytrainer/equipment.py 2010-11-06 09:49:44 UTC (rev 678) @@ -0,0 +1,203 @@ +# -*- 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 logging + +class Equipment(object): + + """An equipment item that can be used during an activity, such as a pair of running shoes.""" + + def __init__(self): + self._id = None + self.description = u"" + self.active = True + self.life_expectancy = 0 + self.notes = u"" + + def _get_id(self): + return self._id + + def _set_id(self, id): + self._id = int(id) + + id = property(_get_id, _set_id) + + def _get_description(self): + return self._description + + def _set_description(self, description): + if not isinstance(description, unicode): + raise TypeError("Description must be unicode string, not {0}.".format(type(description).__name__)) + self._description = description + + description = property(_get_description, _set_description) + + def _get_active(self): + return self._active + + def _set_active(self, active): + if not isinstance(active, bool): + raise TypeError("Active must be boolean, not {0}.".format(type(active).__name__)) + self._active = active + + active = property(_get_active, _set_active) + + def _get_life_expectancy(self): + return self._life_expectancy + + def _set_life_expectancy(self, life_expectancy): + self._life_expectancy = int(life_expectancy) + + life_expectancy = property(_get_life_expectancy, _set_life_expectancy) + + def _get_notes(self): + return self._notes + + def _set_notes(self, notes): + if not isinstance(notes, unicode): + raise TypeError("Notes must be unicode string, not {0}.".format(type(notes).__name__)) + self._notes = notes + + notes = property(_get_notes, _set_notes) + + def __eq__(self, o): + if isinstance(o, Equipment): + if self.id is not None and o.id is not None: + return self.id == o.id + return False + + def __hash__(self): + if self.id is not None: + return self.id + else: + return object.__hash__(self) + +_TABLE_NAME = "equipment" + +_UPDATE_COLUMNS = "description,active,life_expectancy,notes" + +_ALL_COLUMNS = "id," + _UPDATE_COLUMNS + +def _create_row(equipment): + return [equipment.description, + 1 if equipment.active else 0, + equipment.life_expectancy, + equipment.notes] + +class EquipmentServiceException(Exception): + + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) + +class EquipmentService(object): + + """Provides access to stored equipment items.""" + + def __init__(self, ddbb): + self._ddbb = ddbb + + def get_all_equipment(self): + """Get all equipment items.""" + return self._get_equipment(None) + + def get_active_equipment(self): + """Get all the active equipment items.""" + return self._get_equipment("active = 1") + + def _get_equipment(self, condition): + logging.debug("Retrieving all equipment (condition: '{0}').".format(condition)) + resultSet = self._ddbb.select(_TABLE_NAME, _ALL_COLUMNS, condition) + equipmentList = [] + for result in resultSet: + equipmentList.append(self._create_equipment_item(result)) + return equipmentList + + def get_equipment_item(self, item_id): + """Get an individual equipment item by id. + + If no item with the given id exists then None is returned. + """ + resultSet = self._ddbb.select(_TABLE_NAME, _ALL_COLUMNS, "id = {0}".format(item_id)) + if len(resultSet) == 0: + return None + else: + return self._create_equipment_item(resultSet[0]) + + def _create_equipment_item(self, row): + equipment = Equipment() + (id, description, active, life_expectancy, notes) = row + equipment.id = id + equipment.description = description + equipment.active = bool(active) + equipment.life_expectancy = life_expectancy + equipment.notes = notes + return equipment + + def store_equipment(self, equipment): + """Store a new or update an existing equipment item. + + The stored object is returned.""" + logging.debug("Storing equipment item.") + item_id = None + if equipment.id != None: + item_id = self._update_equipment(equipment) + else: + item_id = self._store_new_equipment(equipment) + return self.get_equipment_item(item_id) + + def _update_equipment(self, equipment): + logging.debug("Updating existing equipment item.") + self._assert_exists(equipment) + self._ddbb.update(_TABLE_NAME, _UPDATE_COLUMNS, _create_row(equipment), "id = {0}".format(equipment.id)) + return equipment.id + + def _assert_exists(self, equipment): + if self.get_equipment_item(equipment.id) == None: + raise EquipmentServiceException("No equipment item exists with id '{0}'".format(equipment.id)) + logging.debug("Asserted item exists with id: '{0}'.".format(equipment.id)) + + def _store_new_equipment(self, equipment): + logging.debug("Storing new equipment item.") + self._assert_unique(equipment) + self._ddbb.insert(_TABLE_NAME, _UPDATE_COLUMNS, _create_row(equipment)) + return self._ddbb.select(_TABLE_NAME, "id", "description = \"{0}\"".format(equipment.description))[0][0] + + 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)) + logging.debug("Asserted description is unique: '{0}'.".format(equipment.description)) + + def remove_equipment(self, equipment): + """Remove an existing equipment item.""" + logging.debug("Deleting equipment item with id: '{0}'".format(equipment.id)) + self._ddbb.delete("record_equipment", "equipment_id=\"{0}\"".format(equipment.id)) + self._ddbb.delete(_TABLE_NAME, "id=\"{0}\"".format(equipment.id)) + + def get_equipment_usage(self, equipment): + """Get the total use of the given equipment.""" + result = self._ddbb.select("records inner join record_equipment " + "on records.id_record = record_equipment.record_id", + "sum(distance)", + "record_equipment.equipment_id = {0}".format(equipment.id)) + usage = result[0][0] + return 0 if usage == None else usage + Added: pytrainer/trunk/pytrainer/gui/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/gui/equipment.py (rev 0) +++ pytrainer/trunk/pytrainer/gui/equipment.py 2010-11-06 09:49:44 UTC (rev 678) @@ -0,0 +1,186 @@ +# -*- 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 gtk +from pytrainer.equipment import Equipment + +class EquipmentStore(gtk.ListStore): + + def __init__(self, equipment_service): + super(EquipmentStore, self).__init__(int, str, float, str, bool) + self._equipment_service = equipment_service + for equipment in equipment_service.get_all_equipment(): + self._append_row(equipment) + + def _append_row(self, equipment): + self.append(self._create_tuple(equipment)) + + def _create_tuple(self, equipment): + usage = self._equipment_service.get_equipment_usage(equipment) + return (equipment.id, + equipment.description, + self._calculate_usage_percent(usage, equipment.life_expectancy), + str(int(round(usage))) + " / " + str(equipment.life_expectancy), + equipment.active) + + def _calculate_usage_percent(self, usage, life_expectancy): + if life_expectancy == 0: + return 0 + else: + return 100.0 * usage / life_expectancy + + def add_equipment(self, equipment): + added_equipment = self._equipment_service.store_equipment(equipment) + 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) + + def edit_equipment(self, item_path, equipment): + updated_item = self._equipment_service.store_equipment(equipment) + for (column_index, value) in enumerate(self._create_tuple(updated_item)): + self.set(self.get_iter(item_path), column_index, value) + + def remove_equipment(self, item_path): + item = self.get_equipment_item(item_path) + self._equipment_service.remove_equipment(item) + self.remove(self.get_iter(item_path)) + +class EquipmentUi(gtk.HBox): + + def __init__(self, glade_conf_dir, equipment_service): + gtk.HBox.__init__(self) + self._equipment_store = EquipmentStore(equipment_service) + self._builder = gtk.Builder() + self._builder.add_from_file(glade_conf_dir + "/equipment.glade") + self._init_tree_view() + self._init_signals() + self.add(self._get_notebook()) + self.set_property('visible', True) + + def _get_notebook(self): + return self._builder.get_object("notebookEquipment") + + def _get_tree_view(self): + return self._builder.get_object("treeviewEquipmentList") + + def _init_tree_view(self): + tree_view = self._get_tree_view() + column = gtk.TreeViewColumn("Description", gtk.CellRendererText(), text=1) + column.set_resizable(True) + tree_view.append_column(column) + tree_view.append_column(gtk.TreeViewColumn("Usage", gtk.CellRendererProgress(), value=2, text=3)) + tree_view.append_column(gtk.TreeViewColumn("Active", gtk.CellRendererToggle(), active=4)) + # add filler column + tree_view.append_column(gtk.TreeViewColumn()) + tree_view.set_model(self._equipment_store) + + def _init_signals(self): + self._builder.connect_signals({ + "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, + "edit_equipment_clicked": 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, + "cancel_delete_equipment_clicked": self._cancel_delete_equipment_clicked, + "confirm_delete_equipment_clicked": self._confirm_delete_equipment_clicked}) + + def _get_selected_equipment_path(self): + (path, _) = self._get_tree_view().get_cursor() + return path + + def _get_selected_equipment_item(self): + return self._equipment_store.get_equipment_item(self._get_selected_equipment_path()) + + 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("checkbuttonEquipmentAddActive").set_active(True) + self._builder.get_object("textviewEquipmentAddNotes").get_buffer().set_text("") + + def show_page_equipment_list(self): + self._get_notebook().set_current_page(0) + + def show_page_equipment_add(self): + self._get_notebook().set_current_page(1) + self._builder.get_object("entryEquipmentAddDescription").grab_focus() + + def show_page_equipment_edit(self): + self._get_notebook().set_current_page(2) + + def show_page_equipment_delete(self): + self._get_notebook().set_current_page(3) + ... [truncated message content] |
From: <jb...@us...> - 2010-11-04 01:46:44
|
Revision: 677 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=677&view=rev Author: jblance Date: 2010-11-04 01:46:37 +0000 (Thu, 04 Nov 2010) Log Message: ----------- Modification of activity to better support value conversion Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-03 08:36:49 UTC (rev 676) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-04 01:46:37 UTC (rev 677) @@ -816,74 +816,6 @@ </packing> </child> <child> - <widget class="GtkHBox" id="hbox37"> - <property name="visible">True</property> - <child> - <widget class="GtkLabel" id="record_hour"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label">00</property> - </widget> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label11132"> - <property name="visible">True</property> - <property name="label">:</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="record_minute"> - <property name="visible">True</property> - <property name="label">00</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">2</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label11133"> - <property name="visible">True</property> - <property name="label">:</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">3</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="record_second"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label">00</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">4</property> - </packing> - </child> - </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">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> <widget class="GtkLabel" id="r_speed_unit"> <property name="visible">True</property> <property name="xalign">0</property> @@ -964,6 +896,18 @@ <child> <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> + </child> </widget> <packing> <property name="expand">False</property> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-03 08:36:49 UTC (rev 676) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-04 01:46:37 UTC (rev 677) @@ -275,6 +275,26 @@ def actualize_recordview(self,activity): logging.debug(">>") if activity.id is None: + #Blank out fields + self.record_distance.set_text("") + self.record_upositive.set_text("") + self.record_unegative.set_text("") + self.record_average.set_text("") + self.record_maxspeed.set_text("") + self.record_pace.set_text("") + self.record_maxpace.set_text("") + self.record_sport.set_text("") + self.record_date.set_text("") + self.record_time.set_text("") + self.record_duration.set_text("") + #self.record_minute.set_text("") + #self.record_second.set_text("") + self.record_calories.set_text("") + self.record_title.set_text("") + com_buffer = self.record_comments.get_buffer() + start,end = com_buffer.get_bounds() + com_buffer.set_text("") + #Move to main record page and grey out self.recordview.set_current_page(0) self.recordview.set_sensitive(0) logging.debug("<<") @@ -297,23 +317,19 @@ recordTime = dateTime.strftime("%X") recordDateTimeOffset = dateTime.strftime("%z") - self.record_distance.set_text("%0.2f" %activity.get_value('distance')) - self.record_upositive.set_text("%0.2f" %activity.get_value('upositive')) - self.record_unegative.set_text("%0.2f" %activity.get_value('unegative')) - self.record_average.set_text("%0.2f" %activity.get_value('average')) - self.record_maxspeed.set_text("%0.2f" %activity.get_value('maxspeed')) - self.record_pace.set_text(activity.get_value('pace')) - self.record_maxpace.set_text(activity.get_value('maxpace')) + self.record_distance.set_text(activity.get_value_f('distance', "%0.2f")) + self.record_upositive.set_text(activity.get_value_f('upositive', "%0.2f")) + self.record_unegative.set_text(activity.get_value_f('unegative', "%0.2f")) + self.record_average.set_text(activity.get_value_f('average', "%0.2f")) + self.record_maxspeed.set_text(activity.get_value_f('maxspeed', "%0.2f")) + self.record_pace.set_text(activity.get_value_f('pace', "%s")) + self.record_maxpace.set_text(activity.get_value_f('maxpace', "%s")) self.record_sport.set_text(activity.sport_name) - #self.record_date.set_text(str(date)) self.record_date.set_text(recordDate) self.record_time.set_text(recordTime) - hour,min,sec=self.parent.date.second2time(int(activity.time)) - self.record_hour.set_text("%d" %hour) - self.record_minute.set_text("%02d" %min) - self.record_second.set_text("%02d" %sec) - self.record_calories.set_text("%0.0f" %activity.calories) + self.record_duration.set_text(activity.get_value_f('time', '%s')) + self.record_calories.set_text(activity.get_value_f('calories', "%0.0f")) self.record_title.set_text(activity.title) buffer = self.record_comments.get_buffer() start,end = buffer.get_bounds() Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-11-03 08:36:49 UTC (rev 676) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-11-04 01:46:37 UTC (rev 677) @@ -199,6 +199,7 @@ self.speed_unit = _("km/h") self.pace_unit = _("min/km") self.height_unit = _("m") + self.units = { 'distance': self.distance_unit, 'average': self.speed_unit, 'upositive': self.height_unit, 'unegative': self.height_unit, 'maxspeed': self.speed_unit, 'pace': self.pace_unit, 'maxpace': self.pace_unit } def _init_from_gpx_file(self): ''' @@ -492,6 +493,25 @@ result = 0 return result + def get_value_f(self, param, format=None, with_units=False): + ''' Function to return a value formated as a string + - takes into account US/metric + - also appends units if required + ''' + value = self.get_value(param) + if not value: + #Return blank string if value is None or 0 + return "" + if format is not None: + result = format % value + else: + result = str(value) + if with_units: + if param in self.units: + result += self.units[param] + #print "activity: 509", result + return result + def get_value(self, param): ''' Function to get the value of various params in this activity instance Automatically returns values converted to imperial if needed @@ -531,8 +551,19 @@ return self.pace_from_float(pacekm2miles(self.pace)) else: return self.pace_from_float(self.pace) + elif param == 'calories': + return self.calories + elif param == 'time': + if not self.time: + return "" + _hour,_min,_sec=self.pytrainer_main.date.second2time(self.time) + if _hour == 0: + return "%02d:%02d" % (_min, _sec) + else: + return "%0d:%02d:%02d" % (_hour, _min, _sec) else: print "Unable to provide value for unknown parameter (%s) for activity" % param + return None def set_value(self, param, value): ''' Function to set the value of various params in this activity instance @@ -592,6 +623,8 @@ def pace_from_float(self, value): '''Helper to generate mm:ss from float representation mm.ss (or mm,ss?)''' #Check that value supplied is a float + if not value: + return "" try: _value = "%0.2f" % float(value) except ValueError: Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-03 08:36:49 UTC (rev 676) +++ pytrainer/trunk/pytrainer/main.py 2010-11-04 01:46:37 UTC (rev 677) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#676" + self.version ="1.7.2_svn#677" 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-03 08:36:56
|
Revision: 676 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=676&view=rev Author: jblance Date: 2010-11-03 08:36:49 +0000 (Wed, 03 Nov 2010) Log Message: ----------- Fix for HR percent graph so does not error in hr is None - thanks to Arnd Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-11-03 03:52:54 UTC (rev 675) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-11-03 08:36:49 UTC (rev 676) @@ -30,7 +30,7 @@ class Activity: ''' Class that knows everything about a particular activity - + All values are stored in the class (and DB) in metric and are converted as needed tracks - (list) tracklist from gpx @@ -128,7 +128,7 @@ self.y2_limits_u = (None, None) self.show_laps = False logging.debug("<<") - + def __str__(self): return ''' tracks (%s) @@ -182,7 +182,7 @@ self.distance_unit, self.speed_unit, self.distance_data, self.time_data, self.height_unit, self.pace_unit, self.gpx_file, self.gpx, self.sport_name, self.sport_id, self.title, self.date, self.time, self.time_tuple, self.beats, - self.maxbeats, self.comments, self.calories, self.id_record, self.date_time_local, + self.maxbeats, self.comments, self.calories, self.id_record, self.date_time_local, self.date_time_utc, self.date_time, self.starttime, self.distance, self.average, self.upositive, self.unegative, self.maxspeed, self.maxpace, self.pace, self.has_data, self.x_axis, self.x_limits, self.y1_limits, self.y2_limits, self.x_limits_u, self.y1_limits_u, @@ -436,13 +436,17 @@ except Exception as e: #print type(e), e pace = 0 + try: + hr_p = float(track['hr'])/maxhr*100 + except: + hr_p = 0 if self.us_system: self.distance_data['elevation'].addPoints(x=km2miles(track['elapsed_distance']), y=m2feet(track['ele'])) self.distance_data['cor_elevation'].addPoints(x=km2miles(track['elapsed_distance']), y=m2feet(track['correctedElevation'])) self.distance_data['speed'].addPoints(x=km2miles(track['elapsed_distance']), y=km2miles(track['velocity'])) self.distance_data['pace'].addPoints(x=km2miles(track['elapsed_distance']), y=pacekm2miles(pace)) self.distance_data['hr'].addPoints(x=km2miles(track['elapsed_distance']), y=track['hr']) - self.distance_data['hr_p'].addPoints(x=km2miles(track['elapsed_distance']), y=float(track['hr'])/maxhr*100) + self.distance_data['hr_p'].addPoints(x=km2miles(track['elapsed_distance']), y=hr_p) self.distance_data['cadence'].addPoints(x=km2miles(track['elapsed_distance']), y=track['cadence']) self.time_data['elevation'].addPoints(x=track['time_elapsed'], y=m2feet(track['ele'])) self.time_data['cor_elevation'].addPoints(x=track['time_elapsed'], y=m2feet(track['correctedElevation'])) @@ -454,14 +458,14 @@ self.distance_data['speed'].addPoints(x=track['elapsed_distance'], y=track['velocity']) self.distance_data['pace'].addPoints(x=track['elapsed_distance'], y=pace) self.distance_data['hr'].addPoints(x=track['elapsed_distance'], y=track['hr']) - self.distance_data['hr_p'].addPoints(x=track['elapsed_distance'], y=float(track['hr'])/maxhr*100) + self.distance_data['hr_p'].addPoints(x=track['elapsed_distance'], y=hr_p) self.distance_data['cadence'].addPoints(x=track['elapsed_distance'], y=track['cadence']) self.time_data['elevation'].addPoints(x=track['time_elapsed'], y=track['ele']) self.time_data['cor_elevation'].addPoints(x=track['time_elapsed'], y=track['correctedElevation']) self.time_data['speed'].addPoints(x=track['time_elapsed'], y=track['velocity']) self.time_data['pace'].addPoints(x=track['time_elapsed'], y=pace) self.time_data['hr'].addPoints(x=track['time_elapsed'], y=track['hr']) - self.time_data['hr_p'].addPoints(x=track['time_elapsed'], y=float(track['hr'])/maxhr*100) + self.time_data['hr_p'].addPoints(x=track['time_elapsed'], y=hr_p) self.time_data['cadence'].addPoints(x=track['time_elapsed'], y=track['cadence']) #Remove data with no values for item in self.distance_data.keys(): @@ -487,7 +491,7 @@ except: result = 0 return result - + def get_value(self, param): ''' Function to get the value of various params in this activity instance Automatically returns values converted to imperial if needed @@ -529,7 +533,7 @@ return self.pace_from_float(self.pace) else: print "Unable to provide value for unknown parameter (%s) for activity" % param - + def set_value(self, param, value): ''' Function to set the value of various params in this activity instance Automatically converts from imperial if using them @@ -574,8 +578,8 @@ self.pace = self.pace_to_float(_pace) else: print "Unable to set value (%s) for unknown parameter (%s) for activity" % (str(value), param) - - + + def pace_to_float(self, value): '''Take a mm:ss or mm.ss and return float''' value = value.replace(':', '.') Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-03 03:52:54 UTC (rev 675) +++ pytrainer/trunk/pytrainer/main.py 2010-11-03 08:36:49 UTC (rev 676) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#675" + self.version ="1.7.2_svn#676" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() @@ -68,8 +68,8 @@ self.ddbb = DDBB(self.profile, self) logging.debug('connecting to DDBB') self.ddbb.connect() - + #Get user's DB version currentDB_version = self.profile.getValue("pytraining","DB_version") logging.debug("Current DB version: "+str(currentDB_version)) @@ -322,13 +322,13 @@ self.athlete.refresh() self.windowmain.actualize_athleteview(self.athlete) logging.debug('<<') - + def refreshListView(self,condition=None): logging.debug('>>') record_list = self.record.getRecordListByCondition(condition) self.windowmain.actualize_listview(record_list) logging.debug('<<') - + def refreshWaypointView(self,default_waypoint=None,redrawmap=1): logging.debug('>>') waypoint_list = self.waypoint.getAllWaypoints() @@ -426,7 +426,7 @@ warning.run() self.refreshListRecords() logging.debug('<<') - + def removeWaypoint(self,id_waypoint, confirm = False): logging.debug('>>') if confirm: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-03 03:53:00
|
Revision: 675 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=675&view=rev Author: jblance Date: 2010-11-03 03:52:54 +0000 (Wed, 03 Nov 2010) Log Message: ----------- Add heartrate as % of max to newgraph display Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/profile.py Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-03 03:18:31 UTC (rev 674) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-03 03:52:54 UTC (rev 675) @@ -445,8 +445,11 @@ data = activity.time_data else: print "x axis is unknown" + #Sort data + keys = data.keys() + keys.sort() #Populate Y axis data - for graphdata in data: + for graphdata in keys: #First Y axis... #Create button y1button = gtk.CheckButton(label=data[graphdata].title) Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-11-03 03:18:31 UTC (rev 674) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-11-03 03:52:54 UTC (rev 675) @@ -408,6 +408,16 @@ xlabel=_("Time (seconds)") self.time_data['hr'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel) self.time_data['hr'].set_color('#00ff00', '#00ff00') + #Heartrate as % + maxhr = self.pytrainer_main.profile.getMaxHR() + title=_("Heart Rate (% of max)") + xlabel="%s (%s)" % (_('Distance'), self.distance_unit) + ylabel="%s (%s)" % (_('Heart Rate'), _('%')) + self.distance_data['hr_p'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel) + self.distance_data['hr_p'].set_color('#00ff00', '#00ff00') + xlabel=_("Time (seconds)") + self.time_data['hr_p'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel) + self.time_data['hr_p'].set_color('#00ff00', '#00ff00') #Cadence title=_("Cadence") xlabel="%s (%s)" % (_('Distance'), self.distance_unit) @@ -432,6 +442,7 @@ self.distance_data['speed'].addPoints(x=km2miles(track['elapsed_distance']), y=km2miles(track['velocity'])) self.distance_data['pace'].addPoints(x=km2miles(track['elapsed_distance']), y=pacekm2miles(pace)) self.distance_data['hr'].addPoints(x=km2miles(track['elapsed_distance']), y=track['hr']) + self.distance_data['hr_p'].addPoints(x=km2miles(track['elapsed_distance']), y=float(track['hr'])/maxhr*100) self.distance_data['cadence'].addPoints(x=km2miles(track['elapsed_distance']), y=track['cadence']) self.time_data['elevation'].addPoints(x=track['time_elapsed'], y=m2feet(track['ele'])) self.time_data['cor_elevation'].addPoints(x=track['time_elapsed'], y=m2feet(track['correctedElevation'])) @@ -443,12 +454,14 @@ self.distance_data['speed'].addPoints(x=track['elapsed_distance'], y=track['velocity']) self.distance_data['pace'].addPoints(x=track['elapsed_distance'], y=pace) self.distance_data['hr'].addPoints(x=track['elapsed_distance'], y=track['hr']) + self.distance_data['hr_p'].addPoints(x=track['elapsed_distance'], y=float(track['hr'])/maxhr*100) self.distance_data['cadence'].addPoints(x=track['elapsed_distance'], y=track['cadence']) self.time_data['elevation'].addPoints(x=track['time_elapsed'], y=track['ele']) self.time_data['cor_elevation'].addPoints(x=track['time_elapsed'], y=track['correctedElevation']) self.time_data['speed'].addPoints(x=track['time_elapsed'], y=track['velocity']) self.time_data['pace'].addPoints(x=track['time_elapsed'], y=pace) self.time_data['hr'].addPoints(x=track['time_elapsed'], y=track['hr']) + self.time_data['hr_p'].addPoints(x=track['time_elapsed'], y=float(track['hr'])/maxhr*100) self.time_data['cadence'].addPoints(x=track['time_elapsed'], y=track['cadence']) #Remove data with no values for item in self.distance_data.keys(): Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-03 03:18:31 UTC (rev 674) +++ pytrainer/trunk/pytrainer/main.py 2010-11-03 03:52:54 UTC (rev 675) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#674" + self.version ="1.7.2_svn#675" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() Modified: pytrainer/trunk/pytrainer/profile.py =================================================================== --- pytrainer/trunk/pytrainer/profile.py 2010-11-03 03:18:31 UTC (rev 674) +++ pytrainer/trunk/pytrainer/profile.py 2010-11-03 03:52:54 UTC (rev 675) @@ -25,313 +25,321 @@ from lib.ddbb import DDBB class Profile: - def __init__(self, data_path = None, parent = None): - logging.debug(">>") - 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 - #Set configuration parameters - self._setHome() - self._setConfFiles() - self._setTempDir() - self._setExtensionDir() - self._setPluginDir() - self._setGpxDir() + def __init__(self, data_path = None, parent = None): + logging.debug(">>") + 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 + #Set configuration parameters + self._setHome() + self._setConfFiles() + self._setTempDir() + self._setExtensionDir() + self._setPluginDir() + self._setGpxDir() - #Clear temp dir - logging.debug("clearing tmp directory %s" % self.tmpdir) - self._clearTempDir() + #Clear temp dir + logging.debug("clearing tmp directory %s" % self.tmpdir) + self._clearTempDir() - #Profile Options and Defaults - self.profile_options = { - "prf_name":"default", - "prf_gender":"", - "prf_weight":"", - "prf_height":"", - "prf_age":"", - "prf_ddbb":"sqlite", - "prf_ddbbhost":"", - "prf_ddbbname":"", - "prf_ddbbuser":"", - "prf_ddbbpass":"", - "version":"0.0", - "DB_version":"0", - "prf_us_system":"False", - "prf_hrzones_karvonen":"False", - "prf_maxhr":"", - "prf_minhr":"", - "auto_launch_file_selection":"False", - "import_default_tab":"0", - "default_viewer":"0", - "window_size":"800, 640", - "activitypool_size": "10", - } + #Profile Options and Defaults + self.profile_options = { + "prf_name":"default", + "prf_gender":"", + "prf_weight":"", + "prf_height":"", + "prf_age":"", + "prf_ddbb":"sqlite", + "prf_ddbbhost":"", + "prf_ddbbname":"", + "prf_ddbbuser":"", + "prf_ddbbpass":"", + "version":"0.0", + "DB_version":"0", + "prf_us_system":"False", + "prf_hrzones_karvonen":"False", + "prf_maxhr":"", + "prf_minhr":"", + "auto_launch_file_selection":"False", + "import_default_tab":"0", + "default_viewer":"0", + "window_size":"800, 640", + "activitypool_size": "10", + } - #Parse pytrainer configuration file - self.config_file = self.conffile - 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) - self._setZones() - logging.debug("<<") + #Parse pytrainer configuration file + self.config_file = self.conffile + 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) + 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 _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 _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 _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 _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 _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 _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 _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") - try: - maxhr = int(self.getValue("pytraining","prf_maxhr")) - resthr = int(self.getValue("pytraining","prf_minhr")) - except Exception as e: - logging.debug(str(e)) - maxhr = 220 - resthr = 65 + def _setZones(self): + #maxhr = self.getValue("pytraining","prf_maxhr") + #resthr = self.getValue("pytraining","prf_minhr") + try: + maxhr = int(self.getValue("pytraining","prf_maxhr")) + resthr = int(self.getValue("pytraining","prf_minhr")) + except Exception as e: + logging.debug(str(e)) + maxhr = 220 + resthr = 65 + self.maxhr = maxhr + self.rethr = resthr - if self.getValue("pytraining","prf_hrzones_karvonen")=="True": - #karvonen method - targethr1 = ((maxhr - resthr) * 0.50) + resthr - targethr2 = ((maxhr - resthr) * 0.60) + resthr - targethr3 = ((maxhr - resthr) * 0.70) + resthr - targethr4 = ((maxhr - resthr) * 0.80) + resthr - targethr5 = ((maxhr - resthr) * 0.90) + resthr - targethr6 = maxhr - else: - #not karvonen method - targethr1 = maxhr * 0.50 - targethr2 = maxhr * 0.60 - targethr3 = maxhr * 0.70 - targethr4 = maxhr * 0.80 - targethr5 = maxhr * 0.90 - targethr6 = maxhr + if self.getValue("pytraining","prf_hrzones_karvonen")=="True": + #karvonen method + targethr1 = ((maxhr - resthr) * 0.50) + resthr + targethr2 = ((maxhr - resthr) * 0.60) + resthr + targethr3 = ((maxhr - resthr) * 0.70) + resthr + targethr4 = ((maxhr - resthr) * 0.80) + resthr + targethr5 = ((maxhr - resthr) * 0.90) + resthr + targethr6 = maxhr + else: + #not karvonen method + targethr1 = maxhr * 0.50 + targethr2 = maxhr * 0.60 + targethr3 = maxhr * 0.70 + targethr4 = maxhr * 0.80 + targethr5 = maxhr * 0.90 + targethr6 = maxhr - self.zone1 = (targethr1,targethr2,"#ffff99",_("Moderate activity")) - self.zone2 = (targethr2,targethr3,"#ffcc00",_("Weight Control")) - self.zone3 = (targethr3,targethr4,"#ff9900",_("Aerobic")) - self.zone4 = (targethr4,targethr5,"#ff6600",_("Anaerobic")) - self.zone5 = (targethr5,targethr6,"#ff0000",_("VO2 MAX")) + self.zone1 = (targethr1,targethr2,"#ffff99",_("Moderate activity")) + self.zone2 = (targethr2,targethr3,"#ffcc00",_("Weight Control")) + self.zone3 = (targethr3,targethr4,"#ff9900",_("Aerobic")) + self.zone4 = (targethr4,targethr5,"#ff6600",_("Anaerobic")) + self.zone5 = (targethr5,targethr6,"#ff0000",_("VO2 MAX")) + + def getMaxHR(self): + return self.maxhr + + def getRestHR(self): + return self.resthr - def getZones(self): - return self.zone5,self.zone4,self.zone3,self.zone2,self.zone1 + def getZones(self): + return self.zone5,self.zone4,self.zone3,self.zone2,self.zone1 - def getConfFile(self): - if not os.path.isfile(self.conffile): - return False - else: - return self.conffile + def getConfFile(self): + if not os.path.isfile(self.conffile): + return False + else: + return self.conffile - def _parse_config_file(self, config_file): - ''' - Parse the xml configuration file and convert to a dict + def _parse_config_file(self, config_file): + ''' + Parse the xml configuration file and convert to a dict - returns: dict with option as key - ''' - if config_file is None: - logging.error("Configuration file value not set") - logging.error("Fatal error, exiting") - exit(-3) - if not os.path.isfile(config_file): #File not found - logging.error("Configuration '%s' file does not exist" % config_file) - logging.info("No profile found. Creating default one") - self.setProfile(self.profile_options) - if os.stat(config_file)[stat.ST_SIZE] == 0: #File is empty - logging.error("Configuration '%s' file is empty" % config_file) - logging.info("Creating default profile") - self.setProfile(self.profile_options) - logging.debug("Attempting to parse content from "+ config_file) - try: - parser = etree.XMLParser(encoding='UTF8', recover=True) - self.xml_tree = etree.parse(config_file, parser=parser) - #Have a populated xml tree, get pytraining node (root) and convert it to a dict - pytraining_tag = self.xml_tree.getroot() - config = {} - config_needs_update = False - for key, default in self.profile_options.items(): - value = pytraining_tag.get(key) - #If property is not found, set it to the default - if value is None: - config_needs_update = True - value = default - config[key] = value - #Added a property, so update config - if config_needs_update: - self.setProfile(config) - #Set shorthand var for units of measurement - self.prf_us_system = True if config["prf_us_system"] == "True" else False - return config - except Exception as e: - logging.error("Error parsing file: %s. Exiting" % config_file) - logging.error(str(e)) - logging.error("Fatal error, exiting") - exit(-3) + returns: dict with option as key + ''' + if config_file is None: + logging.error("Configuration file value not set") + logging.error("Fatal error, exiting") + exit(-3) + if not os.path.isfile(config_file): #File not found + logging.error("Configuration '%s' file does not exist" % config_file) + logging.info("No profile found. Creating default one") + self.setProfile(self.profile_options) + if os.stat(config_file)[stat.ST_SIZE] == 0: #File is empty + logging.error("Configuration '%s' file is empty" % config_file) + logging.info("Creating default profile") + self.setProfile(self.profile_options) + logging.debug("Attempting to parse content from "+ config_file) + try: + parser = etree.XMLParser(encoding='UTF8', recover=True) + self.xml_tree = etree.parse(config_file, parser=parser) + #Have a populated xml tree, get pytraining node (root) and convert it to a dict + pytraining_tag = self.xml_tree.getroot() + config = {} + config_needs_update = False + for key, default in self.profile_options.items(): + value = pytraining_tag.get(key) + #If property is not found, set it to the default + if value is None: + config_needs_update = True + value = default + config[key] = value + #Added a property, so update config + if config_needs_update: + self.setProfile(config) + #Set shorthand var for units of measurement + self.prf_us_system = True if config["prf_us_system"] == "True" else False + return config + except Exception as e: + logging.error("Error parsing file: %s. Exiting" % config_file) + logging.error(str(e)) + logging.error("Fatal error, exiting") + exit(-3) - def getIntValue(self, tag, variable, default=0): - ''' Function to return conf value as int - returns - -- default if cannot convert to int - -- None if variable not found - ''' - result = self.getValue(tag, variable) - if result is None: - return None - try: - result = int(result) - except Exception as e: - logging.debug(str(e)) - result = default - return result + def getIntValue(self, tag, variable, default=0): + ''' Function to return conf value as int + returns + -- default if cannot convert to int + -- None if variable not found + ''' + result = self.getValue(tag, variable) + if result is None: + return None + try: + result = int(result) + except Exception as e: + logging.debug(str(e)) + result = default + return result - def getValue(self, tag, variable): - if tag != "pytraining": - print "ERROR - pytraining is the only profile tag supported" - return None - elif not self.configuration.has_key(variable): - return None - return self.configuration[variable] + def getValue(self, tag, variable): + if tag != "pytraining": + print "ERROR - pytraining is the only profile tag supported" + return None + elif not self.configuration.has_key(variable): + return None + return self.configuration[variable] - def setValue(self, tag, variable, value, delay_write=False): - logging.debug(">>") - if tag != "pytraining": - print "ERROR - pytraining is the only profile tag supported" - logging.debug("Setting %s to %s" % (variable, value)) - if self.xml_tree is None: - #new config file.... - self.xml_tree = etree.parse(StringIO('''<?xml version='1.0' encoding='UTF-8'?><pytraining />''')) - self.xml_tree.getroot().set(variable, value.decode('utf-8')) - if not delay_write: - logging.debug("Writting...") - self.xml_tree.write(self.config_file, xml_declaration=True, encoding='UTF-8') - logging.debug("<<") + def setValue(self, tag, variable, value, delay_write=False): + logging.debug(">>") + if tag != "pytraining": + print "ERROR - pytraining is the only profile tag supported" + logging.debug("Setting %s to %s" % (variable, value)) + if self.xml_tree is None: + #new config file.... + self.xml_tree = etree.parse(StringIO('''<?xml version='1.0' encoding='UTF-8'?><pytraining />''')) + self.xml_tree.getroot().set(variable, value.decode('utf-8')) + if not delay_write: + logging.debug("Writting...") + self.xml_tree.write(self.config_file, xml_declaration=True, encoding='UTF-8') + logging.debug("<<") - def setProfile(self,list_options): - logging.debug(">>") - for option, value in list_options.items(): - logging.debug("Adding "+option+"|"+value) - self.setValue("pytraining",option,value,delay_write=True) - self.xml_tree.write(self.config_file, xml_declaration=True, encoding='UTF-8') - logging.debug("<<") + def setProfile(self,list_options): + logging.debug(">>") + for option, value in list_options.items(): + logging.debug("Adding "+option+"|"+value) + self.setValue("pytraining",option,value,delay_write=True) + self.xml_tree.write(self.config_file, xml_declaration=True, encoding='UTF-8') + logging.debug("<<") - def getSportList(self): - logging.debug("--") - #connection = self.pytrainer_main.ddbb.connect() - #if (connection == 1): - logging.debug("retrieving sports info") - return self.pytrainer_main.ddbb.select("sports","name,met,weight,id_sports,max_pace",None) - #else: - # return connection + def getSportList(self): + logging.debug("--") + #connection = self.pytrainer_main.ddbb.connect() + #if (connection == 1): + logging.debug("retrieving sports info") + return self.pytrainer_main.ddbb.select("sports","name,met,weight,id_sports,max_pace",None) + #else: + # return connection - def addNewSport(self,sport,met,weight,maxpace): - """31.08.2008 - dgranda - It adds a new sport. - arguments: - sport: sport's name - met: - weight: - returns: id_sports from new sport""" - logging.debug(">>") - logging.debug("Adding new sport: "+sport+"|"+weight+"|"+met+"|"+maxpace) - sport = [sport,met,weight,maxpace] - self.pytrainer_main.ddbb.insert("sports","name,met,weight,max_pace",sport) - sport_id = self.pytrainer_main.ddbb.select("sports","id_sports","name=\"%s\"" %(sport)) - logging.debug("<<") - return sport_id + def addNewSport(self,sport,met,weight,maxpace): + """31.08.2008 - dgranda + It adds a new sport. + arguments: + sport: sport's name + met: + weight: + returns: id_sports from new sport""" + logging.debug(">>") + logging.debug("Adding new sport: "+sport+"|"+weight+"|"+met+"|"+maxpace) + sport = [sport,met,weight,maxpace] + self.pytrainer_main.ddbb.insert("sports","name,met,weight,max_pace",sport) + sport_id = self.pytrainer_main.ddbb.select("sports","id_sports","name=\"%s\"" %(sport)) + logging.debug("<<") + return sport_id - def delSport(self,sport): - logging.debug(">>") - condition = "name=\"%s\"" %sport - id_sport = self.pytrainer_main.ddbb.select("sports","id_sports",condition)[0][0] - logging.debug("removing records from sport "+ sport + " (id_sport: "+str(id_sport)+")") - self.pytrainer_main.ddbb.delete("records","sport=\"%d\""%id_sport) - self.pytrainer_main.ddbb.delete("sports","id_sports=\"%d\""%id_sport) - logging.debug("<<") + def delSport(self,sport): + logging.debug(">>") + condition = "name=\"%s\"" %sport + id_sport = self.pytrainer_main.ddbb.select("sports","id_sports",condition)[0][0] + logging.debug("removing records from sport "+ sport + " (id_sport: "+str(id_sport)+")") + self.pytrainer_main.ddbb.delete("records","sport=\"%d\""%id_sport) + self.pytrainer_main.ddbb.delete("sports","id_sports=\"%d\""%id_sport) + logging.debug("<<") - def updateSport(self,oldnamesport,newnamesport,newmetsport,newweightsport,newmaxpace=None): - logging.debug("--") - self.pytrainer_main.ddbb.update("sports","name,met,weight,max_pace",[newnamesport,newmetsport,newweightsport, newmaxpace],"name=\"%s\""%oldnamesport) + def updateSport(self,oldnamesport,newnamesport,newmetsport,newweightsport,newmaxpace=None): + logging.debug("--") + self.pytrainer_main.ddbb.update("sports","name,met,weight,max_pace",[newnamesport,newmetsport,newweightsport, newmaxpace],"name=\"%s\""%oldnamesport) - def getSportInfo(self,namesport): - logging.debug("--") - return self.pytrainer_main.ddbb.select("sports","name,met,weight,max_pace","name=\"%s\""%namesport)[0] + def getSportInfo(self,namesport): + logging.debug("--") + return self.pytrainer_main.ddbb.select("sports","name,met,weight,max_pace","name=\"%s\""%namesport)[0] - def build_ddbb(self): - logging.debug("--") - self.pytrainer_main.ddbb.build_ddbb() + def build_ddbb(self): + logging.debug("--") + self.pytrainer_main.ddbb.build_ddbb() - def editProfile(self): - logging.debug(">>") - from gui.windowprofile import WindowProfile - logging.debug("retrieving configuration data") - #Refresh configuration - self.configuration = self._parse_config_file(self.config_file) - profilewindow = WindowProfile(self.data_path, self, pytrainer_main=self.pytrainer_main) - logging.debug("setting data values") - profilewindow.setValues(self.configuration) - profilewindow.run() - self.configuration = self._parse_config_file(self.config_file) - logging.debug("<<") + def editProfile(self): + logging.debug(">>") + from gui.windowprofile import WindowProfile + logging.debug("retrieving configuration data") + #Refresh configuration + self.configuration = self._parse_config_file(self.config_file) + profilewindow = WindowProfile(self.data_path, self, pytrainer_main=self.pytrainer_main) + logging.debug("setting data values") + profilewindow.setValues(self.configuration) + profilewindow.run() + self.configuration = self._parse_config_file(self.config_file) + logging.debug("<<") - def actualize_mainsportlist(self): - logging.debug("--") - self.pytrainer_main.refreshMainSportList() + def actualize_mainsportlist(self): + logging.debug("--") + self.pytrainer_main.refreshMainSportList() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-03 03:18:39
|
Revision: 674 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=674&view=rev Author: jblance Date: 2010-11-03 03:18:31 +0000 (Wed, 03 Nov 2010) Log Message: ----------- Add extra graph data to old graph, still need to migrate to newgraph (from Patrick). Remove Googlemaps API v2 as option (v3 only now), remove testimport options (is no longer experimental) Modified Paths: -------------- pytrainer/trunk/glade/profile.glade pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/extensions/googlemaps.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/gui/windowprofile.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py pytrainer/trunk/pytrainer/recordgraph.py Modified: pytrainer/trunk/glade/profile.glade =================================================================== --- pytrainer/trunk/glade/profile.glade 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/glade/profile.glade 2010-11-03 03:18:31 UTC (rev 674) @@ -1,4 +1,4 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="UTF-8"?> <glade-interface> <!-- interface-requires gtk+ 2.10 --> <!-- interface-naming-policy toplevel-contextual --> @@ -362,7 +362,7 @@ <widget class="GtkEntry" id="entry345"> <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">6</property> </widget> <packing> @@ -539,7 +539,7 @@ <property name="width_request">108</property> <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> @@ -788,7 +788,7 @@ <widget class="GtkEntry" id="newsportentry"> <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> @@ -824,7 +824,7 @@ <widget class="GtkEntry" id="newmetentry"> <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> @@ -851,7 +851,7 @@ <widget class="GtkEntry" id="newweightentry"> <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> @@ -891,15 +891,6 @@ </packing> </child> <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> <widget class="GtkLabel" id="label-10"> <property name="visible">True</property> <property name="xalign">0</property> @@ -916,7 +907,7 @@ <widget class="GtkEntry" id="newmaxpace"> <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> @@ -926,6 +917,15 @@ <property name="y_options"></property> </packing> </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> </widget> <packing> <property name="position">0</property> @@ -1190,7 +1190,7 @@ <widget class="GtkEntry" id="editsportentry"> <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> @@ -1215,7 +1215,7 @@ <widget class="GtkEntry" id="editmetentry"> <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> @@ -1242,7 +1242,7 @@ <widget class="GtkEntry" id="editweightentry"> <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> @@ -1287,7 +1287,7 @@ <widget class="GtkEntry" id="editmaxpace"> <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> @@ -1469,7 +1469,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">4</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> </widget> <packing> @@ -1484,7 +1484,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">4</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> </widget> <packing> @@ -1850,100 +1850,6 @@ </packing> </child> <child> - <widget class="GtkLabel" id="labelGM3"> - <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">Googlemaps v3</property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - </packing> - </child> - <child> - <widget class="GtkCheckButton" id="checkbuttonGM3"> - <property name="label">--gmaps2*</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="xalign">0</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_checkbuttonGM3_toggled"/> - </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_padding">10</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelGM3Description"> - <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"><small>Is the Googlemaps API version 3 in use?</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">3</property> - <property name="bottom_attach">4</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelUnifiedImport"> - <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">Unified Import</property> - </widget> - <packing> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - </packing> - </child> - <child> - <widget class="GtkCheckButton" id="checkbuttonUnifiedImport"> - <property name="label">--testimport</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="xalign">0</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_checkbuttonUnifiedImport_toggled"/> - </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_padding">10</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelUnifiedImportDescription"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="label" translatable="yes"><small>Is the Unified Importer active?</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">4</property> - <property name="bottom_attach">5</property> - </packing> - </child> - <child> <widget class="GtkLabel" id="labelEquip"> <property name="visible">True</property> <property name="xalign">0</property> @@ -2033,6 +1939,24 @@ <property name="bottom_attach">7</property> </packing> </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> </widget> </child> </widget> @@ -2058,18 +1982,7 @@ </packing> </child> <child> - <widget class="GtkLabel" id="labelNote"> - <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"><small>* Note Googlemaps API version 3 is on by default, use --gmaps2 to switch it off</small></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="position">2</property> - </packing> + <placeholder/> </child> </widget> <packing> Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-03 03:18:31 UTC (rev 674) @@ -1111,7 +1111,9 @@ Speed Pace Heart Rate -Cadence</property> +Cadence +Percentage +Zone</property> <signal name="changed" handler="on_day_combovalue_changed"/> </widget> <packing> Modified: pytrainer/trunk/pytrainer/extensions/googlemaps.py =================================================================== --- pytrainer/trunk/pytrainer/extensions/googlemaps.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/extensions/googlemaps.py 2010-11-03 03:18:31 UTC (rev 674) @@ -16,15 +16,12 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -import gtkmozembed import os import re import logging -#from pytrainer.lib.gpx import Gpx import pytrainer.lib.points as Points from pytrainer.lib.fileUtils import fileUtils -#from pytrainer.record import Record class Googlemaps: def __init__(self, data_path = None, waypoint = None, pytrainer_main=None): @@ -37,7 +34,7 @@ def drawMap(self,activity): '''Draw google map - create html file using Google API version?? + create html file using Google API version3 render using embedded Mozilla info at http://www.pygtk.org/pygtkmozembed/class-gtkmozembed.html @@ -65,20 +62,16 @@ logging.debug("minlon: %s, maxlon: %s" % (minlon, maxlon)) points,levels = Points.encodePoints(pointlist) points = points.replace("\\","\\\\") - if self.pytrainer_main.startup_options.gm3: - logging.debug("Using Google Maps version 3 API") - laps = activity.laps - timeHours = int(activity.time) / 3600 - timeMin = (float(activity.time) / 3600.0 - timeHours) * 60 - time = "%d%s %02d%s" % (timeHours, _("h"), timeMin, _("min")) - startinfo = "<div class='info_content'>%s: %s</div>" % (activity.sport_name, activity.title) - 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) - else: - logging.debug("Using Google Maps version 2 API") - self.createHtml(points,levels,pointlist[0]) + logging.debug("Using Google Maps version 3 API") + laps = activity.laps + timeHours = int(activity.time) / 3600 + timeMin = (float(activity.time) / 3600.0 - timeHours) * 60 + time = "%d%s %02d%s" % (timeHours, _("h"), timeMin, _("min")) + startinfo = "<div class='info_content'>%s: %s</div>" % (activity.sport_name, activity.title) + 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) else: self.createErrorHtml() return self.htmlfile @@ -230,108 +223,6 @@ file.run() logging.debug("<<") - def createHtml(self,points,levels,init_point): - logging.debug(">>") - if self.waypoint is not None: - waypoints = self.waypoint.getAllWaypoints() - else: - waypoints = [] - content = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n" - content += " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" - content += " <html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:v=\"urn:schemas-microsoft-com:vml\">\n" - content += " <head>\n" - content += " <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/>\n" - content += " <title>Google Maps JavaScript API Example</title>\n" - content += " <script id=\"googleapiimport\" src=\"http://maps.google.com/maps?file=api&v=2\"\n" - content += " type=\"text/javascript\"></script>\n" - content += " <script type=\"text/javascript\">\n" - content += " //<![CDATA[\n" - i = 0 - arrayjs = "" - for point in waypoints: - content += "lon = '%f';\n"%point[2] - content += "lat = '%f';\n"%point[1] - content += "name = '%s';\n"%point[6] - content += "description = '%s';\n"%point[4] - content += "sym = '%s';\n"%point[7] - content += "id = '%d';\n"%point[0] - content += """waypoint%d = Array (lon,lat,name,description,sym,id);\n"""%i - if i>0: - arrayjs+="," - arrayjs +="waypoint%d"%i - i = i+1 - content += """waypointList = Array (%s);\n""" %arrayjs - content += """ - function createMarker(waypoint,map) { - var lon = waypoint[0]; - var lat = waypoint[1]; - var id = waypoint[5]; - var name = waypoint[2]; - var description = waypoint[3]; - - var point = new GLatLng(lat,lon); - var text = "<b>"+waypoint[2]+"</b><br/>"+waypoint[3]; - - var icon = new GIcon(); - if (sym=="Summit") { - icon.image = \""""+os.path.abspath(self.data_path)+"""/glade/summit.png\"; - } - else { - icon.image = \""""+os.path.abspath(self.data_path)+"""/glade/waypoint.png\"; - } - icon.iconSize = new GSize(32, 32); - icon.iconAnchor = new GPoint(16, 16); - icon.infoWindowAnchor = new GPoint(5, 1); - - var markerD = new GMarker(point, {icon:icon, draggable: false}); - GEvent.addListener(markerD, "click", function() { - markerD.openInfoWindowHtml("<b>" + name + "</b><br/>"+description); - }); - map.addOverlay(markerD); - - }""" - - content += " function load() {\n" - content += " if (GBrowserIsCompatible()) {\n" - content += " var map = new GMap2(document.getElementById(\"map\"));\n" - content += " map.addControl(new GLargeMapControl());\n" - content += " map.addControl(new GMapTypeControl());\n" - content += " map.addControl(new GScaleControl());\n" - content += " map.setCenter(new GLatLng(%f,%f), 11);\n" %(float(init_point[0]),float(init_point[1])) - content += " ovMap=new GOverviewMapControl();\n" - content += " map.addControl(ovMap);\n" - content += " mini=ovMap.getOverviewMap();\n" - content += " //Dibujamos los waypoints\n" - content += " for (i=0; i<waypointList.length; i++){\n" - content += " createMarker(waypointList[i],map);\n" - content += " map.enableDragging();\n" - content += " }\n" - content += " document.getElementById('map').style.top='0px';\n" - content += " document.getElementById('map').style.left='0px';\n" - content += " document.getElementById('map').style.width='100%';\n" - content += " // Add an encoded polyline.\n" - content += " var encodedPolyline = new GPolyline.fromEncoded({\n" - content += " color: \"#3333cc\",\n" - content += " weight: 10,\n" - content += " points: \"%s\",\n" %points - content += " levels: \"%s\",\n" %levels - content += " zoomFactor: 32,\n" - content += " numLevels: 4\n" - content += " });\n" - content += " map.addOverlay(encodedPolyline);\n" - content += " }\n" - content += " }\n " - content += " //]]>\n" - content += " </script>\n" - content += " </head>\n" - content += " <body onload=\"load()\" onunload=\"GUnload()\">\n" - content += " <div id=\"map\" style=\"width: 520px; height: 480px\"></div>\n" - content += " </body>\n" - content += "</html>\n" - file = fileUtils(self.htmlfile,content) - file.run() - logging.debug("<<") - def createErrorHtml(self): logging.debug(">>") content = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-03 03:18:31 UTC (rev 674) @@ -82,7 +82,6 @@ self.listsearch = ListSearch(self, self.pytrainer_main) def new(self): - self.testimport = self.pytrainer_main.startup_options.testimport self.menublocking = 0 self.selected_view="day" self.window1.set_title ("pyTrainer %s" % self.version) @@ -132,9 +131,6 @@ self.allRecordTreeView.set_search_column(1) self.notebook.set_current_page(1) - #Disable import menu item unless specified on startup - self.set_unified_import(self.testimport) - #Set correct map viewer if self.pytrainer_main.profile.getValue("pytraining","default_viewer") == "1": self.radiobuttonOSM.set_active(1) @@ -160,10 +156,6 @@ page = self.notebook.get_current_page() self.on_page_change(None,None,page) - def set_unified_import(self, status=False): - self.menu_importdata.set_sensitive(status) - self.parent.testimport = status - def _createXmlListView(self,file): menufile = XMLParser(file) savedOptions = [] @@ -214,7 +206,7 @@ self.parent.runExtension(extension,id) def createGraphs(self,RecordGraph,DayGraph,WeekGraph, MonthGraph,YearGraph,HeartRateGraph): - self.drawarearecord = RecordGraph(self.record_graph_vbox, self.window1, self.record_combovalue, self.record_combovalue2, self.btnShowLaps, self.tableConfigY1) + 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) self.day_vbox.hide() Modified: pytrainer/trunk/pytrainer/gui/windowprofile.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowprofile.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/gui/windowprofile.py 2010-11-03 03:18:31 UTC (rev 674) @@ -200,19 +200,7 @@ self.checkbuttonCheck.set_active(True) else: self.checkbuttonCheck.set_active(False) - - #Show if using Googlemaps API v3 - if self.pytrainer_main.startup_options.gm3: - self.checkbuttonGM3.set_active(True) - else: - self.checkbuttonGM3.set_active(False) - #Show if unified import activated - if self.pytrainer_main.startup_options.testimport: - self.checkbuttonUnifiedImport.set_active(True) - else: - self.checkbuttonUnifiedImport.set_active(False) - #Show if new graph activated if self.pytrainer_main.startup_options.newgraph: self.checkbuttonNewGraph.set_active(True) @@ -254,32 +242,6 @@ else: logging.debug("Check deactivated") self.pytrainer_main.startup_options.check = False - - def on_checkbuttonGM3_toggled(self, widget): - if self.checkbuttonGM3.get_active(): - logging.debug("GM3 activated") - self.pytrainer_main.startup_options.gm3 = True - else: - logging.debug("GM3 deactivated") - self.pytrainer_main.startup_options.gm3 = False - - def on_checkbuttonUnifiedImport_toggled(self, widget): - if self.checkbuttonUnifiedImport.get_active(): - logging.debug("Unified Import activated") - if self.pytrainer_main.startup_options.testimport is not True: - #Need to enable unified import - logging.debug("Need to enable unified import") - self.pytrainer_main.windowmain.set_unified_import(True) - else: - #No change - logging.debug("No change to unified import") - else: - logging.debug("Unified Import deactivated") - if self.pytrainer_main.startup_options.testimport is True: - logging.debug("Need to deactivate unified import") - self.pytrainer_main.windowmain.set_unified_import(False) - else: - logging.debug("No change to unified import") def on_checkbuttonNewGraph_toggled(self, widget): if self.checkbuttonNewGraph.get_active(): Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-11-03 03:18:31 UTC (rev 674) @@ -212,7 +212,7 @@ self.tracks = self.gpx.getTrackList() #TODO fix - this should removed and replaced with self.tracklist functionality self.tracklist = self.gpx.trkpoints self.gpx_distance = self.gpx.total_dist - print "GPX Distance: %s" % self.gpx_distance + logging.debug("GPX Distance: %s" % self.gpx_distance) logging.debug("<<") def _init_from_db(self): Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/main.py 2010-11-03 03:18:31 UTC (rev 674) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#672" + self.version ="1.7.2_svn#674" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() @@ -113,14 +113,12 @@ For more help on valid options try: %prog -h ''' parser = OptionParser(usage=usage) - parser.set_defaults(log_level=logging.ERROR, validate=False, gm3=True, testimport=True, equip=False, newgraph=False) + parser.set_defaults(log_level=logging.ERROR, validate=False, equip=False, newgraph=False) 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("--gmaps2", action="store_false", dest="gm3", help="Use old Google Maps API version (v2)") - parser.add_option("--testimport", action="store_true", dest="testimport", help="EXPERIMENTAL: show new import functionality - for testing only USE AT YOUR OWN RISK") 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() @@ -231,19 +229,20 @@ self.refreshRecordGraphView("heartrate") elif view=="day": logging.debug('day view') - record_list = self.record.getrecordList(date_selected) + sport = self.windowmain.activeSport + record_list = self.record.getrecordList(date_selected, sport) self.windowmain.actualize_dayview(record_list=record_list) #selected,iter = self.windowmain.recordTreeView.get_selection().get_selected() elif view=="week": logging.debug('week view') date_ini, date_end = self.date.getWeekInterval(date_selected, self.profile.prf_us_system) - sport = self.windowmain.getSportSelected() + sport = self.windowmain.activeSport record_list = self.record.getrecordPeriod(date_ini, date_end, sport) self.windowmain.actualize_weekview(record_list, date_ini, date_end) elif view=="month": logging.debug('month view') date_ini, date_end = self.date.getMonthInterval(date_selected) - sport = self.windowmain.getSportSelected() + sport = self.windowmain.activeSport record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport) nameMonth, daysInMonth = self.date.getNameMonth(date_selected) self.windowmain.actualize_monthview(record_list, nameMonth) @@ -251,7 +250,7 @@ elif view=="year": logging.debug('year view') date_ini, date_end = self.date.getYearInterval(date_selected) - sport = self.windowmain.getSportSelected() + sport = self.windowmain.activeSport year = self.date.getYear(date_selected) record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport) self.windowmain.actualize_yearview(record_list, year) @@ -310,10 +309,11 @@ self.refreshListView(self.windowmain.listsearch.condition) #Refresh list records date = self.date.getDate() - record_ids = self.record.getrecordList(date) + id_sport = self.windowmain.activeSport + record_ids = self.record.getrecordList(date, id_sport) self.windowmain.actualize_recordTreeView(record_ids) #Mark the monthly calendar to show which days have activity? - record_list = self.record.getRecordDayList(date) + record_list = self.record.getRecordDayList(date, id_sport) self.windowmain.actualize_calendar(record_list) logging.debug('<<') Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/record.py 2010-11-03 03:18:31 UTC (rev 674) @@ -324,11 +324,16 @@ "sports.name,date,distance,time,beats,comments,average,calories,id_record,title,upositive,unegative,maxspeed,maxpace,pace,maxbeats,date_time_utc,date_time_local", "id_record=\"%s\" and records.sport=sports.id_sports" %id_record) - def getrecordList(self,date): + def getrecordList(self,date, id_sport=None): logging.debug('--') - return self.pytrainer_main.ddbb.select("records,sports", + if not id_sport: + return self.pytrainer_main.ddbb.select("records,sports", "sports.name,date,distance,time,beats,comments,average,calories,id_record,maxspeed,maxbeats,date_time_utc,date_time_local", "date=\"%s\" and records.sport=sports.id_sports" %date) + else: + return self.pytrainer_main.ddbb.select("records,sports", + "sports.name,date,distance,time,beats,comments,average,calories,id_record,maxspeed,maxbeats,date_time_utc,date_time_local", + "date=\"%s\" and sports.id_sports=\"%s\" and records.sport=sports.id_sports" %(date,id_sport)) def getLaps(self, id_record): logging.debug('--') @@ -449,12 +454,15 @@ "date,distance,average,title,sports.name,id_record,time,beats,calories", "sports.id_sports = records.sport and %s" %condition) - def getRecordDayList(self,date): + def getRecordDayList(self,date, id_sport=None): logging.debug('>>') year,month,day = date.split("-") logging.debug('Retrieving data for '+year+'.'+month+'.'+day) # Why is looking for all days of the same month? - records = self.pytrainer_main.ddbb.select("records","date","date LIKE '"+year+"-"+month+"-%'") + if not id_sport: + records = self.pytrainer_main.ddbb.select("records","date","date LIKE '"+year+"-"+month+"-%'") + else: + records = self.ddbb.select("records","date","date LIKE \"%s-%s-%%\" and sport=\"%s\"" %(year,month,id_sport)) logging.debug('Found '+str(len(records))+' entries') day_list = [] for i in records: Modified: pytrainer/trunk/pytrainer/recordgraph.py =================================================================== --- pytrainer/trunk/pytrainer/recordgraph.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/recordgraph.py 2010-11-03 03:18:31 UTC (rev 674) @@ -18,153 +18,170 @@ import logging from gui.drawArea import DrawArea + import gtk class RecordGraph: - def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None, btnShowLaps = None, tableConfig = None): - logging.debug(">>") - self.drawarea = DrawArea(vbox, window) - self.combovalue = combovalue - self.combovalue2 = combovalue2 - self.showLaps = btnShowLaps - self.config_table = tableConfig - logging.debug("<<") + def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None, btnShowLaps = None, tableConfig = None, pytrainer_main=None): + logging.debug(">>") + self.pytrainer_main = pytrainer_main + self.drawarea = DrawArea(vbox, window) + self.combovalue = combovalue + self.combovalue2 = combovalue2 + self.showLaps = btnShowLaps + self.config_table = tableConfig + logging.debug("<<") - def drawgraph(self,values,laps=None, y1limits=None, y1color=None, y1_linewidth=1): - logging.debug(">>") - #Get the config options - for child in self.config_table.get_children(): - if child.get_name() == "spinbuttonY1Max": - spinbuttonY1Max = child - elif child.get_name() == "spinbuttonY1Min": - spinbuttonY1Min = child - elif child.get_name() == "colorbuttonY1LineColor": - colorbuttonY1LineColor = child - elif child.get_name() == "spinbuttonY1LineWeight": - spinbuttonY1LineWeight = child + def drawgraph(self,values,laps=None, y1limits=None, y1color=None, y1_linewidth=1): + logging.debug(">>") + #Get the config options + for child in self.config_table.get_children(): + if child.get_name() == "spinbuttonY1Max": + spinbuttonY1Max = child + elif child.get_name() == "spinbuttonY1Min": + spinbuttonY1Min = child + elif child.get_name() == "colorbuttonY1LineColor": + colorbuttonY1LineColor = child + elif child.get_name() == "spinbuttonY1LineWeight": + spinbuttonY1LineWeight = child - xval = [] - yval = [] - xlab = [] - ylab = [] - tit = [] - col = [] - value_selected = self.combovalue.get_active() - logging.debug("Value selected 1: "+ str(value_selected)) - value_selected2 = self.combovalue2.get_active() - logging.debug("Value selected 2: "+ str(value_selected2)) - showLaps = self.showLaps.get_active() - logging.debug("Show laps: "+ str(showLaps)) - #Determine left and right lap boundaries - if laps is not None and showLaps: - lapValues = [] - lastPoint = 0.0 - for lap in laps: - thisPoint = float(lap['distance'])/1000.0 + lastPoint - lapValues.append((lastPoint, thisPoint)) - lastPoint = thisPoint - else: - lapValues = None + xval = [] + yval = [] + xlab = [] + ylab = [] + tit = [] + col = [] + value_selected = self.combovalue.get_active() + logging.debug("Value selected 1: "+ str(value_selected)) + value_selected2 = self.combovalue2.get_active() + logging.debug("Value selected 2: "+ str(value_selected2)) + showLaps = self.showLaps.get_active() + logging.debug("Show laps: "+ str(showLaps)) + #Determine left and right lap boundaries + if laps is not None and showLaps: + lapValues = [] + lastPoint = 0.0 + for lap in laps: + thisPoint = float(lap['distance'])/1000.0 + lastPoint + lapValues.append((lastPoint, thisPoint)) + lastPoint = thisPoint + else: + lapValues = None - if value_selected < 0: - self.combovalue.set_active(0) - value_selected = 0 + if value_selected < 0: + self.combovalue.set_active(0) + value_selected = 0 - if value_selected2 < 0: - self.combovalue2.set_active(0) - value_selected2 = 0 - xvalues, yvalues = self.get_values(values,value_selected) - max_yvalue = max(yvalues) - min_yvalue = min(yvalues) - xlabel,ylabel,title,color = self.get_value_params(value_selected) - if y1color is not None: - _color = gtk.gdk.Color(y1color) - color = y1color - else: - _color = gtk.gdk.Color(color) + if value_selected2 < 0: + self.combovalue2.set_active(0) + value_selected2 = 0 + xvalues, yvalues = self.get_values(values,value_selected) + max_yvalue = max(yvalues) + min_yvalue = min(yvalues) + xlabel,ylabel,title,color = self.get_value_params(value_selected) + if y1color is not None: + _color = gtk.gdk.Color(y1color) + color = y1color + else: + _color = gtk.gdk.Color(color) - xval.append(xvalues) - yval.append(yvalues) - if value_selected2 > 0: - xlab.append("") - else: - xlab.append(xlabel) - ylab.append(ylabel) - tit.append(title) - col.append(color) + xval.append(xvalues) + yval.append(yvalues) + if value_selected2 > 0: + xlab.append("") + else: + xlab.append(xlabel) + ylab.append(ylabel) + tit.append(title) + col.append(color) - #_color = gtk.gdk.Color(color) - colorbuttonY1LineColor.set_color(_color) + #_color = gtk.gdk.Color(color) + colorbuttonY1LineColor.set_color(_color) - if value_selected2 > 0: - value_selected2 = value_selected2-1 - xlabel,ylabel,title,color = self.get_value_params(value_selected2) - xvalues,yvalues = self.get_values(values,value_selected2) - max_yvalue=max(max(yvalues), max_yvalue) - min_yvalue=min(min(yvalues), min_yvalue) - xval.append(xvalues) - yval.append(yvalues) - xlab.append(xlabel) - ylab.append(ylabel) - tit.append("") - col.append(color) - logging.info("To show: tit: "+str(tit)+" | col: "+str(col)+" | xlab: "+str(xlab)+" | ylab: "+str(ylab)) - #self.drawPlot(xvalues,yvalues,xlabel,ylabel,title,color,zones) - plot_stats = self.drawarea.drawPlot(xval,yval,xlab,ylab,tit,col,None,lapValues, ylimits=y1limits, y1_linewidth=y1_linewidth) - ymin = plot_stats['y1_min'] - ymax = plot_stats['y1_max'] - y1_linewidth = plot_stats['y1_linewidth'] + if value_selected2 > 0: + value_selected2 = value_selected2-1 + xlabel,ylabel,title,color = self.get_value_params(value_selected2) + xvalues,yvalues = self.get_values(values,value_selected2) + max_yvalue=max(max(yvalues), max_yvalue) + min_yvalue=min(min(yvalues), min_yvalue) + xval.append(xvalues) + yval.append(yvalues) + xlab.append(xlabel) + ylab.append(ylabel) + tit.append("") + col.append(color) + logging.info("To show: tit: "+str(tit)+" | col: "+str(col)+" | xlab: "+str(xlab)+" | ylab: "+str(ylab)) + #self.drawPlot(xvalues,yvalues,xlabel,ylabel,title,color,zones) + plot_stats = self.drawarea.drawPlot(xval,yval,xlab,ylab,tit,col,None,lapValues, ylimits=y1limits, y1_linewidth=y1_linewidth) + ymin = plot_stats['y1_min'] + ymax = plot_stats['y1_max'] + y1_linewidth = plot_stats['y1_linewidth'] - max_yvalue = max(max_yvalue, ymax) - min_yvalue = min(min_yvalue, ymin) - adjY1Min = gtk.Adjustment(value=ymin, lower=min_yvalue,upper=max_yvalue, step_incr=1, page_incr=10) - adjY1Max = gtk.Adjustment(value=ymax, lower=min_yvalue,upper=max_yvalue, step_incr=1, page_incr=10) - spinbuttonY1Min.set_adjustment(adjY1Min) - spinbuttonY1Max.set_adjustment(adjY1Max) - spinbuttonY1Min.set_value(ymin) - spinbuttonY1Max.set_value(ymax) - spinbuttonY1LineWeight.set_value(y1_linewidth) + max_yvalue = max(max_yvalue, ymax) + min_yvalue = min(min_yvalue, ymin) + adjY1Min = gtk.Adjustment(value=ymin, lower=min_yvalue,upper=max_yvalue, step_incr=1, page_incr=10) + adjY1Max = gtk.Adjustment(value=ymax, lower=min_yvalue,upper=max_yvalue, step_incr=1, page_incr=10) + spinbuttonY1Min.set_adjustment(adjY1Min) + spinbuttonY1Max.set_adjustment(adjY1Max) + spinbuttonY1Min.set_value(ymin) + spinbuttonY1Max.set_value(ymax) + spinbuttonY1LineWeight.set_value(y1_linewidth) - logging.debug("<<") + logging.debug("<<") - def get_value_params(self,value): - if value == 0: - return _("Distance (km)"),_("Height (m)"),_("Stage Profile"),"#000000" - if value == 1: - return _("Distance (km)"),_("Speed (Km/h)"),_("Speed"),"#00ff00" - if value == 2: - return _("Distance (km)"),_("Pace (min/km)"),_("Pace"),"#0000ff" - if value == 3: - return _("Distance (km)"),_("Beats (bpm)"),_("Heart Rate"),"#ff0000" - if value == 4: - return _("Distance (km)"),_("Cadence (rpm)"),_("Cadence"),"#7B3F00" + def get_value_params(self,value): + if value == 0: + return _("Distance (km)"),_("Height (m)"),_("Stage Profile"),"#000000" + if value == 1: + return _("Distance (km)"),_("Speed (Km/h)"),_("Speed"),"#00ff00" + if value == 2: + return _("Distance (km)"),_("Pace (min/km)"),_("Pace"),"#0000ff" + if value == 3: + return _("Distance (km)"),_("Beats (bpm)"),_("Heart Rate"),"#ff0000" + if value == 4: + return _("Distance (km)"),_("Cadence (rpm)"),_("Cadence"),"#7B3F00" + if value == 5: + return _("Distance (km)"),_("Beats (%)"),_("Beats"),"#ff0000" + if value == 6: + return _("Distance (km)"),_("Zone"),_("Zone"),"#ff0000" - def get_values(self,values, value_selected): - logging.debug(">>") - xvalue = [] - yvalue = [] - for value in values: - xvalue.append(value[0]) - if value_selected==0: - yvalue.append(value[1]) - if value_selected==1: - yvalue.append(value[3]) - if value_selected==2: - try: - yvalue.append(60/value[3]) - except: - yvalue.append(0) - if value_selected==3: - yvalue.append(value[6]) - if value_selected==4: - yvalue.append(value[7]) - logging.debug("<<") - return xvalue,yvalue + def get_values(self,values, value_selected): + logging.debug(">>") + xvalue = [] + yvalue = [] + zones = self.pytrainer_main.profile.getZones() + for value in values: + xvalue.append(value[0]) + if value_selected==0: + yvalue.append(value[1]) + if value_selected==1: + yvalue.append(value[3]) + if value_selected==2: + try: + yvalue.append(60/value[3]) + except: + yvalue.append(0) + if value_selected==3: + yvalue.append(value[6]) + if value_selected==4: + yvalue.append(value[7]) + if value_selected==5: + if value[6] <= zones[4][0]: + yvalue.append(50.0*value[6]/zones[4][0]) + else: + yvalue.append(50.0+50.0*((value[6]-zones[4][0])/(zones[0][1]-zones[4][0]))) + if value_selected==6: + if value[6] <= zones[4][0]: + yvalue.append(1.0*value[6]/zones[4][0]) + else: + yvalue.append(1.0+5.0*((value[6]-zones[4][0])/(zones[0][1]-zones[4][0]))) + logging.debug("<<") + return xvalue,yvalue - def getFloatValue(self, value): - try: - return float(value) - except: - return float(0) + def getFloatValue(self, value): + try: + return float(value) + except: + return float(0) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-01 23:06:40
|
Revision: 673 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=673&view=rev Author: jblance Date: 2010-11-01 23:06:33 +0000 (Mon, 01 Nov 2010) Log Message: ----------- Fix unified imported to accept Nokia exported GPX files - with sport support Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowrecord.py pytrainer/trunk/pytrainer/lib/activity.py Added Paths: ----------- pytrainer/trunk/import/file_gpxplusNokia.py pytrainer/trunk/schemas/Topografix_gpx11-Nokia.xsd Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-01 03:53:00 UTC (rev 672) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-01 23:06:33 UTC (rev 673) @@ -36,11 +36,12 @@ </child> <child> <widget class="GtkImageMenuItem" id="menu_importdata"> - <property name="label">_Import</property> + <property name="label" translatable="yes">_Import</property> <property name="visible">True</property> <property name="use_underline">True</property> <property name="use_stock">False</property> <signal name="activate" handler="on_menu_importdata_activate"/> + <accelerator key="i" signal="activate" modifiers="GDK_CONTROL_MASK"/> <child internal-child="image"> <widget class="GtkImage" id="image1"> <property name="visible">True</property> Added: pytrainer/trunk/import/file_gpxplusNokia.py =================================================================== --- pytrainer/trunk/import/file_gpxplusNokia.py (rev 0) +++ pytrainer/trunk/import/file_gpxplusNokia.py 2010-11-01 23:06:33 UTC (rev 673) @@ -0,0 +1,130 @@ +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Fiz Vazquez vu...@si... +# Modified by dgranda + +#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 logging +import os +#import StringIO +from lxml import etree +from pytrainer.lib.date import Date + +class gpxplusNokia(): + def __init__(self, parent = None, data_path = None): + self.parent = parent + self.pytrainer_main = parent.parent + self.tmpdir = self.pytrainer_main.profile.tmpdir + self.main_data_path = data_path + self.data_path = os.path.dirname(__file__) + self.xmldoc = None + self.activitiesSummary = [] + + def getXmldoc(self): + ''' Function to return parsed xmlfile ''' + return self.xmldoc + + def getFileType(self): + return _("Nokia Export - GPS eXchange file") + + def getActivitiesSummary(self): + return self.activitiesSummary + + def testFile(self, filename): + logging.debug('>>') + logging.debug("Testing " + filename) + #Check if file is a GPX + try: + #parse as xml + xmldoc = etree.parse(filename) + #Parse XML schema + xmlschema_doc = etree.parse(self.main_data_path+"schemas/Topografix_gpx11-Nokia.xsd") + xmlschema = etree.XMLSchema(xmlschema_doc) + if (xmlschema.validate(xmldoc)): + #Valid gpx file + self.xmldoc = xmldoc + startTime = self.getDateTime(self.startTimeFromFile(xmldoc)) + indatabase = self.inDatabase(xmldoc, startTime) + sport = self.getSport(xmldoc) + duration = self.getDetails(xmldoc, startTime) + distance = "" + self.activitiesSummary.append( (0, + indatabase, + startTime[1].strftime("%Y-%m-%dT%H:%M:%S"), + distance , + str(duration), + sport, + ) ) + return True + except: + #Not gpx file + return False + return False + + def getDateTime(self, time_): + return Date().getDateTime(time_) + + def inDatabase(self, tree, startTime): + #comparing date and start time (sport may have been changed in DB after import) + time = startTime + if time is None: + return False + time = time[0].strftime("%Y-%m-%dT%H:%M:%SZ") + if self.parent.parent.ddbb.select("records","*","date_time_utc=\"%s\"" % (time)): + return True + else: + return False + + def getDetails(self, tree, startTime): + root = tree.getroot() + #Get all times from file + times = root.findall(".//{http://www.topografix.com/GPX/1/1}time") + time = times[-1].text + return self.getDateTime(time)[0]-startTime[0] + + def getSport(self, tree): + #No sport in GPX file + root = tree.getroot() + element = root.find(".//{http://www.topografix.com/GPX/1/1}metadata/{http://www.topografix.com/GPX/1/1}desc") + if element is not None: + return element.text + return None + + def startTimeFromFile(self, tree): + """ Function to return the first time element from a GPX 1.1 file """ + root = tree.getroot() + timeElement = root.find(".//{http://www.topografix.com/GPX/1/1}time") + if timeElement is not None: + return timeElement.text + return None + + def getGPXFile(self, ID, file_id): + """ + Generate GPX file based on activity ID + + Returns (sport, GPX filename) + """ + sport = None + gpxFile = None + if ID == "0": #Only one activity in file + gpxFile = "%s/gpx-%s-%s.gpx" % (self.tmpdir, file_id, ID) + sport = self.getSport(self.xmldoc) + self.createGPXfile(gpxFile, self.xmldoc) + return sport, gpxFile + + def createGPXfile(self, gpxfile, tree): + tree.write(gpxfile, xml_declaration=True, encoding='UTF-8') + Modified: pytrainer/trunk/pytrainer/gui/windowrecord.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-11-01 03:53:00 UTC (rev 672) +++ pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-11-01 23:06:33 UTC (rev 673) @@ -387,6 +387,7 @@ self.activity_data[row]["rcd_starttime"] = start_time self.activity_data[row]["date_time_local"] = gpx_summary['date_time_local'] self.activity_data[row]["date_time_utc"] = gpx_summary['date_time_utc'] + self.activity_data[row]["rcd_distance"] = gpx_summary["rcd_distance"] self.activity_data[row]["rcd_average"] = gpx_summary["rcd_average"] self.activity_data[row]["rcd_calories"] = gpx_summary["rcd_calories"] self.activity_data[row]["rcd_beats"] = gpx_summary["rcd_beats"] @@ -447,7 +448,7 @@ gtk.main_iteration() # before completion of this entire action #Get some info from gpx file self.update_activity_data(row, gpx_file, sport) - + self.setValue("rcd_distance",self.activity_data[row]["rcd_distance"], "%s") self.setValue("rcd_date", self.activity_data[row]["rcd_date"], "%s") self.setValue("rcd_starttime", self.activity_data[row]["rcd_starttime"], "%s") self.setValue("rcd_average",self.activity_data[row]["rcd_average"]) Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-11-01 03:53:00 UTC (rev 672) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-11-01 23:06:33 UTC (rev 673) @@ -101,6 +101,7 @@ self.time_data = {} self.pace_limit = None self.starttime = None + self.gpx_distance = None #self.upositive = 0 #self.unegative = 0 if self.pytrainer_main.profile.getValue("pytraining","prf_us_system") == "True": @@ -210,6 +211,8 @@ self.tree = self.gpx.tree self.tracks = self.gpx.getTrackList() #TODO fix - this should removed and replaced with self.tracklist functionality self.tracklist = self.gpx.trkpoints + self.gpx_distance = self.gpx.total_dist + print "GPX Distance: %s" % self.gpx_distance logging.debug("<<") def _init_from_db(self): @@ -261,6 +264,8 @@ # self.pace = pacekm2miles(self._float(_dict['pace'])) #else: self.distance = self._float(_dict['distance']) + if not self.distance: + self.distance = self.gpx_distance self.average = self._float(_dict['average']) self.upositive = self._float(_dict['upositive']) self.unegative = self._float(_dict['unegative']) Added: pytrainer/trunk/schemas/Topografix_gpx11-Nokia.xsd =================================================================== --- pytrainer/trunk/schemas/Topografix_gpx11-Nokia.xsd (rev 0) +++ pytrainer/trunk/schemas/Topografix_gpx11-Nokia.xsd 2010-11-01 23:06:33 UTC (rev 673) @@ -0,0 +1,800 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.topografix.com/GPX/1/1" targetNamespace="http://www.topografix.com/GPX/1/1" elementFormDefault="qualified"> + +<xsd:annotation> + <xsd:documentation> + GPX schema version 1.1 - For more information on GPX and this schema, visit http://www.topografix.com/gpx.asp + + GPX uses the following conventions: all coordinates are relative to the WGS84 datum. All measurements are in metric units. + </xsd:documentation> +</xsd:annotation> + + <xsd:element name="gpx" type="gpxType"> + <xsd:annotation> + <xsd:documentation> + GPX is the root element in the XML file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:complexType name="gpxType"> + <xsd:annotation> + <xsd:documentation> + GPX documents contain a metadata header, followed by waypoints, routes, and tracks. You can add your own elements + to the extensions section of the GPX document. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="metadata" type="metadataType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Metadata about the file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="wpt" type="wptType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A list of waypoints. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="rte" type="rteType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A list of routes. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="trk" type="trkType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A list of tracks. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + + <xsd:attribute name="version" type="xsd:string" use="required" fixed="1.1"> + <xsd:annotation> + <xsd:documentation> + You must include the version number in your GPX document. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="creator" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation> + You must include the name or URL of the software that created your GPX document. This allows others to + inform the creator of a GPX instance document that fails to validate. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="metadataType"> + <xsd:annotation> + <xsd:documentation> + Information about the GPX file, author, and copyright restrictions goes in the metadata section. Providing rich, + meaningful information about your GPX files allows others to search for and use your GPS data. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="name" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The name of the GPX file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="desc" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + A description of the contents of the GPX file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="author" type="personType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The person or organization who created the GPX file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="copyright" type="copyrightType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Copyright and license information governing use of the file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="link" type="linkType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + URLs associated with the location described in the file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="time" type="xsd:dateTime" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The creation date of the file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="keywords" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Keywords associated with the file. Search engines or databases can use this information to classify the data. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="bounds" type="boundsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Minimum and maximum coordinates which describe the extent of the coordinates in the file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="wptType"> + <xsd:annotation> + <xsd:documentation> + wpt represents a waypoint, point of interest, or named feature on a map. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <!-- Position info --> + <xsd:element name="ele" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Elevation (in meters) of the point. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <!-- Nokia export modifications --> + <xsd:element name="speed" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The speed as calculated by the device + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="course" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The direction? as calculated by the device + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="desc" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + A text description of the element. Holds additional information about the element intended for the user, not the GPS. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="time" type="xsd:dateTime" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Creation/modification timestamp for element. Date and time in are in Univeral Coordinated Time (UTC), not local time! Conforms to ISO 8601 specification for date/time representation. Fractional seconds are allowed for millisecond timing in tracklogs. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="magvar" type="degreesType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Magnetic variation (in degrees) at the point + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="geoidheight" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Height (in meters) of geoid (mean sea level) above WGS84 earth ellipsoid. As defined in NMEA GGA message. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <!-- Description info --> + <xsd:element name="name" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The GPS name of the waypoint. This field will be transferred to and from the GPS. GPX does not place restrictions on the length of this field or the characters contained in it. It is up to the receiving application to validate the field before sending it to the GPS. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="cmt" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS waypoint comment. Sent to GPS as comment. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="src" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Source of data. Included to give user some idea of reliability and accuracy of data. "Garmin eTrex", "USGS quad Boston North", e.g. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="link" type="linkType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + Link to additional information about the waypoint. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="sym" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Text of GPS symbol name. For interchange with other programs, use the exact spelling of the symbol as displayed on the GPS. If the GPS abbreviates words, spell them out. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="type" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Type (classification) of the waypoint. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <!-- Accuracy info --> + <xsd:element name="fix" type="fixType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Type of GPX fix. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="sat" type="xsd:nonNegativeInteger" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Number of satellites used to calculate the GPX fix. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="hdop" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Horizontal dilution of precision. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="vdop" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Vertical dilution of precision. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="pdop" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Position dilution of precision. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="ageofdgpsdata" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Number of seconds since last DGPS update. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="dgpsid" type="dgpsStationType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + ID of DGPS station used in differential correction. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + + <xsd:attribute name="lat" type="latitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The latitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="lon" type="longitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The latitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="rteType"> + <xsd:annotation> + <xsd:documentation> + rte represents route - an ordered list of waypoints representing a series of turn points leading to a destination. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="name" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS name of route. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="cmt" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS comment for route. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="desc" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Text description of route for user. Not sent to GPS. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="src" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Source of data. Included to give user some idea of reliability and accuracy of data. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="link" type="linkType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + Links to external information about the route. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="number" type="xsd:nonNegativeInteger" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS route number. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="type" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Type (classification) of route. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="rtept" type="wptType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A list of route points. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="trkType"> + <xsd:annotation> + <xsd:documentation> + trk represents a track - an ordered list of points describing a path. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="name" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS name of track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="cmt" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS comment for track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="desc" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + User description of track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="src" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Source of data. Included to give user some idea of reliability and accuracy of data. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="link" type="linkType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + Links to external information about track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="number" type="xsd:nonNegativeInteger" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS track number. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="type" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Type (classification) of track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="trkseg" type="trksegType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A Track Segment holds a list of Track Points which are logically connected in order. To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off, start a new Track Segment for each continuous span of track data. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="extensionsType"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> + <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:any> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="trksegType"> + <xsd:annotation> + <xsd:documentation> + A Track Segment holds a list of Track Points which are logically connected in order. To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off, start a new Track Segment for each continuous span of track data. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="trkpt" type="wptType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A Track Point holds the coordinates, elevation, timestamp, and metadata for a single point in a track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="copyrightType"> + <xsd:annotation> + <xsd:documentation> + Information about the copyright holder and any license governing use of this file. By linking to an appropriate license, + you may place your data into the public domain or grant additional usage rights. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="year" type="xsd:gYear" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Year of copyright. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="license" type="xsd:anyURI" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Link to external file containing license text. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="author" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation> + Copyright holder (TopoSoft, Inc.) + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="linkType"> + <xsd:annotation> + <xsd:documentation> + A link to an external resource (Web page, digital photo, video clip, etc) with additional information. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="text" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Text of hyperlink. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="type" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Mime type of content (image/jpeg) + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="href" type="xsd:anyURI" use="required"> + <xsd:annotation> + <xsd:documentation> + URL of hyperlink. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="emailType"> + <xsd:annotation> + <xsd:documentation> + An email address. Broken into two parts (id and domain) to help prevent email harvesting. + </xsd:documentation> + </xsd:annotation> + <xsd:attribute name="id" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation> + id half of email address (billgates2004) + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="domain" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation> + domain half of email address (hotmail.com) + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="personType"> + <xsd:annotation> + <xsd:documentation> + A person or organization. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="name" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Name of person or organization. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="email" type="emailType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Email address. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="link" type="linkType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Link to Web site or other external information about person. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="ptType"> + <xsd:annotation> + <xsd:documentation> + A geographic point with optional elevation and time. Available for use by other schemas. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="ele" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The elevation (in meters) of the point. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="time" type="xsd:dateTime" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The time that the point was recorded. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="lat" type="latitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The latitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="lon" type="longitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The latitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="ptsegType"> + <xsd:annotation> + <xsd:documentation> + An ordered sequence of points. (for polygons or polylines, e.g.) + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="pt" type="ptType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + Ordered list of geographic points. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="boundsType"> + <xsd:annotation> + <xsd:documentation> + Two lat/lon pairs defining the extent of an element. + </xsd:documentation> + </xsd:annotation> + <xsd:attribute name="minlat" type="latitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The minimum latitude. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="minlon" type="longitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The minimum longitude. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="maxlat" type="latitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The maximum latitude. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="maxlon" type="longitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The maximum longitude. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + + <xsd:simpleType name="latitudeType"> + <xsd:annotation> + <xsd:documentation> + The latitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + <xsd:restriction base="xsd:decimal"> + <xsd:minInclusive value="-90.0"/> + <xsd:maxInclusive value="90.0"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="longitudeType"> + <xsd:annotation> + <xsd:documentation> + The longitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + <xsd:restriction base="xsd:decimal"> + <xsd:minInclusive value="-180.0"/> + <xsd:maxExclusive value="180.0"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="degreesType"> + <xsd:annotation> + <xsd:documentation> + Used for bearing, heading, course. Units are decimal degrees, true (not magnetic). + </xsd:documentation> + </xsd:annotation> + <xsd:restriction base="xsd:decimal"> + <xsd:minInclusive value="0.0"/> + <xsd:maxExclusive value="360.0"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="fixType"> + <xsd:annotation> + <xsd:documentation> + Type of GPS fix. none means GPS had no fix. To signify "the fix info is unknown, leave out fixType entirely. pps = military signal used + </xsd:documentation> + </xsd:annotation> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="2d"/> + <xsd:enumeration value="3d"/> + <xsd:enumeration value="dgps"/> + <xsd:enumeration value="pps"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="dgpsStationType"> + <xsd:annotation> + <xsd:documentation> + Represents a differential GPS station. + </xsd:documentation> + </xsd:annotation> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="1023"/> + </xsd:restriction> + </xsd:simpleType> + +</xsd:schema> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-01 03:53:07
|
Revision: 672 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=672&view=rev Author: jblance Date: 2010-11-01 03:53:00 +0000 (Mon, 01 Nov 2010) Log Message: ----------- Fix for US unit display in record list view Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-31 22:34:54 UTC (rev 671) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-01 03:53:00 UTC (rev 672) @@ -93,7 +93,11 @@ pass self.record_list = [] #create the columns for the listdayrecord - columns = [{'name':_("id"), 'visible':False},{'name':_("Start"), }, {'name':_("Sport")},{'name':_("Kilometer")}] + if self.pytrainer_main.profile.prf_us_system: + distance_unit = _("Miles") + else: + distance_unit = _("Km") + columns = [{'name':_("id"), 'visible':False},{'name':_("Start"), }, {'name':_("Sport")},{'name':distance_unit}] self.create_treeview(self.recordTreeView,columns) #create the columns for the listarea # different codings for mean see eg http://de.wikipedia.org/wiki/%C3%98#Kodierung @@ -301,13 +305,13 @@ recordTime = dateTime.strftime("%X") recordDateTimeOffset = dateTime.strftime("%z") - self.record_distance.set_text("%0.2f" %activity.distance) - self.record_upositive.set_text("%0.2f" %activity.upositive) - self.record_unegative.set_text("%0.2f" %activity.unegative) - self.record_average.set_text("%0.2f" %activity.average) - self.record_maxspeed.set_text("%0.2f" %activity.maxspeed) - self.record_pace.set_text(Record().pace_from_float(activity.pace)) - self.record_maxpace.set_text(Record().pace_from_float(activity.maxpace)) + self.record_distance.set_text("%0.2f" %activity.get_value('distance')) + self.record_upositive.set_text("%0.2f" %activity.get_value('upositive')) + self.record_unegative.set_text("%0.2f" %activity.get_value('unegative')) + self.record_average.set_text("%0.2f" %activity.get_value('average')) + self.record_maxspeed.set_text("%0.2f" %activity.get_value('maxspeed')) + self.record_pace.set_text(activity.get_value('pace')) + self.record_maxpace.set_text(activity.get_value('maxpace')) self.record_sport.set_text(activity.sport_name) #self.record_date.set_text(str(date)) @@ -1559,6 +1563,7 @@ object) for i in record_list: #Get lap info + #Could get an activity from the pool here, but is slow?? id_record = i[8] laps = self.parent.record.getLaps(id_record) iter = store.append(None) @@ -1569,18 +1574,27 @@ localTime = dateutil.parser.parse(dateTime).strftime("%H:%M") else: localTime = "" + if self.pytrainer_main.profile.prf_us_system: + dist = km2miles(i[2]) + else: + dist = i[2] + distance = "%0.2f" % (float(dist) ) store.set ( iter, 0, int(i[8]), 1, str(localTime), 2, str(i[0]), - 3, str(i[2]) + 3, str(distance) #Needs to be US pref aware.... ) if laps is not None: for lap in laps: #"id_lap, record, elapsed_time, distance, start_lat, start_lon, end_lat, end_lon, calories, lap_number", lapNumber = "%s%d" % ( _("lap"), int(lap[9])+1 ) - distance = "%0.2f" % (float(lap[3]) / 1000.0) + if self.pytrainer_main.profile.prf_us_system: + dist = km2miles(lap[3]) + else: + dist = lap[3] + distance = "%0.2f" % (float(dist) / 1000.0) timeHours = int(float(lap[2]) / 3600) timeMin = int((float(lap[2]) / 3600.0 - timeHours) * 60) timeSec = float(lap[2]) - (timeHours * 3600) - (timeMin * 60) @@ -1600,8 +1614,7 @@ self.recordTreeView.set_model(store) if iterOne: self.recordTreeView.get_selection().select_iter(iterOne) - logging.debug("<<") - #if len(record_list)>0: + logging.debug("<<") def parseFloat(self,string): try: @@ -1612,8 +1625,10 @@ def actualize_calendar(self,record_list): logging.debug(">>") self.calendar.clear_marks() + #Mark each day that has activity for i in record_list: self.calendar.mark_day(int(i)) + #Turn on displaying of week numbers display_options = self.calendar.get_display_options() self.calendar.set_display_options(display_options|gtk.CALENDAR_SHOW_WEEK_NUMBERS) logging.debug("<<") Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-10-31 22:34:54 UTC (rev 671) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-11-01 03:53:00 UTC (rev 672) @@ -30,6 +30,8 @@ class Activity: ''' Class that knows everything about a particular activity + + All values are stored in the class (and DB) in metric and are converted as needed tracks - (list) tracklist from gpx tracklist - (list of dict) trackpoint data from gpx @@ -249,22 +251,22 @@ self.date_time = tmpDateTime.astimezone(tzlocal()) #datetime with localtime offset (using value from OS) self.starttime = self.date_time.strftime("%X") #Sort data that changes for the US etc - if self.us_system: - self.distance = km2miles(self._float(_dict['distance'])) - self.average = km2miles(self._float(_dict['average'])) - self.upositive = m2feet(self._float(_dict['upositive'])) - self.unegative = m2feet(self._float(_dict['unegative'])) - self.maxspeed = km2miles(self._float(_dict['maxspeed'])) - self.maxpace = pacekm2miles(self._float(_dict['maxpace'])) - self.pace = pacekm2miles(self._float(_dict['pace'])) - else: - self.distance = self._float(_dict['distance']) - self.average = self._float(_dict['average']) - self.upositive = self._float(_dict['upositive']) - self.unegative = self._float(_dict['unegative']) - self.maxspeed = self._float(_dict['maxspeed']) - self.maxpace = self._float(_dict['maxpace']) - self.pace = self._float(_dict['pace']) + #if self.us_system: + # self.distance = km2miles(self._float(_dict['distance'])) + # self.average = km2miles(self._float(_dict['average'])) + # self.upositive = m2feet(self._float(_dict['upositive'])) + # self.unegative = m2feet(self._float(_dict['unegative'])) + # self.maxspeed = km2miles(self._float(_dict['maxspeed'])) + # self.maxpace = pacekm2miles(self._float(_dict['maxpace'])) + # self.pace = pacekm2miles(self._float(_dict['pace'])) + #else: + self.distance = self._float(_dict['distance']) + self.average = self._float(_dict['average']) + self.upositive = self._float(_dict['upositive']) + self.unegative = self._float(_dict['unegative']) + self.maxspeed = self._float(_dict['maxspeed']) + self.maxpace = self._float(_dict['maxpace']) + self.pace = self._float(_dict['pace']) self.has_data = True else: raise Exception( "Error - multiple results from DB for id: %s" % self.id ) @@ -467,3 +469,109 @@ except: result = 0 return result + + def get_value(self, param): + ''' Function to get the value of various params in this activity instance + Automatically returns values converted to imperial if needed + ''' + if param == 'distance': + if self.us_system: + return km2miles(self.distance) + else: + return self.distance + elif param == 'average': + if self.us_system: + return km2miles(self.average) + else: + return self.average + elif param == 'upositive': + if self.us_system: + return m2feet(self.upositive) + else: + return self.upositive + elif param == 'unegative': + if self.us_system: + return m2feet(self.unegative) + else: + return self.unegative + elif param == 'maxspeed': + if self.us_system: + return km2miles(self.maxspeed) + else: + return self.maxspeed + elif param == 'maxpace': + if self.us_system: + return self.pace_from_float(pacekm2miles(self.maxpace)) + else: + return self.pace_from_float(self.maxpace) + elif param == 'pace': + if self.us_system: + return self.pace_from_float(pacekm2miles(self.pace)) + else: + return self.pace_from_float(self.pace) + else: + print "Unable to provide value for unknown parameter (%s) for activity" % param + + def set_value(self, param, value): + ''' Function to set the value of various params in this activity instance + Automatically converts from imperial if using them + ''' + _value = _float(value) + if param == 'distance': + if self.us_system: + self.distance = miles2mk(_value) + else: + self.distance = _value + elif param == 'average': + if self.us_system: + self.average = miles2mk(_value) + else: + self.average = _value + elif param == 'upositive': + if self.us_system: + self.upositive = feet2m(_value) + else: + self.upositive = _value + elif param == 'unegative': + if self.us_system: + self.unegative = feet2m(_value) + else: + self.unegative = _value + elif param == 'maxspeed': + if self.us_system: + self.maxspeed = miles2mk(_value) + else: + self.maxspeed = _value + elif param == 'maxpace': + if self.us_system: + _maxpace = pacemiles2mk(_value) + else: + _maxpace = _value + self.maxpace = self.pace_to_float(_maxpace) + elif param == 'pace': + if self.us_system: + _pace = pacemiles2mk(_value) + else: + _pace = _value + self.pace = self.pace_to_float(_pace) + else: + print "Unable to set value (%s) for unknown parameter (%s) for activity" % (str(value), param) + + + def pace_to_float(self, value): + '''Take a mm:ss or mm.ss and return float''' + value = value.replace(':', '.') + try: + value = float(value) + except ValueError: + value = None + return value + + def pace_from_float(self, value): + '''Helper to generate mm:ss from float representation mm.ss (or mm,ss?)''' + #Check that value supplied is a float + try: + _value = "%0.2f" % float(value) + except ValueError: + _value = str(value) + return _value.replace('.',':') Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-31 22:34:54 UTC (rev 671) +++ pytrainer/trunk/pytrainer/main.py 2010-11-01 03:53:00 UTC (rev 672) @@ -50,13 +50,14 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#670" + self.version ="1.7.2_svn#672" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() #Setup logging self.set_logging(self.startup_options.log_level) logging.debug('>>') + logging.debug("PyTrainer version %s, DB version %s" % (self.version, self.DB_version)) self.data_path = data_path self.date = Date() self.ddbb = None @@ -309,8 +310,9 @@ self.refreshListView(self.windowmain.listsearch.condition) #Refresh list records date = self.date.getDate() - record_list = self.record.getrecordList(date) - self.windowmain.actualize_recordTreeView(record_list) + record_ids = self.record.getrecordList(date) + self.windowmain.actualize_recordTreeView(record_ids) + #Mark the monthly calendar to show which days have activity? record_list = self.record.getRecordDayList(date) self.windowmain.actualize_calendar(record_list) logging.debug('<<') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-10-31 22:35:00
|
Revision: 671 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=671&view=rev Author: jblance Date: 2010-10-31 22:34:54 +0000 (Sun, 31 Oct 2010) Log Message: ----------- Remove debug print statement Modified Paths: -------------- pytrainer/trunk/extensions/fixelevation/fixelevation.py Modified: pytrainer/trunk/extensions/fixelevation/fixelevation.py =================================================================== --- pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-10-31 22:19:28 UTC (rev 670) +++ pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-10-31 22:34:54 UTC (rev 671) @@ -16,7 +16,7 @@ self.conf_dir = conf_dir def run(self, aid, activity=None): #TODO Convert to use activity... - print activity + #print activity logging.debug(">>") gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, aid) ele_fixed = True This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-10-31 22:19:35
|
Revision: 670 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=670&view=rev Author: jblance Date: 2010-10-31 22:19:28 +0000 (Sun, 31 Oct 2010) Log Message: ----------- Update date.py to deal with naive dates correctly Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/date.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/lib/date.py =================================================================== --- pytrainer/trunk/pytrainer/lib/date.py 2010-10-29 04:45:15 UTC (rev 669) +++ pytrainer/trunk/pytrainer/lib/date.py 2010-10-31 22:19:28 UTC (rev 670) @@ -178,13 +178,25 @@ # Time can be in multiple formats # - zulu 2009-12-15T09:00Z # - local ISO8601 2009-12-15T10:00+01:00 - dateTime = dateutil.parser.parse(time_) - timezone = dateTime.tzname() - if timezone == 'UTC': #got a zulu time + try: + dateTime = dateutil.parser.parse(time_) + except ValueError as e: + print "Unable to parse '%s' as a date time" % time_ + print e + logging.debug("Unable to parse %s as a date time" % time_) + logging.debug(str(e)) + return (None, None) + timezone = dateTime.tzinfo + if timezone is None: #got a naive time, so assume is local time + #print 'Naive time' + local_dateTime = dateTime.replace(tzinfo=tzlocal()) + elif timezone == tzutc(): #got a zulu time + #print 'zulu time' local_dateTime = dateTime.astimezone(tzlocal()) #datetime with localtime offset (from OS) else: + #print 'local time' local_dateTime = dateTime #use datetime as supplied - utc_dateTime = dateTime.astimezone(tzutc()) #datetime with 00:00 offset + utc_dateTime = local_dateTime.astimezone(tzutc()) #datetime with 00:00 offset #print utc_dateTime, local_dateTime return (utc_dateTime,local_dateTime) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-29 04:45:15 UTC (rev 669) +++ pytrainer/trunk/pytrainer/main.py 2010-10-31 22:19:28 UTC (rev 670) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#668" + self.version ="1.7.2_svn#670" 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-10-29 04:45:22
|
Revision: 669 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=669&view=rev Author: jblance Date: 2010-10-29 04:45:15 +0000 (Fri, 29 Oct 2010) Log Message: ----------- Minor fixes for us units Modified Paths: -------------- pytrainer/trunk/extensions/fixelevation/fixelevation.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/lib/gpx.py pytrainer/trunk/pytrainer/lib/unitsconversor.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/extensions/fixelevation/fixelevation.py =================================================================== --- pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-10-29 04:45:15 UTC (rev 669) @@ -15,9 +15,10 @@ self.options = options self.conf_dir = conf_dir - def run(self, id, activity=None): #TODO Convert to use activity... + def run(self, aid, activity=None): #TODO Convert to use activity... + print activity logging.debug(">>") - gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, id) + gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, aid) ele_fixed = True if os.path.isfile(gpx_file): @@ -36,6 +37,9 @@ """ self._data = etree.parse(gpx_file) self._xmlns = self._data.getroot().nsmap[None] + nsmap = self._data.getroot().nsmap + pyt_ns = "http://sourceforge.net.project/pytrainer/GPX/0/1" + PYTRAINER = "{%s}" % pyt_ns self._trkpt_path = '{%s}trk/{%s}trkseg/{%s}trkpt' % (self._xmlns, self._xmlns, self._xmlns) """ @@ -48,16 +52,31 @@ ele = trkpt.find('{%s}ele' % self._xmlns) ele_new = self._srtm.get_elevation(lat, lon) + #Add new elevation to extension tag + ''' + <extensions> + <pytrainer:ele method="srtm_bilinear">31.1</pytrainer:ele> + </extensions> + ''' + ext = etree.Element("extensions") + py_ele = etree.SubElement(ext, PYTRAINER + "ele", method="srtm_bilinear") + py_ele.text = str(ele_new) + + #print etree.tostring(ext) + + if not ele_new: ele_fixed = False break - if ele is not None: - ele.text = str(ele_new) - else: - ele = etree.Element('ele') - ele.text = str(ele_new) - trkpt.append(ele) + #if ele is not None: + # #ele.text = str(ele_new) + # ele.append(ext) + #else: + # ele = etree.Element('ele') + # ele.append(py_ele) + trkpt.append(ext) + if ele_fixed: # Write out to original *.gpx. self._data.write( gpx_file, @@ -65,6 +84,8 @@ xml_declaration=True, pretty_print=False) res_msg = "Elevation has been fixed." + #TODO Expire activity out of pool - so get updated info + self.pytrainer_main.activitypool.remove_activity(aid) else: res_msg = "Elevation could not be fixed!" Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-29 04:45:15 UTC (rev 669) @@ -566,7 +566,7 @@ # self.recordview.set_sensitive(0) logging.debug("<<") - def actualize_dayview(self,record_list): + def actualize_dayview(self,record_list=None, activity_list=None): logging.debug(">>") if self.pytrainer_main.profile.getValue("pytraining","prf_us_system") == "True": self.d_distance_unit.set_text(_("miles")) Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-10-29 04:45:15 UTC (rev 669) @@ -125,6 +125,65 @@ self.y2_limits_u = (None, None) self.show_laps = False logging.debug("<<") + + def __str__(self): + return ''' + tracks (%s) + tracklist (%s) + laps (%s) + tree (%s) + us_system (%s) + distance_unit (%s) + speed_unit (%s) + distance_data (%s) + time_data (%s) + height_unit (%s) + pace_unit (%s) + gpx_file (%s) + gpx (%s) + sport_name (%s) + sport_id (%s) + title (%s) + date (%s) + time (%s) + time_tuple (%s) + beats (%s) + maxbeats (%s) + comments (%s) + calories (%s) + id_record (%s) + date_time_local (%s) + date_time_utc (%s) + date_time (%s) + starttime (%s) + distance (%s) + average (%s) + upositive (%s) + unegative (%s) + maxspeed (%s) + maxpace (%s) + pace (%s) + has_data (%s) + x_axis (%s) + x_limits (%s) + y1_limits (%s) + y2_limits (%s) + x_limits_u (%s) + y1_limits_u (%s) + y2_limits_u (%s) + show_laps (%s) + lap_distance (%s) + lap_time (%s) + pace_limit (%s) + ''' % ('self.tracks', self.tracklist, self.laps, self.tree, self.us_system, + self.distance_unit, self.speed_unit, self.distance_data, self.time_data, + self.height_unit, self.pace_unit, self.gpx_file, self.gpx, self.sport_name, + self.sport_id, self.title, self.date, self.time, self.time_tuple, self.beats, + self.maxbeats, self.comments, self.calories, self.id_record, self.date_time_local, + self.date_time_utc, self.date_time, self.starttime, self.distance, self.average, + self.upositive, self.unegative, self.maxspeed, self.maxpace, self.pace, self.has_data, + self.x_axis, self.x_limits, self.y1_limits, self.y2_limits, self.x_limits_u, self.y1_limits_u, + self.y2_limits_u, self.show_laps, self.lap_distance, self.lap_time, self.pace_limit) def _set_units(self): if self.us_system: @@ -163,25 +222,25 @@ "maxspeed","maxpace","pace","maxbeats","date_time_utc","date_time_local", "sports.max_pace"), "id_record=\"%s\" and records.sport=sports.id_sports" %self.id) if len(db_result) == 1: - dict = db_result[0] - self.sport_name = dict['sports.name'] - self.sport_id = dict['id_sports'] - self.pace_limit = dict['sports.max_pace'] + _dict = db_result[0] + self.sport_name = _dict['sports.name'] + self.sport_id = _dict['id_sports'] + self.pace_limit = _dict['sports.max_pace'] if self.pace_limit == 0 or self.pace_limit == "": self.pace_limit = None - self.title = dict['title'] - self.date = dict['date'] - self.time = self._int(dict['time']) + self.title = _dict['title'] + self.date = _dict['date'] + self.time = self._int(_dict['time']) self.time_tuple = Date().second2time(self.time) - self.beats = self._int(dict['beats']) - self.comments = dict['comments'] - self.calories = self._int(dict['calories']) - self.id_record = dict['id_record'] - self.maxbeats = self._int(dict['maxbeats']) + self.beats = self._int(_dict['beats']) + self.comments = _dict['comments'] + self.calories = self._int(_dict['calories']) + self.id_record = _dict['id_record'] + self.maxbeats = self._int(_dict['maxbeats']) #Sort time.... # ... use local time if available otherwise use date_time_utc and create a local datetime... - self.date_time_local = dict['date_time_local'] - self.date_time_utc = dict['date_time_utc'] + self.date_time_local = _dict['date_time_local'] + self.date_time_utc = _dict['date_time_utc'] if self.date_time_local is not None: #Have a local time stored in DB self.date_time = dateutil.parser.parse(self.date_time_local) self.starttime = self.date_time.strftime("%X") @@ -191,21 +250,21 @@ self.starttime = self.date_time.strftime("%X") #Sort data that changes for the US etc if self.us_system: - self.distance = km2miles(self._float(dict['distance'])) - self.average = km2miles(self._float(dict['average'])) - self.upositive = m2feet(self._float(dict['upositive'])) - self.unegative = m2feet(self._float(dict['unegative'])) - self.maxspeed = km2miles(self._float(dict['maxspeed'])) - self.maxpace = pacekm2miles(self._float(dict['maxpace'])) - self.pace = pacekm2miles(self._float(dict['pace'])) + self.distance = km2miles(self._float(_dict['distance'])) + self.average = km2miles(self._float(_dict['average'])) + self.upositive = m2feet(self._float(_dict['upositive'])) + self.unegative = m2feet(self._float(_dict['unegative'])) + self.maxspeed = km2miles(self._float(_dict['maxspeed'])) + self.maxpace = pacekm2miles(self._float(_dict['maxpace'])) + self.pace = pacekm2miles(self._float(_dict['pace'])) else: - self.distance = self._float(dict['distance']) - self.average = self._float(dict['average']) - self.upositive = self._float(dict['upositive']) - self.unegative = self._float(dict['unegative']) - self.maxspeed = self._float(dict['maxspeed']) - self.maxpace = self._float(dict['maxpace']) - self.pace = self._float(dict['pace']) + self.distance = self._float(_dict['distance']) + self.average = self._float(_dict['average']) + self.upositive = self._float(_dict['upositive']) + self.unegative = self._float(_dict['unegative']) + self.maxspeed = self._float(_dict['maxspeed']) + self.maxpace = self._float(_dict['maxpace']) + self.pace = self._float(_dict['pace']) self.has_data = True else: raise Exception( "Error - multiple results from DB for id: %s" % self.id ) @@ -306,6 +365,15 @@ self.time_data['elevation'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel) self.time_data['elevation'].set_color('#ff0000', '#ff0000') self.time_data['elevation'].show_on_y1 = True #Make graph show elevation by default + #Corrected Elevation... + title=_("Corrected Elevation") + xlabel="%s (%s)" % (_('Distance'), self.distance_unit) + ylabel="%s (%s)" % (_('Corrected Elevation'), self.height_unit) + self.distance_data['cor_elevation'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel) + self.distance_data['cor_elevation'].set_color('#993333', '#993333') + xlabel=_("Time (seconds)") + self.time_data['cor_elevation'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel) + self.time_data['cor_elevation'].set_color('#993333', '#993333') #Speed title=_("Speed") xlabel="%s (%s)" % (_('Distance'), self.distance_unit) @@ -353,20 +421,24 @@ pace = 0 if self.us_system: self.distance_data['elevation'].addPoints(x=km2miles(track['elapsed_distance']), y=m2feet(track['ele'])) + self.distance_data['cor_elevation'].addPoints(x=km2miles(track['elapsed_distance']), y=m2feet(track['correctedElevation'])) self.distance_data['speed'].addPoints(x=km2miles(track['elapsed_distance']), y=km2miles(track['velocity'])) self.distance_data['pace'].addPoints(x=km2miles(track['elapsed_distance']), y=pacekm2miles(pace)) self.distance_data['hr'].addPoints(x=km2miles(track['elapsed_distance']), y=track['hr']) self.distance_data['cadence'].addPoints(x=km2miles(track['elapsed_distance']), y=track['cadence']) self.time_data['elevation'].addPoints(x=track['time_elapsed'], y=m2feet(track['ele'])) + self.time_data['cor_elevation'].addPoints(x=track['time_elapsed'], y=m2feet(track['correctedElevation'])) self.time_data['speed'].addPoints(x=track['time_elapsed'], y=km2miles(track['velocity'])) self.time_data['pace'].addPoints(x=track['time_elapsed'], y=pacekm2miles(pace)) else: self.distance_data['elevation'].addPoints(x=track['elapsed_distance'], y=track['ele']) + self.distance_data['cor_elevation'].addPoints(x=track['elapsed_distance'], y=track['correctedElevation']) self.distance_data['speed'].addPoints(x=track['elapsed_distance'], y=track['velocity']) self.distance_data['pace'].addPoints(x=track['elapsed_distance'], y=pace) self.distance_data['hr'].addPoints(x=track['elapsed_distance'], y=track['hr']) self.distance_data['cadence'].addPoints(x=track['elapsed_distance'], y=track['cadence']) self.time_data['elevation'].addPoints(x=track['time_elapsed'], y=track['ele']) + self.time_data['cor_elevation'].addPoints(x=track['time_elapsed'], y=track['correctedElevation']) self.time_data['speed'].addPoints(x=track['time_elapsed'], y=track['velocity']) self.time_data['pace'].addPoints(x=track['time_elapsed'], y=pace) self.time_data['hr'].addPoints(x=track['time_elapsed'], y=track['hr']) Modified: pytrainer/trunk/pytrainer/lib/gpx.py =================================================================== --- pytrainer/trunk/pytrainer/lib/gpx.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/pytrainer/lib/gpx.py 2010-10-29 04:45:15 UTC (rev 669) @@ -48,6 +48,9 @@ elapsedTimeTag = gpxdataNS.substitute(tag="elapsedTime") distanceTag = gpxdataNS.substitute(tag="distance") +pytrainerNS = string.Template(".//{http://sourceforge.net.project/pytrainer/GPX/0/1}$tag") +pyt_eleTag = pytrainerNS.substitute(tag="ele") + class Gpx: def __init__(self, data_path = None, filename = None, trkname = None): logging.debug(">>") @@ -277,6 +280,18 @@ ele = None else: ele = None + + #Get corrected elevation if it exists + correctedEleResult = trkpoint.find(pyt_eleTag) + if correctedEleResult is not None: + try: + corEle = float(correctedEleResult.text) + #Calculate elevation change + except Exception as e: + logging.debug(str(e)) + corEle = None + else: + corEle = None #Calculate climb or decent amount #Allow for some 'jitter' in height here @@ -308,18 +323,18 @@ #This 'fills in' the data for situations where some times are missing from the GPX file if time_ is not None: if len(waiting_points) > 0: - for ((w_total_dist, w_dist, w_alt, w_total_time, w_lat, w_lon, w_hr, w_cadence)) in waiting_points: + for ((w_total_dist, w_dist, w_alt, w_total_time, w_lat, w_lon, w_hr, w_cadence, w_corEle)) in waiting_points: w_time = (w_dist/dist_elapsed) * time_elapsed w_vel = w_dist/((w_time)/3600.0) w_total_time += w_time - retorno.append((w_total_dist, w_alt, w_total_time, w_vel, w_lat, w_lon, w_hr, w_cadence)) + retorno.append((w_total_dist, w_alt, w_total_time, w_vel, w_lat, w_lon, w_hr, w_cadence, w_corEle)) waiting_points = [] dist_elapsed = 0 else: - retorno.append((total_dist,ele, self.total_time,vel,lat,lon,hr,cadence)) + retorno.append((total_dist,ele, self.total_time,vel,lat,lon,hr,cadence,corEle)) dist_elapsed = 0 else: # time_ is None - waiting_points.append((total_dist, dist_elapsed, ele, self.total_time, lat, lon, hr, cadence)) + waiting_points.append((total_dist, dist_elapsed, ele, self.total_time, lat, lon, hr, cadence, corEle)) #Add to dict of values to trkpoint list self.trkpoints.append({ 'id': i, @@ -335,6 +350,7 @@ 'distance_from_previous': dist, 'elapsed_distance': total_dist, 'velocity':vel, + 'correctedElevation':corEle, }) Modified: pytrainer/trunk/pytrainer/lib/unitsconversor.py =================================================================== --- pytrainer/trunk/pytrainer/lib/unitsconversor.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/pytrainer/lib/unitsconversor.py 2010-10-29 04:45:15 UTC (rev 669) @@ -17,25 +17,57 @@ #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. def km2miles(kilometers): - return kilometers*0.621371192 + try: + km = float(kilometers) + return km*0.621371192 + except Exception as e: + return 0.0 def miles2mk(miles): - return miles/0.621371192 + try: + m = float(miles) + return m/0.621371192 + except Exception as e: + return 0.0 def pacekm2miles(kilometers): - return kilometers/0.621371192 + try: + km = float(kilometers) + return km/0.621371192 + except Exception as e: + return 0.0 def pacemiles2mk(miles): - return miles*0.621371192 + try: + m = float(miles) + return m*0.621371192 + except Exception as e: + return 0.0 def m2feet(meter): - return meter*3.2808399 + try: + m = float(meter) + return m*3.2808399 + except Exception as e: + return 0.0 def feet2m(feet): - return feet/3.2808399 + try: + m = float(feet) + return m/3.2808399 + except Exception as e: + return 0.0 def kg2pound(kg): - return kg*2.20462262 + try: + m = float(kg) + return m*2.20462262 + except Exception as e: + return 0.0 def pound2kg(pound): - return pound/2.20462262 + try: + m = float(pound) + return m/2.20462262 + except Exception as e: + return 0.0 Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/pytrainer/main.py 2010-10-29 04:45:15 UTC (rev 669) @@ -231,7 +231,7 @@ elif view=="day": logging.debug('day view') record_list = self.record.getrecordList(date_selected) - self.windowmain.actualize_dayview(record_list) + self.windowmain.actualize_dayview(record_list=record_list) #selected,iter = self.windowmain.recordTreeView.get_selection().get_selected() elif view=="week": logging.debug('week view') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |