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-10-28 23:38:53
|
Revision: 668 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=668&view=rev Author: jblance Date: 2010-10-28 23:38:47 +0000 (Thu, 28 Oct 2010) Log Message: ----------- New menu item works for athlete data if in athlete view Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-28 22:11:55 UTC (rev 667) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-28 23:38:47 UTC (rev 668) @@ -251,7 +251,9 @@ cell.set_property('text', new) def render_float(self, column, cell, model, iter, format): - orig = cell.get_property('text') + #orig = cell.get_property('text') + #To deal with floats displayed with a comma instead of a dot + orig = model.get_value(iter, column.get_sort_column_id()) new = format % float(orig) cell.set_property('text', new) @@ -1370,7 +1372,11 @@ self.parent.exportCsv() def on_newrecord_clicked(self,widget): - self.parent.newRecord() + if self.selected_view == 'athlete': + #print 'New athlete' + self.on_athleteTreeView_edit( None, None) + else: + self.parent.newRecord() def on_edituser_activate(self,widget): self.parent.editProfile() Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-28 22:11:55 UTC (rev 667) +++ pytrainer/trunk/pytrainer/main.py 2010-10-28 23:38:47 UTC (rev 668) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#667" + self.version ="1.7.2_svn#668" 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-28 22:12:02
|
Revision: 667 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=667&view=rev Author: jblance Date: 2010-10-28 22:11:55 +0000 (Thu, 28 Oct 2010) Log Message: ----------- Correction to date handling to work for mysql and sqlite Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/monthgraph.py pytrainer/trunk/pytrainer/yeargraph.py Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-28 21:47:17 UTC (rev 666) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-28 22:11:55 UTC (rev 667) @@ -44,8 +44,8 @@ "maxpace":"float", "pace":"float", "maxbeats":"float", - "date_time_local":"varchar(20)", - "date_time_utc":"varchar(20)", + "date_time_local":"varchar(40)", + "date_time_utc":"varchar(40)", }, "sports":{ "id_sports":"integer primary key autoincrement", "name":"varchar(100)", Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-28 21:47:17 UTC (rev 666) +++ pytrainer/trunk/pytrainer/main.py 2010-10-28 22:11:55 UTC (rev 667) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#666" + self.version ="1.7.2_svn#667" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() Modified: pytrainer/trunk/pytrainer/monthgraph.py =================================================================== --- pytrainer/trunk/pytrainer/monthgraph.py 2010-10-28 21:47:17 UTC (rev 666) +++ pytrainer/trunk/pytrainer/monthgraph.py 2010-10-28 22:11:55 UTC (rev 667) @@ -17,118 +17,123 @@ #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. from gui.drawArea import DrawArea +import dateutil class MonthGraph: - def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None): - self.drawarea = DrawArea(vbox, window) - self.combovalue = combovalue - self.combovalue2 = combovalue2 + def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None): + self.drawarea = DrawArea(vbox, window) + self.combovalue = combovalue + self.combovalue2 = combovalue2 - def drawgraph(self,values, daysInMonth): - xval = [] - yval = [] - xlab = [] - ylab = [] - tit = [] - col = [] - value_selected = self.combovalue.get_active() - value_selected2 = self.combovalue2.get_active() - if value_selected < 0: - self.combovalue.set_active(0) - value_selected = 0 - xlabel,ylabel,title,color = self.get_value_params(value_selected) - xvalues,yvalues = self.get_values(values,value_selected,daysInMonth) + def drawgraph(self,values, daysInMonth): + xval = [] + yval = [] + xlab = [] + ylab = [] + tit = [] + col = [] + value_selected = self.combovalue.get_active() + value_selected2 = self.combovalue2.get_active() + if value_selected < 0: + self.combovalue.set_active(0) + value_selected = 0 + xlabel,ylabel,title,color = self.get_value_params(value_selected) + xvalues,yvalues = self.get_values(values,value_selected,daysInMonth) - 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) - - if value_selected2 < 0: - self.combovalue2.set_active(0) - value_selected2 = 0 - 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,daysInMonth) - xval.append(xvalues) - yval.append(yvalues) - xlab.append(xlabel) - ylab.append(ylabel) - tit.append(title) - col.append(color) - self.drawarea.stadistics("bars",xval,yval,xlab,ylab,tit,col) + 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) + + if value_selected2 < 0: + self.combovalue2.set_active(0) + value_selected2 = 0 + 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,daysInMonth) + xval.append(xvalues) + yval.append(yvalues) + xlab.append(xlabel) + ylab.append(ylabel) + tit.append(title) + col.append(color) + self.drawarea.stadistics("bars",xval,yval,xlab,ylab,tit,col) - def get_value_params(self,value): - if value == 0: - return _("day"),_("Distance (km)"),_("Daily Distance"),"y" - elif value == 1: - return _("day"),_("Time (hours)"), _("Daily Time"),"b" - elif value == 2: - return _("day"),_("Average Heart Rate (bpm)"), _("Daily Average Heart Rate"),"r" - elif value == 3: - return _("day"),_("Average Speed (km/h)"), _("Daily Average Speed"),"g" - elif value == 4: - return _("day"),_("Calories"), _("Daily Calories"),"b" + def get_value_params(self,value): + if value == 0: + return _("day"),_("Distance (km)"),_("Daily Distance"),"y" + elif value == 1: + return _("day"),_("Time (hours)"), _("Daily Time"),"b" + elif value == 2: + return _("day"),_("Average Heart Rate (bpm)"), _("Daily Average Heart Rate"),"r" + elif value == 3: + return _("day"),_("Average Speed (km/h)"), _("Daily Average Speed"),"g" + elif value == 4: + return _("day"),_("Calories"), _("Daily Calories"),"b" - def get_values(self,values,value_selected,daysInMonth): - #hacemos una relacion entre el value_selected y los values / we make a relation between value_selected and the values - conv = { - 0: 1, #value 0 es kilometros (1) - 1: 2, #value 1 es tiempo (2) - 2: 3, #value 2 es pulsaciones(3) - 3: 5, #value 3 es media(5) - 4: 6 #value 4 es calorias(6) - } - list_values = {} - list_average = {} - for i in range(1,daysInMonth+1): - list_values[i]=0 - list_average[i]=0 + def get_values(self,values,value_selected,daysInMonth): + #hacemos una relacion entre el value_selected y los values / we make a relation between value_selected and the values + conv = { + 0: 1, #value 0 es kilometros (1) + 1: 2, #value 1 es tiempo (2) + 2: 3, #value 2 es pulsaciones(3) + 3: 5, #value 3 es media(5) + 4: 6 #value 4 es calorias(6) + } + list_values = {} + list_average = {} + for i in range(1,daysInMonth+1): + list_values[i]=0 + list_average[i]=0 - value_sel = conv[value_selected] - for value in values: - #si la opcion es tiempo lo pasamos a horas / if the option is time we passed it to hours - if (value_sel == 2): - graph_value = self.getFloatValue(value[value_sel])/3600 - else: - graph_value = self.getFloatValue(value[value_sel]) - - date = value[0] - year,month,day = date.split("-") + value_sel = conv[value_selected] + for value in values: + #si la opcion es tiempo lo pasamos a horas / if the option is time we passed it to hours + if (value_sel == 2): + graph_value = self.getFloatValue(value[value_sel])/3600 + else: + graph_value = self.getFloatValue(value[value_sel]) + + #TODO Sort date handling... + date = value[0] + try: + year,month,day = date.year, date.month, date.day + except AttributeError: + year,month,day = date.split("-") - #si es una opcion de suma de absolutos / if it is an option of sum of absolute - if ((value_selected == 0) or (value_selected==1) or (value_selected==4)): - list_values[int(day)] += graph_value - #si se trata de calcular medias / if one is to calculate averages: - else: - if graph_value is not None and graph_value != 0: - list_values[int(day)] += graph_value - list_average[int(day)] += 1 + #si es una opcion de suma de absolutos / if it is an option of sum of absolute + if ((value_selected == 0) or (value_selected==1) or (value_selected==4)): + list_values[int(day)] += graph_value + #si se trata de calcular medias / if one is to calculate averages: + else: + if graph_value is not None and graph_value != 0: + list_values[int(day)] += graph_value + list_average[int(day)] += 1 - xunits = [] - yunits = [] - for i in range (1,daysInMonth+1): - xunits.append(i) - yunits.append(float(0)) - - for value in list_values: - if ((value_selected == 0) or (value_selected==1) or (value_selected==4)): - yunits[value-1] = list_values[value] - else: - if list_average[value]>0: - yunits[value-1] = list_values[value]/list_average[value] + xunits = [] + yunits = [] + for i in range (1,daysInMonth+1): + xunits.append(i) + yunits.append(float(0)) + + for value in list_values: + if ((value_selected == 0) or (value_selected==1) or (value_selected==4)): + yunits[value-1] = list_values[value] + else: + if list_average[value]>0: + yunits[value-1] = list_values[value]/list_average[value] - return xunits,yunits - - def getFloatValue(self, value): - try: - return float(value) - except: - return float(0) + return xunits,yunits + + def getFloatValue(self, value): + try: + return float(value) + except: + return float(0) Modified: pytrainer/trunk/pytrainer/yeargraph.py =================================================================== --- pytrainer/trunk/pytrainer/yeargraph.py 2010-10-28 21:47:17 UTC (rev 666) +++ pytrainer/trunk/pytrainer/yeargraph.py 2010-10-28 22:11:55 UTC (rev 667) @@ -20,116 +20,119 @@ import calendar class YearGraph: - def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None): - self.drawarea = DrawArea(vbox, window) - self.combovalue = combovalue - self.combovalue2 = combovalue2 + def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None): + self.drawarea = DrawArea(vbox, window) + self.combovalue = combovalue + self.combovalue2 = combovalue2 - def drawgraph(self,values): - xval = [] - yval = [] - xlab = [] - ylab = [] - tit = [] - col = [] - value_selected = self.combovalue.get_active() - value_selected2 = self.combovalue2.get_active() - if value_selected < 0: - self.combovalue.set_active(0) - value_selected = 0 - monthsnumber,xlabel,ylabel,title,color = self.get_value_params(value_selected) - xvalues,yvalues = self.get_values(values,value_selected,monthsnumber) + def drawgraph(self,values): + xval = [] + yval = [] + xlab = [] + ylab = [] + tit = [] + col = [] + value_selected = self.combovalue.get_active() + value_selected2 = self.combovalue2.get_active() + if value_selected < 0: + self.combovalue.set_active(0) + value_selected = 0 + monthsnumber,xlabel,ylabel,title,color = self.get_value_params(value_selected) + xvalues,yvalues = self.get_values(values,value_selected,monthsnumber) - 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) - if value_selected2 < 0: - self.combovalue2.set_active(0) - value_selected2 = 0 - if value_selected2 > 0: - value_selected2 = value_selected2-1 - daysmonth,xlabel,ylabel,title,color = self.get_value_params(value_selected2) - xvalues,yvalues = self.get_values(values,value_selected2,daysmonth) - xval.append(xvalues) - yval.append(yvalues) - xlab.append(xlabel) - ylab.append(ylabel) - tit.append(title) - col.append(color) - self.drawarea.stadistics("bars",xval,yval,xlab,ylab,tit,col) + if value_selected2 < 0: + self.combovalue2.set_active(0) + value_selected2 = 0 + if value_selected2 > 0: + value_selected2 = value_selected2-1 + daysmonth,xlabel,ylabel,title,color = self.get_value_params(value_selected2) + xvalues,yvalues = self.get_values(values,value_selected2,daysmonth) + xval.append(xvalues) + yval.append(yvalues) + xlab.append(xlabel) + ylab.append(ylabel) + tit.append(title) + col.append(color) + self.drawarea.stadistics("bars",xval,yval,xlab,ylab,tit,col) - def get_value_params(self,value): - if value == 0: - return 12,_("month"),_("Distance (km)"),_("Monthly Distance"),"y" - elif value == 1: - return 12,_("month"),_("Time (hours)"), _("Monthly Time"),"b" - elif value == 2: - return 12,_("month"),_("Average Heart Rate (bpm)"), _("Monthly Average Heart Rate"),"r" - elif value == 3: - return 12,_("month"),_("Average Speed (km/h)"), _("Monthly Average Speed"),"g" - elif value == 4: - return 12,_("month"),_("Calories"), _("Monthly Calories"),"b" + def get_value_params(self,value): + if value == 0: + return 12,_("month"),_("Distance (km)"),_("Monthly Distance"),"y" + elif value == 1: + return 12,_("month"),_("Time (hours)"), _("Monthly Time"),"b" + elif value == 2: + return 12,_("month"),_("Average Heart Rate (bpm)"), _("Monthly Average Heart Rate"),"r" + elif value == 3: + return 12,_("month"),_("Average Speed (km/h)"), _("Monthly Average Speed"),"g" + elif value == 4: + return 12,_("month"),_("Calories"), _("Monthly Calories"),"b" - def get_values(self,values,value_selected,monthsnumber): - #hacemos una relacion entre el value_selected y los values - conv = { - 0: 1, #value 0 es kilometros (1) - 1: 2, #value 1 es tiempo (2) - 2: 3, #value 2 es pulsaciones(3) - 3: 5, #value 3 es media(5) - 4: 6 #value 4 es calorias(6) - } - list_values = {} - list_average = {} - tm_total = {} - for i in range(1,monthsnumber+1): - list_values[i]=0 - list_average[i]=0 - tm_total[i] = 0 - - value_sel = conv[value_selected] + def get_values(self,values,value_selected,monthsnumber): + #hacemos una relacion entre el value_selected y los values + conv = { + 0: 1, #value 0 es kilometros (1) + 1: 2, #value 1 es tiempo (2) + 2: 3, #value 2 es pulsaciones(3) + 3: 5, #value 3 es media(5) + 4: 6 #value 4 es calorias(6) + } + list_values = {} + list_average = {} + tm_total = {} + for i in range(1,monthsnumber+1): + list_values[i]=0 + list_average[i]=0 + tm_total[i] = 0 + + value_sel = conv[value_selected] - for value in values: - date = value[0] - year,month,day = date.split("-") - month = int(month) - #si la opcion es tiempo lo pasamos a horas / if the option is time we passed it to hours - if (value_sel == 2): - graph_value = self.getFloatValue(value[value_sel])/3600 - else: - graph_value = self.getFloatValue(value[value_sel]) + for value in values: + date = value[0] + try: + year,month,day = date.year, date.month, date.day + except AttributeError: + year,month,day = date.split("-") + month = int(month) + #si la opcion es tiempo lo pasamos a horas / if the option is time we passed it to hours + if (value_sel == 2): + graph_value = self.getFloatValue(value[value_sel])/3600 + else: + graph_value = self.getFloatValue(value[value_sel]) - #si es una opcion de suma de absolutos / if it is an option of sum of absolute - if ((value_selected == 0) or (value_selected==1) or (value_selected==4)): - list_values[int(month)] += graph_value - #si se trata de calcular medias / if one is to calculate averages: - else: - if graph_value is not None and graph_value != 0: - list_values[int(month)] += graph_value - list_average[int(month)] += 1 + #si es una opcion de suma de absolutos / if it is an option of sum of absolute + if ((value_selected == 0) or (value_selected==1) or (value_selected==4)): + list_values[int(month)] += graph_value + #si se trata de calcular medias / if one is to calculate averages: + else: + if graph_value is not None and graph_value != 0: + list_values[int(month)] += graph_value + list_average[int(month)] += 1 - xunits = [] - yunits = [] - for i in range (0,monthsnumber): - xunits.append(unicode(calendar.month_abbr[i+1])) - yunits.append(float(0)) - for value in list_values: - if ((value_selected == 0) or (value_selected==1) or (value_selected==4)): - yunits[value-1] = list_values[value] - else: - if list_average[value]>0: - yunits[value-1] = list_values[value]/list_average[value] - return xunits,yunits - - def getFloatValue(self, value): - try: - return float(value) - except: - return float(0) + xunits = [] + yunits = [] + for i in range (0,monthsnumber): + xunits.append(unicode(calendar.month_abbr[i+1])) + yunits.append(float(0)) + for value in list_values: + if ((value_selected == 0) or (value_selected==1) or (value_selected==4)): + yunits[value-1] = list_values[value] + else: + if list_average[value]>0: + yunits[value-1] = list_values[value]/list_average[value] + return xunits,yunits + + 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-10-28 21:47:24
|
Revision: 666 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=666&view=rev Author: jblance Date: 2010-10-28 21:47:17 +0000 (Thu, 28 Oct 2010) Log Message: ----------- Update to DB code to support MySQL better Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/lib/mysqlUtils.py pytrainer/trunk/pytrainer/lib/sqliteUtils.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/profile.py Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-28 01:35:18 UTC (rev 665) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-28 21:47:17 UTC (rev 666) @@ -44,8 +44,8 @@ "maxpace":"float", "pace":"float", "maxbeats":"float", - "date_time_local":"varchar2(20)", - "date_time_utc":"varchar2(20)", + "date_time_local":"varchar(20)", + "date_time_utc":"varchar(20)", }, "sports":{ "id_sports":"integer primary key autoincrement", "name":"varchar(100)", @@ -82,7 +82,9 @@ "maxhr": "integer", }, } +tablesDefaultData = { "sports": [({ "name":"Mountain Bike" } ), ( {"name": "Bike"}), ({"name": "Run"}) ]} + class DDBB: def __init__(self, configuration, pytrainer_main=None): self.pytrainer_main = pytrainer_main @@ -103,16 +105,15 @@ self.ddbbObject = Sql(ddbb_host,ddbb,ddbb_user,ddbb_pass,self.configuration) def connect(self): - #si devolvemos 1 ha ido todo con exito : return 1 if all successful - #con 0 es que no estaba la bbdd creada : 0 is DB not created - #con -1 imposible conectar a la maquina. : -1 is impossible to connect to the host - var = self.ddbbObject.connect() - if var == 0: - self.ddbbObject.createDDBB() - self.ddbbObject.connect() - self.ddbbObject.createTables() - var = 1 - return var + connection_ok, connection_msg = self.ddbbObject.connect() + if not connection_ok: + print "ERROR: Unable to connect to database" + print connection_msg + sys.exit(connection_ok) + #Do a quick check to ensure all tables are present in DB + if not self.checkDBTables(): + #Some tables missing - do DB check + self.checkDBIntegrity() def disconnect(self): self.ddbbObject.disconnect() @@ -271,20 +272,34 @@ sql = "select %s from %s order by %s Desc limit 0,1" %(id,table,id) ret_val = self.ddbbObject.freeExec(sql) return ret_val[0][0] + + def checkDBTables(self): + '''Quick check that all expected tables existing in DB + return True if OK, False if any tables are missing + ''' + global tablesList + logging.debug('>>') + tablesDB = self.ddbbObject.getTableList() + #Check Tables + for entry in tablesList: + if entry not in tablesDB: + return False + return True def checkDBIntegrity(self): - """17.11.2009 - dgranda + '''17.11.2009 - dgranda Retrieves tables and columns from database, checks current ones and adds something if missed. New in version 1.7.0 args: none - returns: none""" + returns: none''' global tablesList + global tablesDefaultData logging.debug('>>') logging.info('Checking PyTrainer database') - if self.ddbb_type != "sqlite": - logging.error('Support for MySQL database is decommissioned, please migrate to SQLite. Exiting check') - exit(-2) + #if self.ddbb_type != "sqlite": + # logging.error('Support for MySQL database is decommissioned, please migrate to SQLite. Exiting check') + # exit(-2) try: - tablesDBT = self.ddbbObject.select("sqlite_master","name", "type IN ('table','view') AND name NOT LIKE 'sqlite_%' ORDER BY name") + tablesDBT = self.ddbbObject.getTableList() except: logging.error('Not able to retrieve which tables are in DB. Printing traceback') traceback.print_exc() @@ -297,7 +312,7 @@ # Create a compressed copy of current DB try: - self.createDatabaseBackup() + self.ddbbObject.createDatabaseBackup() except: logging.error('Not able to make a copy of current DB. Printing traceback and exiting') traceback.print_exc() @@ -308,6 +323,11 @@ if entry not in tablesDB: logging.warn('Table '+str(entry)+' does not exist in DB') self.ddbbObject.createTableDefault(entry,tablesList[entry]) + #Check if this table has default data to add.. + if entry in tablesDefaultData: + logging.debug("Adding default data to %s" % entry) + for data_dict in tablesDefaultData[entry]: + self.insert_dict(entry, data_dict) else: self.ddbbObject.checkTable(entry,tablesList[entry]) @@ -317,16 +337,6 @@ self.populate_duration_from_time() logging.debug('<<') - def createDatabaseBackup(self): - logging.debug('>>') - logging.debug('Database path: '+str(self.ddbb_path)) - result = commands.getstatusoutput('gzip -c '+self.ddbb_path+' > '+self.ddbb_path+'_`date +%Y%m%d_%H%M`.gz') - if result[0] != 0: - raise Exception, "Copying current database does not work, error #"+str(result[0]) - else: - logging.info('Database backup successfully created') - logging.debug('<<') - def checkDBDataValues(self): ''' Check all data in DB and report values that do not match the type ''' global tablesList Modified: pytrainer/trunk/pytrainer/lib/mysqlUtils.py =================================================================== --- pytrainer/trunk/pytrainer/lib/mysqlUtils.py 2010-10-28 01:35:18 UTC (rev 665) +++ pytrainer/trunk/pytrainer/lib/mysqlUtils.py 2010-10-28 21:47:17 UTC (rev 666) @@ -18,160 +18,226 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#import _mysql +import _mysql_exceptions import MySQLdb -from logs import Log +import logging # Fixed some issues with MySql tables creation (email from Jonas Liljenfeldt) class Sql: - def __init__(self,host=None, ddbb = None, user = None, password = None, configuration = None): - self.ddbb_user = user - self.ddbb_pass = password - self.ddbb_host = host - self.ddbb = ddbb - self.db = None - self.log = Log() - - def connect(self): - #si devolvemos 1 ha ido todo con exito - #con 0 es que no estaba la bbdd creada - #con -1 imposible conectar a la maquina. - try: - self.db=MySQLdb.connect( - host=self.ddbb_host, - user=self.ddbb_user, - passwd=self.ddbb_pass, - db=self.ddbb) - self.select("records","id_record","1=1 limit 0,1") - return 1 - except: - try: - self.createTables() - return 0 - except: - return -1 - - def disconnect(self): - self.db.close() - - def createDDBB(self): - self.db.query("create database %s" %self.ddbb) + def __init__(self,host=None, ddbb = None, user = None, password = None, configuration = None): + self.ddbb_user = user + self.ddbb_pass = password + self.ddbb_host = host + self.ddbb = ddbb + self.db = None + + def connect(self): + #si devolvemos 1 ha ido todo con exito + #con 0 es que no estaba la bbdd creada + #con -1 imposible conectar a la maquina. + try: + self.db=MySQLdb.connect( + host=self.ddbb_host, + user=self.ddbb_user, + passwd=self.ddbb_pass, + db=self.ddbb) + return (True, "OK") + except _mysql_exceptions.OperationalError as e: + error_no, error_description = e + print "ERROR: An error occured while connecting to MySQL DB (%s) %s" % (error_no, error_description) + if error_no == 1049: + #Unknown DB - try to create? + print "Unknown DB given, attempting to create a new DB" + try: + #Connect to DB without specifying the DB + self.db=MySQLdb.connect(host=self.ddbb_host, user=self.ddbb_user, passwd=self.ddbb_pass) + #Create DB + self.createDDBB() + #Reconnect to new DB + self.db=MySQLdb.connect(host=self.ddbb_host, user=self.ddbb_user, passwd=self.ddbb_pass, db=self.ddbb) + return (True, "OK") + except Exception as e: + #No good - so stop + print type(e) + print e + logging.error("Unable to connect to MySQL DB") + return (False, "Unable to connect to MySQL DB") + except Exception as e: + logging.error("Unable to connect to MySQL DB") + print "ERROR: Unable to connect to MySQL DB" + print type(e) + print e + return (False, "Unable to connect to MySQL DB") + + def disconnect(self): + self.db.close() + + def createDDBB(self): + self.db.query("create database %s" %self.ddbb) + + def getTableList(self): + return self.freeExec('show tables') + + def createTableDefault(self,tableName,columns): + ''' + Creates a new table in database given name and column name and data types. New in version 1.7.0 + args: + tableName - string with name of the table + columns - dictionary containing column names and data types coming from definition + returns: none''' + #print self, tableName, columns + logging.debug('>>') + logging.info('Creating '+str(tableName)+' table with default values') + logging.debug('Columns definition: '+str(columns)) + cur = self.db.cursor() + sql = 'CREATE TABLE %s (' %(tableName) + for entry in columns: + if columns[entry].find('autoincrement') != -1: + logging.debug("have a autoincrement field") + fieldtype = columns[entry].replace('autoincrement', 'auto_increment') + sql += '%s %s,' %(entry,fieldtype) + else: + sql += '%s %s,' %(entry,columns[entry]) + # Removing trailing comma + sql = sql.rstrip(',') + sql = sql+");" + logging.debug('SQL sentence: '+str(sql)) + #print sql + cur.execute(sql) + logging.debug('<<') - def createTables(self): - #creamos la tabla sports - self.db.query("""CREATE TABLE `sports` ( - `id_sports` INT( 11 ) NOT NULL AUTO_INCREMENT , - `name` VARCHAR( 100 ) NOT NULL , - `weight` FLOAT NOT NULL , - `met` FLOAT NOT NULL , - INDEX ( `id_sports` ) - ) ENGINE = MYISAM ;""") + def insert(self,table, cells, values): + val = values + count = 0 + string = "" + for i in val: + if count>0: + string+="," + string+="""\"%s\"""" %i + count = count+1 + sql = '''insert into %s (%s) values (%s)''' %(table,cells,string) + self.db.query(sql) - #creamos la tabla records - self.db.query("""CREATE TABLE `records` ( - `id_record` INT( 11 ) NOT NULL AUTO_INCREMENT , - `date` DATE NOT NULL , - `sport` INT( 11 ) NOT NULL , - `distance` FLOAT NOT NULL , - `time` VARCHAR( 200 ) NOT NULL , - `beats` FLOAT NOT NULL , - `average` FLOAT NOT NULL , - `calories` INT( 11 ) NOT NULL , - `comments` TEXT NOT NULL , - `gpslog` VARCHAR( 200 ) NOT NULL , - `title` VARCHAR( 200 ) NOT NULL , - `upositive` FLOAT NOT NULL , - `unegative` FLOAT NOT NULL , - `maxspeed` FLOAT NOT NULL, - maxpace FLOAT NOT NULL, - pace FLOAT NOT NULL, - maxbeats FLOAT NOT NULL, - date_time_utc VARCHAR( 20 ) NOT NULL , - INDEX ( `id_record` ) - ) ENGINE = MYISAM ;""") - - #creamos la tabla waypoints - sql = """CREATE TABLE waypoints ( - id_waypoint INT(11) NOT NULL AUTO_INCREMENT , - lat float NOT NULL, - lon float NOT NULL, - ele float NOT NULL, - time date NOT NULL, - name varchar (200) NOT NULL, - sym varchar (200) NOT NULL, - comment varchar (240) NOT NULL, - INDEX (id_waypoint) - ) ENGINE = MYISAM ;""" - self.db.query(sql) - - self.insert("sports","name",["Mountain Bike"]) - self.insert("sports","name",["Bike"]) - self.insert("sports","name",["Run"]) - def addWaipoints2ddbb(self): - sql = """CREATE TABLE waypoints ( - id_waypoint INT(11) NOT NULL AUTO_INCREMENT , - lat float NOT NULL, - lon float NOT NULL, - ele float NOT NULL, - time date NOT NULL, - name varchar (200) NOT NULL, - sym varchar (200) NOT NULL, - comment varchar (240) NOT NULL, - INDEX (id_waypoint) - ) ENGINE = MYISAM ;""" - self.db.query(sql) + def freeExec(self,sql): + #self.db.query(sql) + cur = self.db.cursor() + cur.execute(sql) + retorno = [] + for row in cur.fetchall(): + retorno.append(row) + self.db.commit() + return retorno + + def delete(self,table,condition): + sql = "delete from %s where %s" %(table,condition) + self.db.query(sql) - def insert(self,table, cells, values): - val = values - count = 0 - string = "" - for i in val: - if count>0: - string+="," - string+="""\"%s\"""" %i - count = count+1 - self.db.query("""insert into %s (%s) values (%s)""" %(table,cells,string)) + def select(self,table,cells,condition, mod=None): + if condition != None: + self.db.query("""select %s from %s where %s""" %(cells,table,condition)) + else: + self.db.query("""select %s from %s """ %(cells,table)) + r = self.db.store_result() + retorno = [] + while 1==1: + sublist = r.fetch_row() + if len(sublist)>0: + retorno.append(sublist[0]) + else: + break + return retorno - def freeExec(self,sql): - #self.db.query(sql) - self.log.run(sql) - cur = self.db.cursor() - cur.execute(sql) - retorno = [] - for row in cur.fetchall(): - retorno.append(row) - self.db.commit() - return retorno - - def delete(self,table,condition): - sql = "delete from %s where %s" %(table,condition) - self.db.query(sql) + def update (self,table,cells,values,condition): + cells = cells.split(",") + count = 0 + string = "" + for val in values: + if count>0: + string+="," + string += """%s="%s" """ %(cells[count],values[count]) + count = count+1 - def select(self,table,cells,condition, mod=None): - if condition != None: - self.db.query("""select %s from %s where %s""" %(cells,table,condition)) - else: - self.db.query("""select %s from %s """ %(cells,table)) - r = self.db.store_result() - retorno = [] - while 1==1: - sublist = r.fetch_row() - if len(sublist)>0: - retorno.append(sublist[0]) - else: - break - return retorno + string +=" where %s" %condition + sql = "update %s set %s" %(table,string) + self.db.query(sql) + + def checkTable(self,tableName,columns): + ''' + Checks column names and values from table and adds something if missed. New in version 1.7.0 + args: + tableName - string with name of the table + columns - dictionary containing column names and data types coming from definition + returns: none''' + logging.debug('>>') + logging.info('Inspecting '+str(tableName)+' table') + logging.debug('Columns definition: '+str(columns)) - def update (self,table,cells,values,condition): - cells = cells.split(",") - count = 0 - string = "" - for val in values: - if count>0: - string+="," - string += """%s="%s" """ %(cells[count],values[count]) - count = count+1 + # Retrieving data from DB + tableInfo = self.retrieveTableInfo(tableName) + logging.debug('Raw data retrieved from DB '+str(tableName)+': '+str(tableInfo)) + #print('Raw data retrieved from DB '+str(tableName)+': '+str(tableInfo)) + #Raw data retrieved from DB sports: [('met', 'float', 'YES', '', None, ''), ('id_sports', 'int(11)', 'NO', 'PRI', None, 'auto_increment'), ('max_pace', 'int(11)', 'YES', '', None, ''), ('name', 'varchar(100)', 'YES', '', None, ''), ('weight', 'float', 'YES', '', None, '')] - string +=" where %s" %condition - sql = "update %s set %s" %(table,string) - self.db.query(sql) + # Comparing data retrieved from DB with what comes from definition + columnsDB = {} + for field in tableInfo: + newField = {field[0]:field[1]} + columnsDB.update(newField) + logging.debug('Useful data retrieved from '+str(tableName)+' in DB: '+str(columnsDB)) + #print('Useful data retrieved from '+str(tableName)+' in DB: '+str(columnsDB)) + + # http://mail.python.org/pipermail/python-list/2002-May/141458.html + #tempDict = dict(zip(columns,columns)) + tempDict = dict(columns) + #Test for columns that are in DB that shouldn't be + result = [x for x in columnsDB if x not in tempDict] + #Test for columns that are not in the DB that should be + result2 = [x for x in tempDict if x not in columnsDB] + + logging.debug("Columns in DB that shouldnt be: "+str(result)) + logging.debug("Columns missing from DB: "+str(result2)) + + table_ok = True + if len(result) > 0: + logging.debug('Found columns in DB that should not be: '+ str(result)) + table_ok = False + for entry in result: + logging.debug('Column '+ str(entry) +' in DB but not in definition') + print "Column %s in DB but not in definition - please fix manually" % (str(entry)) + print "#TODO need to add auto fix code" + sys.exit(1) + if len(result2) > 0: # may have also different data type + logging.debug('Found columns missed in DB: '+ str(result2)) + table_ok = False + for entry in result2: + logging.debug('Column '+ str(entry) +' not found in DB') + self.addColumn(tableName,str(entry),columns[entry]) + if table_ok: + logging.info('Table '+ str(tableName) +' is OK') + logging.debug('<<') + + def retrieveTableInfo(self,tableName): + cur = self.db.cursor() + sql = "desc %s;" %tableName + cur.execute(sql) + tableInfo = [] + for row in cur: + tableInfo.append(row) + return tableInfo + return + + def addColumn(self,tableName,columnName,dataType): + if dataType.find('autoincrement') != -1: + dataType = dataType.replace('autoincrement', 'auto_increment') + sql = "alter table %s add %s %s" %(tableName,columnName,dataType) + logging.debug("Trying SQL: %s" % sql) + try: + self.freeExec(sql) + except: + logging.error('Not able to add/change column '+columnName+' to table '+tableName) + traceback.print_exc() + + def createDatabaseBackup(self): + logging.debug('>>') + logging.info("Unable to create backup for MySQL DB") + logging.debug('<<') Modified: pytrainer/trunk/pytrainer/lib/sqliteUtils.py =================================================================== --- pytrainer/trunk/pytrainer/lib/sqliteUtils.py 2010-10-28 01:35:18 UTC (rev 665) +++ pytrainer/trunk/pytrainer/lib/sqliteUtils.py 2010-10-28 21:47:17 UTC (rev 666) @@ -19,7 +19,7 @@ #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import logging -import sys, traceback +import sys, traceback, commands try: from sqlite3 import dbapi2 as sqlite except ImportError: @@ -27,89 +27,39 @@ from pysqlite2 import dbapi2 as sqlite logging.info('Using pysqlite2 module to access DB. Think about upgrading to python 2.5!') -from logs import Log - class Sql: def __init__(self,host=None, ddbb = None, user = None, password = None, configuration = None): self.db = None confdir = configuration.confdir self.ddbb = "%s/pytrainer.ddbb" %confdir - self.log = Log() def connect(self): #si devolvemos 1 ha ido todo con exito self.db = sqlite.connect(self.ddbb) + return (True, "OK") #probamos si estan las tablas creadas, y sino.. las creamos - try: + '''try: self.select("records","id_record","1=1 limit 0,1") except: self.createTables() - return 1 + return 1''' def disconnect(self): self.db.close() def createDDBB(self): pass + + def getTableList(self): + return self.select("sqlite_master","name", "type IN ('table','view') AND name NOT LIKE 'sqlite_%' ORDER BY name") - def createTables(self): #TODO Needs to be fixed to create tables based on definition, perhaps replaced by createTableDefault? - cur = self.db.cursor() - #creamos la tabla sports - sql = """CREATE TABLE sports ( - id_sports integer primary key autoincrement, - name varchar (100), - weight float, - met float - );""" - cur.execute(sql) - - #creamos la tabla records - sql = """CREATE TABLE records ( - id_record integer primary key autoincrement , - date date, - sport integer, - distance float, - time varchar (200), - beats float, - average float, - calories int, - comments text, - gpslog varchar(200), - title varchar(200), - upositive float, - unegative float, - maxspeed float, - maxpace float, - pace float, - maxbeats float, - date_time_utc varchar2(20) - ) ;""" - cur.execute(sql) - - #creamos la tabla waypoints - sql = """CREATE TABLE waypoints ( - id_waypoint integer primary key autoincrement , - lat float, - lon float, - ele float, - comment varchar (240), - time date, - name varchar (200), - sym varchar (200) - ) ;""" - cur.execute(sql) - - self.insert("sports","name",["Mountain Bike"]); - self.insert("sports","name",["Bike"]); - self.insert("sports","name",["Run"]); - def createTableDefault(self,tableName,columns): - """22.11.2009 - dgranda + '''22.11.2009 - dgranda Creates a new table in database given name and column name and data types. New in version 1.7.0 args: tableName - string with name of the table columns - dictionary containing column names and data types coming from definition - returns: none""" + returns: none''' logging.debug('>>') logging.info('Creating '+str(tableName)+' table with default values') logging.debug('Columns definition: '+str(columns)) @@ -123,21 +73,7 @@ logging.debug('SQL sentence: '+str(sql)) cur.execute(sql) logging.debug('<<') - - def addWaipoints2ddbb(self): #TODO Remove? - cur = self.db.cursor() - sql = """CREATE TABLE waypoints ( - id_waypoint integer primary key autoincrement , - lat float, - lon float, - ele float, - comment varchar (240), - time date, - name varchar (200), - sym varchar (200) - ) ;""" - cur.execute(sql) - + def insert(self,table, cells, values): cur = self.db.cursor() val = values @@ -149,13 +85,11 @@ string+="""\"%s\"""" %i count = count+1 sql = "insert into %s (%s) values (%s)" %(table,cells,string) - self.log.run(sql) cur.execute(sql) self.db.commit() def freeExec(self,sql): cur = self.db.cursor() - self.log.run(sql) cur.execute(sql) retorno = [] for row in cur: @@ -166,7 +100,6 @@ def delete(self,table,condition): cur = self.db.cursor() sql = "delete from %s where %s" %(table,condition) - self.log.run(sql) cur.execute(sql) self.db.commit() @@ -183,7 +116,6 @@ string +=" where %s" %condition sql = "update %s set %s" %(table,string) - self.log.run(sql) cur.execute(sql) self.db.commit() @@ -198,7 +130,6 @@ sql = "select %s from %s where %s" %(cells,table,condition) else: sql = "select %s from %s " %(cells,table)''' - self.log.run(sql) cur.execute(sql) retorno = [] for row in cur: @@ -206,19 +137,20 @@ return retorno def checkTable(self,tableName,columns): - """19.11.2009 - dgranda + '''19.11.2009 - dgranda Checks column names and values from table and adds something if missed. New in version 1.7.0 args: tableName - string with name of the table columns - dictionary containing column names and data types coming from definition - returns: none""" + returns: none''' logging.debug('>>') logging.info('Inspecting '+str(tableName)+' table') logging.debug('Columns definition: '+str(columns)) # Retrieving data from DB tableInfo = self.retrieveTableInfo(tableName) - #logging.debug('Raw data retrieved from DB '+str(tableName)+': '+str(tableInfo)) + logging.debug('Raw data retrieved from DB '+str(tableName)+': '+str(tableInfo)) + #Raw data retrieved from DB laps: [(0, u'elapsed_time', u'varchar(20)', 0, None, 0), (1, u'record', u'integer', 0, None, 0), (2, u'end_lon', u'float', 0, None, 0), (3, u'lap_number', u'integer', 0, None, 0), (4, u'end_lat', u'float', 0, None, 0), (5, u'distance', u'float', 0, None, 0), (6, u'start_lon', u'float', 0, None, 0), (7, u'id_lap', u'integer', 0, None, 1), (8, u'calories', u'int', 0, None, 0), (9, u'start_lat', u'float', 0, None, 0)] # Comparing data retrieved from DB with what comes from definition columnsDB = {} @@ -226,7 +158,8 @@ newField = {field[1]:field[2]} columnsDB.update(newField) logging.debug('Useful data retrieved from '+str(tableName)+' in DB: '+str(columnsDB)) - + #Useful data retrieved from laps in DB: {u'elapsed_time': u'varchar(20)', u'record': u'integer', u'end_lon': u'float', u'start_lon': u'float', u'end_lat': u'float', u'distance': u'float', u'id_lap': u'integer', u'lap_number': u'integer', u'calories': u'int', u'start_lat': u'float'} + # http://mail.python.org/pipermail/python-list/2002-May/141458.html #tempDict = dict(zip(columns,columns)) tempDict = dict(columns) @@ -275,3 +208,13 @@ logging.error('Not able to add/change column '+columnName+' to table '+tableName) traceback.print_exc() + + def createDatabaseBackup(self): + logging.debug('>>') + logging.debug('Database path: '+str(self.ddbb)) + result = commands.getstatusoutput('gzip -c '+self.ddbb+' > '+self.ddbb+'_`date +%Y%m%d_%H%M`.gz') + if result[0] != 0: + raise Exception, "Copying current database does not work, error #"+str(result[0]) + else: + logging.info('Database backup successfully created') + logging.debug('<<') Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-28 01:35:18 UTC (rev 665) +++ pytrainer/trunk/pytrainer/main.py 2010-10-28 21:47:17 UTC (rev 666) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#665" + self.version ="1.7.2_svn#666" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() @@ -64,9 +64,10 @@ logging.debug('Checking configuration and profile...') self.profile = Profile(self.data_path,self) self.windowmain = None - self.ddbb = DDBB(self.profile) + 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") Modified: pytrainer/trunk/pytrainer/profile.py =================================================================== --- pytrainer/trunk/pytrainer/profile.py 2010-10-28 01:35:18 UTC (rev 665) +++ pytrainer/trunk/pytrainer/profile.py 2010-10-28 21:47:17 UTC (rev 666) @@ -78,7 +78,7 @@ 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.pytrainer_main.ddbb = DDBB(self, pytrainer_main=self.pytrainer_main) self._setZones() logging.debug("<<") @@ -273,12 +273,12 @@ 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 + #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 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-10-28 01:35:28
|
Revision: 665 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=665&view=rev Author: jblance Date: 2010-10-28 01:35:18 +0000 (Thu, 28 Oct 2010) Log Message: ----------- Moved Athlete to tab, changed new/edit functionality Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowcalendar.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-10-14 20:46:47 UTC (rev 664) +++ pytrainer/trunk/glade/pytrainer.glade 2010-10-28 01:35:18 UTC (rev 665) @@ -135,17 +135,6 @@ </widget> </child> <child> - <widget class="GtkRadioMenuItem" id="athleteview_item"> - <property name="visible">True</property> - <property name="label" translatable="yes"> _Athlete Data</property> - <property name="use_underline">True</property> - <property name="draw_as_radio">True</property> - <property name="group">classicview_item</property> - <signal name="activate" handler="on_athleteview_activate"/> - <accelerator key="a" signal="activate" modifiers="GDK_CONTROL_MASK"/> - </widget> - </child> - <child> <widget class="GtkRadioMenuItem" id="waipointsview_item"> <property name="visible">True</property> <property name="label" translatable="yes"> _Waypoints Editor</property> @@ -5225,6 +5214,227 @@ <property name="type">tab</property> </packing> </child> + <child> + <widget class="GtkHBox" id="athletearea"> + <property name="visible">True</property> + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <child> + <widget class="GtkFrame" id="frame3"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <child> + <widget class="GtkAlignment" id="alignment9"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <widget class="GtkTable" id="table2"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">4</property> + <child> + <widget class="GtkLabel" id="label21"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Name:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">5</property> + <property name="y_padding">5</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label22"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Date of birth:</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">5</property> + <property name="y_padding">5</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label23"> + <property name="visible">True</property> + <property name="label" translatable="yes">Height:</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">5</property> + <property name="y_padding">5</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelName"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">5</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">4</property> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">10</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelDOB"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">5</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">GTK_FILL</property> + <property name="x_padding">10</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelHeight"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">5</property> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="x_padding">10</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label24"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Athlete Details</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="padding">6</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkFrame" id="frame6"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <child> + <widget class="GtkAlignment" id="alignment13"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <widget class="GtkHBox" id="boxAthleteGraph"> + <property name="height_request">150</property> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label25"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Graph</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">1</property> + </packing> + </child> + <child> + <widget class="GtkFrame" id="frame5"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <child> + <widget class="GtkAlignment" id="alignment12"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <widget class="GtkTreeView" id="athleteTreeView"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <signal name="button_press_event" handler="on_athleteTreeView_button_press_event"/> + </widget> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label26"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>History</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">5</property> + <property name="position">2</property> + </packing> + </child> + </widget> + <packing> + <property name="position">0</property> + </packing> + </child> + </widget> + <packing> + <property name="position">6</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label20"> + <property name="visible">True</property> + <property name="label" translatable="yes">Athlete</property> + </widget> + <packing> + <property name="position">6</property> + <property name="tab_fill">False</property> + <property name="type">tab</property> + </packing> + </child> </widget> <packing> <property name="position">1</property> @@ -5689,479 +5899,7 @@ </packing> </child> <child> - <widget class="GtkHBox" id="athletearea"> - <property name="visible">True</property> - <child> - <widget class="GtkVBox" id="vbox1"> - <property name="visible">True</property> - <child> - <widget class="GtkFrame" id="frame3"> - <property name="visible">True</property> - <property name="label_xalign">0</property> - <child> - <widget class="GtkAlignment" id="alignment9"> - <property name="visible">True</property> - <property name="left_padding">12</property> - <child> - <widget class="GtkTable" id="table2"> - <property name="visible">True</property> - <property name="n_rows">2</property> - <property name="n_columns">4</property> - <child> - <widget class="GtkLabel" id="label21"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label" translatable="yes">Name:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="x_padding">5</property> - <property name="y_padding">5</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label22"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label" translatable="yes">Date of birth:</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="x_padding">5</property> - <property name="y_padding">5</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label23"> - <property name="visible">True</property> - <property name="label" translatable="yes">Height:</property> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="x_padding">5</property> - <property name="y_padding">5</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelName"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">4</property> - <property name="x_options">GTK_FILL</property> - <property name="x_padding">10</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelDOB"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</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">GTK_FILL</property> - <property name="x_padding">10</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelHeight"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - </widget> - <packing> - <property name="left_attach">3</property> - <property name="right_attach">4</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="x_padding">10</property> - </packing> - </child> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkLabel" id="label20"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>Athlete Details</b></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="type">label_item</property> - </packing> - </child> - </widget> - <packing> - <property name="expand">False</property> - <property name="padding">6</property> - <property name="position">0</property> - </packing> - </child> - <child> - <widget class="GtkFrame" id="frame6"> - <property name="visible">True</property> - <property name="label_xalign">0</property> - <child> - <widget class="GtkAlignment" id="alignment13"> - <property name="visible">True</property> - <property name="left_padding">12</property> - <child> - <widget class="GtkHBox" id="hbox7"> - <property name="visible">True</property> - <child> - <widget class="GtkTable" id="table3"> - <property name="visible">True</property> - <property name="n_rows">7</property> - <property name="n_columns">3</property> - <child> - <widget class="GtkLabel" id="labelAthleteDate"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label" translatable="yes">Date:</property> - </widget> - <packing> - <property name="y_options"></property> - <property name="x_padding">5</property> - <property name="y_padding">5</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelAthleteWeight"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label" translatable="yes">Weight:</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - <property name="x_padding">5</property> - <property name="y_padding">5</property> - </packing> - </child> - <child> - <widget class="GtkEntry" id="entryAthleteDate"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">●</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="x_options">GTK_EXPAND</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkEntry" id="entryAthleteWeight"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">●</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">GTK_EXPAND</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelAthleteBF"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label" translatable="yes">Body Fat:</property> - </widget> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"></property> - <property name="x_padding">5</property> - <property name="y_padding">5</property> - </packing> - </child> - <child> - <widget class="GtkEntry" id="entryAthleteBF"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">●</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">GTK_EXPAND</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkEntry" id="entryAthleteRestingHR"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">●</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">GTK_EXPAND</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelRestingHeartRate"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label" translatable="yes">Resting Heart Rate:</property> - </widget> - <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"></property> - <property name="x_padding">5</property> - <property name="y_padding">5</property> - </packing> - </child> - <child> - <widget class="GtkEntry" id="entryAthleteMaxHR"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">●</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">GTK_EXPAND</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelMaxHeartRate"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label" translatable="yes">Max Heart Rate:</property> - </widget> - <packing> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_options"></property> - <property name="x_padding">5</property> - <property name="y_padding">5</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelAthleteIdx"/> - <packing> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="x_options">GTK_EXPAND</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkHBox" id="hbox9"> - <property name="visible">True</property> - <child> - <widget class="GtkButton" id="buttonAthleteNew"> - <property name="label" translatable="yes">New</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="clicked" handler="on_buttonAthleteNew_clicked"/> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <placeholder/> - </child> - <child> - <widget class="GtkButton" id="buttonAlthleteSave"> - <property name="label" translatable="yes">Save</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="clicked" handler="on_buttonAlthleteSave_clicked"/> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="pack_type">end</property> - <property name="position">0</property> - </packing> - </child> - </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="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="clicked" handler="on_athletecalendar_clicked"/> - <child> - <widget class="GtkImage" id="image7"> - <property name="visible">True</property> - <property name="stock">gtk-index</property> - </widget> - </child> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="x_options"></property> - <property name="y_options"></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> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <widget class="GtkHBox" id="boxAthleteGraph"> - <property name="visible">True</property> - <child> - <placeholder/> - </child> - </widget> - <packing> - <property name="position">1</property> - </packing> - </child> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkLabel" id="label25"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>Detail</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">1</property> - </packing> - </child> - <child> - <widget class="GtkFrame" id="frame5"> - <property name="visible">True</property> - <property name="label_xalign">0</property> - <child> - <widget class="GtkAlignment" id="alignment12"> - <property name="visible">True</property> - <property name="left_padding">12</property> - <child> - <widget class="GtkVBox" id="boxAthleteHistory"> - <property name="visible">True</property> - <child> - <widget class="GtkScrolledWindow" id="scrolledwindow2"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hscrollbar_policy">automatic</property> - <property name="vscrollbar_policy">automatic</property> - <child> - <widget class="GtkTreeView" id="athleteTreeView"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <signal name="button_press_event" handler="on_athleteTreeView_button_press_event"/> - </widget> - </child> - </widget> - <packing> - <property name="position">0</property> - </packing> - </child> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkLabel" id="label24"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>History</b></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="type">label_item</property> - </packing> - </child> - </widget> - <packing> - <property name="padding">5</property> - <property name="position">2</property> - </packing> - </child> - </widget> - <packing> - <property name="position">0</property> - </packing> - </child> - </widget> - <packing> - <property name="position">3</property> - </packing> + <placeholder/> </child> <child> <placeholder/> Modified: pytrainer/trunk/pytrainer/gui/windowcalendar.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowcalendar.py 2010-10-14 20:46:47 UTC (rev 664) +++ pytrainer/trunk/pytrainer/gui/windowcalendar.py 2010-10-28 01:35:18 UTC (rev 665) @@ -17,32 +17,35 @@ #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. from SimpleGladeApp import SimpleGladeApp +import logging class WindowCalendar(SimpleGladeApp): - def __init__(self, data_path = None, parent = None, date = None): - self.parent = parent - glade_path="glade/calendar.glade" - root = "calendardialog" - domain = None - SimpleGladeApp.__init__(self, data_path+glade_path, root, domain) - if date is not None: - try: - year, month, day = date.split("-") - self.calendar.select_month( int(month)-1, int(year) ) - self.calendar.select_day( int(day) ) - except: - pass - - def on_accept_clicked(self,widget): - date = self.calendar.get_date() - date = "%0.4d-%0.2d-%0.2d" %(date[0],date[1]+1,date[2]) - self.parent.setDate(date) - self.close_window() + def __init__(self, data_path = None, parent = None, date = None): + logging.debug(">>") + self.parent = parent + glade_path="glade/calendar.glade" + root = "calendardialog" + domain = None + SimpleGladeApp.__init__(self, data_path+glade_path, root, domain) + if date is not None: + try: + year, month, day = date.split("-") + self.calendar.select_month( int(month)-1, int(year) ) + self.calendar.select_day( int(day) ) + except: + pass + logging.debug("<<") + + def on_accept_clicked(self,widget): + date = self.calendar.get_date() + date = "%0.4d-%0.2d-%0.2d" %(date[0],date[1]+1,date[2]) + self.parent.setDate(date) + self.close_window() - def on_cancel_clicked(self,widget): - self.close_window() + def on_cancel_clicked(self,widget): + self.close_window() - def close_window(self): - self.calendardialog.hide() - self.calendardialog = None - self.quit() + def close_window(self): + self.calendardialog.hide() + self.calendardialog = None + self.quit() Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-14 20:46:47 UTC (rev 664) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-28 01:35:18 UTC (rev 665) @@ -93,20 +93,34 @@ pass self.record_list = [] #create the columns for the listdayrecord - column_names=[_("id"),_("Start"), _("Sport"),_("Kilometer")] - self.create_treeview(self.recordTreeView,column_names) + columns = [{'name':_("id"), 'visible':False},{'name':_("Start"), }, {'name':_("Sport")},{'name':_("Kilometer")}] + 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 - #column_names=[_("id"),_("Title"),_("Date"),_("Distance"),_("Sport"),_("Time"),_("Beats"),_("Average"),("Calories")] - column_names=[_("id"),_("Title"),_("Date"),_("Distance"),_("Sport"),_("Time"),_(u"\u2300 HR"),_(u"\u2300 Speed"),("Calories")] - self.create_treeview(self.allRecordTreeView,column_names) - self.create_menulist(column_names) + columns=[ {'name':_("id"), 'visible':False}, + {'name':_("Title")}, + {'name':_("Date")}, + {'name':_("Distance"), 'xalign':1.0, 'format_float':'%.2f'}, + {'name':_("Sport")}, + {'name':_("Time"), 'xalign':1.0, 'format_duration':True}, + {'name':_(u"\u2300 HR"), 'xalign':1.0}, + {'name':_(u"\u2300 Speed"), 'xalign':1.0, 'format_float':'%.1f'}, + {'name':_("Calories"), 'xalign':1.0} + ] + self.create_treeview(self.allRecordTreeView,columns) + self.create_menulist(columns) #create the columns for the waypoints treeview - column_names=[_("id"),_("Waypoint")] - self.create_treeview(self.waypointTreeView,column_names) - #create the columns for the history treeview - column_names=[_("id"),_("Date"),_("Weight"),_("Body Fat %"),_("Resting HR"),_("Max HR")] - self.create_treeview(self.athleteTreeView,column_names) + columns=[{'name':_("id"), 'visible':False},{'name':_("Waypoint")}] + self.create_treeview(self.waypointTreeView,columns) + #create the columns for the athlete history treeview + columns=[ {'name':_("id"), 'visible':False}, + {'name':_("Date")}, + {'name':_("Weight"), 'xalign':1.0}, + {'name':_("Body Fat %"), 'xalign':1.0}, + {'name':_("Resting HR"), 'xalign':1.0}, + {'name':_("Max HR"), 'xalign':1.0} + ] + self.create_treeview(self.athleteTreeView,columns) self.fileconf = self.pytrainer_main.profile.confdir+"/listviewmenu.xml" if not os.path.isfile(self.fileconf): self._createXmlListView(self.fileconf) @@ -235,36 +249,30 @@ elif orig[:3] == ' 0:': new = orig[3:] cell.set_property('text', new) + + def render_float(self, column, cell, model, iter, format): + orig = cell.get_property('text') + new = format % float(orig) + cell.set_property('text', new) - def create_treeview(self,treeview,column_names): - i=0 - for column_index, column_name in enumerate(column_names): - #column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) - column = gtk.TreeViewColumn(column_name) + def create_treeview(self,treeview,columns): + for column_index, column_dict in enumerate(columns): + column = gtk.TreeViewColumn(column_dict['name']) renderer = gtk.CellRendererText() column.pack_start(renderer, expand=False) column.add_attribute(renderer, 'text', column_index) column.set_resizable(True) - column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) - if i in (3,5,6,7,8): - renderer.set_property('xalign', 1.0) - - if i == 0: - column.set_visible(False) - elif i == 3: # distance to 2 decimals - column.set_cell_data_func(renderer, - lambda column, cell, model, iter:cell.set_property('text', '%.2f' % - float(model.get_value(iter,column.get_sort_column_id())))) - elif i == 7: # speed to one decimal - column.set_cell_data_func(renderer, - lambda column, cell, model, iter:cell.set_property('text', '%.1f' % - float(model.get_value(iter,column.get_sort_column_id())))) - elif i == 5: # duration, erase leading zeros + column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) + if 'xalign' in column_dict: + renderer.set_property('xalign', column_dict['xalign']) + if 'visible' in column_dict: + column.set_visible(column_dict['visible']) + if 'format_float' in column_dict: + column.set_cell_data_func(renderer, self.render_float, column_dict['format_float']) + if 'format_duration' in column_dict and column_dict['format_duration']: column.set_cell_data_func(renderer, self.render_duration) - - column.set_sort_column_id(i) + column.set_sort_column_id(column_index) treeview.append_column(column) - i+=1 def actualize_recordview(self,activity): logging.debug(">>") @@ -893,7 +901,6 @@ self.labelDOB.set_text(athlete.age) self.labelHeight.set_text(athlete.height+" cm") - #TODO #Create history treeview history_store = gtk.ListStore( gobject.TYPE_STRING, #id @@ -911,7 +918,7 @@ history_store.set ( iter, 0, (data['id_athletestat']), - 1, date, #TODO need to sort date graphing... + 1, date, 2, weight, 3, (data['bodyfat']), 4, (data['restinghr']), @@ -1084,15 +1091,15 @@ self.listsearch.reset_lsa() self.parent.refreshListView(self.listsearch.condition) - def create_menulist(self,column_names): - i=0 - for name in column_names: - if i!=0: - item = gtk.CheckMenuItem(name) + def create_menulist(self,columns): + for i, column_dict in enumerate(columns): + if 'visible' in column_dict and not column_dict['visible']: + pass + else: + item = gtk.CheckMenuItem(column_dict['name']) #self.lsa_searchoption.append_text(name) item.connect("button_press_event", self.on_menulistview_activate, i) self.menulistviewOptions.append(item) - i+=1 self.menulistviewOptions.show_all() def on_menulistview_activate(self,widget,widget2,widget_position): @@ -1391,6 +1398,12 @@ self.selected_view="month" elif page == 4: self.selected_view="year" + elif page == 5: + self.selected_view="equipment" + elif page == 6: ... [truncated message content] |
From: <jb...@us...> - 2010-10-14 20:46:53
|
Revision: 664 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=664&view=rev Author: jblance Date: 2010-10-14 20:46:47 +0000 (Thu, 14 Oct 2010) Log Message: ----------- Formating improvements to List View from Arnd Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-13 22:30:44 UTC (rev 663) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-14 20:46:47 UTC (rev 664) @@ -227,17 +227,41 @@ self.sportlist.set_active(0) logging.debug("<<") + def render_duration(self, column, cell, model, iter): + orig = cell.get_property('text') + new = orig + if orig[:4] == ' 0:0': + new = orig[4:] + elif orig[:3] == ' 0:': + new = orig[3:] + cell.set_property('text', new) + def create_treeview(self,treeview,column_names): i=0 for column_index, column_name in enumerate(column_names): - column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) + #column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) + column = gtk.TreeViewColumn(column_name) + renderer = gtk.CellRendererText() + column.pack_start(renderer, expand=False) + column.add_attribute(renderer, 'text', column_index) column.set_resizable(True) - if i==0: + column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) + if i in (3,5,6,7,8): + renderer.set_property('xalign', 1.0) + + if i == 0: column.set_visible(False) - # experimental az - if column_name =='time': - print 'found Time' - column.set_alignment(0) + elif i == 3: # distance to 2 decimals + column.set_cell_data_func(renderer, + lambda column, cell, model, iter:cell.set_property('text', '%.2f' % + float(model.get_value(iter,column.get_sort_column_id())))) + elif i == 7: # speed to one decimal + column.set_cell_data_func(renderer, + lambda column, cell, model, iter:cell.set_property('text', '%.1f' % + float(model.get_value(iter,column.get_sort_column_id())))) + elif i == 5: # duration, erase leading zeros + column.set_cell_data_func(renderer, self.render_duration) + column.set_sort_column_id(i) treeview.append_column(column) i+=1 Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-13 22:30:44 UTC (rev 663) +++ pytrainer/trunk/pytrainer/main.py 2010-10-14 20:46:47 UTC (rev 664) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#663" + self.version ="1.7.2_svn#664" 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-13 22:30:51
|
Revision: 663 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=663&view=rev Author: jblance Date: 2010-10-13 22:30:44 +0000 (Wed, 13 Oct 2010) Log Message: ----------- Implement List view reset button (from Arnd) Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/lib/listview.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-10-12 22:18:45 UTC (rev 662) +++ pytrainer/trunk/glade/pytrainer.glade 2010-10-13 22:30:44 UTC (rev 663) @@ -1,4 +1,4 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="UTF-8"?> <glade-interface> <!-- interface-requires gtk+ 2.6 --> <!-- interface-naming-policy toplevel-contextual --> @@ -1326,7 +1326,7 @@ <widget class="GtkSpinButton" id="spinbuttonY1Min"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> <signal name="value_changed" handler="on_spinbuttonY1_value_changed"/> @@ -1344,7 +1344,7 @@ <widget class="GtkSpinButton" id="spinbuttonY1Max"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> <signal name="value_changed" handler="on_spinbuttonY1_value_changed"/> @@ -1407,7 +1407,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 1 10 1 1 0</property> <signal name="value_changed" handler="on_spinbuttonY1LineWeight_value_changed"/> </widget> @@ -1449,7 +1449,7 @@ <property name="sensitive">False</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1541,7 +1541,7 @@ <widget class="GtkSpinButton" id="spinbuttonY2Min"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -1558,7 +1558,7 @@ <widget class="GtkSpinButton" id="spinbuttonY2Max"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">1 -500 1000 1 10 0</property> </widget> @@ -1628,7 +1628,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1660,7 +1660,7 @@ <property name="sensitive">False</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1737,7 +1737,7 @@ <widget class="GtkSpinButton" id="spinbuttonXMin"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -1754,7 +1754,7 @@ <widget class="GtkSpinButton" id="spinbuttonXMax"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -5268,7 +5268,7 @@ <widget class="GtkEntry" id="lsa_searchvalue"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="expand">False</property> @@ -5340,6 +5340,19 @@ </packing> </child> <child> + <widget class="GtkButton" id="lsa_reset"> + <property name="label">gtk-clear</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="on_listareareset_clicked"/> + </widget> + <packing> + <property name="position">8</property> + </packing> + </child> + <child> <widget class="GtkMenuBar" id="listviewOptions"> <property name="visible">True</property> <child> @@ -5356,7 +5369,7 @@ <packing> <property name="expand">False</property> <property name="fill">False</property> - <property name="position">8</property> + <property name="position">9</property> </packing> </child> </widget> @@ -5557,7 +5570,7 @@ <widget class="GtkEntry" id="waypoint_longitude"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">3</property> @@ -5572,7 +5585,7 @@ <widget class="GtkEntry" id="waypoint_description"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -5587,7 +5600,7 @@ <widget class="GtkEntry" id="waypoint_latitude"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">3</property> @@ -5600,7 +5613,7 @@ <widget class="GtkEntry" id="waypoint_name"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -5845,7 +5858,7 @@ <widget class="GtkEntry" id="entryAthleteDate"> <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> @@ -5858,7 +5871,7 @@ <widget class="GtkEntry" id="entryAthleteWeight"> <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> @@ -5887,7 +5900,7 @@ <widget class="GtkEntry" id="entryAthleteBF"> <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> @@ -5902,7 +5915,7 @@ <widget class="GtkEntry" id="entryAthleteRestingHR"> <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> @@ -5931,7 +5944,7 @@ <widget class="GtkEntry" id="entryAthleteMaxHR"> <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> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-12 22:18:45 UTC (rev 662) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-13 22:30:44 UTC (rev 663) @@ -1055,6 +1055,10 @@ self.listsearch.duration = self.lsa_duration.get_active() self.listsearch.distance = self.lsa_distance.get_active() self.parent.refreshListView(self.listsearch.condition) + + def on_listareareset_clicked(self, widget): + self.listsearch.reset_lsa() + self.parent.refreshListView(self.listsearch.condition) def create_menulist(self,column_names): i=0 Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-12 22:18:45 UTC (rev 662) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-13 22:30:44 UTC (rev 663) @@ -341,14 +341,14 @@ ''' logging.debug('--') listOfRecords = self.select_dict("records",('id_record','time'), "duration is NULL") - print("Found %d records in DB without date_time_local field populated" % (len(listOfRecords) ) ) + logging.debug("Found %d records in DB without date_time_local field populated" % (len(listOfRecords) ) ) for record in listOfRecords: try: duration = int(record['time']) except Exception as e: - print "Error parsing time (%s) as int for record_id: %s" % (record['time'], record['id_record']) + logging.info( "Error parsing time (%s) as int for record_id: %s" % (record['time'], record['id_record'])) continue - print "setting record %s duration to %d" % (record['id_record'], duration) + logging.debug("setting record %s duration to %d" % (record['id_record'], duration)) data = {'duration': duration} self.update_dict("records",data ,"id_record = %d"%record['id_record']) Modified: pytrainer/trunk/pytrainer/lib/listview.py =================================================================== --- pytrainer/trunk/pytrainer/lib/listview.py 2010-10-12 22:18:45 UTC (rev 662) +++ pytrainer/trunk/pytrainer/lib/listview.py 2010-10-13 22:30:44 UTC (rev 663) @@ -87,7 +87,7 @@ else: _search = _here _add_and = True - print _search + #print _search return _search def get_listDistance(self): @@ -156,4 +156,16 @@ #Add handler manually, so above changes do not trigger recursive loop self.parent.lsa_distance.connect("changed", self.parent.on_listareasearch_clicked) + def reset_lsa(self): + """ Reset all query parameters to default values """ + self.title = '' + self.sport = 0 + self.past = 0 + self.duration = 0 + self.distance = 0 + self.parent.lsa_searchvalue.set_text('') + self.parent.lsa_sport.set_active(0) + self.parent.lsa_past.set_active(0) + self.parent.lsa_duration.set_active(0) + self.parent.lsa_distance.set_active(0) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-12 22:18:45 UTC (rev 662) +++ pytrainer/trunk/pytrainer/main.py 2010-10-13 22:30:44 UTC (rev 663) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#662" + self.version ="1.7.2_svn#663" 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-10-12 22:18:45 UTC (rev 662) +++ pytrainer/trunk/pytrainer/record.py 2010-10-13 22:30:44 UTC (rev 663) @@ -444,7 +444,7 @@ if condition is None: return self.getAllRecordList() else: - print "condition: ", condition + logging.debug("condition: %s" % condition) return self.pytrainer_main.ddbb.select("records,sports", "date,distance,average,title,sports.name,id_record,time,beats,calories", "sports.id_sports = records.sport and %s" %condition) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-10-12 22:18:51
|
Revision: 662 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=662&view=rev Author: jblance Date: 2010-10-12 22:18:45 +0000 (Tue, 12 Oct 2010) Log Message: ----------- Added duration (int) to record table, updated DB check to populate and newrecord to populate, updated listview to use duration instead of time Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/lib/listview.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-12 20:29:55 UTC (rev 661) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-12 22:18:45 UTC (rev 662) @@ -31,6 +31,7 @@ "sport":"integer", "distance":"float", "time":"varchar(200)", + "duration": "integer", "beats":"float", "average":"float", "calories":"int", @@ -313,6 +314,7 @@ #Run any functions to update or correct data #These functions _must_ be safe to run at any time (i.e. not be version specfic or only safe to run once) self.populate_date_time_local() + self.populate_duration_from_time() logging.debug('<<') def createDatabaseBackup(self): @@ -332,6 +334,23 @@ for table in tablesList.keys(): pass + def populate_duration_from_time(self): + ''' + Populate duration from time field + only for empty durations and where time can be parsed as an int + ''' + logging.debug('--') + listOfRecords = self.select_dict("records",('id_record','time'), "duration is NULL") + print("Found %d records in DB without date_time_local field populated" % (len(listOfRecords) ) ) + for record in listOfRecords: + try: + duration = int(record['time']) + except Exception as e: + print "Error parsing time (%s) as int for record_id: %s" % (record['time'], record['id_record']) + continue + print "setting record %s duration to %d" % (record['id_record'], duration) + data = {'duration': duration} + self.update_dict("records",data ,"id_record = %d"%record['id_record']) def populate_date_time_local(self): ''' Populate date_time_local and date from date_time_utc Modified: pytrainer/trunk/pytrainer/lib/listview.py =================================================================== --- pytrainer/trunk/pytrainer/lib/listview.py 2010-10-12 20:29:55 UTC (rev 661) +++ pytrainer/trunk/pytrainer/lib/listview.py 2010-10-12 22:18:45 UTC (rev 662) @@ -72,7 +72,7 @@ if self.listDuration[self.duration][1]: _dur_min = int(self.listDuration[self.duration][1][0]) _dur_max = int(self.listDuration[self.duration][1][1]) - _here = "(time between %s and %s)" % (_dur_min, _dur_max) + _here = "(duration between %s and %s)" % (_dur_min, _dur_max) if _add_and: _search += " and " + _here else: Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-12 20:29:55 UTC (rev 661) +++ pytrainer/trunk/pytrainer/main.py 2010-10-12 22:18:45 UTC (rev 662) @@ -50,8 +50,8 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#661" - self.DB_version = 5 + self.version ="1.7.2_svn#662" + self.DB_version = 6 #Process command line options self.startup_options = self.get_options() #Setup logging Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2010-10-12 20:29:55 UTC (rev 661) +++ pytrainer/trunk/pytrainer/record.py 2010-10-12 22:18:45 UTC (rev 662) @@ -144,7 +144,7 @@ logging.debug('>>') time = self.date.time2second(list_options["rcd_time"]) average = self.parseFloatRecord(list_options["rcd_average"]) - keys= "date,sport,distance,time,beats,comments,average,calories,title,upositive,unegative,maxspeed,maxpace,pace,maxbeats,date_time_utc,date_time_local" + keys= "date,sport,distance,time,beats,comments,average,calories,title,upositive,unegative,maxspeed,maxpace,pace,maxbeats,date_time_utc,date_time_local, duration" if (list_options["rcd_beats"] == ""): list_options["rcd_beats"] = 0 @@ -169,6 +169,7 @@ self.parseFloatRecord(list_options["rcd_maxbeats"]), list_options["date_time_utc"], list_options["date_time_local"], + time, ) logging.debug('<<') return keys,values @@ -443,6 +444,7 @@ if condition is None: return self.getAllRecordList() else: + print "condition: ", condition return self.pytrainer_main.ddbb.select("records,sports", "date,distance,average,title,sports.name,id_record,time,beats,calories", "sports.id_sports = records.sport and %s" %condition) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-10-12 20:30:02
|
Revision: 661 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=661&view=rev Author: jblance Date: 2010-10-12 20:29:55 +0000 (Tue, 12 Oct 2010) Log Message: ----------- Committing Arnd updates to listview Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/listview.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-10-12 10:30:51 UTC (rev 660) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-12 20:29:55 UTC (rev 661) @@ -1054,7 +1054,7 @@ self.listsearch.past = self.lsa_past.get_active() self.listsearch.duration = self.lsa_duration.get_active() self.listsearch.distance = self.lsa_distance.get_active() - self.parent.searchListView(self.listsearch.condition) + self.parent.refreshListView(self.listsearch.condition) def create_menulist(self,column_names): i=0 @@ -1444,7 +1444,8 @@ self.classicarea.hide() self.athletearea.hide() self.selected_view = "listview" - self.parent.refreshListView() + #self.parent.refreshListView() + self.parent.refreshListView(self.listsearch.condition) self.listarea.show() def on_athleteview_activate(self,widget): Modified: pytrainer/trunk/pytrainer/lib/listview.py =================================================================== --- pytrainer/trunk/pytrainer/lib/listview.py 2010-10-12 10:30:51 UTC (rev 660) +++ pytrainer/trunk/pytrainer/lib/listview.py 2010-10-12 20:29:55 UTC (rev 661) @@ -9,10 +9,12 @@ def __init__(self, parent = None, pytrainer_main = None): self.parent = parent self.pytrainer_main = pytrainer_main + """ Initialize all query parameters to valid default values""" self.title = '' self.sport = 0 - self.past = None - self.duration = None + self.past = 0 + self.duration = 0 + self.distance = 0 self.listSport = self.pytrainer_main.profile.getSportList() self.listPast = [['All Time', -99999], ['Last 4 Weeks', -31], ['Last 6 Months', -183], ['Last 12 Months', -366]] @@ -20,7 +22,16 @@ ['<1 Hour', [0,3600]], ['1-2 Hours', [3600,7200]], ['>2 Hours', [7200,999999]]] - + + #if self.pytrainer_main.profile.prf_us_system == True: + self.listDistanceUS = [['All Distances', [0.0,999999.9]], + ['<1 mi', [0.0, 1.609344]], + ['1-5 mi', [1.609344, 8.04672]], + ['5-10 mi', [8.04672, 16.09344]], + ['10-20 mi', [16.09344, 32.18688]], + ['20-50 mi', [32.18688, 80.4672]], + ['>50 mi', [80.4672, 999999.9]]] + self.listDistance = [['All Distances', [0.0,999999.9]], ['<1 km', [0.0, 1.0]], ['1-5 km', [1.0, 5.0]], Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-12 10:30:51 UTC (rev 660) +++ pytrainer/trunk/pytrainer/main.py 2010-10-12 20:29:55 UTC (rev 661) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#660" + self.version ="1.7.2_svn#661" self.DB_version = 5 #Process command line options self.startup_options = self.get_options() @@ -298,7 +298,8 @@ def refreshListRecords(self): logging.debug('>>') #Refresh list view - self.refreshListView() + #self.refreshListView() # old variant + self.refreshListView(self.windowmain.listsearch.condition) #Refresh list records date = self.date.getDate() record_list = self.record.getrecordList(date) @@ -312,25 +313,19 @@ self.athlete.refresh() self.windowmain.actualize_athleteview(self.athlete) logging.debug('<<') - - def refreshListView(self): + + def refreshListView(self,condition=None): logging.debug('>>') - record_list = self.record.getAllRecordList() + 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() self.windowmain.actualize_waypointview(waypoint_list,default_waypoint,redrawmap) logging.debug('<<') - def searchListView(self,condition): - logging.debug('>>') - record_list = self.record.getRecordListByCondition(condition) - self.windowmain.actualize_listview(record_list) - logging.debug('<<') - def editExtensions(self): logging.debug('>>') before = self.extension.getActiveExtensions() Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2010-10-12 10:30:51 UTC (rev 660) +++ pytrainer/trunk/pytrainer/record.py 2010-10-12 20:29:55 UTC (rev 661) @@ -440,9 +440,12 @@ def getRecordListByCondition(self,condition): logging.debug('--') - return self.pytrainer_main.ddbb.select("records,sports", - "date,distance,average,title,sports.name,id_record,time,beats,calories", - "sports.id_sports = records.sport and %s" %condition) + if condition is None: + return self.getAllRecordList() + else: + return self.pytrainer_main.ddbb.select("records,sports", + "date,distance,average,title,sports.name,id_record,time,beats,calories", + "sports.id_sports = records.sport and %s" %condition) def getRecordDayList(self,date): 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-12 10:30:58
|
Revision: 660 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=660&view=rev Author: jblance Date: 2010-10-12 10:30:51 +0000 (Tue, 12 Oct 2010) Log Message: ----------- Fix for GPX files with no lap info Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/gpx.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py Modified: pytrainer/trunk/pytrainer/lib/gpx.py =================================================================== --- pytrainer/trunk/pytrainer/lib/gpx.py 2010-10-12 09:56:48 UTC (rev 659) +++ pytrainer/trunk/pytrainer/lib/gpx.py 2010-10-12 10:30:51 UTC (rev 660) @@ -49,373 +49,382 @@ distanceTag = gpxdataNS.substitute(tag="distance") class Gpx: - def __init__(self, data_path = None, filename = None, trkname = None): - logging.debug(">>") - #print("GPX init-ing") - global mainNS, timeTag, trackTag, trackPointTag, trackPointTagLast, trackSegTag, elevationTag, nameTag - self.data_path = data_path - self.filename = filename - self.trkname = trkname - logging.debug(str(data_path)+"|"+str(filename)+"|"+str(trkname)) - self.trkpoints = [] - self.vel_array = [] - self.total_dist = 0 - self.total_time = 0 - self.upositive = 0 - self.unegative = 0 - self.maxvel = 0 - self.maxhr = 0 - self.hr_average = 0 - self.date = "" - #self.Date = Date() - self.calories= 0 - self.tree = None - if filename != None: - if not os.path.isfile(self.filename): - return None - logging.debug("parsing content from "+self.filename) - self.tree = etree.ElementTree(file=filename).getroot() - if self.tree.get("version") == "1.0": - #Got an old GPX file - logging.debug("Old gpx version") - mainNS = string.Template(".//{http://www.topografix.com/GPX/1/0}$tag") - timeTag = mainNS.substitute(tag="time") - trackTag = mainNS.substitute(tag="trk") - trackPointTag = mainNS.substitute(tag="trkpt") - trackPointTagLast = mainNS.substitute(tag="trkpt[last()]") - trackSegTag = mainNS.substitute(tag="trkseg") - elevationTag = mainNS.substitute(tag="ele") - nameTag = mainNS.substitute(tag="name") - else: - logging.debug("Importing version %s gpx file" % self.tree.get("version")) - mainNS = string.Template(".//{http://www.topografix.com/GPX/1/1}$tag") - timeTag = mainNS.substitute(tag="time") - trackTag = mainNS.substitute(tag="trk") - trackPointTag = mainNS.substitute(tag="trkpt") - trackPointTagLast = mainNS.substitute(tag="trkpt[last()]") - trackSegTag = mainNS.substitute(tag="trkseg") - elevationTag = mainNS.substitute(tag="ele") - nameTag = mainNS.substitute(tag="name") + def __init__(self, data_path = None, filename = None, trkname = None): + logging.debug(">>") + #print("GPX init-ing") + global mainNS, timeTag, trackTag, trackPointTag, trackPointTagLast, trackSegTag, elevationTag, nameTag + self.data_path = data_path + self.filename = filename + self.trkname = trkname + logging.debug(str(data_path)+"|"+str(filename)+"|"+str(trkname)) + self.trkpoints = [] + self.vel_array = [] + self.total_dist = 0 + self.total_time = 0 + self.upositive = 0 + self.unegative = 0 + self.maxvel = 0 + self.maxhr = 0 + self.hr_average = 0 + self.date = "" + #self.Date = Date() + self.calories= 0 + self.tree = None + if filename != None: + if not os.path.isfile(self.filename): + return None + logging.debug("parsing content from "+self.filename) + self.tree = etree.ElementTree(file=filename).getroot() + if self.tree.get("version") == "1.0": + #Got an old GPX file + logging.debug("Old gpx version") + mainNS = string.Template(".//{http://www.topografix.com/GPX/1/0}$tag") + timeTag = mainNS.substitute(tag="time") + trackTag = mainNS.substitute(tag="trk") + trackPointTag = mainNS.substitute(tag="trkpt") + trackPointTagLast = mainNS.substitute(tag="trkpt[last()]") + trackSegTag = mainNS.substitute(tag="trkseg") + elevationTag = mainNS.substitute(tag="ele") + nameTag = mainNS.substitute(tag="name") + else: + logging.debug("Importing version %s gpx file" % self.tree.get("version")) + mainNS = string.Template(".//{http://www.topografix.com/GPX/1/1}$tag") + timeTag = mainNS.substitute(tag="time") + trackTag = mainNS.substitute(tag="trk") + trackPointTag = mainNS.substitute(tag="trkpt") + trackPointTagLast = mainNS.substitute(tag="trkpt[last()]") + trackSegTag = mainNS.substitute(tag="trkseg") + elevationTag = mainNS.substitute(tag="ele") + nameTag = mainNS.substitute(tag="name") - logging.debug("getting values...") - self.Values = self._getValues() - logging.debug("<<") + logging.debug("getting values...") + self.Values = self._getValues() + logging.debug("<<") - def getMaxValues(self): - return self.total_dist, self.total_time, self.maxvel, self.maxhr + def getMaxValues(self): + return self.total_dist, self.total_time, self.maxvel, self.maxhr - def getDate(self): - return self.date + def getDate(self): + return self.date - def getTrackRoutes(self): - trks = self.tree.findall(trackTag) - tracks = [] - retorno = [] - for trk in trks: - nameResult = trk.find(nameTag) - if nameResult is not None: - name = nameResult.text - else: - name = _("No Name") - timeResult = trk.find(timeTag) - if timeResult is not None: - time_ = timeResult.text # check timezone - mk_time = self.getDateTime(time_)[0] - time_ = mk_time.strftime("%Y-%m-%d") - else: - time_ = _("No Data") - logging.debug("name: "+name+" | time: "+time_) - tracks.append((name,time_)) - return tracks + def getTrackRoutes(self): + trks = self.tree.findall(trackTag) + tracks = [] + retorno = [] + for trk in trks: + nameResult = trk.find(nameTag) + if nameResult is not None: + name = nameResult.text + else: + name = _("No Name") + timeResult = trk.find(timeTag) + if timeResult is not None: + time_ = timeResult.text # check timezone + mk_time = self.getDateTime(time_)[0] + time_ = mk_time.strftime("%Y-%m-%d") + else: + time_ = _("No Data") + logging.debug("name: "+name+" | time: "+time_) + tracks.append((name,time_)) + return tracks - def getDateTime(self, time_): - return Date().getDateTime(time_) + def getDateTime(self, time_): + return Date().getDateTime(time_) - def getUnevenness(self): - return self.upositive,self.unegative + def getUnevenness(self): + return self.upositive,self.unegative - def getTrackList(self): - return self.Values + def getTrackList(self): + return self.Values - def getHeartRateAverage(self): - return self.hr_average + def getHeartRateAverage(self): + return self.hr_average - def getCalories(self): - return self.calories + def getCalories(self): + return self.calories - def getLaps(self): - logging.debug(">>") - lapInfo = [] - if self.tree is None: - return lapInfo - tree = self.tree - laps = tree.findall(lapTag) - logging.debug("Found %d laps" % len(laps)) - for lap in laps: - endPoint = lap.find(endPointTag) - lat = endPoint.get("lat") - lon = endPoint.get("lon") - startPoint = lap.find(startPointTag) - if startPoint is not None: - stLat = startPoint.get("lat") - stLon = startPoint.get("lon") - else: - stLat, stLon = "","" - elapsedTime = lap.findtext(elapsedTimeTag) - if elapsedTime.count(":") == 2: # got a 0:41:42.14 type elasped time - hours, mins, secs = elapsedTime.split(":") - elapsedTime = (int(hours) *3600) + (int(mins) * 60) + float(secs) - #print elapsedTime - calories = lap.findtext(calorieTag) - distance = lap.findtext(distanceTag) - logging.debug("Found time: %s, lat: %s lon: %s cal: %s dist: %s " % (elapsedTime, lat, lon, calories, distance)) - lapInfo.append((elapsedTime, lat, lon, calories, distance, stLat, stLon)) - logging.debug("<<") - return lapInfo + def getLaps(self): + logging.debug(">>") + lapInfo = [] + if self.tree is None: + return lapInfo + tree = self.tree + laps = tree.findall(lapTag) + logging.debug("Found %d laps" % len(laps)) + if len(laps) == 0: + #Found no laps, so add single lap with totals + stLat = self.trkpoints[0]['lat'] + stLon = self.trkpoints[0]['lon'] + lat = self.trkpoints[-1]['lat'] + lon = self.trkpoints[-1]['lon'] + #print ((self.total_time, lat, lon, self.calories, self.total_dist, stLat, stLon)) + lapInfo.append((self.total_time, lat, lon, self.calories, self.total_dist*1000, stLat, stLon)) + else: + for lap in laps: + endPoint = lap.find(endPointTag) + lat = endPoint.get("lat") + lon = endPoint.get("lon") + startPoint = lap.find(startPointTag) + if startPoint is not None: + stLat = startPoint.get("lat") + stLon = startPoint.get("lon") + else: + stLat, stLon = "","" + elapsedTime = lap.findtext(elapsedTimeTag) + if elapsedTime.count(":") == 2: # got a 0:41:42.14 type elasped time + hours, mins, secs = elapsedTime.split(":") + elapsedTime = (int(hours) *3600) + (int(mins) * 60) + float(secs) + #print elapsedTime + calories = lap.findtext(calorieTag) + distance = lap.findtext(distanceTag) + logging.debug("Found time: %s, lat: %s lon: %s cal: %s dist: %s " % (elapsedTime, lat, lon, calories, distance)) + lapInfo.append((elapsedTime, lat, lon, calories, distance, stLat, stLon)) + logging.debug("<<") + return lapInfo - def _getValues(self): - ''' - Migrated to eTree XML processing 26 Nov 2009 - jblance - ''' - logging.debug(">>") - tree = self.tree - # Calories data comes within laps. Maybe more than one, adding them together - dgranda 20100114 - laps = tree.findall(lapTag) - if laps is not None and laps != "": - for lap in laps: - lapCalories = lap.findtext(calorieTag) - logging.debug("Lap calories: "+str(lapCalories)) - self.calories += int(lapCalories) - logging.debug("Calories: "+str(self.calories)) - else: - laps = [] + def _getValues(self): + ''' + Migrated to eTree XML processing 26 Nov 2009 - jblance + ''' + logging.debug(">>") + tree = self.tree + # Calories data comes within laps. Maybe more than one, adding them together - dgranda 20100114 + laps = tree.findall(lapTag) + if laps is not None and laps != "": + for lap in laps: + lapCalories = lap.findtext(calorieTag) + logging.debug("Lap calories: "+str(lapCalories)) + self.calories += int(lapCalories) + logging.debug("Calories: "+str(self.calories)) + else: + laps = [] - retorno = [] - his_vel = [] - last_lat = None - last_lon = None - last_time = None - total_dist = 0 - dist_elapsed = 0 # distance since the last time found - total_hr = 0 - tmp_alt = 0 - len_validhrpoints = 0 - trkpoints = tree.findall(trackPointTag) - if trkpoints is None or len(trkpoints) == 0: - logging.debug( "No trkpoints found in file") - return retorno - logging.debug("%d trkpoints in file" % len(trkpoints)) + retorno = [] + his_vel = [] + last_lat = None + last_lon = None + last_time = None + total_dist = 0 + dist_elapsed = 0 # distance since the last time found + total_hr = 0 + tmp_alt = 0 + len_validhrpoints = 0 + trkpoints = tree.findall(trackPointTag) + if trkpoints is None or len(trkpoints) == 0: + logging.debug( "No trkpoints found in file") + return retorno + logging.debug("%d trkpoints in file" % len(trkpoints)) - date_ = tree.find(timeTag).text - #mk_time = self.getDateTime(date_)[0] #UTC Date - mk_time = self.getDateTime(date_)[1] #Local Date - self.date = mk_time.strftime("%Y-%m-%d") - waiting_points = [] + date_ = tree.find(timeTag).text + #mk_time = self.getDateTime(date_)[0] #UTC Date + mk_time = self.getDateTime(date_)[1] #Local Date + self.date = mk_time.strftime("%Y-%m-%d") + waiting_points = [] - for i, trkpoint in enumerate(trkpoints): - #Get data from trkpoint - try: - lat = float(trkpoint.get("lat")) - lon = float(trkpoint.get("lon")) - except Exception as e: - logging.debug(str(e)) - lat = lon = None - if lat is None or lat == "" or lat == 0 or lon is None or lon == "" or lon == 0: - logging.debug("lat or lon is blank or zero") - continue - #get the heart rate value from the gpx extended format file - hrResult = trkpoint.find(hrTag) - if hrResult is not None: - hr = int(hrResult.text) - len_validhrpoints += 1 - total_hr += hr #TODO fix - if hr>self.maxhr: - self.maxhr = hr - else: - hr = None - #get the cadence (if present) - cadResult = trkpoint.find(cadTag) - if cadResult is not None: - cadence = int(cadResult.text) - else: - cadence = None - #get the time - timeResult = trkpoint.find(timeTag) - if timeResult is not None: - date_ = timeResult.text - mk_time = self.getDateTime(date_)[0] - time_ = time.mktime(mk_time.timetuple()) #Convert date to seconds - if i == 0: - time_elapsed = 0 - else: - time_elapsed = time_ - self.trkpoints[i-1]['time'] if self.trkpoints[i-1]['time'] is not None else 0 - self.total_time += time_elapsed - else: - time_ = None - time_elapsed = None - #get the elevation - eleResult = trkpoint.find(elevationTag) - rel_alt = 0 - if eleResult is not None: - try: - ele = float(eleResult.text) - #Calculate elevation change - if i != 0: - rel_alt = ele - self.trkpoints[i-1]['ele'] if self.trkpoints[i-1]['ele'] is not None else 0 - except Exception as e: - logging.debug(str(e)) - ele = None - else: - ele = None + for i, trkpoint in enumerate(trkpoints): + #Get data from trkpoint + try: + lat = float(trkpoint.get("lat")) + lon = float(trkpoint.get("lon")) + except Exception as e: + logging.debug(str(e)) + lat = lon = None + if lat is None or lat == "" or lat == 0 or lon is None or lon == "" or lon == 0: + logging.debug("lat or lon is blank or zero") + continue + #get the heart rate value from the gpx extended format file + hrResult = trkpoint.find(hrTag) + if hrResult is not None: + hr = int(hrResult.text) + len_validhrpoints += 1 + total_hr += hr #TODO fix + if hr>self.maxhr: + self.maxhr = hr + else: + hr = None + #get the cadence (if present) + cadResult = trkpoint.find(cadTag) + if cadResult is not None: + cadence = int(cadResult.text) + else: + cadence = None + #get the time + timeResult = trkpoint.find(timeTag) + if timeResult is not None: + date_ = timeResult.text + mk_time = self.getDateTime(date_)[0] + time_ = time.mktime(mk_time.timetuple()) #Convert date to seconds + if i == 0: + time_elapsed = 0 + else: + time_elapsed = time_ - self.trkpoints[i-1]['time'] if self.trkpoints[i-1]['time'] is not None else 0 + self.total_time += time_elapsed + else: + time_ = None + time_elapsed = None + #get the elevation + eleResult = trkpoint.find(elevationTag) + rel_alt = 0 + if eleResult is not None: + try: + ele = float(eleResult.text) + #Calculate elevation change + if i != 0: + rel_alt = ele - self.trkpoints[i-1]['ele'] if self.trkpoints[i-1]['ele'] is not None else 0 + except Exception as e: + logging.debug(str(e)) + ele = None + else: + ele = None - #Calculate climb or decent amount - #Allow for some 'jitter' in height here - JITTER_VALUE = 0 #Elevation changes less than this value are not counted in +- - if abs(rel_alt) < JITTER_VALUE: - rel_alt = 0 - if rel_alt > 0: - self.upositive += rel_alt - elif rel_alt < 0: - self.unegative -= rel_alt + #Calculate climb or decent amount + #Allow for some 'jitter' in height here + JITTER_VALUE = 0 #Elevation changes less than this value are not counted in +- + if abs(rel_alt) < JITTER_VALUE: + rel_alt = 0 + if rel_alt > 0: + self.upositive += rel_alt + elif rel_alt < 0: + self.unegative -= rel_alt - #Calculate distance between two points - if i == 0: #First point - dist = None - else: - dist = self._distance_between_points(lat1=self.trkpoints[i-1]['lat'], lon1=self.trkpoints[i-1]['lon'], lat2=lat, lon2=lon) + #Calculate distance between two points + if i == 0: #First point + dist = None + else: + dist = self._distance_between_points(lat1=self.trkpoints[i-1]['lat'], lon1=self.trkpoints[i-1]['lon'], lat2=lat, lon2=lon) - #Accumulate distances - if dist is not None: - dist_elapsed += dist #TODO fix - total_dist += dist + #Accumulate distances + if dist is not None: + dist_elapsed += dist #TODO fix + total_dist += dist - #Calculate speed... - vel = self._calculate_speed(dist, time_elapsed, smoothing_factor=3) - if vel>self.maxvel: - self.maxvel=vel + #Calculate speed... + vel = self._calculate_speed(dist, time_elapsed, smoothing_factor=3) + if vel>self.maxvel: + self.maxvel=vel - #The waiting point stuff.... - #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: - 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)) - waiting_points = [] - dist_elapsed = 0 - else: - retorno.append((total_dist,ele, self.total_time,vel,lat,lon,hr,cadence)) - dist_elapsed = 0 - else: # time_ is None - waiting_points.append((total_dist, dist_elapsed, ele, self.total_time, lat, lon, hr, cadence)) + #The waiting point stuff.... + #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: + 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)) + waiting_points = [] + dist_elapsed = 0 + else: + retorno.append((total_dist,ele, self.total_time,vel,lat,lon,hr,cadence)) + dist_elapsed = 0 + else: # time_ is None + waiting_points.append((total_dist, dist_elapsed, ele, self.total_time, lat, lon, hr, cadence)) - #Add to dict of values to trkpoint list - self.trkpoints.append({ 'id': i, - 'lat':lat, - 'lon':lon, - 'hr':hr, - 'cadence':cadence, - 'time':time_, - 'time_since_previous': time_elapsed, - 'time_elapsed': self.total_time, - 'ele':ele, - 'ele_change': rel_alt, - 'distance_from_previous': dist, - 'elapsed_distance': total_dist, - 'velocity':vel, + #Add to dict of values to trkpoint list + self.trkpoints.append({ 'id': i, + 'lat':lat, + 'lon':lon, + 'hr':hr, + 'cadence':cadence, + 'time':time_, + 'time_since_previous': time_elapsed, + 'time_elapsed': self.total_time, + 'ele':ele, + 'ele_change': rel_alt, + 'distance_from_previous': dist, + 'elapsed_distance': total_dist, + 'velocity':vel, - }) + }) - #end of for trkpoint in trkpoints loop + #end of for trkpoint in trkpoints loop - #Calculate averages etc - self.hr_average = 0 - if len_validhrpoints > 0: - self.hr_average = total_hr/len_validhrpoints - self.total_dist = total_dist - logging.debug("<<") - return retorno + #Calculate averages etc + self.hr_average = 0 + if len_validhrpoints > 0: + self.hr_average = total_hr/len_validhrpoints + self.total_dist = total_dist + logging.debug("<<") + return retorno - def _distance_between_points(self, lat1, lon1, lat2, lon2): - ''' - Function to calculate the distance between two lat, lon points on the earths surface + def _distance_between_points(self, lat1, lon1, lat2, lon2): + ''' + Function to calculate the distance between two lat, lon points on the earths surface - History of this function is unknown.... - -- David "no me mates que esto lo escribi hace anhos" - -- http://faculty.washington.edu/blewis/ocn499/EXER04.htm equation for the distance between 2 points on a spherical earth - -- 0.01745329252 = number of radians in a degree - -- 57.29577951 = 1/0.01745329252 or degrees per radian - requires - - start lat and lon as floats - - finish lat and lon as floats + History of this function is unknown.... + -- David "no me mates que esto lo escribi hace anhos" + -- http://faculty.washington.edu/blewis/ocn499/EXER04.htm equation for the distance between 2 points on a spherical earth + -- 0.01745329252 = number of radians in a degree + -- 57.29577951 = 1/0.01745329252 or degrees per radian + requires + - start lat and lon as floats + - finish lat and lon as floats - returns - - distance between points in kilometers if successful - - None if any error situation occurs - ''' - RADIANS_PER_DEGREE = 0.01745329252 - DEGREES_PER_RADIAN = 57.29577951 - #Check for invalid variables - for var in (lat1, lon1, lat2, lon2): - if var is None or var == 0 or var == "": #TODO Need this?? if (float(lat) < -0.000001) or (float(lat) > 0.0000001): - return None - if type(var) is not type(float()): - return None - #Convert lat and lon from degrees to radians - last_lat = lat1*RADIANS_PER_DEGREE - last_lon = lon1*RADIANS_PER_DEGREE - tmp_lat = lat2*RADIANS_PER_DEGREE - tmp_lon = lon2*RADIANS_PER_DEGREE - #Pasamos la distancia de radianes a metros.. creo / We convert the distance from radians to meters - try: - dist=math.acos((math.sin(last_lat)*math.sin(tmp_lat))+(math.cos(last_lat)*math.cos(tmp_lat)*math.cos(tmp_lon-last_lon)))*111.302*DEGREES_PER_RADIAN - except Exception as e: - logging.debug(str(e)) - dist=None - return dist + returns + - distance between points in kilometers if successful + - None if any error situation occurs + ''' + RADIANS_PER_DEGREE = 0.01745329252 + DEGREES_PER_RADIAN = 57.29577951 + #Check for invalid variables + for var in (lat1, lon1, lat2, lon2): + if var is None or var == 0 or var == "": #TODO Need this?? if (float(lat) < -0.000001) or (float(lat) > 0.0000001): + return None + if type(var) is not type(float()): + return None + #Convert lat and lon from degrees to radians + last_lat = lat1*RADIANS_PER_DEGREE + last_lon = lon1*RADIANS_PER_DEGREE + tmp_lat = lat2*RADIANS_PER_DEGREE + tmp_lon = lon2*RADIANS_PER_DEGREE + #Pasamos la distancia de radianes a metros.. creo / We convert the distance from radians to meters + try: + dist=math.acos((math.sin(last_lat)*math.sin(tmp_lat))+(math.cos(last_lat)*math.cos(tmp_lat)*math.cos(tmp_lon-last_lon)))*111.302*DEGREES_PER_RADIAN + except Exception as e: + logging.debug(str(e)) + dist=None + return dist - def _calculate_speed(self, dist_elapsed, time_elapsed, smoothing_factor=3): - '''Function to calculate moving average for speed''' + def _calculate_speed(self, dist_elapsed, time_elapsed, smoothing_factor=3): + '''Function to calculate moving average for speed''' - if dist_elapsed is None or dist_elapsed == 0 or time_elapsed is None or time_elapsed == 0: - velocity = 0 - else: - velocity = (dist_elapsed/time_elapsed) * 3600 # 3600 to convert km/sec to km/hour - self.vel_array.append(velocity) - if len(self.vel_array)>smoothing_factor: - self.vel_array.pop(0) - if len(self.vel_array)<smoothing_factor: - #Got too few numbers to average - #Pad with duplicates - for x in range(len(self.vel_array), smoothing_factor): - self.vel_array.append(velocity) - vel = 0 - for v in self.vel_array: - vel+= v - vel /= smoothing_factor - return vel + if dist_elapsed is None or dist_elapsed == 0 or time_elapsed is None or time_elapsed == 0: + velocity = 0 + else: + velocity = (dist_elapsed/time_elapsed) * 3600 # 3600 to convert km/sec to km/hour + self.vel_array.append(velocity) + if len(self.vel_array)>smoothing_factor: + self.vel_array.pop(0) + if len(self.vel_array)<smoothing_factor: + #Got too few numbers to average + #Pad with duplicates + for x in range(len(self.vel_array), smoothing_factor): + self.vel_array.append(velocity) + vel = 0 + for v in self.vel_array: + vel+= v + vel /= smoothing_factor + return vel - def getStartTimeFromGPX(self, gpxFile): - '''03.05.2008 - dgranda - Retrieves start time from a given gpx file - args: - - gpxFile: path to xml file (gpx format) - returns: tuple (string with start time as UTC timezone - 2008-03-22T12:17:43Z, datetime of time in local timezone) - ''' - logging.debug(">>") - date_time = self.tree.find(timeTag) #returns first instance found - if date_time is None: - print "Problems when retrieving start time from "+gpxFile+". Please check data integrity" - return 0 - dateTime = self.getDateTime(date_time.text) - zuluDateTime = dateTime[0].strftime("%Y-%m-%dT%H:%M:%SZ") - localDateTime = dateTime[1] - logging.debug(gpxFile+" | "+ date_time.text +" | " + zuluDateTime + " | " + str(localDateTime)) - #print localDateTime - #return date_time.text - logging.debug("<<") - return (zuluDateTime, localDateTime) + def getStartTimeFromGPX(self, gpxFile): + '''03.05.2008 - dgranda + Retrieves start time from a given gpx file + args: + - gpxFile: path to xml file (gpx format) + returns: tuple (string with start time as UTC timezone - 2008-03-22T12:17:43Z, datetime of time in local timezone) + ''' + logging.debug(">>") + date_time = self.tree.find(timeTag) #returns first instance found + if date_time is None: + print "Problems when retrieving start time from "+gpxFile+". Please check data integrity" + return 0 + dateTime = self.getDateTime(date_time.text) + zuluDateTime = dateTime[0].strftime("%Y-%m-%dT%H:%M:%SZ") + localDateTime = dateTime[1] + logging.debug(gpxFile+" | "+ date_time.text +" | " + zuluDateTime + " | " + str(localDateTime)) + #print localDateTime + #return date_time.text + logging.debug("<<") + return (zuluDateTime, localDateTime) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-12 09:56:48 UTC (rev 659) +++ pytrainer/trunk/pytrainer/main.py 2010-10-12 10:30:51 UTC (rev 660) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#658" + self.version ="1.7.2_svn#660" self.DB_version = 5 #Process command line options self.startup_options = self.get_options() Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2010-10-12 09:56:48 UTC (rev 659) +++ pytrainer/trunk/pytrainer/record.py 2010-10-12 10:30:51 UTC (rev 660) @@ -117,7 +117,7 @@ ) logging.debug('<<') return cells,values - + def pace_to_float(self, value): '''Take a mm:ss or mm.ss and return float''' value = value.replace(':', '.') @@ -126,7 +126,7 @@ 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 @@ -336,6 +336,7 @@ "record=\"%s\"" % id_record) if laps is None or laps == []: #No laps stored - update DB logging.debug("No laps in DB for record %d" % id_record) + #print ("No laps in DB for record %d" % id_record) gpx_dest = self.pytrainer_main.profile.gpxdir gpxfile = gpx_dest+"/%d.gpx"%id_record gpx = Gpx(self.data_path,gpxfile) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-10-12 09:56:54
|
Revision: 659 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=659&view=rev Author: jblance Date: 2010-10-12 09:56:48 +0000 (Tue, 12 Oct 2010) Log Message: ----------- Fix error in select_dict Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/ddbb.py Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-12 09:26:33 UTC (rev 658) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-12 09:56:48 UTC (rev 659) @@ -180,21 +180,19 @@ #TODO need to check if multivalue cell type specified # eg integer primary key autoincrement #print "Checking if %s is of type %s" % (value, cell_type) - if not value: - return None - elif cell_type.startswith('float'): + if cell_type.startswith('float'): try: result = float(value) return result except Exception as e: - print "%s not float" % value + #print "%s not float" % value return None elif cell_type.startswith('int'): try: result = int(value) return result except Exception as e: - print "%s not int" % value + #print "%s not int" % value return None elif cell_type.startswith('text'): #Text so is OK?? @@ -209,9 +207,9 @@ result = dateutil.parser.parse(value).date() return result except Exception as e: - print type(e) - print e - print "%s not date" % value + #print type(e) + #print e + #print "%s not date" % value return None print "Unknown datatype: (%s) for data (%s)" % (cell_type, value) return None This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-10-12 09:26:40
|
Revision: 658 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=658&view=rev Author: jblance Date: 2010-10-12 09:26:33 +0000 (Tue, 12 Oct 2010) Log Message: ----------- Arnd added distance options to list view filters Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/listview.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/lib/listview.py =================================================================== --- pytrainer/trunk/pytrainer/lib/listview.py 2010-10-12 09:24:04 UTC (rev 657) +++ pytrainer/trunk/pytrainer/lib/listview.py 2010-10-12 09:26:33 UTC (rev 658) @@ -1,8 +1,8 @@ import datetime import math -LISTPAST = [['All Time', -99999], ['Last 4 Weeks', -31], - ['Last 6 Months', -183], ['Last 12 Months', -366]] +#LISTPAST = [['All Time', -99999], ['Last 4 Weeks', -31], +# ['Last 6 Months', -183], ['Last 12 Months', -366]] class ListSearch(object): """ Builds SQLite condition out of search parameters""" @@ -19,8 +19,15 @@ self.listDuration = [['All Durations', [0,999999]], ['<1 Hour', [0,3600]], ['1-2 Hours', [3600,7200]], - ['>2 Hours', [7200,999999]]] - self.listDistance = self.get_listDistance() + ['>2 Hours', [7200,999999]]] + + self.listDistance = [['All Distances', [0.0,999999.9]], + ['<1 km', [0.0, 1.0]], + ['1-5 km', [1.0, 5.0]], + ['5-20 km', [5.0, 20.0]], + ['20-50 km', [20.0, 50.0]], + ['50-100 km', [50.0, 100.0]], + ['>100 km', [100.0, 999999.9]]] #print self.listDistance self.setup_lsa_sport() self.setup_lsa_past() @@ -60,9 +67,9 @@ else: _search = _here _add_and = True - if self.listDistance[self.sport][self.distance][1]: - _dis_min = int(self.listDistance[self.sport][self.distance][1][0]) - _dis_max = int(self.listDistance[self.sport][self.distance][1][1]) + if self.listDistance[self.distance][1]: + _dis_min = int(self.listDistance[self.distance][1][0]) + _dis_max = int(self.listDistance[self.distance][1][1]) _here = "(distance between %s and %s)" % (_dis_min, _dis_max) if _add_and: _search += " and " + _here @@ -132,7 +139,7 @@ self.parent.lsa_distance.set_active(0) firstEntry = self.parent.lsa_distance.get_active_text() liststore_lsa.clear() #Delete all items - for i in self.listDistance[self.sport]: + for i in self.listDistance: liststore_lsa.append([i[0]]) self.parent.lsa_distance.set_active(0) #Add handler manually, so above changes do not trigger recursive loop Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-12 09:24:04 UTC (rev 657) +++ pytrainer/trunk/pytrainer/main.py 2010-10-12 09:26:33 UTC (rev 658) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#657" + self.version ="1.7.2_svn#658" self.DB_version = 5 #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-12 09:24:11
|
Revision: 657 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=657&view=rev Author: jblance Date: 2010-10-12 09:24:04 +0000 (Tue, 12 Oct 2010) Log Message: ----------- Update week numbering to use ISO as per Arnd suggestion Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-12 09:14:05 UTC (rev 656) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-12 09:24:04 UTC (rev 657) @@ -62,7 +62,7 @@ glade_path="glade/pytrainer.glade" root = "window1" domain = None - + SimpleGladeApp.__init__(self, self.data_path+glade_path, root, domain) self.popup = PopupMenu(data_path,self) @@ -80,7 +80,7 @@ self.y1_linewidth = 1 # setup Search ListView self.listsearch = ListSearch(self, self.pytrainer_main) - + def new(self): self.testimport = self.pytrainer_main.startup_options.testimport self.menublocking = 0 @@ -123,8 +123,8 @@ else: self.radiobuttonGMap.set_active(1) - - + + def _float_or(self, value, default): '''Function to parse and return a float, or the default if the parsing fails''' try: @@ -639,8 +639,8 @@ logging.debug(">>") date_s = datetime.datetime.strptime(date_ini, "%Y-%m-%d") date_e = datetime.datetime.strptime(date_end, "%Y-%m-%d") - self.week_date.set_text("%s - %s (%d)" % (datetime.datetime.strftime(date_s, "%a %d %b"), datetime.datetime.strftime(date_e, "%a %d %b"), int(datetime.datetime.strftime(date_e, "%W"))+1) ) - + #self.week_date.set_text("%s - %s (%d)" % (datetime.datetime.strftime(date_s, "%a %d %b"), datetime.datetime.strftime(date_e, "%a %d %b"), int(datetime.datetime.strftime(date_e, "%W"))+1) ) + self.week_date.set_text("%s - %s (%d)" % (datetime.datetime.strftime(date_s, "%a %d %b"), datetime.datetime.strftime(date_e, "%a %d %b"), int(datetime.datetime.strftime(date_e, "%V"))) ) km = calories = time = average = beats = 0 num_records = len(record_list) logging.info("Number of records selected week: "+str(num_records)) @@ -922,7 +922,7 @@ if hour >0: _hh = "%2d:%02d:%02d" %(hour, min, sec) else: - _hh = "___%2d:%02d" %(min, sec) + _hh = "___%2d:%02d" %(min, sec) #_time =_hh try: _id = int(i[5]) @@ -1053,7 +1053,7 @@ self.listsearch.sport = self.lsa_sport.get_active() self.listsearch.past = self.lsa_past.get_active() self.listsearch.duration = self.lsa_duration.get_active() - self.listsearch.distance = self.lsa_distance.get_active() + self.listsearch.distance = self.lsa_distance.get_active() self.parent.searchListView(self.listsearch.condition) def create_menulist(self,column_names): @@ -1214,7 +1214,7 @@ activity.time_data[item].show_on_y2 = child.get_active() #Replot the activity self.actualize_recordgraph(activity) - + def on_setlimits(self, widget, activity, reset, data): '''Handler for setting graph limits buttons''' if data is None: @@ -1566,6 +1566,8 @@ self.calendar.clear_marks() for i in record_list: self.calendar.mark_day(int(i)) + #display_options = self.calendar.get_display_options() + #self.calendar.set_display_options(display_options|gtk.CALENDAR_SHOW_WEEK_NUMBERS) logging.debug("<<") def on_about_activate(self,widget): @@ -1596,7 +1598,7 @@ def on_recordTree_clicked(self,widget,num,num2): selected,iter = self.recordTreeView.get_selection().get_selected() self.parent.editRecord(selected.get_value(iter,0)) - + ### athleteview events ### def on_athleteTreeView_button_press_event(self, treeview, event): x = int(event.x) @@ -1633,7 +1635,7 @@ self.update_athlete_item(idx, date, weight, bf, restingHR, maxHR) def on_athleteTreeView_delete(self, widget, data): - '''User has opted to delete entry''' + '''User has opted to delete entry''' logging.debug(">>") msg = _("Delete this database entry?") md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, msg) @@ -1647,7 +1649,7 @@ else: logging.debug("User canceled athlete record deletion for id %s" % data) logging.debug("<<") - + def on_buttonAthleteNew_clicked(self, widget): #Reset Fields self.labelAthleteIdx.set_text("") @@ -1656,7 +1658,7 @@ self.entryAthleteBF.set_text("") self.entryAthleteRestingHR.set_text("") self.entryAthleteMaxHR.set_text("") - + def on_buttonAlthleteSave_clicked(self, widget): #Get data in fields id_athletestat = self.labelAthleteIdx.get_text() @@ -1674,7 +1676,7 @@ restinghr = self.entryAthleteRestingHR.get_text() maxhr = self.entryAthleteMaxHR.get_text() #TODO - are any other fields required? - + #Check if an entry has been edited or is a new one if id_athletestat is None or id_athletestat == "": #New entry @@ -1685,11 +1687,11 @@ logging.debug('Updating id_athletestat:%s with values: date %s, weight %s, bodyfat %s, restinghr %s, maxhr %s' % (id_athletestat, date, weight, bodyfat, restinghr, maxhr) ) self.parent.athlete.update_athlete_stats(id_athletestat, date, weight, bodyfat, restinghr, maxhr) self.parent.refreshAthleteView() - + def on_athletecalendar_clicked(self,widget): calendardialog = WindowCalendar(self.data_path,self) calendardialog.run() - + def setDate(self,date): self.entryAthleteDate.set_text(date) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-12 09:14:05 UTC (rev 656) +++ pytrainer/trunk/pytrainer/main.py 2010-10-12 09:24:04 UTC (rev 657) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#656" + self.version ="1.7.2_svn#657" self.DB_version = 5 #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-12 09:14:11
|
Revision: 656 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=656&view=rev Author: jblance Date: 2010-10-12 09:14:05 +0000 (Tue, 12 Oct 2010) Log Message: ----------- Fixes to athlete view to account for missing data Modified Paths: -------------- pytrainer/trunk/pytrainer/athlete.py pytrainer/trunk/pytrainer/gui/drawGraph.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/athlete.py =================================================================== --- pytrainer/trunk/pytrainer/athlete.py 2010-10-12 08:47:22 UTC (rev 655) +++ pytrainer/trunk/pytrainer/athlete.py 2010-10-12 09:14:05 UTC (rev 656) @@ -33,12 +33,12 @@ self.data = self.get_athlete_stats() self.graphdata = self.get_athlete_data() logging.debug('<<') - + def refresh(self): self.init_from_conf() self.data = self.get_athlete_stats() self.graphdata = self.get_athlete_data() - + def init_from_conf(self): logging.debug('>>') self.name = self.pytrainer_main.profile.getValue("pytraining","prf_name") @@ -53,7 +53,7 @@ else: self.weight_unit = _("kg") logging.debug('<<') - + def get_athlete_stats(self): logging.debug('>>') results = self.pytrainer_main.ddbb.select_dict("athletestats", ('id_athletestat', 'date', 'weight', 'bodyfat', 'restinghr', 'maxhr'), mod="order by date") @@ -65,16 +65,16 @@ logging.debug('Found %d athlete stats results' % len(results)) logging.debug('<<') return results - + def get_athlete_data(self): logging.debug('>>') graphdata = {} graphdata['weight'] = GraphData(title="Weight", xlabel="Date", ylabel="Weight (%s)" % (self.weight_unit)) graphdata['weight'].set_color('#3300FF', '#3300FF') - #graphdata['weight'].graphType = 'fill' + #graphdata['weight'].graphType = 'date' graphdata['bodyfat'] = GraphData(title="Body Fat", xlabel="Date", ylabel="Body Fat (%s)" % (self.weight_unit)) graphdata['bodyfat'].set_color('#FF6600', '#FF6600') - #graphdata['bf'].graphType = 'fill' + #graphdata['bf'].graphType = 'date' graphdata['restinghr'] = GraphData(title="Resting Heartrate", xlabel="Date", ylabel="Resting Heartrate (bpm)") graphdata['restinghr'].set_color('#660000', '#660000') graphdata['restinghr'].show_on_y2 = True @@ -84,6 +84,8 @@ for row in self.data: if not 'date' in row or not row['date']: continue + else: + date = row['date'] if 'weight' in row and row['weight']: weight = float(row['weight']) else: @@ -92,13 +94,18 @@ bf = float(row['bodyfat']) / 100 * weight else: bf = "" - graphdata['weight'].addPoints(x=row['date'], y=weight) - graphdata['bodyfat'].addPoints(x=row['date'], y=bf) - graphdata['restinghr'].addPoints(x=row['date'], y=row['restinghr']) - graphdata['maxhr'].addPoints(x=row['date'], y=row['maxhr']) + graphdata['weight'].addPoints(x=date, y=weight) + graphdata['bodyfat'].addPoints(x=date, y=bf) + graphdata['restinghr'].addPoints(x=date, y=row['restinghr']) + graphdata['maxhr'].addPoints(x=date, y=row['maxhr']) + #Remove empty data + for item in graphdata.keys(): + if len(graphdata[item]) == 0: + logging.debug( "No values for %s. Removing...." % item ) + del graphdata[item] return graphdata - - + + def update_athlete_stats(self, id_athletestat, date, weight, bodyfat, restinghr, maxhr): logging.debug('>>') try: @@ -113,7 +120,7 @@ self.pytrainer_main.ddbb.update_dict("athletestats",data, condition) #self.pytrainer_main.ddbb.update("athletestats",cells,values," id_athletestat=%d" %int(id_athletestat)) logging.debug('<<') - + def insert_athlete_stats(self, date, weight, bodyfat, restinghr, maxhr): logging.debug('>>') if not date and not weight and not bodyfat and not restinghr and not maxhr: @@ -131,7 +138,7 @@ data = {'date': date, 'weight': weight, 'bodyfat': bodyfat, 'restinghr': restinghr, 'maxhr': maxhr} self.pytrainer_main.ddbb.insert_dict("athletestats",data) logging.debug('<<') - + def delete_record(self, data): logging.debug('>>') self.pytrainer_main.ddbb.delete("athletestats","id_athletestat=%d" % int(data)) Modified: pytrainer/trunk/pytrainer/gui/drawGraph.py =================================================================== --- pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-10-12 08:47:22 UTC (rev 655) +++ pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-10-12 09:14:05 UTC (rev 656) @@ -65,7 +65,7 @@ if datalist is None: logging.debug("drawPlot called with no data") - return + return figure if y2 and self.ax2 is None: self.ax2 = plt.twinx() @@ -111,11 +111,11 @@ else: self.ax2.axvspan(datalist.x_values[i], datalist.x_values[i]+datalist.bar_widths[i], alpha=0.15, facecolor=datalist.y2linecolor) i += 1 - elif datalist.graphType == "fill": + elif datalist.graphType == "date": if not y2: - self.ax1.fill_between(datalist.x_values, datalist.y_values, color=datalist.linecolor, label=datalist.ylabel, alpha=0.5) + self.ax1.plot_date(datalist.x_values, datalist.y_values, color=datalist.linecolor, label=datalist.ylabel, alpha=0.5) else: - self.ax2.fill_between(datalist.x_values, datalist.y_values, color=datalist.y2linecolor, label=datalist.ylabel, alpha=0.5) + self.ax2.plot_date(datalist.x_values, datalist.y_values, color=datalist.y2linecolor, label=datalist.ylabel, alpha=0.5) else: print "Unknown/unimplemented graph type: %s" % datalist.graphType return figure @@ -151,6 +151,7 @@ #print("drawPlot....") for item in athlete.graphdata: #print "drawing", item + #print athlete.graphdata[item] figure = self.draw(athlete.graphdata[item], box=box, figure=figure, title=_("Athlete Data"), y2=athlete.graphdata[item].show_on_y2) def drawActivityGraph(self, activity = None, box = None): @@ -217,12 +218,12 @@ activity.x_limits = self.ax1.get_xlim() activity.y1_limits = self.ax1.get_ylim() else: - activity.y1_limits = (None, None) + activity.y1_limits = (None, None) if self.ax2 is not None: activity.x_limits = self.ax2.get_xlim() activity.y2_limits = self.ax2.get_ylim() else: - activity.y2_limits = (None, None) + activity.y2_limits = (None, None) #Set axis limits if requested #X Axis if activity.x_limits_u[0] is not None: @@ -238,6 +239,6 @@ if activity.y2_limits_u[0] is not None: if self.ax2 is not None: self.ax2.set_ylim(activity.y2_limits_u) - + return activity logging.debug('<<') Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-12 08:47:22 UTC (rev 655) +++ pytrainer/trunk/pytrainer/main.py 2010-10-12 09:14:05 UTC (rev 656) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#655" + self.version ="1.7.2_svn#656" self.DB_version = 5 #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-12 08:47:28
|
Revision: 655 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=655&view=rev Author: jblance Date: 2010-10-12 08:47:22 +0000 (Tue, 12 Oct 2010) Log Message: ----------- Fix Record graphs broken by 654 Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-12 04:53:01 UTC (rev 654) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-12 08:47:22 UTC (rev 655) @@ -141,13 +141,26 @@ return_value = [] #Only query db if table and cells are supplied if table is not None and cells is not None: - if table in tablesList: + if table.find(',') != -1: + #multiple tables in select + #TODO fix so works.... + print 'TODO fix select_dict to work with multiple tables' cellString = ','.join(cells) #create cell list string results = self.ddbbObject.select(table,cellString,condition,mod) for result in results: dict = {} #Loop through cells and create dict of results for i, cell in enumerate(cells): + #cell_type = tablesList[table][cell] + dict[cell] = result[i] + return_value.append(dict) + elif table in tablesList: + cellString = ','.join(cells) #create cell list string + results = self.ddbbObject.select(table,cellString,condition,mod) + for result in results: + dict = {} + #Loop through cells and create dict of results + for i, cell in enumerate(cells): #check result is correct type if cell not in tablesList[table]: logging.error('select includes invalid cell (%s) for table %s' % (cell, table)) @@ -159,7 +172,7 @@ logging.error('select on invalid table name') logging.debug("<<") return return_value - + def parseByCellType(self, value, cell_type): ''' Function to validate that value is of type cell_type @@ -205,7 +218,7 @@ def insert(self,table,cells,values): self.ddbbObject.insert(table,cells,values) - + def insert_dict(self, table, data): logging.debug(">>") global tablesList @@ -221,7 +234,7 @@ if cell_value is not None: cells.append(cell) values.append(cell_value) - #Create string of cell names for sql... + #Create string of cell names for sql... #TODO fix sql objects so dont need to join... cells_string = ",".join(cells) self.ddbbObject.insert(table,cells_string,values) @@ -232,7 +245,7 @@ def update(self,table,cells,value,condition): self.ddbbObject.update(table,cells,value,condition) - + def update_dict(self, table, data, condition): logging.debug(">>") global tablesList @@ -248,7 +261,7 @@ if cell_value is not None: cells.append(cell) values.append(cell_value) - #Create string of cell names for sql... + #Create string of cell names for sql... #TODO fix sql objects so dont need to join... cells_string = ",".join(cells) self.ddbbObject.update(table,cells_string,values,condition) @@ -313,15 +326,15 @@ else: logging.info('Database backup successfully created') logging.debug('<<') - + def checkDBDataValues(self): ''' Check all data in DB and report values that do not match the type ''' global tablesList - + for table in tablesList.keys(): pass - + def populate_date_time_local(self): ''' Populate date_time_local and date from date_time_utc only access records that date_time_local is NULL Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-12 04:53:01 UTC (rev 654) +++ pytrainer/trunk/pytrainer/main.py 2010-10-12 08:47:22 UTC (rev 655) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#654" + self.version ="1.7.2_svn#655" self.DB_version = 5 #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-12 04:53:08
|
Revision: 654 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=654&view=rev Author: jblance Date: 2010-10-12 04:53:01 +0000 (Tue, 12 Oct 2010) Log Message: ----------- Updated date to _hopefully_ deal with different week start days 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-12 02:49:58 UTC (rev 653) +++ pytrainer/trunk/pytrainer/lib/date.py 2010-10-12 04:53:01 UTC (rev 654) @@ -24,126 +24,167 @@ import datetime import dateutil.parser from dateutil.tz import * # for tzutc() +from subprocess import Popen, PIPE class Date: - def __init__(self, calendar=None): - self.calendar = calendar - - def second2time(self,seconds): - if not seconds: - return 0,0,0 - time_in_hour = seconds/3600.0 - hour = int(time_in_hour) - min = int((time_in_hour-hour)*60) - sec = (((time_in_hour-hour)*60)-min)*60 - sec = seconds-(hour*3600)-(min*60) - return hour,min,sec + def __init__(self, calendar=None): + self.calendar = calendar + + def second2time(self,seconds): + if not seconds: + return 0,0,0 + time_in_hour = seconds/3600.0 + hour = int(time_in_hour) + min = int((time_in_hour-hour)*60) + sec = (((time_in_hour-hour)*60)-min)*60 + sec = seconds-(hour*3600)-(min*60) + return hour,min,sec - def time2second(self,time): - hour,min,sec = time - return int(sec)+(int(min)*60)+(int(hour)*3600) + def time2second(self,time): + hour,min,sec = time + return int(sec)+(int(min)*60)+(int(hour)*3600) - def getLocalTZ(self): - ''' Returns string representation of local timezone''' - return datetime.datetime.now(tzlocal()).tzname() + def getLocalTZ(self): + ''' Returns string representation of local timezone''' + return datetime.datetime.now(tzlocal()).tzname() - def getDate(self): - #hack for the gtk calendar widget - if self.calendar is not None: - year,month,day = self.calendar.get_date() - return "%0.4d-%0.2d-%0.2d" %(year,month+1,day) - else: - return datetime.date.today().strftime("%Y-%m-%d") + def getDate(self): + #hack for the gtk calendar widget + if self.calendar is not None: + year,month,day = self.calendar.get_date() + return "%0.4d-%0.2d-%0.2d" %(year,month+1,day) + else: + return datetime.date.today().strftime("%Y-%m-%d") - def setDate(self,newdate): - year,month,day = newdate.split("-") - self.calendar.select_month(int(month)-1,int(year)) - self.calendar.select_day(int(day)) - - def time2string(self,date): - return "%0.4d-%0.2d-%0.2d" %(int(date[0]),int(date[1]),int(date[2])) + def setDate(self,newdate): + year,month,day = newdate.split("-") + self.calendar.select_month(int(month)-1,int(year)) + self.calendar.select_day(int(day)) + + def time2string(self,date): + return "%0.4d-%0.2d-%0.2d" %(int(date[0]),int(date[1]),int(date[2])) + + def getFirstDayOfWeek(self): + ''' + Function to determine the first day of the week from the locale + from http://blogs.gnome.org/patrys/2008/09/29/how-to-determine-the-first-day-of-week/ + + $ locale first_weekday week-1stday + 2 + 19971130 + ''' + + CMD=('locale', 'first_weekday', 'week-1stday') + p=Popen(CMD, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate() + #print "STDOUT\n"+stdout + #print "STDERR\n"+stderr + #print "RETURNCODE: "+str(p.returncode) + if p.returncode != 0: + #Error in command execution + return None + results = stdout.split('\n') + if len(results) < 2: + #print "len error", len(results), results + return None + try: + day_delta = datetime.timedelta(days=int(results[0]) - 1) + base_date = dateutil.parser.parse(results[1]) + first_day = base_date + day_delta + print "First day of week based on locale is:", first_day.strftime("%A") + return first_day + except Exception as e: + print type(e) + print e + return None + + - def getWeekInterval(self,date, prf_us_system): - ''' Function to provide beginning and ending of the week that a certain day is in - Problems as python date functions do not respect locale (i.e. Sunday is always start of week????) - Note: %w gives weekday as a decimal number [0(Sunday),6(Saturday)]. - ''' - if prf_us_system: - #Sunday is first day of week - weekDate = datetime.datetime.strptime(date, "%Y-%m-%d") - dayOfWeek = int(weekDate.strftime("%w")) - else: - #Monday is first day of week - weekDate = datetime.datetime.strptime(date, "%Y-%m-%d") - dayOfWeek = int(weekDate.strftime("%w")) - if dayOfWeek == 0: #Sunday, need to adjust - dayOfWeek = 7 - dayOfWeek -= 1 - date_ini = weekDate + datetime.timedelta(days=0-dayOfWeek) - date_end = weekDate + datetime.timedelta(days=6-dayOfWeek) - return date_ini.strftime("%Y-%m-%d"), date_end.strftime("%Y-%m-%d") - - def getMonthInterval(self,date): - year,month,day = date.split("-") - date_ini = "%0.4d-%0.2d-00" %(int(year),int(month)) - if (int(month)<12): - month = int(month)+1 - else: - year = int(year)+1 - month = 1 - date_end = "%0.4d-%0.2d-01" %(int(year),int(month)) - return date_ini, date_end + def getWeekInterval(self,date, prf_us_system): + ''' Function to provide beginning and ending of the week that a certain day is in + Problems as python date functions do not respect locale (i.e. Sunday is always start of week????) + Note: %w gives weekday as a decimal number [0(Sunday),6(Saturday)]. + ''' + weekDate = datetime.datetime.strptime(date, "%Y-%m-%d") + dayOfWeek = int(weekDate.strftime("%w")) + #print "Today is %s day of the week:" % dayOfWeek + first_day = self.getFirstDayOfWeek().strftime("%w") #0 = Sun is first, 1 = Mon is first, 6 = Sat is first + #first_day = 6 + if first_day is not None: + #got response from locale query... + #print "first day of week is:", first_day + #Adjust dayOfweek... + dayOfWeek -= int(first_day) + if dayOfWeek < 0: + dayOfWeek += 7 + #print "Adjusted today is %s day of the week:" % dayOfWeek + date_ini = weekDate + datetime.timedelta(days=0-dayOfWeek) + date_end = weekDate + datetime.timedelta(days=6-dayOfWeek) + #print "weekrange", date_ini.strftime("%A"), date_end.strftime("%A") + #print "dates", date_ini.strftime("%Y-%m-%d"), date_end.strftime("%Y-%m-%d") + return date_ini.strftime("%Y-%m-%d"), date_end.strftime("%Y-%m-%d") + + def getMonthInterval(self,date): + year,month,day = date.split("-") + date_ini = "%0.4d-%0.2d-00" %(int(year),int(month)) + if (int(month)<12): + month = int(month)+1 + else: + year = int(year)+1 + month = 1 + date_end = "%0.4d-%0.2d-01" %(int(year),int(month)) + return date_ini, date_end - def getYearInterval(self,date): - year,month,day = date.split("-") - date_ini = "%0.4d-0.1-01" %int(year) - year = int(year)+1 - date_end = "%0.4d-01-01" %int(year) - return date_ini, date_end - - def getNameMonth(self, date): - #month_name = { - # "01":_("January"), - # "02":_("Febrary"), - # "03":_("March"), - # "04":_("April"), - # "05":_("May"), - # "06":_("June"), - # "07":_("July"), - # "08":_("August"), - # "09":_("September"), - # "10":_("October"), - # "11":_("November"), - # "12":_("December") - # } - year,month,day = date.split("-") - day, daysInMonth = calendar.monthrange(int(year), int(month)) - monthName = calendar.month_name[int(month)] - return monthName, daysInMonth + def getYearInterval(self,date): + year,month,day = date.split("-") + date_ini = "%0.4d-0.1-01" %int(year) + year = int(year)+1 + date_end = "%0.4d-01-01" %int(year) + return date_ini, date_end + + def getNameMonth(self, date): + #month_name = { + # "01":_("January"), + # "02":_("Febrary"), + # "03":_("March"), + # "04":_("April"), + # "05":_("May"), + # "06":_("June"), + # "07":_("July"), + # "08":_("August"), + # "09":_("September"), + # "10":_("October"), + # "11":_("November"), + # "12":_("December") + # } + year,month,day = date.split("-") + day, daysInMonth = calendar.monthrange(int(year), int(month)) + monthName = calendar.month_name[int(month)] + return monthName, daysInMonth - def getYear(self,date): - year,month,day = date.split("-") - return year + def getYear(self,date): + year,month,day = date.split("-") + return year - def unixtime2date(self,unixtime): - print unixtime - tm = time.gmtime(unixtime) - year = tm[0] - month = tm[1] - day = tm[2] - return "%0.4d-%0.2d-%0.2d" %(year,month,day) + def unixtime2date(self,unixtime): + print unixtime + tm = time.gmtime(unixtime) + year = tm[0] + month = tm[1] + day = tm[2] + return "%0.4d-%0.2d-%0.2d" %(year,month,day) - def getDateTime(self, time_): - # 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 - local_dateTime = dateTime.astimezone(tzlocal()) #datetime with localtime offset (from OS) - else: - local_dateTime = dateTime #use datetime as supplied - utc_dateTime = dateTime.astimezone(tzutc()) #datetime with 00:00 offset - #print utc_dateTime, local_dateTime - return (utc_dateTime,local_dateTime) + def getDateTime(self, time_): + # 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 + local_dateTime = dateTime.astimezone(tzlocal()) #datetime with localtime offset (from OS) + else: + local_dateTime = dateTime #use datetime as supplied + utc_dateTime = 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-12 02:49:58 UTC (rev 653) +++ pytrainer/trunk/pytrainer/main.py 2010-10-12 04:53:01 UTC (rev 654) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#653" + self.version ="1.7.2_svn#654" self.DB_version = 5 #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-12 02:50:04
|
Revision: 653 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=653&view=rev Author: jblance Date: 2010-10-12 02:49:58 +0000 (Tue, 12 Oct 2010) Log Message: ----------- Athlete view - delete record, improved DB access (uses dicts and checks data type) Modified Paths: -------------- pytrainer/trunk/pytrainer/athlete.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/athlete.py =================================================================== --- pytrainer/trunk/pytrainer/athlete.py 2010-10-11 21:18:37 UTC (rev 652) +++ pytrainer/trunk/pytrainer/athlete.py 2010-10-12 02:49:58 UTC (rev 653) @@ -56,14 +56,15 @@ def get_athlete_stats(self): logging.debug('>>') - stats = [] - results = self.pytrainer_main.ddbb.select("athletestats", "id_athletestat, date, weight, bodyfat, restinghr, maxhr", mod="order by date") + results = self.pytrainer_main.ddbb.select_dict("athletestats", ('id_athletestat', 'date', 'weight', 'bodyfat', 'restinghr', 'maxhr'), mod="order by date") + #Remove None values + for i, row in enumerate(results): + for cell in results[i]: + if results[i][cell] == None: + results[i][cell] = "" logging.debug('Found %d athlete stats results' % len(results)) - for row in results: - date = dateutil.parser.parse(row[1]).date() - stats.append({'id_athletestat': row[0], 'Date': row[1], 'Weight':row[2], 'BF': row[3], 'RestingHR':row[4], 'MaxHR':row[5]}) logging.debug('<<') - return stats + return results def get_athlete_data(self): logging.debug('>>') @@ -71,8 +72,8 @@ graphdata['weight'] = GraphData(title="Weight", xlabel="Date", ylabel="Weight (%s)" % (self.weight_unit)) graphdata['weight'].set_color('#3300FF', '#3300FF') #graphdata['weight'].graphType = 'fill' - graphdata['bf'] = GraphData(title="Body Fat", xlabel="Date", ylabel="Body Fat (%s)" % (self.weight_unit)) - graphdata['bf'].set_color('#FF6600', '#FF6600') + graphdata['bodyfat'] = GraphData(title="Body Fat", xlabel="Date", ylabel="Body Fat (%s)" % (self.weight_unit)) + graphdata['bodyfat'].set_color('#FF6600', '#FF6600') #graphdata['bf'].graphType = 'fill' graphdata['restinghr'] = GraphData(title="Resting Heartrate", xlabel="Date", ylabel="Resting Heartrate (bpm)") graphdata['restinghr'].set_color('#660000', '#660000') @@ -81,32 +82,36 @@ graphdata['maxhr'].set_color('#33CC99', '#33CC99') graphdata['maxhr'].show_on_y2 = True for row in self.data: - date = dateutil.parser.parse(row['Date']).date() - if row['Weight']: - weight = float(row['Weight']) + if not 'date' in row or not row['date']: + continue + if 'weight' in row and row['weight']: + weight = float(row['weight']) else: - weight = None - if row['BF']: - bf = float(row['BF']) / 100 * weight + weight = "" + if 'bodyfat' in row and row['bodyfat'] and weight: + bf = float(row['bodyfat']) / 100 * weight else: - bf = None - graphdata['weight'].addPoints(x=date, y=weight) - graphdata['bf'].addPoints(x=date, y=bf) - graphdata['restinghr'].addPoints(x=date, y=row['RestingHR']) - graphdata['maxhr'].addPoints(x=date, y=row['MaxHR']) + bf = "" + graphdata['weight'].addPoints(x=row['date'], y=weight) + graphdata['bodyfat'].addPoints(x=row['date'], y=bf) + graphdata['restinghr'].addPoints(x=row['date'], y=row['restinghr']) + graphdata['maxhr'].addPoints(x=row['date'], y=row['maxhr']) return graphdata def update_athlete_stats(self, id_athletestat, date, weight, bodyfat, restinghr, maxhr): logging.debug('>>') try: - date = dateutil.parser.parse(date).date() + dateutil.parser.parse(date).date() + logging.debug("update_athlete_stats called with invalid date") + logging.debug('!<<') except ValueError: return - cells = "date, weight, bodyfat, restinghr, maxhr" - values = (date, weight, bodyfat, restinghr, maxhr) - #Update database - self.pytrainer_main.ddbb.update("athletestats",cells,values," id_athletestat=%d" %int(id_athletestat)) + #Update DB + data = {'date': date, 'weight': weight, 'bodyfat': bodyfat, 'restinghr': restinghr, 'maxhr': maxhr} + condition = "id_athletestat=%d" % int(id_athletestat) + self.pytrainer_main.ddbb.update_dict("athletestats",data, condition) + #self.pytrainer_main.ddbb.update("athletestats",cells,values," id_athletestat=%d" %int(id_athletestat)) logging.debug('<<') def insert_athlete_stats(self, date, weight, bodyfat, restinghr, maxhr): @@ -117,11 +122,17 @@ logging.debug('!<<') return try: - date = dateutil.parser.parse(date).date() + dateutil.parser.parse(date).date() except ValueError: + logging.debug("insert_athlete_stats called with invalid date") + logging.debug('!<<') return - cells = "date, weight, bodyfat, restinghr, maxhr" - values = (date, weight, bodyfat, restinghr, maxhr) #Update DB - self.pytrainer_main.ddbb.insert("athletestats",cells,values) + data = {'date': date, 'weight': weight, 'bodyfat': bodyfat, 'restinghr': restinghr, 'maxhr': maxhr} + self.pytrainer_main.ddbb.insert_dict("athletestats",data) logging.debug('<<') + + def delete_record(self, data): + logging.debug('>>') + self.pytrainer_main.ddbb.delete("athletestats","id_athletestat=%d" % int(data)) + logging.debug('<<') Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-11 21:18:37 UTC (rev 652) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-12 02:49:58 UTC (rev 653) @@ -880,8 +880,8 @@ gobject.TYPE_STRING #max HR ) for data in athlete.data: - weight = (data['Weight']) - date = dateutil.parser.parse(data['Date']).date() + weight = data['weight'] + date = data['date'] iter = history_store.append() history_store.set ( @@ -889,9 +889,9 @@ 0, (data['id_athletestat']), 1, date, #TODO need to sort date graphing... 2, weight, - 3, (data['BF']), - 4, (data['RestingHR']), - 5, (data['MaxHR']), + 3, (data['bodyfat']), + 4, (data['restinghr']), + 5, (data['maxhr']), ) self.athleteTreeView.set_model(history_store) self.grapher.drawAthleteGraph(athlete=athlete, box=self.boxAthleteGraph) @@ -1608,14 +1608,45 @@ treeview.grab_focus() treeview.set_cursor(path, col, 0) selected,iter = treeview.get_selection().get_selected() - idx = selected.get_value(iter,0) - date = selected.get_value(iter,1) - weight = selected.get_value(iter,2) - bf = selected.get_value(iter,3) - restingHR = selected.get_value(iter,4) - maxHR = selected.get_value(iter,5) - self.update_athlete_item(idx, date, weight, bf, restingHR, maxHR) - #print path, col, cellx, celly + if event.button == 3: + #Right mouse button... + idx = selected.get_value(iter,0) + date = selected.get_value(iter,1) + #print "show popup etc (clicked on idx %s, date %s)" % (idx, date) + #Show popup menu... + popup = gtk.Menu() + menuitem = gtk.MenuItem(label=_("Delete Entry")) + menuitem.connect("activate", self.on_athleteTreeView_delete, idx) + popup.attach(menuitem, 0, 1, 0, 1) + popup.show_all() + popup.popup( None, None, None, event.button, time) + #self.popup.show(selected.get_value(iter,0), event.button, time) + #self.popup.popup( None, None, None, event_button, time) + else: + #Left mouse - so display this row + idx = selected.get_value(iter,0) + date = selected.get_value(iter,1) + weight = selected.get_value(iter,2) + bf = selected.get_value(iter,3) + restingHR = selected.get_value(iter,4) + maxHR = selected.get_value(iter,5) + self.update_athlete_item(idx, date, weight, bf, restingHR, maxHR) + + def on_athleteTreeView_delete(self, widget, data): + '''User has opted to delete entry''' + logging.debug(">>") + msg = _("Delete this database entry?") + md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, msg) + md.set_title(_("Are you sure?")) + response = md.run() + md.destroy() + if response == gtk.RESPONSE_OK: + logging.debug("User confirmed deletion of athlete entry with id: %s" % data) + self.pytrainer_main.athlete.delete_record(data) + self.parent.refreshAthleteView() + else: + logging.debug("User canceled athlete record deletion for id %s" % data) + logging.debug("<<") def on_buttonAthleteNew_clicked(self, widget): #Reset Fields Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-11 21:18:37 UTC (rev 652) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-12 02:49:58 UTC (rev 653) @@ -22,6 +22,7 @@ import logging import traceback import commands, os +import dateutil from pytrainer.lib.date import Date #Define the tables and their columns that should be in the database @@ -124,37 +125,134 @@ def select(self,table,cells,condition=None, mod=None): return self.ddbbObject.select(table,cells,condition,mod) - def select_dict(self,table,cells,condition=None): + def select_dict(self,table,cells,condition=None, mod=None): ''' Function to query DB -- inputs ---- table - string tablename(s) ---- cells - list of cells to select ---- condition - string to fit SQL where clause or None + ---- mod - string of select clause modifier, eg "order by date" -- returns ---- list of dicts with cells as keys ''' + logging.debug(">>") + global tablesList return_value = [] #Only query db if table and cells are supplied if table is not None and cells is not None: - cellString = ','.join(cells) #create cell list string - results = self.ddbbObject.select(table,cellString,condition) - for result in results: - dict = {} - #Loop through cells and create dict of results - for i, cell in enumerate(cells): - dict[cell] = result[i] - return_value.append(dict) + if table in tablesList: + cellString = ','.join(cells) #create cell list string + results = self.ddbbObject.select(table,cellString,condition,mod) + for result in results: + dict = {} + #Loop through cells and create dict of results + for i, cell in enumerate(cells): + #check result is correct type + if cell not in tablesList[table]: + logging.error('select includes invalid cell (%s) for table %s' % (cell, table)) + else: + cell_type = tablesList[table][cell] + dict[cell] = self.parseByCellType(result[i], cell_type) + return_value.append(dict) + else: + logging.error('select on invalid table name') + logging.debug("<<") return return_value + + def parseByCellType(self, value, cell_type): + ''' + Function to validate that value is of type cell_type + ''' + #TODO need to check if multivalue cell type specified + # eg integer primary key autoincrement + #print "Checking if %s is of type %s" % (value, cell_type) + if not value: + return None + elif cell_type.startswith('float'): + try: + result = float(value) + return result + except Exception as e: + print "%s not float" % value + return None + elif cell_type.startswith('int'): + try: + result = int(value) + return result + except Exception as e: + print "%s not int" % value + return None + elif cell_type.startswith('text'): + #Text so is OK?? + #TODO anytests required here?? + return value + elif cell_type.startswith('varchar'): + #Text so is OK?? + #TODO check length against spec? + return value + elif cell_type.startswith('date'): + try: + result = dateutil.parser.parse(value).date() + return result + except Exception as e: + print type(e) + print e + print "%s not date" % value + return None + print "Unknown datatype: (%s) for data (%s)" % (cell_type, value) + return None def insert(self,table,cells,values): self.ddbbObject.insert(table,cells,values) + + def insert_dict(self, table, data): + logging.debug(">>") + global tablesList + if not table or not data or table not in tablesList: + print "insert_dict called with invalid table or no data" + logging.debug("!<<") + return False + cells = [] + values = [] + for cell in data: + cell_type = tablesList[table][cell] + cell_value = self.parseByCellType(data[cell], cell_type) + if cell_value is not None: + cells.append(cell) + values.append(cell_value) + #Create string of cell names for sql... + #TODO fix sql objects so dont need to join... + cells_string = ",".join(cells) + self.ddbbObject.insert(table,cells_string,values) + logging.debug("<<") def delete(self,table,condition): self.ddbbObject.delete(table,condition) def update(self,table,cells,value,condition): self.ddbbObject.update(table,cells,value,condition) + + def update_dict(self, table, data, condition): + logging.debug(">>") + global tablesList + if not table or not data or table not in tablesList: + print "update_dict called with invalid table or no data" + logging.debug("!<<") + return False + cells = [] + values = [] + for cell in data: + cell_type = tablesList[table][cell] + cell_value = self.parseByCellType(data[cell], cell_type) + if cell_value is not None: + cells.append(cell) + values.append(cell_value) + #Create string of cell names for sql... + #TODO fix sql objects so dont need to join... + cells_string = ",".join(cells) + self.ddbbObject.update(table,cells_string,values,condition) + logging.debug("<<") def lastRecord(self,table): id = "id_" + table[:-1] #prune 's' of table name and pre-pend 'id_' to get id column Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-11 21:18:37 UTC (rev 652) +++ pytrainer/trunk/pytrainer/main.py 2010-10-12 02:49:58 UTC (rev 653) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#652" + self.version ="1.7.2_svn#653" self.DB_version = 5 #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-11 21:18:44
|
Revision: 652 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=652&view=rev Author: jblance Date: 2010-10-11 21:18:37 +0000 (Mon, 11 Oct 2010) Log Message: ----------- Listview search improvements from Arnd Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/lib/listview.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-10-11 04:07:51 UTC (rev 651) +++ pytrainer/trunk/glade/pytrainer.glade 2010-10-11 21:18:37 UTC (rev 652) @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0"?> <glade-interface> <!-- interface-requires gtk+ 2.6 --> <!-- interface-naming-policy toplevel-contextual --> @@ -1326,7 +1326,7 @@ <widget class="GtkSpinButton" id="spinbuttonY1Min"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> <signal name="value_changed" handler="on_spinbuttonY1_value_changed"/> @@ -1344,7 +1344,7 @@ <widget class="GtkSpinButton" id="spinbuttonY1Max"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> <signal name="value_changed" handler="on_spinbuttonY1_value_changed"/> @@ -1407,7 +1407,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 1 10 1 1 0</property> <signal name="value_changed" handler="on_spinbuttonY1LineWeight_value_changed"/> </widget> @@ -1449,7 +1449,7 @@ <property name="sensitive">False</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1541,7 +1541,7 @@ <widget class="GtkSpinButton" id="spinbuttonY2Min"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -1558,7 +1558,7 @@ <widget class="GtkSpinButton" id="spinbuttonY2Max"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">1 -500 1000 1 10 0</property> </widget> @@ -1628,7 +1628,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1660,7 +1660,7 @@ <property name="sensitive">False</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1737,7 +1737,7 @@ <widget class="GtkSpinButton" id="spinbuttonXMin"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -1754,7 +1754,7 @@ <widget class="GtkSpinButton" id="spinbuttonXMax"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -5268,7 +5268,7 @@ <widget class="GtkEntry" id="lsa_searchvalue"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="expand">False</property> @@ -5300,6 +5300,24 @@ </packing> </child> <child> + <widget class="GtkComboBox" id="lsa_distance"> + <property name="visible">True</property> + <property name="items" translatable="yes">All Distances</property> + </widget> + <packing> + <property name="position">4</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="lsa_duration"> + <property name="visible">True</property> + <property name="items" translatable="yes">All Durations</property> + </widget> + <packing> + <property name="position">5</property> + </packing> + </child> + <child> <widget class="GtkComboBox" id="lsa_past"> <property name="visible">True</property> <property name="active">0</property> @@ -5309,7 +5327,7 @@ Last 12 months</property> </widget> <packing> - <property name="position">4</property> + <property name="position">6</property> </packing> </child> <child> @@ -5318,7 +5336,7 @@ <property name="items" translatable="yes">All Sports</property> </widget> <packing> - <property name="position">5</property> + <property name="position">7</property> </packing> </child> <child> @@ -5338,7 +5356,7 @@ <packing> <property name="expand">False</property> <property name="fill">False</property> - <property name="position">6</property> + <property name="position">8</property> </packing> </child> </widget> @@ -5539,7 +5557,7 @@ <widget class="GtkEntry" id="waypoint_longitude"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">3</property> @@ -5554,7 +5572,7 @@ <widget class="GtkEntry" id="waypoint_description"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -5569,7 +5587,7 @@ <widget class="GtkEntry" id="waypoint_latitude"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">3</property> @@ -5582,7 +5600,7 @@ <widget class="GtkEntry" id="waypoint_name"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -5827,7 +5845,7 @@ <widget class="GtkEntry" id="entryAthleteDate"> <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> @@ -5840,7 +5858,7 @@ <widget class="GtkEntry" id="entryAthleteWeight"> <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> @@ -5869,7 +5887,7 @@ <widget class="GtkEntry" id="entryAthleteBF"> <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> @@ -5884,7 +5902,7 @@ <widget class="GtkEntry" id="entryAthleteRestingHR"> <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> @@ -5913,7 +5931,7 @@ <widget class="GtkEntry" id="entryAthleteMaxHR"> <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> @@ -5992,7 +6010,24 @@ </packing> </child> <child> - <placeholder/> + <widget class="GtkButton" id="button1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="on_athletecalendar_clicked"/> + <child> + <widget class="GtkImage" id="image7"> + <property name="visible">True</property> + <property name="stock">gtk-index</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> </child> <child> <placeholder/> @@ -6016,24 +6051,7 @@ <placeholder/> </child> <child> - <widget class="GtkButton" id="button1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="clicked" handler="on_athletecalendar_clicked"/> - <child> - <widget class="GtkImage" id="image7"> - <property name="visible">True</property> - <property name="stock">gtk-index</property> - </widget> - </child> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="x_options"></property> - <property name="y_options"></property> - </packing> + <placeholder/> </child> </widget> <packing> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-11 04:07:51 UTC (rev 651) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-11 21:18:37 UTC (rev 652) @@ -79,7 +79,7 @@ self.y1_color = None self.y1_linewidth = 1 # setup Search ListView - self.mylistsearch = ListSearch(self, self.pytrainer_main) + self.listsearch = ListSearch(self, self.pytrainer_main) def new(self): self.testimport = self.pytrainer_main.startup_options.testimport @@ -1049,15 +1049,12 @@ _("Average"):"average", _("Calories"):"calories" } - #search_string = self.lsa_searchvalue.get_text() - #print widget - self.mylistsearch.title = self.lsa_searchvalue.get_text() - self.mylistsearch.sport = self.lsa_sport.get_active() - self.mylistsearch.past = self.lsa_past.get_active() - #print self.mylistsearch.past - #search_string2 = "title like '%"+search_string+"%'" - #ddbb_field = lisOpt[self.lsa_searchoption.get_active_text()] - self.parent.searchListView(self.mylistsearch.condition) + self.listsearch.title = self.lsa_searchvalue.get_text() + self.listsearch.sport = self.lsa_sport.get_active() + self.listsearch.past = self.lsa_past.get_active() + self.listsearch.duration = self.lsa_duration.get_active() + self.listsearch.distance = self.lsa_distance.get_active() + self.parent.searchListView(self.listsearch.condition) def create_menulist(self,column_names): i=0 Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-11 04:07:51 UTC (rev 651) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-11 21:18:37 UTC (rev 652) @@ -24,6 +24,63 @@ import commands, os from pytrainer.lib.date import Date +#Define the tables and their columns that should be in the database +tablesList = { "records":{ "id_record":"integer primary key autoincrement", + "date":"date", + "sport":"integer", + "distance":"float", + "time":"varchar(200)", + "beats":"float", + "average":"float", + "calories":"int", + "comments":"text", + "gpslog":"varchar(200)", + "title":"varchar(200)", + "upositive":"float", + "unegative":"float", + "maxspeed":"float", + "maxpace":"float", + "pace":"float", + "maxbeats":"float", + "date_time_local":"varchar2(20)", + "date_time_utc":"varchar2(20)", + }, + "sports":{ "id_sports":"integer primary key autoincrement", + "name":"varchar(100)", + "weight":"float", + "met":"float", + "max_pace":"integer", + }, + "waypoints":{ "id_waypoint":"integer primary key autoincrement", + "lat":"float", + "lon":"float", + "ele":"float", + "comment":"varchar(240)", + "time":"date", + "name":"varchar(200)", + "sym":"varchar(200)", + }, + "laps":{ "id_lap": "integer primary key autoincrement", + "record": "integer", + "lap_number": "integer", + "elapsed_time": "varchar(20)", + "distance": "float", + "start_lat": "float", + "start_lon": "float", + "end_lat": "float", + "end_lon": "float", + "calories": "int", + }, + "athletestats": { + "id_athletestat": "integer primary key autoincrement", + "date": "date", + "weight": "float", + "bodyfat": "float", + "restinghr": "integer", + "maxhr": "integer", + }, + } + class DDBB: def __init__(self, configuration, pytrainer_main=None): self.pytrainer_main = pytrainer_main @@ -110,67 +167,12 @@ Retrieves tables and columns from database, checks current ones and adds something if missed. New in version 1.7.0 args: none returns: none""" + global tablesList logging.debug('>>') logging.info('Checking PyTrainer database') if self.ddbb_type != "sqlite": logging.error('Support for MySQL database is decommissioned, please migrate to SQLite. Exiting check') exit(-2) - #Define the tables and their columns that should be in the database - tablesList = { "records":{ "id_record":"integer primary key autoincrement", - "date":"date", - "sport":"integer", - "distance":"float", - "time":"varchar(200)", - "beats":"float", - "average":"float", - "calories":"int", - "comments":"text", - "gpslog":"varchar(200)", - "title":"varchar(200)", - "upositive":"float", - "unegative":"float", - "maxspeed":"float", - "maxpace":"float", - "pace":"float", - "maxbeats":"float", - "date_time_local":"varchar2(20)", - "date_time_utc":"varchar2(20)", - }, - "sports":{ "id_sports":"integer primary key autoincrement", - "name":"varchar(100)", - "weight":"float", - "met":"float", - "max_pace":"integer", - }, - "waypoints":{ "id_waypoint":"integer primary key autoincrement", - "lat":"float", - "lon":"float", - "ele":"float", - "comment":"varchar(240)", - "time":"date", - "name":"varchar(200)", - "sym":"varchar(200)", - }, - "laps":{ "id_lap": "integer primary key autoincrement", - "record": "integer", - "lap_number": "integer", - "elapsed_time": "varchar(20)", - "distance": "float", - "start_lat": "float", - "start_lon": "float", - "end_lat": "float", - "end_lon": "float", - "calories": "int", - }, - "athletestats": { - "id_athletestat": "integer primary key autoincrement", - "date": "date", - "weight": "float", - "bodyfat": "float", - "restinghr": "integer", - "maxhr": "integer", - }, - } try: tablesDBT = self.ddbbObject.select("sqlite_master","name", "type IN ('table','view') AND name NOT LIKE 'sqlite_%' ORDER BY name") except: @@ -213,6 +215,14 @@ else: logging.info('Database backup successfully created') logging.debug('<<') + + def checkDBDataValues(self): + ''' Check all data in DB and report values that do not match the type ''' + global tablesList + + for table in tablesList.keys(): + pass + def populate_date_time_local(self): ''' Populate date_time_local and date from date_time_utc Modified: pytrainer/trunk/pytrainer/lib/listview.py =================================================================== --- pytrainer/trunk/pytrainer/lib/listview.py 2010-10-11 04:07:51 UTC (rev 651) +++ pytrainer/trunk/pytrainer/lib/listview.py 2010-10-11 21:18:37 UTC (rev 652) @@ -1,31 +1,34 @@ import datetime -#from profile import Profile +import math +LISTPAST = [['All Time', -99999], ['Last 4 Weeks', -31], + ['Last 6 Months', -183], ['Last 12 Months', -366]] + class ListSearch(object): """ Builds SQLite condition out of search parameters""" - def __init__(self, parent = None, pytrainer_main = None): #, data_path = None): + def __init__(self, parent = None, pytrainer_main = None): self.parent = parent self.pytrainer_main = pytrainer_main self.title = '' - self.sport = None + self.sport = 0 self.past = None - - #print self.pytrainer_main.__dict__.keys() - - #self.data_path = data_path - # just dummy until get the right listSport - #self.listSport = [0,1,2,3,4,5,6,7,8,9,10] - + self.duration = None self.listSport = self.pytrainer_main.profile.getSportList() - #print self.listSport - # make this a constant? -az self.listPast = [['All Time', -99999], ['Last 4 Weeks', -31], - ['Last 6 Months', -183], ['Last 12 Months', -366]] + ['Last 6 Months', -183], ['Last 12 Months', -366]] + self.listDuration = [['All Durations', [0,999999]], + ['<1 Hour', [0,3600]], + ['1-2 Hours', [3600,7200]], + ['>2 Hours', [7200,999999]]] + self.listDistance = self.get_listDistance() + #print self.listDistance self.setup_lsa_sport() self.setup_lsa_past() + self.setup_lsa_duration() + self.setup_lsa_distance() def get_condition(self): - ''' sqlite condition is glued together here''' + """ Assembles sqlite condition """ _search = "" _add_and = False if self.title != "": @@ -35,26 +38,57 @@ _sport = self.listSport[self.sport-1][3] _here = "sport=%s" % _sport if _add_and: - _search +=" and " + _here + _search += " and " + _here else: _search = _here _add_and = True if self.listPast[self.past][1]: _delta = datetime.timedelta(days=self.listPast[self.past][1] ) _date = datetime.datetime.today() + _delta - _here = "date>'"+ _date.isoformat() + "'" + _here = "date>'" + _date.isoformat() + "'" if _add_and: _search += " and " + _here else: _search = _here _add_and = True + if self.listDuration[self.duration][1]: + _dur_min = int(self.listDuration[self.duration][1][0]) + _dur_max = int(self.listDuration[self.duration][1][1]) + _here = "(time between %s and %s)" % (_dur_min, _dur_max) + if _add_and: + _search += " and " + _here + else: + _search = _here + _add_and = True + if self.listDistance[self.sport][self.distance][1]: + _dis_min = int(self.listDistance[self.sport][self.distance][1][0]) + _dis_max = int(self.listDistance[self.sport][self.distance][1][1]) + _here = "(distance between %s and %s)" % (_dis_min, _dis_max) + if _add_and: + _search += " and " + _here + else: + _search = _here + _add_and = True print _search return _search + + def get_listDistance(self): + """ Not Finished. Eperimentally. Goal: compute distance intervals + for each sport individually from average and standard deviation. + """ + _all = ['All Distances', [0.0, 99999.9]] + _back = [] + _back.append( [_all] ) + for sp in self.listSport: + _back.append( [_all] ) + return _back + condition = property(get_condition) - + #listDuration = property(get_listDuration) + def setup_lsa_sport(self): - liststore_lsa = self.parent.lsa_sport.get_model() #az + liststore_lsa = self.parent.lsa_sport.get_model() if self.parent.lsa_sport.get_active() is not 0: self.parent.lsa_sport.set_active(0) #Set first item active if isnt firstEntry = self.parent.lsa_sport.get_active_text() @@ -69,7 +103,7 @@ self.parent.lsa_sport.connect("changed", self.parent.on_listareasearch_clicked) def setup_lsa_past(self): - liststore_lsa = self.parent.lsa_past.get_model() #az + liststore_lsa = self.parent.lsa_past.get_model() if self.parent.lsa_past.get_active() > 0: self.parent.lsa_past.set_active(0) #Set first item active isnt firstEntry = self.parent.lsa_past.get_active_text() @@ -79,4 +113,29 @@ self.parent.lsa_past.set_active(0) #Add handler manually, so above changes do not trigger recursive loop self.parent.lsa_past.connect("changed", self.parent.on_listareasearch_clicked) + + def setup_lsa_duration(self): + liststore_lsa = self.parent.lsa_duration.get_model() + if self.parent.lsa_duration.get_active() > 0: + self.parent.lsa_duration.set_active(0) + firstEntry = self.parent.lsa_duration.get_active_text() + liststore_lsa.clear() #Delete all items + for i in self.listDuration: + liststore_lsa.append([i[0]]) + self.parent.lsa_duration.set_active(0) + #Add handler manually, so above changes do not trigger recursive loop + self.parent.lsa_duration.connect("changed", self.parent.on_listareasearch_clicked) + + def setup_lsa_distance(self): + liststore_lsa = self.parent.lsa_distance.get_model() + if self.parent.lsa_distance.get_active() > 0: + self.parent.lsa_distance.set_active(0) + firstEntry = self.parent.lsa_distance.get_active_text() + liststore_lsa.clear() #Delete all items + for i in self.listDistance[self.sport]: + liststore_lsa.append([i[0]]) + self.parent.lsa_distance.set_active(0) + #Add handler manually, so above changes do not trigger recursive loop + self.parent.lsa_distance.connect("changed", self.parent.on_listareasearch_clicked) + Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-11 04:07:51 UTC (rev 651) +++ pytrainer/trunk/pytrainer/main.py 2010-10-11 21:18:37 UTC (rev 652) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#651" + self.version ="1.7.2_svn#652" self.DB_version = 5 #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-11 04:07:59
|
Revision: 651 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=651&view=rev Author: jblance Date: 2010-10-11 04:07:51 +0000 (Mon, 11 Oct 2010) Log Message: ----------- Athlete view additions, graphs all data, new and save implemented Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/athlete.py pytrainer/trunk/pytrainer/gui/drawGraph.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/lib/graphdata.py pytrainer/trunk/pytrainer/lib/mysqlUtils.py pytrainer/trunk/pytrainer/lib/sqliteUtils.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-10-10 22:48:12 UTC (rev 650) +++ pytrainer/trunk/glade/pytrainer.glade 2010-10-11 04:07:51 UTC (rev 651) @@ -5795,7 +5795,7 @@ <child> <widget class="GtkTable" id="table3"> <property name="visible">True</property> - <property name="n_rows">6</property> + <property name="n_rows">7</property> <property name="n_columns">3</property> <child> <widget class="GtkLabel" id="labelAthleteDate"> @@ -5824,25 +5824,6 @@ </packing> </child> <child> - <widget class="GtkButton" id="buttonAlthleteSave"> - <property name="label" translatable="yes">Save</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="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="x_options">GTK_EXPAND</property> - <property name="y_options"></property> - <property name="x_padding">5</property> - <property name="y_padding">5</property> - </packing> - </child> - <child> <widget class="GtkEntry" id="entryAthleteDate"> <property name="visible">True</property> <property name="can_focus">True</property> @@ -5958,13 +5939,55 @@ </packing> </child> <child> - <widget class="GtkLabel" id="labelAthleteIdx"> + <widget class="GtkLabel" id="labelAthleteIdx"/> + <packing> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + <property name="x_options">GTK_EXPAND</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkHBox" id="hbox9"> <property name="visible">True</property> + <child> + <widget class="GtkButton" id="buttonAthleteNew"> + <property name="label" translatable="yes">New</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="on_buttonAthleteNew_clicked"/> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <widget class="GtkButton" id="buttonAlthleteSave"> + <property name="label" translatable="yes">Save</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="on_buttonAlthleteSave_clicked"/> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> </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">GTK_EXPAND</property> <property name="y_options"></property> </packing> </child> @@ -5986,6 +6009,32 @@ <child> <placeholder/> </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <widget class="GtkButton" id="button1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="on_athletecalendar_clicked"/> + <child> + <widget class="GtkImage" id="image7"> + <property name="visible">True</property> + <property name="stock">gtk-index</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> </widget> <packing> <property name="expand">False</property> Modified: pytrainer/trunk/pytrainer/athlete.py =================================================================== --- pytrainer/trunk/pytrainer/athlete.py 2010-10-10 22:48:12 UTC (rev 650) +++ pytrainer/trunk/pytrainer/athlete.py 2010-10-11 04:07:51 UTC (rev 651) @@ -18,8 +18,10 @@ #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import logging +import dateutil -from lib.ddbb import DDBB +from pytrainer.lib.ddbb import DDBB +from pytrainer.lib.graphdata import GraphData class Athlete: def __init__(self, data_path = None, parent = None): @@ -27,16 +29,99 @@ self.parent = parent self.pytrainer_main = parent self.data_path = data_path + self.init_from_conf() + self.data = self.get_athlete_stats() + self.graphdata = self.get_athlete_data() logging.debug('<<') + def refresh(self): + self.init_from_conf() + self.data = self.get_athlete_stats() + self.graphdata = self.get_athlete_data() + + def init_from_conf(self): + logging.debug('>>') + self.name = self.pytrainer_main.profile.getValue("pytraining","prf_name") + self.age = self.pytrainer_main.profile.getValue("pytraining","prf_age") + self.height = self.pytrainer_main.profile.getValue("pytraining","prf_height") + if self.pytrainer_main.profile.getValue("pytraining","prf_us_system") == "True": + self.us_system = True + else: + self.us_system = False + if self.us_system: + self.weight_unit = _("lb") + else: + self.weight_unit = _("kg") + logging.debug('<<') + def get_athlete_stats(self): - print('>>') + logging.debug('>>') stats = [] - results = self.pytrainer_main.ddbb.select("athletestats", "id_athletestat, date, weight, bodyfat, restinghr, maxhr") - print('Found %d athlete stats results' % len(results)) + results = self.pytrainer_main.ddbb.select("athletestats", "id_athletestat, date, weight, bodyfat, restinghr, maxhr", mod="order by date") + logging.debug('Found %d athlete stats results' % len(results)) for row in results: + date = dateutil.parser.parse(row[1]).date() stats.append({'id_athletestat': row[0], 'Date': row[1], 'Weight':row[2], 'BF': row[3], 'RestingHR':row[4], 'MaxHR':row[5]}) + logging.debug('<<') return stats - print('<<') + def get_athlete_data(self): + logging.debug('>>') + graphdata = {} + graphdata['weight'] = GraphData(title="Weight", xlabel="Date", ylabel="Weight (%s)" % (self.weight_unit)) + graphdata['weight'].set_color('#3300FF', '#3300FF') + #graphdata['weight'].graphType = 'fill' + graphdata['bf'] = GraphData(title="Body Fat", xlabel="Date", ylabel="Body Fat (%s)" % (self.weight_unit)) + graphdata['bf'].set_color('#FF6600', '#FF6600') + #graphdata['bf'].graphType = 'fill' + graphdata['restinghr'] = GraphData(title="Resting Heartrate", xlabel="Date", ylabel="Resting Heartrate (bpm)") + graphdata['restinghr'].set_color('#660000', '#660000') + graphdata['restinghr'].show_on_y2 = True + graphdata['maxhr'] = GraphData(title="Maximum Heartrate", xlabel="Date", ylabel="Maximum Heartrate (bpm)") + graphdata['maxhr'].set_color('#33CC99', '#33CC99') + graphdata['maxhr'].show_on_y2 = True + for row in self.data: + date = dateutil.parser.parse(row['Date']).date() + if row['Weight']: + weight = float(row['Weight']) + else: + weight = None + if row['BF']: + bf = float(row['BF']) / 100 * weight + else: + bf = None + graphdata['weight'].addPoints(x=date, y=weight) + graphdata['bf'].addPoints(x=date, y=bf) + graphdata['restinghr'].addPoints(x=date, y=row['RestingHR']) + graphdata['maxhr'].addPoints(x=date, y=row['MaxHR']) + return graphdata + + def update_athlete_stats(self, id_athletestat, date, weight, bodyfat, restinghr, maxhr): + logging.debug('>>') + try: + date = dateutil.parser.parse(date).date() + except ValueError: + return + cells = "date, weight, bodyfat, restinghr, maxhr" + values = (date, weight, bodyfat, restinghr, maxhr) + #Update database + self.pytrainer_main.ddbb.update("athletestats",cells,values," id_athletestat=%d" %int(id_athletestat)) + logging.debug('<<') + + def insert_athlete_stats(self, date, weight, bodyfat, restinghr, maxhr): + logging.debug('>>') + if not date and not weight and not bodyfat and not restinghr and not maxhr: + #no data supplied + logging.debug("insert_athlete_stats called with no data") + logging.debug('!<<') + return + try: + date = dateutil.parser.parse(date).date() + except ValueError: + return + cells = "date, weight, bodyfat, restinghr, maxhr" + values = (date, weight, bodyfat, restinghr, maxhr) + #Update DB + self.pytrainer_main.ddbb.insert("athletestats",cells,values) + logging.debug('<<') Modified: pytrainer/trunk/pytrainer/gui/drawGraph.py =================================================================== --- pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-10-10 22:48:12 UTC (rev 650) +++ pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-10-11 04:07:51 UTC (rev 651) @@ -85,6 +85,11 @@ #Determine graph type.... #print "Got graphtype: %s" % datalist.graphType + #print datalist.x_values + #print datalist.y_values + #print datalist.linewidth + #print datalist.linecolor + #print datalist.ylabel if datalist.graphType == "plot": #Plot data if not y2: @@ -106,6 +111,11 @@ else: self.ax2.axvspan(datalist.x_values[i], datalist.x_values[i]+datalist.bar_widths[i], alpha=0.15, facecolor=datalist.y2linecolor) i += 1 + elif datalist.graphType == "fill": + if not y2: + self.ax1.fill_between(datalist.x_values, datalist.y_values, color=datalist.linecolor, label=datalist.ylabel, alpha=0.5) + else: + self.ax2.fill_between(datalist.x_values, datalist.y_values, color=datalist.y2linecolor, label=datalist.ylabel, alpha=0.5) else: print "Unknown/unimplemented graph type: %s" % datalist.graphType return figure @@ -124,105 +134,28 @@ logging.debug("<<") return figure - def drawPlot(self, datalist = None, box = None): + def drawAthleteGraph(self, athlete = None, box = None): ''' Draw a plot style graph ''' - print "drawGraph 131: DEPRECIATED drawPlot called" - #data = {'linewidth':3, 'x':(1,2,3), 'y':(3,9,1)} logging.debug('>>') + #TODO - supply athlete class (and have that populated with all data required... if box is None: logging.error("Must supply a vbox or hbox to display the graph") return - #Remove existing plot (if any) - for child in box.get_children(): - logging.debug('Removing box child: '+str(child)) - box.remove(child) - if datalist is None: # or len(datalist) == 0: - logging.debug("drawPlot called with no data") + if athlete is None: # or len(datalist) == 0: + logging.error("Must supply data to graph graph") return + figure = None #Debug info - to remove - print("drawPlot....") - #print datalist + #print("drawPlot....") + for item in athlete.graphdata: + #print "drawing", item + figure = self.draw(athlete.graphdata[item], box=box, figure=figure, title=_("Athlete Data"), y2=athlete.graphdata[item].show_on_y2) - #Set up drawing area - figure = plt.figure() - canvas = FigureCanvasGTK(figure) # a gtk.DrawingArea - canvas.show() - #Display title etc - plt.xlabel(datalist.xlabel) - plt.ylabel(datalist.ylabel) - plt.title(datalist.title) - #Plot data - plt.plot(datalist.x_values, datalist.y_values, linewidth=datalist.linewidth, color=datalist.linecolor ) - #Set axis limits - plt.axis([datalist.min_x_value, datalist.max_x_value, datalist.min_y_value, datalist.max_y_value]) - - #axis.set_xlim(0, data.max_x_value) - #axis.set_ylim(0, data.max_y_value) - - #Display plot - box.pack_start(canvas, True, True) - - return - #(self,xvalues,yvalues,xlabel,ylabel,title,color,zones=None,xzones=None, ylimits=None, y1_linewidth=None): - logging.debug("Type: plot | title: "+str(title)+" | col: "+str(color)+" | xlabel: "+str(xlabel)+" | ylabel: "+str(ylabel)) - logging.debug('xlabel: '+str(xlabel)+' | ylabel: '+str(ylabel)+' | title: '+str(title)) - #self.removeVboxChildren() - i = 0 - for value in xvalues: - if i<1: - axis = figure.add_subplot(111) - line = axis.plot(xvalues[i],yvalues[i], color=color[i]) - if y1_linewidth is not None: - line[0].set_linewidth(y1_linewidth) - linewidth = line[0].get_linewidth() - - axis.grid(True) - for tl in axis.get_yticklabels(): - tl.set_color('%s' %color[i]) - #Draw zones on graph, eg for each lap - if xzones is not None: - for xzone in xzones: - if xzones.index(xzone) % 2: - zonecolor='b' - else: - zonecolor='g' - axis.axvspan(xzone[0], xzone[1], alpha=0.25, facecolor=zonecolor) - maxX = max(xvalues[i]) - if i>=1: - ax2 = axis.twinx() - ax2.plot(xvalues[i], yvalues[i], color=color[i]) - for tl in ax2.get_yticklabels(): - tl.set_color('%s' %color[i]) - maxXt = max(xvalues[i]) - if maxXt > maxX: - maxX = maxXt - axis.set_xlabel(xlabel[i]) - i+=1 - axis.set_xlim(0, maxX) - - if (len(xvalues)>1): - axis.set_title("%s vs %s" %(ylabel[0],ylabel[1])) - else: - axis.set_title("%s" %(ylabel[0])) - - ylim_min, ylim_max = axis.get_ylim() - if ylimits is not None: - logging.debug("Using ylimits: %s" % str(ylimits)) - if ylimits[0] is not None: - ylim_min = ylimits[0] - if ylimits[1] is not None: - ylim_max = ylimits[1] - axis.set_ylim(ylim_min, ylim_max) - - - logging.debug('<<') - return {'y1_min': ylim_min, 'y1_max': ylim_max, 'y1_linewidth': linewidth} - - def drawMultiPlot(self, activity = None, box = None): + def drawActivityGraph(self, activity = None, box = None): ''' - Draw a plot style graph with multiple traces on each axis + Draw a multiple style graph using data in an activity (with multiple traces on each axis) ''' logging.debug('>>') if box is None: Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-10 22:48:12 UTC (rev 650) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-11 04:07:51 UTC (rev 651) @@ -46,6 +46,7 @@ from pytrainer.extensions.waypointeditor import WaypointEditor from pytrainer.gui.drawGraph import DrawGraph +from pytrainer.gui.windowcalendar import WindowCalendar from pytrainer.lib.listview import ListSearch class Main(SimpleGladeApp): @@ -456,7 +457,7 @@ self.graph_data_hbox.pack_start(limitsFrame, expand=False, fill=True, padding=5) self.graph_data_hbox.show_all() self.buttonGraphShowOptions.hide() - act = self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) + act = self.grapher.drawActivityGraph(activity=activity, box=self.record_graph_vbox) if act.x_limits_u[0] is not None: xmin, xmax = act.x_limits_u else: @@ -862,42 +863,38 @@ self.drawareayear.drawgraph(record_list) logging.debug("<<") - def actualize_athleteview(self, athletedata): + def actualize_athleteview(self, athlete): logging.debug(">>") - self.labelName.set_text(athletedata["prf_name"]) - self.labelDOB.set_text(athletedata["prf_age"]) - self.labelHeight.set_text(athletedata["prf_height"]+" cm") - #Setup graph - #self.grapher = DrawGraph(self, self.pytrainer_main) - from pytrainer.lib.graphdata import GraphData - datalist = GraphData(title="Weight", xlabel="Date", ylabel="kg") + self.labelName.set_text(athlete.name) + self.labelDOB.set_text(athlete.age) + self.labelHeight.set_text(athlete.height+" cm") + #TODO #Create history treeview history_store = gtk.ListStore( - gobject.TYPE_INT, #id + gobject.TYPE_STRING, #id gobject.TYPE_STRING, #date gobject.TYPE_STRING, #weight gobject.TYPE_STRING, #body fat % - gobject.TYPE_INT, #resting HR - gobject.TYPE_INT #max HR + gobject.TYPE_STRING, #resting HR + gobject.TYPE_STRING #max HR ) - for data_index, data in enumerate(athletedata['history']): - weight = float(data['Weight']) + for data in athlete.data: + weight = (data['Weight']) date = dateutil.parser.parse(data['Date']).date() iter = history_store.append() history_store.set ( iter, - 0, int(data['id_athletestat']), + 0, (data['id_athletestat']), 1, date, #TODO need to sort date graphing... - 2, "%0.2f" % weight, - 3, "%0.2f" % float(data['BF']), - 4, int(data['RestingHR']), - 5, int(data['MaxHR']), + 2, weight, + 3, (data['BF']), + 4, (data['RestingHR']), + 5, (data['MaxHR']), ) - datalist.addPoints(x=date, y=weight) self.athleteTreeView.set_model(history_store) - self.grapher.drawPlot(datalist=datalist, box=self.boxAthleteGraph) + self.grapher.drawAthleteGraph(athlete=athlete, box=self.boxAthleteGraph) logging.debug("<<") def actualize_listview(self,record_list): @@ -1173,7 +1170,6 @@ elif activity.x_axis == "time": activity.time_data[graphdata].set_color(str(widget.get_color())) #Replot the activity - #self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) self.actualize_recordgraph(activity) def on_y2colorchange(self, widget, box, graphdata, activity): @@ -1184,7 +1180,6 @@ elif activity.x_axis == "time": activity.time_data[graphdata].set_color(None, str(widget.get_color())) #Replot the activity - #self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) self.actualize_recordgraph(activity) def on_y1change(self, widget, box, graphdata, activity): @@ -1203,7 +1198,6 @@ logging.debug( "Setting %s to %s" % (item, str(child.get_active()) ) ) activity.time_data[item].show_on_y1 = child.get_active() #Replot the activity - #self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) self.actualize_recordgraph(activity) def on_y2change(self, widget, box, graphdata, activity): @@ -1222,7 +1216,6 @@ logging.debug( "Setting %s to %s" % (item, str(child.get_active()) ) ) activity.time_data[item].show_on_y2 = child.get_active() #Replot the activity - #self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) self.actualize_recordgraph(activity) def on_setlimits(self, widget, activity, reset, data): @@ -1251,25 +1244,6 @@ #Replot the activity self.actualize_recordgraph(activity) - def on_athleteTreeView_button_press_event(self, treeview, event): - x = int(event.x) - y = int(event.y) - time = event.time - pthinfo = treeview.get_path_at_pos(x, y) - if pthinfo is not None: - path, col, cellx, celly = pthinfo - treeview.grab_focus() - treeview.set_cursor(path, col, 0) - selected,iter = treeview.get_selection().get_selected() - idx = selected.get_value(iter,0) - date = selected.get_value(iter,1) - weight = selected.get_value(iter,2) - bf = selected.get_value(iter,3) - restingHR = selected.get_value(iter,4) - maxHR = selected.get_value(iter,5) - self.update_athlete_item(idx, date, weight, bf, restingHR, maxHR) - #print path, col, cellx, celly - def on_window1_configure_event(self, widget, event): #print widget #window widget #print event # resize event @@ -1625,6 +1599,71 @@ def on_recordTree_clicked(self,widget,num,num2): selected,iter = self.recordTreeView.get_selection().get_selected() self.parent.editRecord(selected.get_value(iter,0)) + + ### athleteview events ### + def on_athleteTreeView_button_press_event(self, treeview, event): + x = int(event.x) + y = int(event.y) + time = event.time + pthinfo = treeview.get_path_at_pos(x, y) + if pthinfo is not None: + path, col, cellx, celly = pthinfo + treeview.grab_focus() + treeview.set_cursor(path, col, 0) + selected,iter = treeview.get_selection().get_selected() + idx = selected.get_value(iter,0) + date = selected.get_value(iter,1) + weight = selected.get_value(iter,2) + bf = selected.get_value(iter,3) + restingHR = selected.get_value(iter,4) + maxHR = selected.get_value(iter,5) + self.update_athlete_item(idx, date, weight, bf, restingHR, maxHR) + #print path, col, cellx, celly + + def on_buttonAthleteNew_clicked(self, widget): + #Reset Fields + self.labelAthleteIdx.set_text("") + self.entryAthleteDate.set_text("") + self.entryAthleteWeight.set_text("") + self.entryAthleteBF.set_text("") + self.entryAthleteRestingHR.set_text("") + self.entryAthleteMaxHR.set_text("") + + def on_buttonAlthleteSave_clicked(self, widget): + #Get data in fields + id_athletestat = self.labelAthleteIdx.get_text() + date = self.entryAthleteDate.get_text() + #Check if valid date supplied + try: + _date = dateutil.parser.parse(date).date() + except (ValueError) as e: + #TODO generate error message + print type(e) + print e + return + weight = self.entryAthleteWeight.get_text() + bodyfat = self.entryAthleteBF.get_text() + restinghr = self.entryAthleteRestingHR.get_text() + maxhr = self.entryAthleteMaxHR.get_text() + #TODO - are any other fields required? + + #Check if an entry has been edited or is a new one + if id_athletestat is None or id_athletestat == "": + #New entry + logging.debug('Creating new entry with values: date %s, weight %s, bodyfat %s, restinghr %s, maxhr %s' % (date, weight, bodyfat, restinghr, maxhr) ) + self.parent.athlete.insert_athlete_stats(date, weight, bodyfat, restinghr, maxhr) + else: + #Edited existing entry + logging.debug('Updating id_athletestat:%s with values: date %s, weight %s, bodyfat %s, restinghr %s, maxhr %s' % (id_athletestat, date, weight, bodyfat, restinghr, maxhr) ) + self.parent.athlete.update_athlete_stats(id_athletestat, date, weight, bodyfat, restinghr, maxhr) + self.parent.refreshAthleteView() + + def on_athletecalendar_clicked(self,widget): + calendardialog = WindowCalendar(self.data_path,self) + calendardialog.run() + + def setDate(self,date): + self.entryAthleteDate.set_text(date) ######## waypoints events ########## def on_savewaypoint_clicked(self,widget): Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-10 22:48:12 UTC (rev 650) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-11 04:07:51 UTC (rev 651) @@ -64,8 +64,8 @@ self.ddbbObject.createTables() self.ddbbObject.createTableVersion() - def select(self,table,cells,condition=None): - return self.ddbbObject.select(table,cells,condition) + def select(self,table,cells,condition=None, mod=None): + return self.ddbbObject.select(table,cells,condition,mod) def select_dict(self,table,cells,condition=None): ''' Modified: pytrainer/trunk/pytrainer/lib/graphdata.py =================================================================== --- pytrainer/trunk/pytrainer/lib/graphdata.py 2010-10-10 22:48:12 UTC (rev 650) +++ pytrainer/trunk/pytrainer/lib/graphdata.py 2010-10-11 04:07:51 UTC (rev 651) @@ -65,7 +65,8 @@ self.bar_bottoms.append(0) def addPoints(self, x=None, y=None): - if x is None or y is None: + #if x is None or y is None or x is "": + if not x or not y: #logging.debug("Must supply both x and y data points, got x:'%s' y:'%s'" % (str(x), str(y))) return #print('Adding point: %s %s' % (str(x), str(y))) Modified: pytrainer/trunk/pytrainer/lib/mysqlUtils.py =================================================================== --- pytrainer/trunk/pytrainer/lib/mysqlUtils.py 2010-10-10 22:48:12 UTC (rev 650) +++ pytrainer/trunk/pytrainer/lib/mysqlUtils.py 2010-10-11 04:07:51 UTC (rev 651) @@ -147,7 +147,7 @@ sql = "delete from %s where %s" %(table,condition) self.db.query(sql) - def select(self,table,cells,condition): + def select(self,table,cells,condition, mod=None): if condition != None: self.db.query("""select %s from %s where %s""" %(cells,table,condition)) else: Modified: pytrainer/trunk/pytrainer/lib/sqliteUtils.py =================================================================== --- pytrainer/trunk/pytrainer/lib/sqliteUtils.py 2010-10-10 22:48:12 UTC (rev 650) +++ pytrainer/trunk/pytrainer/lib/sqliteUtils.py 2010-10-11 04:07:51 UTC (rev 651) @@ -21,252 +21,257 @@ import logging import sys, traceback try: - from sqlite3 import dbapi2 as sqlite + from sqlite3 import dbapi2 as sqlite except ImportError: - logging.error('Not able to find sqlite2 module (new in python 2.5)') - from pysqlite2 import dbapi2 as sqlite - logging.info('Using pysqlite2 module to access DB. Think about upgrading to python 2.5!') - + logging.error('Not able to find sqlite2 module (new in python 2.5)') + from pysqlite2 import dbapi2 as sqlite + logging.info('Using pysqlite2 module to access DB. Think about upgrading to python 2.5!') + from logs import Log class Sql: - def __init__(self,host=None, ddbb = None, user = None, password = None, configuration = None): - self.db = None - confdir = configuration.confdir - self.ddbb = "%s/pytrainer.ddbb" %confdir - self.log = Log() - - def connect(self): - #si devolvemos 1 ha ido todo con exito - self.db = sqlite.connect(self.ddbb) - #probamos si estan las tablas creadas, y sino.. las creamos - try: - self.select("records","id_record","1=1 limit 0,1") - except: - self.createTables() - return 1 + def __init__(self,host=None, ddbb = None, user = None, password = None, configuration = None): + self.db = None + confdir = configuration.confdir + self.ddbb = "%s/pytrainer.ddbb" %confdir + self.log = Log() + + def connect(self): + #si devolvemos 1 ha ido todo con exito + self.db = sqlite.connect(self.ddbb) + #probamos si estan las tablas creadas, y sino.. las creamos + try: + self.select("records","id_record","1=1 limit 0,1") + except: + self.createTables() + return 1 - def disconnect(self): - self.db.close() - - def createDDBB(self): - pass + def disconnect(self): + self.db.close() + + def createDDBB(self): + pass - def createTables(self): #TODO Needs to be fixed to create tables based on definition, perhaps replaced by createTableDefault? - cur = self.db.cursor() - #creamos la tabla sports - sql = """CREATE TABLE sports ( - id_sports integer primary key autoincrement, - name varchar (100), - weight float, - met float - );""" - cur.execute(sql) + def createTables(self): #TODO Needs to be fixed to create tables based on definition, perhaps replaced by createTableDefault? + cur = self.db.cursor() + #creamos la tabla sports + sql = """CREATE TABLE sports ( + id_sports integer primary key autoincrement, + name varchar (100), + weight float, + met float + );""" + cur.execute(sql) - #creamos la tabla records - sql = """CREATE TABLE records ( - id_record integer primary key autoincrement , - date date, - sport integer, - distance float, - time varchar (200), - beats float, - average float, - calories int, - comments text, - gpslog varchar(200), - title varchar(200), - upositive float, - unegative float, - maxspeed float, - maxpace float, - pace float, - maxbeats float, + #creamos la tabla records + sql = """CREATE TABLE records ( + id_record integer primary key autoincrement , + date date, + sport integer, + distance float, + time varchar (200), + beats float, + average float, + calories int, + comments text, + gpslog varchar(200), + title varchar(200), + upositive float, + unegative float, + maxspeed float, + maxpace float, + pace float, + maxbeats float, date_time_utc varchar2(20) - ) ;""" - cur.execute(sql) + ) ;""" + cur.execute(sql) - #creamos la tabla waypoints - sql = """CREATE TABLE waypoints ( - id_waypoint integer primary key autoincrement , - lat float, - lon float, - ele float, - comment varchar (240), - time date, - name varchar (200), - sym varchar (200) - ) ;""" - cur.execute(sql) + #creamos la tabla waypoints + sql = """CREATE TABLE waypoints ( + id_waypoint integer primary key autoincrement , + lat float, + lon float, + ele float, + comment varchar (240), + time date, + name varchar (200), + sym varchar (200) + ) ;""" + cur.execute(sql) - self.insert("sports","name",["Mountain Bike"]); - self.insert("sports","name",["Bike"]); - self.insert("sports","name",["Run"]); + self.insert("sports","name",["Mountain Bike"]); + self.insert("sports","name",["Bike"]); + self.insert("sports","name",["Run"]); - def createTableDefault(self,tableName,columns): - """22.11.2009 - dgranda - Creates a new table in database given name and column name and data types. New in version 1.7.0 - args: - tableName - string with name of the table - columns - dictionary containing column names and data types coming from definition - returns: none""" - logging.debug('>>') - logging.info('Creating '+str(tableName)+' table with default values') - logging.debug('Columns definition: '+str(columns)) - cur = self.db.cursor() - sql = 'CREATE TABLE %s (' %(tableName) - for entry in columns: - sql += '%s %s,' %(entry,columns[entry]) - # Removing trailing comma - sql = sql.rstrip(',') - sql = sql+");" - logging.debug('SQL sentence: '+str(sql)) - cur.execute(sql) - logging.debug('<<') - - def addWaipoints2ddbb(self): #TODO Remove? - cur = self.db.cursor() - sql = """CREATE TABLE waypoints ( - id_waypoint integer primary key autoincrement , - lat float, - lon float, - ele float, - comment varchar (240), - time date, - name varchar (200), - sym varchar (200) - ) ;""" - cur.execute(sql) - - def insert(self,table, cells, values): - cur = self.db.cursor() - val = values - count = 0 - string = "" - for i in val: - if count>0: - string+="," - string+="""\"%s\"""" %i - count = count+1 - sql = "insert into %s (%s) values (%s)" %(table,cells,string) - self.log.run(sql) - cur.execute(sql) - self.db.commit() + def createTableDefault(self,tableName,columns): + """22.11.2009 - dgranda + Creates a new table in database given name and column name and data types. New in version 1.7.0 + args: + tableName - string with name of the table + columns - dictionary containing column names and data types coming from definition + returns: none""" + logging.debug('>>') + logging.info('Creating '+str(tableName)+' table with default values') + logging.debug('Columns definition: '+str(columns)) + cur = self.db.cursor() + sql = 'CREATE TABLE %s (' %(tableName) + for entry in columns: + sql += '%s %s,' %(entry,columns[entry]) + # Removing trailing comma + sql = sql.rstrip(',') + sql = sql+");" + logging.debug('SQL sentence: '+str(sql)) + cur.execute(sql) + logging.debug('<<') + + def addWaipoints2ddbb(self): #TODO Remove? + cur = self.db.cursor() + sql = """CREATE TABLE waypoints ( + id_waypoint integer primary key autoincrement , + lat float, + lon float, + ele float, + comment varchar (240), + time date, + name varchar (200), + sym varchar (200) + ) ;""" + cur.execute(sql) + + def insert(self,table, cells, values): + cur = self.db.cursor() + val = values + count = 0 + string = "" + for i in val: + if count>0: + string+="," + string+="""\"%s\"""" %i + count = count+1 + sql = "insert into %s (%s) values (%s)" %(table,cells,string) + self.log.run(sql) + cur.execute(sql) + self.db.commit() - def freeExec(self,sql): - cur = self.db.cursor() - self.log.run(sql) - cur.execute(sql) - retorno = [] - for row in cur: - retorno.append(row) - self.db.commit() - return retorno + def freeExec(self,sql): + cur = self.db.cursor() + self.log.run(sql) + cur.execute(sql) + retorno = [] + for row in cur: + retorno.append(row) + self.db.commit() + return retorno - def delete(self,table,condition): - cur = self.db.cursor() - sql = "delete from %s where %s" %(table,condition) - self.log.run(sql) - cur.execute(sql) - self.db.commit() + def delete(self,table,condition): + cur = self.db.cursor() + sql = "delete from %s where %s" %(table,condition) + self.log.run(sql) + cur.execute(sql) + self.db.commit() - def update(self,table,cells,values, condition): - cur = self.db.cursor() - cells = cells.split(",") - count = 0 - string = "" - for val in values: - if count>0: - string+="," - string += """%s="%s" """ %(cells[count],values[count]) - count = count+1 + def update(self,table,cells,values, condition): + cur = self.db.cursor() + cells = cells.split(",") + count = 0 + string = "" + for val in values: + if count>0: + string+="," + string += """%s="%s" """ %(cells[count],values[count]) + count = count+1 - string +=" where %s" %condition - sql = "update %s set %s" %(table,string) - self.log.run(sql) - cur.execute(sql) - self.db.commit() + string +=" where %s" %condition + sql = "update %s set %s" %(table,string) + self.log.run(sql) + cur.execute(sql) + self.db.commit() - def select(self,table,cells,condition): - cur = self.db.cursor() - if condition != None: - sql = "select %s from %s where %s" %(cells,table,condition) - else: - sql = "select %s from %s " %(cells,table) - self.log.run(sql) - cur.execute(sql) - retorno = [] - for row in cur: - retorno.append(row) - return retorno + def select(self,table,cells,condition, mod=None): + cur = self.db.cursor() + sql = "select %s from %s" %(cells,table) + if condition is not None: + sql = "%s where %s" % (sql, condition) + if mod is not None: + sql = "%s %s" % (sql, mod) + '''if condition != None: + sql = "select %s from %s where %s" %(cells,table,condition) + else: + sql = "select %s from %s " %(cells,table)''' + self.log.run(sql) + cur.execute(sql) + retorno = [] + for row in cur: + retorno.append(row) + return retorno - def checkTable(self,tableName,columns): - """19.11.2009 - dgranda - Checks column names and values from table and adds something if missed. New in version 1.7.0 - args: - tableName - string with name of the table - columns - dictionary containing column names and data types coming from definition - returns: none""" - logging.debug('>>') - logging.info('Inspecting '+str(tableName)+' table') - logging.debug('Columns definition: '+str(columns)) + def checkTable(self,tableName,columns): + """19.11.2009 - dgranda + Checks column names and values from table and adds something if missed. New in version 1.7.0 + args: + tableName - string with name of the table + columns - dictionary containing column names and data types coming from definition + returns: none""" + logging.debug('>>') + logging.info('Inspecting '+str(tableName)+' table') + logging.debug('Columns definition: '+str(columns)) - # Retrieving data from DB - tableInfo = self.retrieveTableInfo(tableName) - #logging.debug('Raw data retrieved from DB '+str(tableName)+': '+str(tableInfo)) + # Retrieving data from DB + tableInfo = self.retrieveTableInfo(tableName) + #logging.debug('Raw data retrieved from DB '+str(tableName)+': '+str(tableInfo)) - # Comparing data retrieved from DB with what comes from definition - columnsDB = {} - for field in tableInfo: - newField = {field[1]:field[2]} - columnsDB.update(newField) - logging.debug('Useful data retrieved from '+str(tableName)+' in DB: '+str(columnsDB)) + # Comparing data retrieved from DB with what comes from definition + columnsDB = {} + for field in tableInfo: + newField = {field[1]:field[2]} + columnsDB.update(newField) + logging.debug('Useful data retrieved from '+str(tableName)+' in DB: '+str(columnsDB)) - # http://mail.python.org/pipermail/python-list/2002-May/141458.html - #tempDict = dict(zip(columns,columns)) - tempDict = dict(columns) - #Test for columns that are in DB that shouldn't be - result = [x for x in columnsDB if x not in tempDict] - #Test for columns that are not in the DB that should be - result2 = [x for x in tempDict if x not in columnsDB] + # http://mail.python.org/pipermail/python-list/2002-May/141458.html + #tempDict = dict(zip(columns,columns)) + tempDict = dict(columns) + #Test for columns that are in DB that shouldn't be + result = [x for x in columnsDB if x not in tempDict] + #Test for columns that are not in the DB that should be + result2 = [x for x in tempDict if x not in columnsDB] - logging.debug("Columns in DB that shouldnt be: "+str(result)) - logging.debug("Columns missing from DB: "+str(result2)) + logging.debug("Columns in DB that shouldnt be: "+str(result)) + logging.debug("Columns missing from DB: "+str(result2)) - table_ok = True - if len(result) > 0: - logging.debug('Found columns in DB that should not be: '+ str(result)) - table_ok = False - for entry in result: - logging.debug('Column '+ str(entry) +' in DB but not in definition') - print "Column %s in DB but not in definition - please fix manually" % (str(entry)) - print "#TODO need to add auto fix code" - sys.exit(1) - if len(result2) > 0: # may have also different data type - logging.debug('Found columns missed in DB: '+ str(result2)) - table_ok = False - for entry in result2: - logging.debug('Column '+ str(entry) +' not found in DB') - self.addColumn(tableName,str(entry),columns[entry]) - if table_ok: - logging.info('Table '+ str(tableName) +' is OK') - logging.debug('<<') + table_ok = True + if len(result) > 0: + logging.debug('Found columns in DB that should not be: '+ str(result)) + table_ok = False + for entry in result: + logging.debug('Column '+ str(entry) +' in DB but not in definition') + print "Column %s in DB but not in definition - please fix manually" % (str(entry)) + print "#TODO need to add auto fix code" + sys.exit(1) + if len(result2) > 0: # may have also different data type + logging.debug('Found columns missed in DB: '+ str(result2)) + table_ok = False + for entry in result2: + logging.debug('Column '+ str(entry) +' not found in DB') + self.addColumn(tableName,str(entry),columns[entry]) + if table_ok: + logging.info('Table '+ str(tableName) +' is OK') + logging.debug('<<') - def retrieveTableInfo(self,tableName): - cur = self.db.cursor() - sql = "PRAGMA table_info(%s);" %tableName - cur.execute(sql) - tableInfo = [] - for row in cur: - tableInfo.append(row) - return tableInfo + def retrieveTableInfo(self,tableName): + cur = self.db.cursor() + sql = "PRAGMA table_info(%s);" %tableName + cur.execute(sql) + tableInfo = [] + for row in cur: + tableInfo.append(row) + return tableInfo - def addColumn(self,tableName,columnName,dataType): - sql = "alter table %s add %s %s" %(tableName,columnName,dataType) - logging.debug("Trying SQL: %s" % sql) - try: - self.freeExec(sql) - except: - logging.error('Not able to add/change column '+columnName+' to table '+tableName) - traceback.print_exc() + def addColumn(self,tableName,columnName,dataType): + sql = "alter table %s add %s %s" %(tableName,columnName,dataType) + logging.debug("Trying SQL: %s" % sql) + try: + self.freeExec(sql) + except: + logging.error('Not able to add/change column '+columnName+' to table '+tableName) + traceback.print_exc() Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-10 22:48:12 UTC (rev 650) +++ pytrainer/trunk/pytrainer/main.py 2010-10-11 04:07:51 UTC (rev 651) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#650" + self.version ="1.7.2_svn#651" self.DB_version = 5 #Process command line options self.startup_options = self.get_options() @@ -309,12 +309,8 @@ def refreshAthleteView(self): logging.debug('>>') - athletedata = {} - athletedata['prf_name'] = self.profile.getValue("pytraining","prf_name") - athletedata['prf_age'] = self.profile.getValue("pytraining","prf_age") - athletedata['prf_height'] = self.profile.getValue("pytraining","prf_height") - athletedata['history'] = self.athlete.get_athlete_stats() - self.windowmain.actualize_athleteview(athletedata) + self.athlete.refresh() + self.windowmain.actualize_athleteview(self.athlete) logging.debug('<<') def refreshListView(self): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-10-10 22:48:18
|
Revision: 650 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=650&view=rev Author: jblance Date: 2010-10-10 22:48:12 +0000 (Sun, 10 Oct 2010) Log Message: ----------- List View improvements from Arnd Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/main.py Added Paths: ----------- pytrainer/trunk/pytrainer/lib/listview.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-10-08 04:08:23 UTC (rev 649) +++ pytrainer/trunk/glade/pytrainer.glade 2010-10-10 22:48:12 UTC (rev 650) @@ -296,6 +296,7 @@ <widget class="GtkComboBoxEntry" id="sportlist"> <property name="width_request">52</property> <property name="visible">True</property> + <property name="active">0</property> <property name="items" translatable="yes">All Sports</property> <signal name="changed" handler="on_sportlist_changed"/> </widget> @@ -5299,6 +5300,28 @@ </packing> </child> <child> + <widget class="GtkComboBox" id="lsa_past"> + <property name="visible">True</property> + <property name="active">0</property> + <property name="items" translatable="yes">All time +Last 4 weeks +Last 6 months +Last 12 months</property> + </widget> + <packing> + <property name="position">4</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="lsa_sport"> + <property name="visible">True</property> + <property name="items" translatable="yes">All Sports</property> + </widget> + <packing> + <property name="position">5</property> + </packing> + </child> + <child> <widget class="GtkMenuBar" id="listviewOptions"> <property name="visible">True</property> <child> @@ -5315,7 +5338,7 @@ <packing> <property name="expand">False</property> <property name="fill">False</property> - <property name="position">4</property> + <property name="position">6</property> </packing> </child> </widget> @@ -5326,14 +5349,7 @@ </packing> </child> <child> - <widget class="GtkHSeparator" id="hseparator5"> - <property name="visible">True</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> + <placeholder/> </child> <child> <widget class="GtkScrolledWindow" id="listare"> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-08 04:08:23 UTC (rev 649) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-10 22:48:12 UTC (rev 650) @@ -46,6 +46,7 @@ from pytrainer.extensions.waypointeditor import WaypointEditor from pytrainer.gui.drawGraph import DrawGraph +from pytrainer.lib.listview import ListSearch class Main(SimpleGladeApp): def __init__(self, data_path = None, parent = None, version = None, gpxDir = None): @@ -60,6 +61,7 @@ glade_path="glade/pytrainer.glade" root = "window1" domain = None + SimpleGladeApp.__init__(self, self.data_path+glade_path, root, domain) self.popup = PopupMenu(data_path,self) @@ -75,7 +77,9 @@ self.y1_limits = None self.y1_color = None self.y1_linewidth = 1 - + # setup Search ListView + self.mylistsearch = ListSearch(self, self.pytrainer_main) + def new(self): self.testimport = self.pytrainer_main.startup_options.testimport self.menublocking = 0 @@ -91,7 +95,9 @@ column_names=[_("id"),_("Start"), _("Sport"),_("Kilometer")] self.create_treeview(self.recordTreeView,column_names) #create the columns for the listarea - column_names=[_("id"),_("Title"),_("Date"),_("Distance"),_("Sport"),_("Time"),_("Beats"),_("Average"),("Calories")] + # different codings for mean see eg http://de.wikipedia.org/wiki/%C3%98#Kodierung + #column_names=[_("id"),_("Title"),_("Date"),_("Distance"),_("Sport"),_("Time"),_("Beats"),_("Average"),("Calories")] + column_names=[_("id"),_("Title"),_("Date"),_("Distance"),_("Sport"),_("Time"),_(u"\u2300 HR"),_(u"\u2300 Speed"),("Calories")] self.create_treeview(self.allRecordTreeView,column_names) self.create_menulist(column_names) #create the columns for the waypoints treeview @@ -115,6 +121,8 @@ self.radiobuttonOSM.set_active(1) else: self.radiobuttonGMap.set_active(1) + + def _float_or(self, value, default): '''Function to parse and return a float, or the default if the parsing fails''' @@ -225,6 +233,10 @@ column.set_resizable(True) if i==0: column.set_visible(False) + # experimental az + if column_name =='time': + print 'found Time' + column.set_alignment(0) column.set_sort_column_id(i) treeview.append_column(column) i+=1 @@ -908,7 +920,13 @@ object) for i in record_list: hour,min,sec = date.second2time(int(i[6])) - _time = "%d:%02d:%02d" %(hour,min,sec) + _time = "%2d:%02d:%02d" %(hour,min,sec) #original + # experimental only + if hour >0: + _hh = "%2d:%02d:%02d" %(hour, min, sec) + else: + _hh = "___%2d:%02d" %(min, sec) + #_time =_hh try: _id = int(i[5]) except (ValueError, TypeError) as e: @@ -943,6 +961,7 @@ ) #self.allRecordTreeView.set_headers_clickable(True) self.allRecordTreeView.set_model(store) + self.allRecordTreeView.set_rules_hint(True) logging.debug("<<") def actualize_waypointview(self,record_list,default_waypoint,redrawmap = 1): @@ -1022,7 +1041,7 @@ self.parent.refreshWaypointView(id_waypoint) return False - def on_listareasearch_clicked(self,widget): + def on_listareasearch_clicked(self, widget): lisOpt = { _("Title"):"title", _("Date"):"date", @@ -1033,9 +1052,15 @@ _("Average"):"average", _("Calories"):"calories" } - search_string = self.lsa_searchvalue.get_text() + #search_string = self.lsa_searchvalue.get_text() + #print widget + self.mylistsearch.title = self.lsa_searchvalue.get_text() + self.mylistsearch.sport = self.lsa_sport.get_active() + self.mylistsearch.past = self.lsa_past.get_active() + #print self.mylistsearch.past + #search_string2 = "title like '%"+search_string+"%'" #ddbb_field = lisOpt[self.lsa_searchoption.get_active_text()] - self.parent.searchListView("title like '%"+search_string+"%'") + self.parent.searchListView(self.mylistsearch.condition) def create_menulist(self,column_names): i=0 Added: pytrainer/trunk/pytrainer/lib/listview.py =================================================================== --- pytrainer/trunk/pytrainer/lib/listview.py (rev 0) +++ pytrainer/trunk/pytrainer/lib/listview.py 2010-10-10 22:48:12 UTC (rev 650) @@ -0,0 +1,82 @@ +import datetime +#from profile import Profile + +class ListSearch(object): + """ Builds SQLite condition out of search parameters""" + def __init__(self, parent = None, pytrainer_main = None): #, data_path = None): + self.parent = parent + self.pytrainer_main = pytrainer_main + self.title = '' + self.sport = None + self.past = None + + #print self.pytrainer_main.__dict__.keys() + + #self.data_path = data_path + # just dummy until get the right listSport + #self.listSport = [0,1,2,3,4,5,6,7,8,9,10] + + self.listSport = self.pytrainer_main.profile.getSportList() + #print self.listSport + # make this a constant? -az + self.listPast = [['All Time', -99999], ['Last 4 Weeks', -31], + ['Last 6 Months', -183], ['Last 12 Months', -366]] + self.setup_lsa_sport() + self.setup_lsa_past() + + def get_condition(self): + ''' sqlite condition is glued together here''' + _search = "" + _add_and = False + if self.title != "": + _search = "title like '%" +self.title + "%'" + _add_and = True + if self.sport > 0: + _sport = self.listSport[self.sport-1][3] + _here = "sport=%s" % _sport + if _add_and: + _search +=" and " + _here + else: + _search = _here + _add_and = True + if self.listPast[self.past][1]: + _delta = datetime.timedelta(days=self.listPast[self.past][1] ) + _date = datetime.datetime.today() + _delta + _here = "date>'"+ _date.isoformat() + "'" + if _add_and: + _search += " and " + _here + else: + _search = _here + _add_and = True + print _search + return _search + + condition = property(get_condition) + + def setup_lsa_sport(self): + liststore_lsa = self.parent.lsa_sport.get_model() #az + if self.parent.lsa_sport.get_active() is not 0: + self.parent.lsa_sport.set_active(0) #Set first item active if isnt + firstEntry = self.parent.lsa_sport.get_active_text() + liststore_lsa.clear() #Delete all items + #Re-add "All Sports" + liststore_lsa.append([firstEntry]) + #Re-add all sports in listSport + for i in self.listSport: + liststore_lsa.append([i[0]]) + self.parent.lsa_sport.set_active(0) + #Add handler manually, so above changes do not trigger recursive loop + self.parent.lsa_sport.connect("changed", self.parent.on_listareasearch_clicked) + + def setup_lsa_past(self): + liststore_lsa = self.parent.lsa_past.get_model() #az + if self.parent.lsa_past.get_active() > 0: + self.parent.lsa_past.set_active(0) #Set first item active isnt + firstEntry = self.parent.lsa_past.get_active_text() + liststore_lsa.clear() #Delete all items + for i in self.listPast: + liststore_lsa.append([i[0]]) + self.parent.lsa_past.set_active(0) + #Add handler manually, so above changes do not trigger recursive loop + self.parent.lsa_past.connect("changed", self.parent.on_listareasearch_clicked) + Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-08 04:08:23 UTC (rev 649) +++ pytrainer/trunk/pytrainer/main.py 2010-10-10 22:48:12 UTC (rev 650) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#649" + self.version ="1.7.2_svn#650" self.DB_version = 5 #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-08 04:08:29
|
Revision: 649 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=649&view=rev Author: jblance Date: 2010-10-08 04:08:23 +0000 (Fri, 08 Oct 2010) Log Message: ----------- Add athlete stats DB table Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/main.py Added Paths: ----------- pytrainer/trunk/pytrainer/athlete.py Added: pytrainer/trunk/pytrainer/athlete.py =================================================================== --- pytrainer/trunk/pytrainer/athlete.py (rev 0) +++ pytrainer/trunk/pytrainer/athlete.py 2010-10-08 04:08:23 UTC (rev 649) @@ -0,0 +1,42 @@ +# -*- 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 + +from lib.ddbb import DDBB + +class Athlete: + def __init__(self, data_path = None, parent = None): + logging.debug('>>') + self.parent = parent + self.pytrainer_main = parent + self.data_path = data_path + logging.debug('<<') + + def get_athlete_stats(self): + print('>>') + stats = [] + results = self.pytrainer_main.ddbb.select("athletestats", "id_athletestat, date, weight, bodyfat, restinghr, maxhr") + print('Found %d athlete stats results' % len(results)) + for row in results: + stats.append({'id_athletestat': row[0], 'Date': row[1], 'Weight':row[2], 'BF': row[3], 'RestingHR':row[4], 'MaxHR':row[5]}) + return stats + print('<<') + + Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-07 03:53:23 UTC (rev 648) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-08 04:08:23 UTC (rev 649) @@ -862,7 +862,7 @@ #TODO #Create history treeview history_store = gtk.ListStore( - gobject.TYPE_INT, #index + gobject.TYPE_INT, #id gobject.TYPE_STRING, #date gobject.TYPE_STRING, #weight gobject.TYPE_STRING, #body fat % @@ -876,7 +876,7 @@ iter = history_store.append() history_store.set ( iter, - 0, data_index, + 0, int(data['id_athletestat']), 1, date, #TODO need to sort date graphing... 2, "%0.2f" % weight, 3, "%0.2f" % float(data['BF']), Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-07 03:53:23 UTC (rev 648) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-08 04:08:23 UTC (rev 649) @@ -162,6 +162,14 @@ "end_lon": "float", "calories": "int", }, + "athletestats": { + "id_athletestat": "integer primary key autoincrement", + "date": "date", + "weight": "float", + "bodyfat": "float", + "restinghr": "integer", + "maxhr": "integer", + }, } try: tablesDBT = self.ddbbObject.select("sqlite_master","name", "type IN ('table','view') AND name NOT LIKE 'sqlite_%' ORDER BY name") Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-07 03:53:23 UTC (rev 648) +++ pytrainer/trunk/pytrainer/main.py 2010-10-08 04:08:23 UTC (rev 649) @@ -38,6 +38,7 @@ from importdata import Importdata from plugins import Plugins from profile import Profile +from athlete import Athlete from gui.windowimportdata import WindowImportdata from gui.windowmain import Main @@ -49,8 +50,8 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#648" - self.DB_version = 4 + self.version ="1.7.2_svn#649" + self.DB_version = 5 #Process command line options self.startup_options = self.get_options() #Setup logging @@ -80,6 +81,7 @@ else: logging.info('No sanity check requested') self.record = Record(data_path,self) + self.athlete = Athlete(data_path,self) pool_size = self.profile.getIntValue("pytraining","activitypool_size", default=1) self.activitypool = ActivityPool(self, size=pool_size) #preparamos la ventana principal @@ -311,14 +313,7 @@ athletedata['prf_name'] = self.profile.getValue("pytraining","prf_name") athletedata['prf_age'] = self.profile.getValue("pytraining","prf_age") athletedata['prf_height'] = self.profile.getValue("pytraining","prf_height") - athletedata['history'] = ( - {'Date':'2010-01-01', 'Weight':88.8, 'BF':15.0, 'RestingHR':67, 'MaxHR':220}, - {'Date':'2010-02-01', 'Weight':89.8, 'BF':16.0, 'RestingHR':68, 'MaxHR':221}, - {'Date':'2010-03-01', 'Weight':99.1, 'BF':13.0, 'RestingHR':65, 'MaxHR':212}, - {'Date':'2010-04-01', 'Weight':79.5, 'BF':11.0, 'RestingHR':61, 'MaxHR':210}, - {'Date':'2010-05-01', 'Weight':67.2, 'BF':13.0, 'RestingHR':60, 'MaxHR':205}, - {'Date':'2010-06-01', 'Weight':83.8, 'BF':16.0, 'RestingHR':56, 'MaxHR':200}, - ) + athletedata['history'] = self.athlete.get_athlete_stats() self.windowmain.actualize_athleteview(athletedata) 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-07 03:53:30
|
Revision: 648 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=648&view=rev Author: jblance Date: 2010-10-07 03:53:23 +0000 (Thu, 07 Oct 2010) Log Message: ----------- Allow axis limits to be set and reset (for newgraph only) Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/drawGraph.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/gui/drawGraph.py =================================================================== --- pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-10-06 22:48:47 UTC (rev 647) +++ pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-10-07 03:53:23 UTC (rev 648) @@ -290,5 +290,21 @@ activity.y2_limits = self.ax2.get_ylim() else: activity.y2_limits = (None, None) + #Set axis limits if requested + #X Axis + if activity.x_limits_u[0] is not None: + if self.ax1 is not None: + self.ax1.set_xlim(activity.x_limits_u) + elif self.ax2 is not None: + self.ax2.set_xlim(activity.x_limits_u) + #Y1 Axis + if activity.y1_limits_u[0] is not None: + if self.ax1 is not None: + self.ax1.set_ylim(activity.y1_limits_u) + #Y2 Axis + if activity.y2_limits_u[0] is not None: + if self.ax2 is not None: + self.ax2.set_ylim(activity.y2_limits_u) + return activity logging.debug('<<') Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-06 22:48:47 UTC (rev 647) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-07 03:53:23 UTC (rev 648) @@ -115,6 +115,16 @@ self.radiobuttonOSM.set_active(1) else: self.radiobuttonGMap.set_active(1) + + def _float_or(self, value, default): + '''Function to parse and return a float, or the default if the parsing fails''' + try: + result = float(value) + except Exception as e: + #print type(e) + #print e + result = default + return result def setup(self): self.createGraphs(RecordGraph,DayGraph,WeekGraph, MonthGraph,YearGraph,HeartRateGraph) @@ -332,19 +342,44 @@ #Populate axis limits frame #TODO Need to change these to editable objects and redraw graphs if changed.... + #Create labels etc minlabel = gtk.Label("<small>Min</small>") minlabel.set_use_markup(True) maxlabel = gtk.Label("<small>Max</small>") maxlabel.set_use_markup(True) xlimlabel = gtk.Label("X") - xminlabel = gtk.Label() - xmaxlabel = gtk.Label() + limits = {} + xminlabel = gtk.Entry(max=10) + xmaxlabel = gtk.Entry(max=10) + limits['xminlabel'] = xminlabel + limits['xmaxlabel'] = xmaxlabel + xminlabel.set_width_chars(5) + xminlabel.set_alignment(1.0) + xmaxlabel.set_width_chars(5) + xmaxlabel.set_alignment(1.0) y1limlabel = gtk.Label("Y1") - y1minlabel = gtk.Label() - y1maxlabel = gtk.Label() + y1minlabel = gtk.Entry(max=10) + y1maxlabel = gtk.Entry(max=10) + limits['y1minlabel'] = y1minlabel + limits['y1maxlabel'] = y1maxlabel + y1minlabel.set_width_chars(5) + y1minlabel.set_alignment(1.0) + y1maxlabel.set_width_chars(5) + y1maxlabel.set_alignment(1.0) y2limlabel = gtk.Label("Y2") - y2minlabel = gtk.Label() - y2maxlabel = gtk.Label() + y2minlabel = gtk.Entry(max=10) + y2maxlabel = gtk.Entry(max=10) + limits['y2minlabel'] = y2minlabel + limits['y2maxlabel'] = y2maxlabel + y2minlabel.set_width_chars(5) + y2minlabel.set_alignment(1.0) + y2maxlabel.set_width_chars(5) + y2maxlabel.set_alignment(1.0) + resetbutton = gtk.Button(_('Reset Limits')) + resetbutton.connect("clicked", self.on_setlimits, activity, True, None) + setbutton = gtk.Button(_('Set Limits')) + setbutton.connect("clicked", self.on_setlimits, activity, False, limits) + #Add labels etc to table limitsbox.attach(minlabel, 1, 2, 0, 1, yoptions=gtk.SHRINK) limitsbox.attach(maxlabel, 2, 3, 0, 1, yoptions=gtk.SHRINK) limitsbox.attach(xlimlabel, 0, 1, 1, 2, yoptions=gtk.SHRINK) @@ -356,6 +391,8 @@ limitsbox.attach(y2limlabel, 0, 1, 3, 4, yoptions=gtk.SHRINK) limitsbox.attach(y2minlabel, 1, 2, 3, 4, yoptions=gtk.SHRINK, xpadding=5) limitsbox.attach(y2maxlabel, 2, 3, 3, 4, yoptions=gtk.SHRINK, xpadding=5) + limitsbox.attach(setbutton, 0, 3, 4, 5, yoptions=gtk.SHRINK) + limitsbox.attach(resetbutton, 0, 3, 5, 6, yoptions=gtk.SHRINK) limitsFrame.add(limitsbox) row = 0 @@ -408,17 +445,26 @@ self.graph_data_hbox.show_all() self.buttonGraphShowOptions.hide() act = self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) - xmin, xmax = act.x_limits - y1min, y1max = act.y1_limits - y2min, y2max = act.y2_limits + if act.x_limits_u[0] is not None: + xmin, xmax = act.x_limits_u + else: + xmin, xmax = act.x_limits + if act.y1_limits_u[0] is not None: + y1min, y1max = act.y1_limits_u + else: + y1min, y1max = act.y1_limits + if act.y2_limits_u[0] is not None: + y2min, y2max = act.y2_limits_u + else: + y2min, y2max = act.y2_limits #print y1min, y1max, y2min, y2max if xmin is not None and xmax is not None: xminlabel.set_text(str(xmin)) xmaxlabel.set_text(str(xmax)) - if y1min is not None and y1min is not None: + if y1min is not None and y1max is not None: y1minlabel.set_text(str(y1min)) y1maxlabel.set_text(str(y1max)) - if y2min is not None and y2min is not None: + if y2min is not None and y2max is not None: y2minlabel.set_text(str(y2min)) y2maxlabel.set_text(str(y2max)) else: @@ -1153,6 +1199,32 @@ #Replot the activity #self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) self.actualize_recordgraph(activity) + + def on_setlimits(self, widget, activity, reset, data): + '''Handler for setting graph limits buttons''' + if data is None: + logging.debug("Resetting graph limits...") + activity.x_limits_u = (None, None) + activity.y1_limits_u = (None, None) + activity.y2_limits_u = (None, None) + #Replot the activity + self.actualize_recordgraph(activity) + else: + #Setting to limits in boxes + logging.debug("Setting graph limits...") + #Determine contents of boxes... + xmin = self._float_or(data['xminlabel'].get_text(), activity.x_limits[0]) + xmax = self._float_or(data['xmaxlabel'].get_text(), activity.x_limits[1]) + y1min = self._float_or(data['y1minlabel'].get_text(), activity.y1_limits[0]) + y1max = self._float_or(data['y1maxlabel'].get_text(), activity.y1_limits[1]) + y2min = self._float_or(data['y2minlabel'].get_text(), activity.y2_limits[0]) + y2max = self._float_or(data['y2maxlabel'].get_text(), activity.y2_limits[1]) + logging.debug("Setting graph limits x: (%s,%s), y1: (%s,%s), y2: (%s,%s)" % (str(xmin), str(xmax), str(y1min), str(y1max), str(y2min), str(y2max)) ) + activity.x_limits_u = (xmin, xmax) + activity.y1_limits_u = (y1min, y1max) + activity.y2_limits_u = (y2min, y2max) + #Replot the activity + self.actualize_recordgraph(activity) def on_athleteTreeView_button_press_event(self, treeview, event): x = int(event.x) Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-10-06 22:48:47 UTC (rev 647) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-10-07 03:53:23 UTC (rev 648) @@ -68,6 +68,12 @@ pace - (float) average pace for activity has_data - (bool) true if instance has data populated x_axis - (string) distance or time, determines what will be graphed on x axis + x_limits - (tuple of float) start, end limits of x axis (as determined by matplotlib) + y1_limits - (tuple of float) start, end limits of y1 axis (as determined by matplotlib) + y2_limits - (tuple of float) start, end limits of y2 axis (as determined by matplotlib) + x_limits_u - (tuple of float) start, end limits of x axis (as requested by user) + y1_limits_u - (tuple of float) start, end limits of y1 axis (as requested by user) + y2_limits_u - (tuple of float) start, end limits of y2 axis (as requested by user) show_laps - (bool) display laps on graphs lap_distance - (graphdata) lap_time - (graphdata) @@ -114,6 +120,9 @@ self.x_limits = (None, None) self.y1_limits = (None, None) self.y2_limits = (None, None) + self.x_limits_u = (None, None) + self.y1_limits_u = (None, None) + self.y2_limits_u = (None, None) self.show_laps = False logging.debug("<<") Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-06 22:48:47 UTC (rev 647) +++ pytrainer/trunk/pytrainer/main.py 2010-10-07 03:53:23 UTC (rev 648) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#647" + self.version ="1.7.2_svn#648" self.DB_version = 4 #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-06 22:48:58
|
Revision: 647 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=647&view=rev Author: jblance Date: 2010-10-06 22:48:47 +0000 (Wed, 06 Oct 2010) Log Message: ----------- Rename record tab icons from Arnd Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/main.py Added Paths: ----------- pytrainer/trunk/glade/graph.png pytrainer/trunk/glade/heartrate.png pytrainer/trunk/glade/map.png Removed Paths: ------------- pytrainer/trunk/glade/heartrate.jpg pytrainer/trunk/glade/path2766.png pytrainer/trunk/glade/path2772.png Copied: pytrainer/trunk/glade/graph.png (from rev 646, pytrainer/trunk/glade/path2766.png) =================================================================== (Binary files differ) Deleted: pytrainer/trunk/glade/heartrate.jpg =================================================================== (Binary files differ) Added: pytrainer/trunk/glade/heartrate.png =================================================================== (Binary files differ) Property changes on: pytrainer/trunk/glade/heartrate.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Copied: pytrainer/trunk/glade/map.png (from rev 646, pytrainer/trunk/glade/path2772.png) =================================================================== (Binary files differ) Deleted: pytrainer/trunk/glade/path2766.png =================================================================== (Binary files differ) Deleted: pytrainer/trunk/glade/path2772.png =================================================================== (Binary files differ) Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-10-05 10:31:59 UTC (rev 646) +++ pytrainer/trunk/glade/pytrainer.glade 2010-10-06 22:48:47 UTC (rev 647) @@ -1969,7 +1969,7 @@ <child> <widget class="GtkImage" id="image25"> <property name="visible">True</property> - <property name="pixbuf">path2766.png</property> + <property name="pixbuf">graph.png</property> </widget> <packing> <property name="position">1</property> @@ -2070,7 +2070,7 @@ <child> <widget class="GtkImage" id="image26"> <property name="visible">True</property> - <property name="pixbuf">path2772.png</property> + <property name="pixbuf">map.png</property> </widget> <packing> <property name="position">2</property> @@ -2646,7 +2646,7 @@ <child> <widget class="GtkImage" id="image28"> <property name="visible">True</property> - <property name="pixbuf">heartrate.jpg</property> + <property name="pixbuf">heartrate.png</property> </widget> <packing> <property name="position">3</property> Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-05 10:31:59 UTC (rev 646) +++ pytrainer/trunk/pytrainer/main.py 2010-10-06 22:48:47 UTC (rev 647) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#646" + self.version ="1.7.2_svn#647" self.DB_version = 4 #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-05 10:32:06
|
Revision: 646 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=646&view=rev Author: jblance Date: 2010-10-05 10:31:59 +0000 (Tue, 05 Oct 2010) Log Message: ----------- Start of implementation of user selectable graph axis limits for newgraph - currently only displaying the limits Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/drawGraph.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/gui/drawGraph.py =================================================================== --- pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-10-05 09:04:44 UTC (rev 645) +++ pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-10-05 10:31:59 UTC (rev 646) @@ -34,18 +34,18 @@ self.ax1 = None self.ax2 = None logging.debug('<<') - + def draw(self, datalist = None, box = None, figure = None, title = None, y2 = False): ''' Draw a graph using supplied information into supplied gtk.box - + datalist = populated graphdata class (required) box = gtk.box object (required) figure = matplotlib figure (optional) if supplied will add graph to this figure - title = - y2 = - - return = figure + title = + y2 = + + return = figure ''' logging.debug('>>') if box is None: @@ -62,19 +62,19 @@ for child in box.get_children(): logging.debug('Removing box child: '+str(child)) box.remove(child) - + if datalist is None: logging.debug("drawPlot called with no data") return - + if y2 and self.ax2 is None: self.ax2 = plt.twinx() - - + + #Create canvas canvas = FigureCanvasGTK(figure) # a gtk.DrawingArea canvas.show() - + #Display title etc if datalist.xlabel is not None: plt.xlabel(datalist.xlabel) @@ -117,10 +117,10 @@ self.ax2.legend(loc = 'upper right', bbox_to_anchor = (1, 1)) #axis.set_xlim(0, data.max_x_value) #axis.set_ylim(0, data.max_y_value) - + #Display plot box.pack_start(canvas, True, True) - + logging.debug("<<") return figure @@ -144,7 +144,7 @@ #Debug info - to remove print("drawPlot....") #print datalist - + #Set up drawing area figure = plt.figure() canvas = FigureCanvasGTK(figure) # a gtk.DrawingArea @@ -219,7 +219,7 @@ logging.debug('<<') return {'y1_min': ylim_min, 'y1_max': ylim_max, 'y1_linewidth': linewidth} - + def drawMultiPlot(self, activity = None, box = None): ''' Draw a plot style graph with multiple traces on each axis @@ -230,7 +230,7 @@ return if activity is None: logging.error("Must supply data to graph graph") - return + return #TODO Check that datalist is of type dict (and contains has correct items) figure = None datalist = [] @@ -242,7 +242,7 @@ _title = "%s%s of %s on %s" % (str(activity.distance), activity.distance_unit, activity.sport_name, activity.date) else: _title = "%s: %s%s of %s on %s" % (activity.title, str(activity.distance), activity.distance_unit, activity.sport_name, activity.date) - + #Loop through data items and graph the selected ones for item in activity.distance_data: if activity.distance_data[item].show_on_y1: @@ -271,7 +271,7 @@ #Display lap divisions if required if activity.show_laps: figure = self.draw(activity.lap_time, box=box, figure=figure) - + #Sort out graph errors... if y1count == 0 and y2count == 0: logging.debug("No items to graph.. Removing graph") @@ -279,4 +279,16 @@ elif y1count == 0: logging.debug("No items on y1 axis... ") #TODO Sort + #Get axis limits.. + if self.ax1 is not None: + activity.x_limits = self.ax1.get_xlim() + activity.y1_limits = self.ax1.get_ylim() + else: + activity.y1_limits = (None, None) + if self.ax2 is not None: + activity.x_limits = self.ax2.get_xlim() + activity.y2_limits = self.ax2.get_ylim() + else: + activity.y2_limits = (None, None) + return activity logging.debug('<<') Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-05 09:04:44 UTC (rev 645) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-05 10:31:59 UTC (rev 646) @@ -68,10 +68,10 @@ self.gpxDir = gpxDir self.record_list = None self.laps = None - + #Setup graph self.grapher = DrawGraph(self, self.pytrainer_main) - + self.y1_limits = None self.y1_color = None self.y1_linewidth = 1 @@ -300,19 +300,15 @@ for child in self.graph_data_hbox.get_children(): if isinstance(child, gtk.Frame): self.graph_data_hbox.remove(child) - #Remove graph - #for child in self.record_graph_vbox.get_children(): - # #Remove all FigureCanvasGTK and NavigationToolbar2GTKAgg to stop double ups of graphs - # #if isinstance(child, matplotlib.backends.backend_gtkagg.FigureCanvasGTK) or isinstance(child, matplotlib.backends.backend_gtkagg.NavigationToolbar2GTKAgg): - # print('Removing child: '+str(child)) - # self.record_graph_vbox.remove(child) #Build frames and vboxs to hold checkbuttons xFrame = gtk.Frame(label="Show on X Axis") y1Frame = gtk.Frame(label="Show on Y1 Axis") y2Frame = gtk.Frame(label="Show on Y2 Axis") + limitsFrame = gtk.Frame(label="Axis Limits") xvbox = gtk.VBox() y1box = gtk.Table() y2box = gtk.Table() + limitsbox = gtk.Table() #Populate X axis data #Create x axis items xdistancebutton = gtk.RadioButton(label=_("Distance")) @@ -329,11 +325,39 @@ xtimebutton.connect("toggled", self.on_xaxischange, "time", activity) xlapsbutton.connect("toggled", self.on_xlapschange, activity) #Add buttons to frame - xvbox.add(xdistancebutton) - xvbox.add(xtimebutton) - xvbox.add(xlapsbutton) + xvbox.pack_start(xdistancebutton, expand=False) + xvbox.pack_start(xtimebutton, expand=False) + xvbox.pack_start(xlapsbutton, expand=False) xFrame.add(xvbox) - + + #Populate axis limits frame + #TODO Need to change these to editable objects and redraw graphs if changed.... + minlabel = gtk.Label("<small>Min</small>") + minlabel.set_use_markup(True) + maxlabel = gtk.Label("<small>Max</small>") + maxlabel.set_use_markup(True) + xlimlabel = gtk.Label("X") + xminlabel = gtk.Label() + xmaxlabel = gtk.Label() + y1limlabel = gtk.Label("Y1") + y1minlabel = gtk.Label() + y1maxlabel = gtk.Label() + y2limlabel = gtk.Label("Y2") + y2minlabel = gtk.Label() + y2maxlabel = gtk.Label() + limitsbox.attach(minlabel, 1, 2, 0, 1, yoptions=gtk.SHRINK) + limitsbox.attach(maxlabel, 2, 3, 0, 1, yoptions=gtk.SHRINK) + limitsbox.attach(xlimlabel, 0, 1, 1, 2, yoptions=gtk.SHRINK) + limitsbox.attach(xminlabel, 1, 2, 1, 2, yoptions=gtk.SHRINK, xpadding=5) + limitsbox.attach(xmaxlabel, 2, 3, 1, 2, yoptions=gtk.SHRINK, xpadding=5) + limitsbox.attach(y1limlabel, 0, 1, 2, 3, yoptions=gtk.SHRINK) + limitsbox.attach(y1minlabel, 1, 2, 2, 3, yoptions=gtk.SHRINK, xpadding=5) + limitsbox.attach(y1maxlabel, 2, 3, 2, 3, yoptions=gtk.SHRINK, xpadding=5) + limitsbox.attach(y2limlabel, 0, 1, 3, 4, yoptions=gtk.SHRINK) + limitsbox.attach(y2minlabel, 1, 2, 3, 4, yoptions=gtk.SHRINK, xpadding=5) + limitsbox.attach(y2maxlabel, 2, 3, 3, 4, yoptions=gtk.SHRINK, xpadding=5) + limitsFrame.add(limitsbox) + row = 0 if activity.x_axis == "distance": data = activity.distance_data @@ -361,7 +385,7 @@ y1color.connect("color-set", self.on_y1colorchange, y1box, graphdata, activity) #Attach to container y1box.attach(y1color, 1, 2, row, row+1) - + #Second Y axis y2button = gtk.CheckButton(label=data[graphdata].title) y2button.set_active(data[graphdata].show_on_y2) @@ -374,18 +398,29 @@ #Attach to container y2box.attach(y2color, 1, 2, row, row+1) row += 1 - + y1Frame.add(y1box) y2Frame.add(y2box) - self.graph_data_hbox.pack_start(xFrame, expand=False, fill=False, padding=0) - self.graph_data_hbox.pack_start(y1Frame, expand=False, fill=True, padding=0) - self.graph_data_hbox.pack_start(y2Frame, expand=False, fill=True, padding=0) - #expandbutton = gtk.Button(label=_("Hide")) - #self.graph_data_hbox.pack_start(expandbutton, expand=False, fill=False, padding=0) + self.graph_data_hbox.pack_start(xFrame, expand=False, fill=False, padding=5) + self.graph_data_hbox.pack_start(y1Frame, expand=False, fill=False, padding=5) + self.graph_data_hbox.pack_start(y2Frame, expand=False, fill=False, padding=5) + self.graph_data_hbox.pack_start(limitsFrame, expand=False, fill=True, padding=5) self.graph_data_hbox.show_all() self.buttonGraphShowOptions.hide() - self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) - + act = self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) + xmin, xmax = act.x_limits + y1min, y1max = act.y1_limits + y2min, y2max = act.y2_limits + #print y1min, y1max, y2min, y2max + if xmin is not None and xmax is not None: + xminlabel.set_text(str(xmin)) + xmaxlabel.set_text(str(xmax)) + if y1min is not None and y1min is not None: + y1minlabel.set_text(str(y1min)) + y1maxlabel.set_text(str(y1max)) + if y2min is not None and y2min is not None: + y2minlabel.set_text(str(y2min)) + y2maxlabel.set_text(str(y2max)) else: logging.debug("Activity has no GPX data") #Show drop down boxes @@ -507,7 +542,7 @@ else: self.dayview.set_sensitive(0) logging.debug("<<") - + def actualize_daygraph(self,record_list): logging.debug(">>") if len(record_list)>0: @@ -795,7 +830,7 @@ iter = history_store.append() history_store.set ( iter, - 0, data_index, + 0, data_index, 1, date, #TODO need to sort date graphing... 2, "%0.2f" % weight, 3, "%0.2f" % float(data['BF']), @@ -846,7 +881,7 @@ logging.debug("Unable to parse beats for %s" % str(i[7]) ) logging.debug(str(e)) _beats = 0.0 - + iter = store.append() store.set ( iter, @@ -1023,7 +1058,7 @@ logging.debug("Reseting graph Y axis with ylimits: %s" % str(y1limits) ) self.drawarearecord.drawgraph(self.record_list,self.laps, y1limits=y1limits, y1color=y1color, y1_linewidth=y1_linewidth) logging.debug("<<") - + def update_athlete_item(self, idx, date, weight, bf, restingHR, maxHR): logging.debug(">>") #Prepare vars @@ -1045,45 +1080,47 @@ ###################### ## Lista de eventos ## ###################### - - def on_xaxischange(self, widget, data=None, activity=None): - '''Handler for record graph axis selection changes''' - if widget.get_active(): + + def on_xaxischange(self, widget, data=None, activity=None): + '''Handler for record graph axis selection changes''' + if widget.get_active(): activity.x_axis = data self.actualize_recordgraph(activity) - - def on_xlapschange(self, widget, activity=None): - if widget.get_active(): + + def on_xlapschange(self, widget, activity=None): + if widget.get_active(): activity.show_laps = True else: activity.show_laps = False self.actualize_recordgraph(activity) - - def on_y1colorchange(self, widget, box, graphdata, activity): - '''Hander for changes to y1 color selection''' + + def on_y1colorchange(self, widget, box, graphdata, activity): + '''Hander for changes to y1 color selection''' logging.debug("Setting %s to color %s" % (graphdata, widget.get_color() ) ) if activity.x_axis == "distance": activity.distance_data[graphdata].set_color(str(widget.get_color())) elif activity.x_axis == "time": activity.time_data[graphdata].set_color(str(widget.get_color())) #Replot the activity - self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) - - def on_y2colorchange(self, widget, box, graphdata, activity): - '''Hander for changes to y2 color selection''' + #self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) + self.actualize_recordgraph(activity) + + def on_y2colorchange(self, widget, box, graphdata, activity): + '''Hander for changes to y2 color selection''' logging.debug("Setting %s to color %s" % (graphdata, widget.get_color() ) ) if activity.x_axis == "distance": activity.distance_data[graphdata].set_color(None, str(widget.get_color())) elif activity.x_axis == "time": activity.time_data[graphdata].set_color(None, str(widget.get_color())) #Replot the activity - self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) - - def on_y1change(self, widget, box, graphdata, activity): - '''Hander for changes to y1 selection''' + #self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) + self.actualize_recordgraph(activity) + + def on_y1change(self, widget, box, graphdata, activity): + '''Hander for changes to y1 selection''' logging.debug("Y1 selection toggled: %s" % graphdata) #Loop through all options at set data correctly - for child in box.get_children(): + for child in box.get_children(): if activity.x_axis == "distance": for item in activity.distance_data: if activity.distance_data[item].title == child.get_label(): @@ -1095,13 +1132,14 @@ logging.debug( "Setting %s to %s" % (item, str(child.get_active()) ) ) activity.time_data[item].show_on_y1 = child.get_active() #Replot the activity - self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) - + #self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) + self.actualize_recordgraph(activity) + def on_y2change(self, widget, box, graphdata, activity): - '''Hander for changes to y2 selection''' + '''Hander for changes to y2 selection''' logging.debug("Y2 selection toggled: %s" % graphdata) #Loop through all options at set data correctly - for child in box.get_children(): + for child in box.get_children(): if activity.x_axis == "distance": for item in activity.distance_data: if activity.distance_data[item].title == child.get_label(): @@ -1113,8 +1151,9 @@ logging.debug( "Setting %s to %s" % (item, str(child.get_active()) ) ) activity.time_data[item].show_on_y2 = child.get_active() #Replot the activity - self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) - + #self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) + self.actualize_recordgraph(activity) + def on_athleteTreeView_button_press_event(self, treeview, event): x = int(event.x) y = int(event.y) @@ -1151,7 +1190,7 @@ self.buttonShowOptions.set_tooltip_text(_('Show graph display options') ) #logging.debug('Position: %d' % self.hpaned1.get_position() ) logging.debug('Position set: %s' % self.hpaned1.get_property('position-set') ) - + def on_buttonGraphHideOptions_clicked(self, widget): logging.debug('on_buttonGraphHideOptions_clicked') self.buttonGraphHideOptions.hide() @@ -1159,8 +1198,8 @@ if isinstance(child, gtk.Frame): child.hide() self.buttonGraphShowOptions.show() - - + + def on_buttonGraphShowOptions_clicked(self, widget): logging.debug('on_buttonGraphShowOptions_clicked') self.buttonGraphShowOptions.hide() @@ -1365,9 +1404,9 @@ #hasta aqui revisado def on_allRecordTreeView_button_press(self, treeview, event): - ''' - Handler for clicks on recordview list (list of activities for the day) - + ''' + Handler for clicks on recordview list (list of activities for the day) + event.button = mouse button pressed (i.e. 1 = left, 3 = right) ''' logging.debug(">>") Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-10-05 09:04:44 UTC (rev 645) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-10-05 10:31:59 UTC (rev 646) @@ -111,6 +111,9 @@ self._init_graph_data() self._generate_per_lap_graphs() self.x_axis = "distance" + self.x_limits = (None, None) + self.y1_limits = (None, None) + self.y2_limits = (None, None) self.show_laps = False logging.debug("<<") Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-05 09:04:44 UTC (rev 645) +++ pytrainer/trunk/pytrainer/main.py 2010-10-05 10:31:59 UTC (rev 646) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#645" + self.version ="1.7.2_svn#646" self.DB_version = 4 #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-05 09:04:50
|
Revision: 645 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=645&view=rev Author: jblance Date: 2010-10-05 09:04:44 +0000 (Tue, 05 Oct 2010) Log Message: ----------- Fix pace by lap to check max pace setting 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-10-05 04:00:20 UTC (rev 644) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-10-05 09:04:44 UTC (rev 645) @@ -237,6 +237,9 @@ 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 + 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 logging.debug("Time: %f, Dist: %f, Pace: %f" % (time, dist, pace) ) self.lap_time.addBars(x=time, y=10) if self.us_system: Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-05 04:00:20 UTC (rev 644) +++ pytrainer/trunk/pytrainer/main.py 2010-10-05 09:04:44 UTC (rev 645) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#644" + self.version ="1.7.2_svn#645" self.DB_version = 4 #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-05 04:00:28
|
Revision: 644 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=644&view=rev Author: jblance Date: 2010-10-05 04:00:20 +0000 (Tue, 05 Oct 2010) Log Message: ----------- Added ability to hide options in newgraph functionality 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-10-05 00:14:54 UTC (rev 643) +++ pytrainer/trunk/glade/pytrainer.glade 2010-10-05 04:00:20 UTC (rev 644) @@ -1,4 +1,4 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="UTF-8"?> <glade-interface> <!-- interface-requires gtk+ 2.6 --> <!-- interface-naming-policy toplevel-contextual --> @@ -1199,7 +1199,51 @@ <placeholder/> </child> <child> - <placeholder/> + <widget class="GtkVBox" id="vbox2"> + <property name="visible">True</property> + <child> + <widget class="GtkButton" id="buttonGraphHideOptions"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="on_buttonGraphHideOptions_clicked"/> + <child> + <widget class="GtkImage" id="image5"> + <property name="visible">True</property> + <property name="stock">gtk-goto-top</property> + </widget> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <widget class="GtkButton" id="buttonGraphShowOptions"> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="on_buttonGraphShowOptions_clicked"/> + <child> + <widget class="GtkImage" id="image6"> + <property name="visible">True</property> + <property name="stock">gtk-goto-bottom</property> + </widget> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> </child> </widget> <packing> @@ -1281,7 +1325,7 @@ <widget class="GtkSpinButton" id="spinbuttonY1Min"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> <signal name="value_changed" handler="on_spinbuttonY1_value_changed"/> @@ -1299,7 +1343,7 @@ <widget class="GtkSpinButton" id="spinbuttonY1Max"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> <signal name="value_changed" handler="on_spinbuttonY1_value_changed"/> @@ -1362,7 +1406,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 1 10 1 1 0</property> <signal name="value_changed" handler="on_spinbuttonY1LineWeight_value_changed"/> </widget> @@ -1404,7 +1448,7 @@ <property name="sensitive">False</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1496,7 +1540,7 @@ <widget class="GtkSpinButton" id="spinbuttonY2Min"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -1513,7 +1557,7 @@ <widget class="GtkSpinButton" id="spinbuttonY2Max"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">1 -500 1000 1 10 0</property> </widget> @@ -1583,7 +1627,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1615,7 +1659,7 @@ <property name="sensitive">False</property> <property name="can_focus">True</property> <property name="max_length">2</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="adjustment">1 0 10 1 1 0</property> </widget> <packing> @@ -1692,7 +1736,7 @@ <widget class="GtkSpinButton" id="spinbuttonXMin"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -1709,7 +1753,7 @@ <widget class="GtkSpinButton" id="spinbuttonXMax"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> <property name="adjustment">0 -500 1000 1 10 0</property> </widget> @@ -5223,7 +5267,7 @@ <widget class="GtkEntry" id="lsa_searchvalue"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="expand">False</property> @@ -5479,7 +5523,7 @@ <widget class="GtkEntry" id="waypoint_longitude"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">3</property> @@ -5494,7 +5538,7 @@ <widget class="GtkEntry" id="waypoint_description"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -5509,7 +5553,7 @@ <widget class="GtkEntry" id="waypoint_latitude"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">3</property> @@ -5522,7 +5566,7 @@ <widget class="GtkEntry" id="waypoint_name"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -5786,7 +5830,7 @@ <widget class="GtkEntry" id="entryAthleteDate"> <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> @@ -5799,7 +5843,7 @@ <widget class="GtkEntry" id="entryAthleteWeight"> <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> @@ -5828,7 +5872,7 @@ <widget class="GtkEntry" id="entryAthleteBF"> <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> @@ -5843,7 +5887,7 @@ <widget class="GtkEntry" id="entryAthleteRestingHR"> <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> @@ -5872,7 +5916,7 @@ <widget class="GtkEntry" id="entryAthleteMaxHR"> <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> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-05 00:14:54 UTC (rev 643) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-05 04:00:20 UTC (rev 644) @@ -298,7 +298,8 @@ #Create a frame showing data available for graphing #Remove existing frames for child in self.graph_data_hbox.get_children(): - self.graph_data_hbox.remove(child) + if isinstance(child, gtk.Frame): + self.graph_data_hbox.remove(child) #Remove graph #for child in self.record_graph_vbox.get_children(): # #Remove all FigureCanvasGTK and NavigationToolbar2GTKAgg to stop double ups of graphs @@ -363,6 +364,7 @@ #Second Y axis y2button = gtk.CheckButton(label=data[graphdata].title) + y2button.set_active(data[graphdata].show_on_y2) y2button.connect("toggled", self.on_y2change, y2box, graphdata, activity) y2box.attach(y2button, 0, 1, row, row+1, xoptions=gtk.EXPAND|gtk.FILL) y2color = gtk.ColorButton() @@ -381,6 +383,7 @@ #expandbutton = gtk.Button(label=_("Hide")) #self.graph_data_hbox.pack_start(expandbutton, expand=False, fill=False, padding=0) self.graph_data_hbox.show_all() + self.buttonGraphShowOptions.hide() self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) else: @@ -1148,6 +1151,23 @@ self.buttonShowOptions.set_tooltip_text(_('Show graph display options') ) #logging.debug('Position: %d' % self.hpaned1.get_position() ) logging.debug('Position set: %s' % self.hpaned1.get_property('position-set') ) + + def on_buttonGraphHideOptions_clicked(self, widget): + logging.debug('on_buttonGraphHideOptions_clicked') + self.buttonGraphHideOptions.hide() + for child in self.graph_data_hbox.get_children(): + if isinstance(child, gtk.Frame): + child.hide() + self.buttonGraphShowOptions.show() + + + def on_buttonGraphShowOptions_clicked(self, widget): + logging.debug('on_buttonGraphShowOptions_clicked') + self.buttonGraphShowOptions.hide() + for child in self.graph_data_hbox.get_children(): + if isinstance(child, gtk.Frame): + child.show() + self.buttonGraphHideOptions.show() def on_buttonRedrawMap_clicked(self, widget): logging.debug('on_buttonRedrawMap_clicked') Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-10-05 00:14:54 UTC (rev 643) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-10-05 04:00:20 UTC (rev 644) @@ -286,10 +286,11 @@ ylabel="%s (%s)" % (_('Elevation'), self.height_unit) self.distance_data['elevation'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel) self.distance_data['elevation'].set_color('#ff0000', '#ff0000') - self.distance_data['elevation'].show_on_y1 = True #Make graph show elevation vs distance by default + self.distance_data['elevation'].show_on_y1 = True #Make graph show elevation by default xlabel=_("Time (seconds)") 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 #Speed title=_("Speed") xlabel="%s (%s)" % (_('Distance'), self.distance_unit) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-05 00:14:54 UTC (rev 643) +++ pytrainer/trunk/pytrainer/main.py 2010-10-05 04:00:20 UTC (rev 644) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#643" + self.version ="1.7.2_svn#644" self.DB_version = 4 #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. |