From: <jb...@us...> - 2010-09-21 05:00:31
|
Revision: 614 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=614&view=rev Author: jblance Date: 2010-09-21 05:00:23 +0000 (Tue, 21 Sep 2010) Log Message: ----------- Initial checkin of fixelevation code from Arnd - currently in progress. May not function correctly Modified Paths: -------------- pytrainer/trunk/pytrainer/main.py pytrainer/trunk/setup.py Added Paths: ----------- pytrainer/trunk/extensions/fixelevation/ pytrainer/trunk/extensions/fixelevation/README.txt pytrainer/trunk/extensions/fixelevation/conf.xml pytrainer/trunk/extensions/fixelevation/fixelevation.py Added: pytrainer/trunk/extensions/fixelevation/README.txt =================================================================== --- pytrainer/trunk/extensions/fixelevation/README.txt (rev 0) +++ pytrainer/trunk/extensions/fixelevation/README.txt 2010-09-21 05:00:23 UTC (rev 614) @@ -0,0 +1,41 @@ + Fix Elevation pytrainer extension + =============================== + This extension allows you to correct elevations within gpx data. + Code is based on Wojciech Lichota's gpxtools + http://lichota.pl/blog/topics/gpxtools + Elevations are corrected using SRTM data, therefore on first usage the necessary + SRTM tile will be downloaded (large!). Tiles will be cached. + + Extension requires 'GDAL python bindings'. Install e.g. + apt-get install python-gdal + or + yum install gdal-python + + + CONFIG OPTIONS + ============== + n.n. + + USAGE + ===== + Simply submit the fixelevation extension preferences form and then go + to the record tab and press "Fix Elevation". + +--------------------------- + + IMPORTANT + ========= + + - On first use, the extension will download a geo_tif File (about 79mb) for your region, there is no warning dialog or similiar. + - Original gpx data (in '.pytrainer/gpx/') will be overwritten. + - The main record isn't forced to be reloaded at the moment, so restart pytrainer to study the manipulated heights. + + TODO + ==== + (?) Interface to specify source of SRTM data (at the moment hardcoded CGIAR mirror) + (?) Interface to specify where to store SRTM data (at the moment .pytrainer/SRTM_data) + (?) Store original gpx elevation data (gpx extension or whole backup file?); offer revert possibility + (?) Improve Wojciech's border trick. + (?) Offer alternative SRTM/DEM Sources eg http://www.viewfinderpanoramas.org/dem3.html + (?) Offer batch mode to fix bundle of tracks + (?) Higher order of interpolation (ie bicubic) Added: pytrainer/trunk/extensions/fixelevation/conf.xml =================================================================== --- pytrainer/trunk/extensions/fixelevation/conf.xml (rev 0) +++ pytrainer/trunk/extensions/fixelevation/conf.xml 2010-09-21 05:00:23 UTC (rev 614) @@ -0,0 +1,12 @@ +<?xml version="1.0" ?> +<pytrainer-extension + name="Elevation correction" + description="Correct the GPX elevation using GDAL" + extensionbutton="Fix Elevation" + extensioncode="fixelevation" + type="record" + helpfile="README.txt" + executable="fixelevation" +> + +</pytrainer-extension> Added: pytrainer/trunk/extensions/fixelevation/fixelevation.py =================================================================== --- pytrainer/trunk/extensions/fixelevation/fixelevation.py (rev 0) +++ pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-09-21 05:00:23 UTC (rev 614) @@ -0,0 +1,293 @@ +#!/usr/bin/env python +import os, stat, sys +import logging +import gtk + +import random, re, urllib2, zipfile +from math import floor, ceil +from cStringIO import StringIO +from optparse import OptionParser + +from osgeo import gdal, gdalnumeric +from lxml import etree + + + +# from gpxtools +def bilinear_interpolation(tl, tr, bl, br, a, b): + """ + Based on equation from: + http://en.wikipedia.org/wiki/Bilinear_interpolation + + :Parameters: + tl : int + top-left + tr : int + top-right + bl : int + buttom-left + br : int + bottom-right + a : float + x distance to top-left + b : float + y distance to top-right + + :Returns: (float) + interpolated value + """ + b1 = tl + b2 = bl - tl + b3 = tr - tl + b4 = tl - bl - tr + br + + return b1 + b2 * a + b3 * b + b4 * a * b + +class SrtmTiff(object): + """ + Provides an interface to SRTM elevation data stored in GeoTIFF file. + + Based on code from `eleserver` code by grahamjones139. + http://code.google.com/p/eleserver/ + """ + tile = {} + + def __init__(self, filename): + """ + Reads the GeoTIFF files into memory ready for processing. + """ + self.tile = self.load_tile(filename) + + def load_tile(self, filename): + """ + Loads a GeoTIFF tile from disk and returns a dictionary containing + the file data, plus metadata about the tile. + + The dictionary returned by this function contains the following data: + xsize - the width of the tile in pixels. + ysize - the height of the tile in pixels. + lat_origin - the latitude of the top left pixel in the tile. + lon_origin - the longitude of the top left pixel in the tile. + lat_pixel - the height of one pixel in degrees latitude. + lon_pixel - the width of one pixel in degrees longitude. + N, S, E, W - the bounding box for this tile in degrees. + data - a two dimensional array containing the tile data. + + """ + dataset = gdal.Open(filename) + geotransform = dataset.GetGeoTransform() + xsize = dataset.RasterXSize + ysize = dataset.RasterYSize + lon_origin = geotransform[0] + lat_origin = geotransform[3] + lon_pixel = geotransform[1] + lat_pixel = geotransform[5] + + retdict = { + 'xsize': xsize, + 'ysize': ysize, + 'lat_origin': lat_origin, + 'lon_origin': lon_origin, + 'lon_pixel': lon_pixel, + 'lat_pixel': lat_pixel, + 'N': lat_origin, + 'S': lat_origin + lat_pixel*ysize, + 'E': lon_origin + lon_pixel*xsize, + 'W': lon_origin, + 'dataset': dataset, + } + + return retdict + + def pos_from_lat_lon(self, lat, lon): + """ + Converts coordinates (lat,lon) into the appropriate (row,column) + position in the GeoTIFF tile data stored in td. + """ + td = self.tile + N = td['N'] + S = td['S'] + E = td['E'] + W = td['W'] + lat_pixel = td['lat_pixel'] + lon_pixel = td['lon_pixel'] + xsize = td['xsize'] + ysize = td['ysize'] + + rowno_f = (lat-N)/lat_pixel + colno_f = (lon-W)/lon_pixel + rowno = int(floor(rowno_f)) + colno = int(floor(colno_f)) + + # Error checking to correct any rounding errors. + if (rowno<0): + rowno = 0 + if (rowno>(xsize-1)): + rowno = xsize-1 + if (colno<0): + colno = 0 + if (colno>(ysize-1)): + colno = xsize-1 + + return (rowno, colno, rowno_f, colno_f) + + def get_elevation(self, lat, lon): + """ + Returns the elevation in metres of point (lat, lon). + + Uses bilinar interpolation to interpolate the SRTM data to the + required point. + """ + row, col, row_f, col_f = self.pos_from_lat_lon(lat, lon) + + # NOTE - THIS IS A FIDDLE TO STOP ERRORS AT THE EDGE OF + # TILES - IT IS NO CORRECT - WE SHOULD GET TWO POINTS + # FROM THE NEXT TILE. + if row==5999: row=5998 + if col==5999: col=5998 + + htarr = gdalnumeric.DatasetReadAsArray(self.tile['dataset'], col, row, 2, 2) + height = bilinear_interpolation(htarr[0][0], htarr[0][1], htarr[1][0], htarr[1][1], + row_f-row, col_f-col) + + return height + + +class SrtmLayer(object): + """ + Provides an interface to SRTM elevation data stored in GeoTIFF files. + Files are automaticly downloaded from mirror server and cached. + + Sample usage: + + >>> lat = 52.25 + >>> lon = 16.75 + >>> srtm = SrtmLayer() + >>> ele = srtm.get_elevation(lat, lon) + >>> round(ele, 4) + 63.9979 + + """ + _cache = {} + + def _download_srtm_tiff(self, srtm_filename): + """ + Download and unzip GeoTIFF file. + """ + #msg = _("Downloading SRTM Data from server. This might take some time...") + #md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, msg) + #md.set_title(_("Downloading SRTM Data")) + #md.set_modal(True) + #md.show() + + logging.info('Downloading SRTM data file, it may take some time ...') + url = 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/%s.ZIP' % srtm_filename[:-4] + print "Attempting to get URL: %s" % url + zobj = StringIO() + zobj.write(urllib2.urlopen(url).read()) + z = zipfile.ZipFile(zobj) + + gpxtools_dir = os.path.expanduser('~/.pytrainer/SRTM_data') + if not os.path.isdir(gpxtools_dir): + os.mkdir(gpxtools_dir) + + srtm_path = os.path.join(gpxtools_dir, srtm_filename) + out_file = open(srtm_path, 'w') + out_file.write(z.read(srtm_filename)) + + z.close() + out_file.close() + #md.destroy() + + + def get_srtm_filename(self, lat, lon): + """ + Filename of GeoTIFF file containing data with given coordinates. + """ + colmin = floor((6000 * (180 + lon)) / 5) + rowmin = floor((6000 * (60 - lat)) / 5) + + ilon = ceil(colmin / 6000.0) + ilat = ceil(rowmin / 6000.0) + + return 'srtm_%02d_%02d.TIF' % (ilon, ilat) + + def get_elevation(self, lat, lon): + """ + Returns the elevation in metres of point (lat, lon). + """ + srtm_filename = self.get_srtm_filename(lat, lon) + if srtm_filename not in self._cache: + srtm_path = os.path.join(os.path.expanduser('~/.pytrainer/SRTM_data'), srtm_filename) + if not os.path.isfile(srtm_path): + self._download_srtm_tiff(srtm_filename) + + self._cache[srtm_filename] = SrtmTiff(srtm_path) + + srtm = self._cache[srtm_filename] + return srtm.get_elevation(lat, lon) + +class fixelevation: + _data = None + _srtm = SrtmLayer() + + def __init__(self, parent = None, pytrainer_main = None, conf_dir = None, options = None): + self.parent = parent + self.pytrainer_main = pytrainer_main + self.options = options + self.conf_dir = conf_dir + + def run(self, id, activity=None): #TODO Convert to use activity... + logging.debug(">>") + gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, id) + if os.path.isfile(gpx_file): + #GPX file is ok and found, so open it + logging.debug("ELE GPX file: %s found, size: %d" % (gpx_file, os.path.getsize(gpx_file))) + """ + Parse GPX file to ElementTree instance. + """ + self._data = etree.parse(gpx_file) + self._xmlns = self._data.getroot().nsmap[None] + self._trkpt_path = '{%s}trk/{%s}trkseg/{%s}trkpt' % (self._xmlns, self._xmlns, self._xmlns) + + """ + Replace elevation from GPX by data from SRTM. + TODO (Arnd) make a function within class fixelevation out of this for better reuse + """ + for trkpt in self._data.findall(self._trkpt_path): + lat = float(trkpt.attrib['lat']) + lon = float(trkpt.attrib['lon']) + + ele = trkpt.find('{%s}ele' % self._xmlns) + if ele is not None: + ele.text = str(self._srtm.get_elevation(lat, lon)) + else: + ele = etree.Element('ele') + ele.text = str(self._srtm.get_elevation(lat, lon)) + trkpt.append(ele) + """ + write out to original *.gpx. Shall original ele-values backuped/stored somewhere ? + """ + self._data.write( gpx_file, + encoding=self._data.docinfo.encoding, + xml_declaration=True, + pretty_print=False) + + + #print trkpt + res_msg = "Elevation has been fixed." + #Show the user the result + md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, res_msg) + md.set_title(_("Elevation Correction Complete")) + md.set_modal(False) + md.run() + md.destroy() + #TODO reload gpx data in main window + + else: + logging.error("ELE GPX file: %s NOT found!!!" % (gpx_file)) + logging.debug("<<") + + + + Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-09-21 04:23:13 UTC (rev 613) +++ pytrainer/trunk/pytrainer/main.py 2010-09-21 05:00:23 UTC (rev 614) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#613" + self.version ="1.7.2_svn#614" self.DB_version = 3 #Process command line options self.startup_options = self.get_options() Modified: pytrainer/trunk/setup.py =================================================================== --- pytrainer/trunk/setup.py 2010-09-21 04:23:13 UTC (rev 613) +++ pytrainer/trunk/setup.py 2010-09-21 05:00:23 UTC (rev 614) @@ -45,6 +45,7 @@ install_plugin("garmintools_full"), install_extension("wordpress"), install_extension("openstreetmap"), + install_extension("fixelevation"), (install_locale("ca")), (install_locale("cs")), (install_locale("da")), This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-09-21 11:35:39
|
Revision: 616 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=616&view=rev Author: jblance Date: 2010-09-21 11:35:28 +0000 (Tue, 21 Sep 2010) Log Message: ----------- Some additional (disabled) code for new graphing approach 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-09-21 10:22:04 UTC (rev 615) +++ pytrainer/trunk/glade/pytrainer.glade 2010-09-21 11:35:28 UTC (rev 616) @@ -1187,6 +1187,25 @@ </packing> </child> <child> + <widget class="GtkHBox" id="graph_data_hbox"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> <widget class="GtkHPaned" id="hpaned1"> <property name="visible">True</property> <property name="can_focus">True</property> @@ -1892,7 +1911,7 @@ </child> </widget> <packing> - <property name="position">1</property> + <property name="position">2</property> </packing> </child> </widget> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-09-21 10:22:04 UTC (rev 615) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-09-21 11:35:28 UTC (rev 616) @@ -275,6 +275,38 @@ logging.debug("Activity has GPX data") self.record_vbox.set_sensitive(1) self.drawarearecord.drawgraph(self.record_list,self.laps) + #Create a frame showing data available for graphing + if False: #Still just test code + #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") + xvbox = gtk.VBox() + y1vbox = gtk.VBox() + y2vbox = gtk.VBox() + #Populate X axis data + xdistancebutton = gtk.RadioButton(label="Distance") + xdistancebutton.connect("toggled", self.on_xaxischange, "distance") + xdistancebutton.set_active(True) + xvbox.add(xdistancebutton) + xtimebutton = gtk.RadioButton(group=xdistancebutton, label="Time") + xtimebutton.connect("toggled", self.on_xaxischange, "time") + xvbox.add(xtimebutton) + xFrame.add(xvbox) + #Populate Y axis data + for graphdata in activity.distance_data: + y1checkbutton = gtk.CheckButton(label=activity.distance_data[graphdata].title) + y1checkbutton.connect("toggled", self.on_y1change, y1vbox) + y2checkbutton = gtk.CheckButton(label=activity.distance_data[graphdata].title) + y2checkbutton.connect("toggled", self.on_y2change, y2vbox) + y1vbox.add(y1checkbutton) + y2vbox.add(y2checkbutton) + y1Frame.add(y1vbox) + y2Frame.add(y2vbox) + self.graph_data_hbox.pack_start(xFrame, expand=False, fill=True, 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) + self.graph_data_hbox.show_all() else: logging.debug("Activity has no GPX data") #Remove graph @@ -913,6 +945,27 @@ ## Lista de eventos ## ###################### + def on_xaxischange(self, widget, data=None): + '''Handler for record graph axis selection changes''' + if widget.get_active(): + print data + + def on_y1change(self, widget, box): + '''Hander for changes to y1 selection''' + print "Y1 selected: ", + for child in box.get_children(): + if child.get_active(): + print child.get_label(), + print + + def on_y2change(self, widget, box): + '''Hander for changes to y2 selection''' + print "Y2 selected: ", + for child in box.get_children(): + if child.get_active(): + print child.get_label(), + print + def on_athleteTreeView_button_press_event(self, treeview, event): x = int(event.x) y = int(event.y) Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-09-21 10:22:04 UTC (rev 615) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-09-21 11:35:28 UTC (rev 616) @@ -38,6 +38,8 @@ us_system - (bool) True: imperial measurement False: metric measurement distance_unit - (string) unit to use for distance speed_unit - (string) unit to use for speed + distance_data - (dict of graphdata classes) contains the graph data with x axis distance + time_data - (dict of graphdata classes) contains the graph data with x axis time height_unit - (string) unit to use for height pace_unit - (string) unit to use for pace gpx_file - (string) gpx file name @@ -220,30 +222,30 @@ logging.debug("<<") return #Profile - title=_("Elevation v Distance") + title=_("Elevation") xlabel="%s (%s)" % (_('Distance'), self.distance_unit) ylabel="%s (%s)" % (_('Elevation'), self.height_unit) self.distance_data['elevation'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel) - title=_("Elevation v Time") + title=_("Elevation") xlabel=_("Time (hours)") self.time_data['elevation'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel) #Speed - title=_("Speed v Distance") + title=_("Speed") xlabel="%s (%s)" % (_('Distance'), self.distance_unit) ylabel="%s (%s)" % (_('Speed'), self.speed_unit) self.distance_data['speed'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel) #Pace - title=_("Pace v Distance") + title=_("Pace") xlabel="%s (%s)" % (_('Distance'), self.distance_unit) ylabel="%s (%s)" % (_('Pace'), self.pace_unit) self.distance_data['pace'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel) #Heartrate - title=_("Heart Rate v Distance") + title=_("Heart Rate") xlabel="%s (%s)" % (_('Distance'), self.distance_unit) ylabel="%s (%s)" % (_('Heart Rate'), _('bpm')) self.distance_data['hr'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel) #Cadence - title=_("Cadence v Distance") + title=_("Cadence") xlabel="%s (%s)" % (_('Distance'), self.distance_unit) ylabel="%s (%s)" % (_('Cadence'), _('rpm')) self.distance_data['cadence'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel) @@ -270,11 +272,11 @@ #Remove data with no values for item in self.distance_data.keys(): if len(self.distance_data[item]) == 0: - print "No values for %s. Removing...." % item + logging.debug( "No values for %s. Removing...." % item ) del self.distance_data[item] for item in self.time_data.keys(): if len(self.time_data[item]) == 0: - print "No values for %s. Removing...." % item + logging.debug( "No values for %s. Removing...." % item ) del self.time_data[item] logging.debug("<<") Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-09-21 10:22:04 UTC (rev 615) +++ pytrainer/trunk/pytrainer/main.py 2010-09-21 11:35:28 UTC (rev 616) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#615" + self.version ="1.7.2_svn#616" self.DB_version = 3 #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-09-23 10:57:56
|
Revision: 619 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=619&view=rev Author: jblance Date: 2010-09-23 10:57:50 +0000 (Thu, 23 Sep 2010) Log Message: ----------- Fix elevation improvements from Arnd Modified Paths: -------------- pytrainer/trunk/extensions/fixelevation/fixelevation.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/extensions/fixelevation/fixelevation.py =================================================================== --- pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-09-23 10:45:08 UTC (rev 618) +++ pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-09-23 10:57:50 UTC (rev 619) @@ -11,8 +11,18 @@ from osgeo import gdal, gdalnumeric from lxml import etree +""" +A list of servers providing SRTM data in GeoTIFF +""" +srtm_server_list = [ + {'url' : 'http://droppr.org/srtm/v4.1/6_5x5_TIFs/', 'ext' : '.zip', 'active' : True }, \ + {'url' : 'ftp://xftp.jrc.it/pub/srtmV4/tiff/' , 'ext' : '.zip', 'active' : True }, \ + {'url' : 'http://srtm.csi.cgiar.org/SRT-ZIP/SRTM_V41/SRTM_Data_GeoTiff/' , 'ext' : '.zip' , 'active' : True }, \ + {'url' : 'ftp://srtm.csi.cgiar.org/SRTM_V41/SRTM_Data_GeoTiff/' , 'ext' : '.zip' , 'active' : True }, \ + {'url' : 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/', 'ext' : '.ZIP', 'active' : False } + ] +srtm_server = srtm_server_list[0] - # from gpxtools def bilinear_interpolation(tl, tr, bl, br, a, b): """ @@ -180,18 +190,19 @@ #md.set_modal(True) #md.show() + srtm_dir = os.path.expanduser('~/.pytrainer/SRTM_data') + if not os.path.isdir(srtm_dir): + os.mkdir(srtm_dir) + logging.info('Downloading SRTM data file, it may take some time ...') - url = 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/%s.ZIP' % srtm_filename[:-4] + #url = 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/%s.ZIP' % srtm_filename[:-4] + url = '%s%s%s' % (srtm_server['url'], srtm_filename[:-4],srtm_server['ext'] ) print "Attempting to get URL: %s" % url zobj = StringIO() zobj.write(urllib2.urlopen(url).read()) z = zipfile.ZipFile(zobj) - - gpxtools_dir = os.path.expanduser('~/.pytrainer/SRTM_data') - if not os.path.isdir(gpxtools_dir): - os.mkdir(gpxtools_dir) - srtm_path = os.path.join(gpxtools_dir, srtm_filename) + srtm_path = os.path.join(srtm_dir, srtm_filename) out_file = open(srtm_path, 'w') out_file.write(z.read(srtm_filename)) @@ -210,8 +221,9 @@ ilon = ceil(colmin / 6000.0) ilat = ceil(rowmin / 6000.0) - return 'srtm_%02d_%02d.TIF' % (ilon, ilat) - + #return 'srtm_%02d_%02d.TIF' % (ilon, ilat) + return 'srtm_%02d_%02d.tif' % (ilon, ilat) + def get_elevation(self, lat, lon): """ Returns the elevation in metres of point (lat, lon). @@ -241,8 +253,18 @@ logging.debug(">>") gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, id) if os.path.isfile(gpx_file): + # Backup original raw data as *.orig.gpx + orig_file = open(gpx_file, 'r') + orig_data = orig_file.read() + orig_file.close() + backup_file = open("%s/gpx/%s.orig.gpx" % (self.conf_dir, id), 'w') + backup_file.write(orig_data) + backup_file.close() #GPX file is ok and found, so open it logging.debug("ELE GPX file: %s found, size: %d" % (gpx_file, os.path.getsize(gpx_file))) + + + """ Parse GPX file to ElementTree instance. """ @@ -266,7 +288,7 @@ ele.text = str(self._srtm.get_elevation(lat, lon)) trkpt.append(ele) """ - write out to original *.gpx. Shall original ele-values backuped/stored somewhere ? + write out to original *.gpx. """ self._data.write( gpx_file, encoding=self._data.docinfo.encoding, Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-09-23 10:45:08 UTC (rev 618) +++ pytrainer/trunk/pytrainer/main.py 2010-09-23 10:57:50 UTC (rev 619) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#618" + self.version ="1.7.2_svn#619" self.DB_version = 3 #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-09-28 00:20:47
|
Revision: 622 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=622&view=rev Author: jblance Date: 2010-09-28 00:20:39 +0000 (Tue, 28 Sep 2010) Log Message: ----------- Reinstate new graphing approach test code - including update to options to allow 'turning on' Modified Paths: -------------- pytrainer/trunk/glade/profile.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/gui/windowprofile.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/profile.glade =================================================================== --- pytrainer/trunk/glade/profile.glade 2010-09-27 23:13:43 UTC (rev 621) +++ pytrainer/trunk/glade/profile.glade 2010-09-28 00:20:39 UTC (rev 622) @@ -1659,7 +1659,7 @@ <child> <widget class="GtkTable" id="table1"> <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="labelLogLevel"> @@ -1931,6 +1931,51 @@ <property name="bottom_attach">6</property> </packing> </child> + <child> + <widget class="GtkLabel" id="labelNewGraph"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">5</property> + <property name="ypad">5</property> + <property name="label" translatable="yes">New Graph</property> + </widget> + <packing> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + </packing> + </child> + <child> + <widget class="GtkCheckButton" id="checkbuttonNewGraph"> + <property name="label">--newgraph</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_checkbuttonNewGraph_toggled"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + <property name="x_padding">10</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelNewGraphDescription"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">5</property> + <property name="label" translatable="yes"><small>Want to use experimental new approach to graphing?</small></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + </packing> + </child> </widget> </child> </widget> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-09-27 23:13:43 UTC (rev 621) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-09-28 00:20:39 UTC (rev 622) @@ -271,19 +271,74 @@ logging.debug(">>") self.record_list = activity.tracks self.laps = activity.laps - if self.record_list is not None and len(self.record_list)>0: - self.record_vbox.set_sensitive(1) - self.drawarearecord.drawgraph(self.record_list,self.laps) + if activity.gpx_file is not None: + if not self.pytrainer_main.startup_options.newgraph: + logging.debug("Using the original graphing") + logging.debug("Activity has GPX data") + #Show drop down boxes + self.hbox30.show() + #Hide new graph details + self.graph_data_hbox.hide() + self.record_vbox.set_sensitive(1) + self.drawarearecord.drawgraph(self.record_list,self.laps) + else: + #Still just test code.... + logging.debug("Using the new TEST graphing approach") + #Hide current drop down boxes + self.hbox30.hide() + #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) + #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") + xvbox = gtk.VBox() + y1vbox = gtk.VBox() + y2vbox = gtk.VBox() + #Populate X axis data + xdistancebutton = gtk.RadioButton(label="Distance") + xdistancebutton.connect("toggled", self.on_xaxischange, "distance") + xdistancebutton.set_active(True) + xvbox.add(xdistancebutton) + xtimebutton = gtk.RadioButton(group=xdistancebutton, label="Time") + xtimebutton.connect("toggled", self.on_xaxischange, "time") + xvbox.add(xtimebutton) + xFrame.add(xvbox) + #Populate Y axis data + for graphdata in activity.distance_data: + y1button = gtk.CheckButton(label=activity.distance_data[graphdata].title) + y1button.connect("toggled", self.on_y1change, y1vbox, activity.distance_data[graphdata]) + y2button = gtk.CheckButton(label=activity.distance_data[graphdata].title) + y2button.connect("toggled", self.on_y2change, y2vbox) + y1vbox.add(y1button) + y2vbox.add(y2button) + y1Frame.add(y1vbox) + y2Frame.add(y2vbox) + self.graph_data_hbox.pack_start(xFrame, expand=False, fill=True, 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) + self.graph_data_hbox.show_all() + + #TODO Fix... + self.record_vbox.set_sensitive(1) + self.drawarearecord.drawgraph(self.record_list,self.laps) else: + logging.debug("Activity has no GPX data") + #Show drop down boxes + self.hbox30.show() + #Hide new graph details + self.graph_data_hbox.hide() #Remove graph - vboxChildren = self.record_vbox.get_children() + vboxChildren = self.record_graph_vbox.get_children() logging.debug('Vbox has %d children %s' % (len(vboxChildren), str(vboxChildren) )) # ToDo: check why vertical container is shared for child in vboxChildren: #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): logging.debug('Removing child: '+str(child)) - self.record_vbox.remove(child) + self.record_graph_vbox.remove(child) self.record_vbox.set_sensitive(0) logging.debug("<<") @@ -929,6 +984,28 @@ ## Lista de eventos ## ###################### + def on_xaxischange(self, widget, data=None): + '''Handler for record graph axis selection changes''' + if widget.get_active(): + print data + + def on_y1change(self, widget, box, data): + '''Hander for changes to y1 selection''' + print "Y1 selected: " + for child in box.get_children(): + if child.get_active(): + #This check box is active, so display graph... + #drawgraph to self.record_graph_vbox with data... + print child.get_label(), data + + def on_y2change(self, widget, box): + '''Hander for changes to y2 selection''' + print "Y2 selected: ", + for child in box.get_children(): + if child.get_active(): + print child.get_label(), + print + def on_athleteTreeView_button_press_event(self, treeview, event): x = int(event.x) y = int(event.y) Modified: pytrainer/trunk/pytrainer/gui/windowprofile.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowprofile.py 2010-09-27 23:13:43 UTC (rev 621) +++ pytrainer/trunk/pytrainer/gui/windowprofile.py 2010-09-28 00:20:39 UTC (rev 622) @@ -23,367 +23,382 @@ import logging class WindowProfile(SimpleGladeApp): - def __init__(self, data_path = None, parent=None, pytrainer_main=None): - glade_path="glade/profile.glade" - root = "newprofile" - domain = None - self.parent = parent - self.pytrainer_main = pytrainer_main - self.data_path = data_path - SimpleGladeApp.__init__(self, data_path+glade_path, root, domain) - self.conf_options = parent.profile_options + def __init__(self, data_path = None, parent=None, pytrainer_main=None): + glade_path="glade/profile.glade" + root = "newprofile" + domain = None + self.parent = parent + self.pytrainer_main = pytrainer_main + self.data_path = data_path + SimpleGladeApp.__init__(self, data_path+glade_path, root, domain) + self.conf_options = parent.profile_options - def new(self): - self.gender_options = { - 0:_("Male"), - 1:_("Female") - } + def new(self): + self.gender_options = { + 0:_("Male"), + 1:_("Female") + } - self.ddbb_type = { - 0:"sqlite", - 1:"mysql" - } - - #anhadimos las opciones al combobox gender - for i in self.gender_options: - self.prf_gender.insert_text(i,self.gender_options[i]) - - #hacemos lo propio para el combobox ddbb - for i in self.ddbb_type: - self.prf_ddbb.insert_text(i,self.ddbb_type[i]) + self.ddbb_type = { + 0:"sqlite", + 1:"mysql" + } + + #anhadimos las opciones al combobox gender + for i in self.gender_options: + self.prf_gender.insert_text(i,self.gender_options[i]) + + #hacemos lo propio para el combobox ddbb + for i in self.ddbb_type: + self.prf_ddbb.insert_text(i,self.ddbb_type[i]) - #preparamos la lista sports: - column_names=[_("Sport"),_("MET"),_("Extra Weight")] - for column_index, column_name in enumerate(column_names): - column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) - column.set_resizable(True) - self.sportTreeView.append_column(column) - - def setValues(self,list_options): - for i in self.conf_options.keys(): - if not list_options.has_key(i): - print 'no list options for: ' + i - continue - if i == "default_viewer": - if list_options[i] == "1": - logging.debug("Setting defult map viewer to OSM") - self.radiobuttonDefaultOSM.set_active(1) - else: - logging.debug("Setting defult map viewer to Google") - self.radiobuttonDefaultGMap.set_active(1) - else: - try: - var = getattr(self,i) - except AttributeError as e: - continue - if i == "prf_hrzones_karvonen" or i == "prf_us_system": - if list_options[i]=="True": - var.set_active(True) - - elif i == "prf_gender": - for j in self.gender_options: - if self.gender_options[j]==list_options[i]: - var.set_active(j) - elif i == "prf_ddbb": - for j in self.ddbb_type: - if self.ddbb_type[j]==list_options[i]: - var.set_active(j) - if j==0: - self._ddbb_value_deactive() - else: - self._ddbb_value_active() - else: - var.set_text(list_options[i]) - - def saveOptions(self): - list_options = {} - for i in self.conf_options.keys(): - if i == "default_viewer": - if self.radiobuttonDefaultOSM.get_active(): - list_options[i] = "1" - else: - list_options[i] = "0" - else: - try: - var = getattr(self,i) - except AttributeError as e: - continue - if i == "prf_hrzones_karvonen" or i == "prf_us_system": - if var.get_active(): - list_options[i] = "True" - else: - list_options[i] = "False" - elif i == "prf_gender" or i == "prf_ddbb": - list_options[i] = var.get_active_text() - else: - list_options[i] = var.get_text() - self.parent.setProfile(list_options) - - def on_calendar_clicked(self,widget): - calendardialog = WindowCalendar(self.data_path,self) - calendardialog.run() + #preparamos la lista sports: + column_names=[_("Sport"),_("MET"),_("Extra Weight")] + for column_index, column_name in enumerate(column_names): + column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) + column.set_resizable(True) + self.sportTreeView.append_column(column) + + def setValues(self,list_options): + for i in self.conf_options.keys(): + if not list_options.has_key(i): + print 'no list options for: ' + i + continue + if i == "default_viewer": + if list_options[i] == "1": + logging.debug("Setting defult map viewer to OSM") + self.radiobuttonDefaultOSM.set_active(1) + else: + logging.debug("Setting defult map viewer to Google") + self.radiobuttonDefaultGMap.set_active(1) + else: + try: + var = getattr(self,i) + except AttributeError as e: + continue + if i == "prf_hrzones_karvonen" or i == "prf_us_system": + if list_options[i]=="True": + var.set_active(True) + + elif i == "prf_gender": + for j in self.gender_options: + if self.gender_options[j]==list_options[i]: + var.set_active(j) + elif i == "prf_ddbb": + for j in self.ddbb_type: + if self.ddbb_type[j]==list_options[i]: + var.set_active(j) + if j==0: + self._ddbb_value_deactive() + else: + self._ddbb_value_active() + else: + var.set_text(list_options[i]) + + def saveOptions(self): + list_options = {} + for i in self.conf_options.keys(): + if i == "default_viewer": + if self.radiobuttonDefaultOSM.get_active(): + list_options[i] = "1" + else: + list_options[i] = "0" + else: + try: + var = getattr(self,i) + except AttributeError as e: + continue + if i == "prf_hrzones_karvonen" or i == "prf_us_system": + if var.get_active(): + list_options[i] = "True" + else: + list_options[i] = "False" + elif i == "prf_gender" or i == "prf_ddbb": + list_options[i] = var.get_active_text() + else: + list_options[i] = var.get_text() + self.parent.setProfile(list_options) + + def on_calendar_clicked(self,widget): + calendardialog = WindowCalendar(self.data_path,self) + calendardialog.run() - def setDate(self,date): - self.prf_age.set_text(date) + def setDate(self,date): + self.prf_age.set_text(date) - def on_switch_page(self,widget,pointer,frame): - #print widget, pointer, frame - if frame==2: - self.saveOptions() - sport_list = self.parent.getSportList() - if sport_list == 0: - pass - elif sport_list == -1: - self.sportlistbutton.set_label("It is not possible connect to the server") - else: - store = gtk.ListStore( - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - object) - for i in sport_list: - if not i[1]: - met = i[1] - else: - met = 0 - if not i[2]: - weight = i[2] - else: - weight = 0 - iter = store.append() - store.set ( - iter, - 0, str(i[0]), - 1, i[1], - 2, i[2] - ) - self.sportTreeView.set_model(store) - #self.sportlistbutton.hide() - self.sportlist.show() - elif frame == 4: #Startup Parameters page selected - self.init_params_tab() - - def init_params_tab(self): - #Show log level - if self.pytrainer_main.startup_options.log_level == logging.ERROR: - self.comboboxLogLevel.set_active(0) - elif self.pytrainer_main.startup_options.log_level == logging.WARNING: - self.comboboxLogLevel.set_active(1) - elif self.pytrainer_main.startup_options.log_level == logging.INFO: - self.comboboxLogLevel.set_active(2) - elif self.pytrainer_main.startup_options.log_level == logging.DEBUG: - self.comboboxLogLevel.set_active(3) - else: - self.comboboxLogLevel.set_active(0) - print "Unknown logging level specified" + def on_switch_page(self,widget,pointer,frame): + #print widget, pointer, frame + if frame==2: + self.saveOptions() + sport_list = self.parent.getSportList() + logging.debug("Got sport_list: %s" % str(sport_list) ) + if sport_list == 0: + pass + elif sport_list == -1: + self.sportlistbutton.set_label("It is not possible connect to the server") + else: + store = gtk.ListStore( + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + object) + for i in sport_list: + if not i[1]: + met = i[1] + else: + met = 0 + if not i[2]: + weight = i[2] + else: + weight = 0 + iter = store.append() + store.set ( + iter, + 0, str(i[0]), + 1, i[1], + 2, i[2] + ) + self.sportTreeView.set_model(store) + #self.sportlistbutton.hide() + self.sportlist.show() + elif frame == 4: #Startup Parameters page selected + self.init_params_tab() + + def init_params_tab(self): + #Show log level + if self.pytrainer_main.startup_options.log_level == logging.ERROR: + self.comboboxLogLevel.set_active(0) + elif self.pytrainer_main.startup_options.log_level == logging.WARNING: + self.comboboxLogLevel.set_active(1) + elif self.pytrainer_main.startup_options.log_level == logging.INFO: + self.comboboxLogLevel.set_active(2) + elif self.pytrainer_main.startup_options.log_level == logging.DEBUG: + self.comboboxLogLevel.set_active(3) + else: + self.comboboxLogLevel.set_active(0) + print "Unknown logging level specified" - #Show if validation requested - if self.pytrainer_main.startup_options.validate: - self.checkbuttonValidate.set_active(True) - else: - self.checkbuttonValidate.set_active(False) - - #Show if database and config check requested - if self.pytrainer_main.startup_options.check: - self.checkbuttonCheck.set_active(True) - else: - self.checkbuttonCheck.set_active(False) - - #Show if using Googlemaps API v3 - if self.pytrainer_main.startup_options.gm3: - self.checkbuttonGM3.set_active(True) - else: - self.checkbuttonGM3.set_active(False) - - #Show if unified import activated - if self.pytrainer_main.startup_options.testimport: - self.checkbuttonUnifiedImport.set_active(True) - else: - self.checkbuttonUnifiedImport.set_active(False) - - def on_comboboxLogLevel_changed(self, widget): - active = self.comboboxLogLevel.get_active() - if active == 1: - logging.debug("Setting log level to WARNING") - self.pytrainer_main.startup_options.log_level = logging.WARNING - elif active == 2: - logging.debug("Setting log level to INFO") - self.pytrainer_main.startup_options.log_level = logging.INFO - elif active == 3: - logging.debug("Setting log level to DEBUG") - self.pytrainer_main.startup_options.log_level = logging.DEBUG - else: - logging.debug("Setting log level to ERROR") - self.pytrainer_main.startup_options.log_level = logging.ERROR - self.pytrainer_main.set_logging_level(self.pytrainer_main.startup_options.log_level) - - def on_checkbuttonValidate_toggled(self, widget): - if self.checkbuttonValidate.get_active(): - logging.debug( "Validate activated") - self.pytrainer_main.startup_options.validate = True - else: - logging.debug("Validate deactivated") - self.pytrainer_main.startup_options.validate = False - - def on_checkbuttonCheck_toggled(self, widget): - if self.checkbuttonCheck.get_active(): - logging.debug( "Check activated") - if self.pytrainer_main.startup_options.check is not True: - #Need to do sanitycheck - logging.debug("Need to do sanitycheck") - self.pytrainer_main.sanityCheck() - self.pytrainer_main.startup_options.check = True - else: - logging.debug("Check deactivated") - self.pytrainer_main.startup_options.check = False - - def on_checkbuttonGM3_toggled(self, widget): - if self.checkbuttonGM3.get_active(): - logging.debug("GM3 activated") - self.pytrainer_main.startup_options.gm3 = True - else: - logging.debug("GM3 deactivated") - self.pytrainer_main.startup_options.gm3 = False - - def on_checkbuttonUnifiedImport_toggled(self, widget): - if self.checkbuttonUnifiedImport.get_active(): - logging.debug("Unified Import activated") - if self.pytrainer_main.startup_options.testimport is not True: - #Need to enable unified import - logging.debug("Need to enable unified import") - self.pytrainer_main.windowmain.set_unified_import(True) - else: - #No change - logging.debug("No change to unified import") - else: - logging.debug("Unified Import deactivated") - if self.pytrainer_main.startup_options.testimport is True: - logging.debug("Need to deactivate unified import") - self.pytrainer_main.windowmain.set_unified_import(False) - else: - logging.debug("No change to unified import") - - def on_sportlistbutton_clicked(self,widget): - sport_list = self.parent.getSportList() - if sport_list == 0: - self.parent.build_ddbb() - self.sportlistbutton.hide() - self.sportlist.show() - - - def on_accept_clicked(self,widget): - self.saveOptions() - self.close_window() - - def on_cancel_clicked(self,widget): - self.close_window() + #Show if validation requested + if self.pytrainer_main.startup_options.validate: + self.checkbuttonValidate.set_active(True) + else: + self.checkbuttonValidate.set_active(False) + + #Show if database and config check requested + if self.pytrainer_main.startup_options.check: + self.checkbuttonCheck.set_active(True) + else: + self.checkbuttonCheck.set_active(False) + + #Show if using Googlemaps API v3 + if self.pytrainer_main.startup_options.gm3: + self.checkbuttonGM3.set_active(True) + else: + self.checkbuttonGM3.set_active(False) + + #Show if unified import activated + if self.pytrainer_main.startup_options.testimport: + self.checkbuttonUnifiedImport.set_active(True) + else: + self.checkbuttonUnifiedImport.set_active(False) + + #Show if new graph activated + if self.pytrainer_main.startup_options.newgraph: + self.checkbuttonNewGraph.set_active(True) + else: + self.checkbuttonNewGraph.set_active(False) + + def on_comboboxLogLevel_changed(self, widget): + active = self.comboboxLogLevel.get_active() + if active == 1: + logging.debug("Setting log level to WARNING") + self.pytrainer_main.startup_options.log_level = logging.WARNING + elif active == 2: + logging.debug("Setting log level to INFO") + self.pytrainer_main.startup_options.log_level = logging.INFO + elif active == 3: + logging.debug("Setting log level to DEBUG") + self.pytrainer_main.startup_options.log_level = logging.DEBUG + else: + logging.debug("Setting log level to ERROR") + self.pytrainer_main.startup_options.log_level = logging.ERROR + self.pytrainer_main.set_logging_level(self.pytrainer_main.startup_options.log_level) + + def on_checkbuttonValidate_toggled(self, widget): + if self.checkbuttonValidate.get_active(): + logging.debug( "Validate activated") + self.pytrainer_main.startup_options.validate = True + else: + logging.debug("Validate deactivated") + self.pytrainer_main.startup_options.validate = False + + def on_checkbuttonCheck_toggled(self, widget): + if self.checkbuttonCheck.get_active(): + logging.debug( "Check activated") + if self.pytrainer_main.startup_options.check is not True: + #Need to do sanitycheck + logging.debug("Need to do sanitycheck") + self.pytrainer_main.sanityCheck() + self.pytrainer_main.startup_options.check = True + else: + logging.debug("Check deactivated") + self.pytrainer_main.startup_options.check = False + + def on_checkbuttonGM3_toggled(self, widget): + if self.checkbuttonGM3.get_active(): + logging.debug("GM3 activated") + self.pytrainer_main.startup_options.gm3 = True + else: + logging.debug("GM3 deactivated") + self.pytrainer_main.startup_options.gm3 = False + + def on_checkbuttonUnifiedImport_toggled(self, widget): + if self.checkbuttonUnifiedImport.get_active(): + logging.debug("Unified Import activated") + if self.pytrainer_main.startup_options.testimport is not True: + #Need to enable unified import + logging.debug("Need to enable unified import") + self.pytrainer_main.windowmain.set_unified_import(True) + else: + #No change + logging.debug("No change to unified import") + else: + logging.debug("Unified Import deactivated") + if self.pytrainer_main.startup_options.testimport is True: + logging.debug("Need to deactivate unified import") + self.pytrainer_main.windowmain.set_unified_import(False) + else: + logging.debug("No change to unified import") + + def on_checkbuttonNewGraph_toggled(self, widget): + if self.checkbuttonNewGraph.get_active(): + logging.debug("NewGraph activated") + self.pytrainer_main.startup_options.newgraph = True + else: + logging.debug("NewGraph deactivated") + self.pytrainer_main.startup_options.newgraph = False + + def on_sportlistbutton_clicked(self,widget): + sport_list = self.parent.getSportList() + if sport_list == 0: + self.parent.build_ddbb() + self.sportlistbutton.hide() + self.sportlist.show() + + + def on_accept_clicked(self,widget): + self.saveOptions() + self.close_window() + + def on_cancel_clicked(self,widget): + self.close_window() - def close_window(self): - self.newprofile.hide() - self.newprofile = None - self.quit() + def close_window(self): + self.newprofile.hide() + self.newprofile = None + self.quit() - def _ddbb_value_active(self): - self.prf_ddbbhost_label.set_sensitive(1) - self.prf_ddbbname_label.set_sensitive(1) - self.prf_ddbbuser_label.set_sensitive(1) - self.prf_ddbbpass_label.set_sensitive(1) - self.prf_ddbbhost.set_sensitive(1) - self.prf_ddbbname.set_sensitive(1) - self.prf_ddbbuser.set_sensitive(1) - self.prf_ddbbpass.set_sensitive(1) - - def _ddbb_value_deactive(self): - self.prf_ddbbhost_label.set_sensitive(0) - self.prf_ddbbname_label.set_sensitive(0) - self.prf_ddbbuser_label.set_sensitive(0) - self.prf_ddbbpass_label.set_sensitive(0) - self.prf_ddbbhost.set_sensitive(0) - self.prf_ddbbname.set_sensitive(0) - self.prf_ddbbuser.set_sensitive(0) - self.prf_ddbbpass.set_sensitive(0) + def _ddbb_value_active(self): + self.prf_ddbbhost_label.set_sensitive(1) + self.prf_ddbbname_label.set_sensitive(1) + self.prf_ddbbuser_label.set_sensitive(1) + self.prf_ddbbpass_label.set_sensitive(1) + self.prf_ddbbhost.set_sensitive(1) + self.prf_ddbbname.set_sensitive(1) + self.prf_ddbbuser.set_sensitive(1) + self.prf_ddbbpass.set_sensitive(1) + + def _ddbb_value_deactive(self): + self.prf_ddbbhost_label.set_sensitive(0) + self.prf_ddbbname_label.set_sensitive(0) + self.prf_ddbbuser_label.set_sensitive(0) + self.prf_ddbbpass_label.set_sensitive(0) + self.prf_ddbbhost.set_sensitive(0) + self.prf_ddbbname.set_sensitive(0) + self.prf_ddbbuser.set_sensitive(0) + self.prf_ddbbpass.set_sensitive(0) - def on_prf_ddbb_changed(self,widget): - i = self.prf_ddbb.get_active_text() - if i == "mysql": - self._ddbb_value_active() - else: - self._ddbb_value_deactive() + def on_prf_ddbb_changed(self,widget): + i = self.prf_ddbb.get_active_text() + if i == "mysql": + self._ddbb_value_active() + else: + self._ddbb_value_deactive() - def on_addsport_clicked(self,widget): - self.hidesportsteps() - self.buttonbox.set_sensitive(0) - self.addsport.show() + def on_addsport_clicked(self,widget): + self.hidesportsteps() + self.buttonbox.set_sensitive(0) + self.addsport.show() - def on_newsport_accept_clicked(self,widget): - sport = self.newsportentry.get_text() - met = self.newmetentry.get_text() - weight = self.newweightentry.get_text() - self.parent.addNewSport(sport,met,weight) - self.parent.actualize_mainsportlist() - self.on_switch_page(None,None,2) - self.hidesportsteps() - self.buttonbox.set_sensitive(1) - self.sportlist.show() + def on_newsport_accept_clicked(self,widget): + sport = self.newsportentry.get_text() + met = self.newmetentry.get_text() + weight = self.newweightentry.get_text() + self.parent.addNewSport(sport,met,weight) + self.parent.actualize_mainsportlist() + self.on_switch_page(None,None,2) + self.hidesportsteps() + self.buttonbox.set_sensitive(1) + self.sportlist.show() - def on_delsport_clicked(self,widget): - selected,iter = self.sportTreeView.get_selection().get_selected() - if iter: - self.buttonbox.set_sensitive(0) - sport = selected.get_value(iter,0) - self.sportnamedel.set_text(sport) - self.hidesportsteps() - self.deletesport.show() + def on_delsport_clicked(self,widget): + selected,iter = self.sportTreeView.get_selection().get_selected() + if iter: + self.buttonbox.set_sensitive(0) + sport = selected.get_value(iter,0) + self.sportnamedel.set_text(sport) + self.hidesportsteps() + self.deletesport.show() - def on_deletesport_clicked(self,widget): - sport = self.sportnamedel.get_text() - self.parent.delSport(sport) - self.parent.actualize_mainsportlist() - self.on_switch_page(None,None,2) - self.hidesportsteps() - self.buttonbox.set_sensitive(1) - self.sportlist.show() - - def on_editsport_clicked(self,widget): - self.buttonbox.set_sensitive(0) - selected,iter = self.sportTreeView.get_selection().get_selected() - if iter: - sport = selected.get_value(iter,0) - name,met,weight = self.parent.getSportInfo(sport) - self.editsportentry.set_text(sport) - self.sportnameedit.set_text(sport) - self.editweightentry.set_text(str(weight)) - self.editmetentry.set_text(str(met)) - self.hidesportsteps() - self.editsport.show() - - def on_editsport_accept_clicked(self,widget): - oldnamesport = self.sportnameedit.get_text() - newnamesport = self.editsportentry.get_text() - newmetsport = self.editmetentry.get_text() - newweightsport = self.editweightentry.get_text() - self.parent.updateSport(oldnamesport,newnamesport,newmetsport,newweightsport) - self.parent.actualize_mainsportlist() - self.on_switch_page(None,None,2) - self.hidesportsteps() - self.buttonbox.set_sensitive(1) - self.sportlist.show() - - def on_sportcancel_clicked(self,widget): - self.hidesportsteps() - self.buttonbox.set_sensitive(1) - self.sportlist.show() + def on_deletesport_clicked(self,widget): + sport = self.sportnamedel.get_text() + self.parent.delSport(sport) + self.parent.actualize_mainsportlist() + self.on_switch_page(None,None,2) + self.hidesportsteps() + self.buttonbox.set_sensitive(1) + self.sportlist.show() + + def on_editsport_clicked(self,widget): + self.buttonbox.set_sensitive(0) + selected,iter = self.sportTreeView.get_selection().get_selected() + if iter: + sport = selected.get_value(iter,0) + name,met,weight = self.parent.getSportInfo(sport) + self.editsportentry.set_text(sport) + self.sportnameedit.set_text(sport) + self.editweightentry.set_text(str(weight)) + self.editmetentry.set_text(str(met)) + self.hidesportsteps() + self.editsport.show() + + def on_editsport_accept_clicked(self,widget): + oldnamesport = self.sportnameedit.get_text() + newnamesport = self.editsportentry.get_text() + newmetsport = self.editmetentry.get_text() + newweightsport = self.editweightentry.get_text() + self.parent.updateSport(oldnamesport,newnamesport,newmetsport,newweightsport) + self.parent.actualize_mainsportlist() + self.on_switch_page(None,None,2) + self.hidesportsteps() + self.buttonbox.set_sensitive(1) + self.sportlist.show() + + def on_sportcancel_clicked(self,widget): + self.hidesportsteps() + self.buttonbox.set_sensitive(1) + self.sportlist.show() - def on_calculatemaxhr_clicked(self,widget=None): - import datetime - today = "%s"%datetime.date.today() - year1,month1,day1 = today.split("-") - year2,month2,day2 = self.prf_age.get_text().split("-") - diff = datetime.datetime(int(year1), int(month1), int(day1),0,0,0) - datetime.datetime(int(year2), int(month2), int(day2),0,0,0) - self.prf_maxhr.set_text("%d" %(220-int(diff.days/365))) + def on_calculatemaxhr_clicked(self,widget=None): + import datetime + today = "%s"%datetime.date.today() + year1,month1,day1 = today.split("-") + year2,month2,day2 = self.prf_age.get_text().split("-") + diff = datetime.datetime(int(year1), int(month1), int(day1),0,0,0) - datetime.datetime(int(year2), int(month2), int(day2),0,0,0) + self.prf_maxhr.set_text("%d" %(220-int(diff.days/365))) - def hidesportsteps(self): - self.sportlist.hide() - self.addsport.hide() - self.deletesport.hide() - self.editsport.hide() + def hidesportsteps(self): + self.sportlist.hide() + self.addsport.hide() + self.deletesport.hide() + self.editsport.hide() Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-09-27 23:13:43 UTC (rev 621) +++ pytrainer/trunk/pytrainer/main.py 2010-09-28 00:20:39 UTC (rev 622) @@ -47,431 +47,432 @@ from lib.ddbb import DDBB class pyTrainer: - def __init__(self,filename = None, data_path = None): - #Version constants - self.version ="1.7.2_svn#621" - self.DB_version = 3 - #Process command line options - self.startup_options = self.get_options() - #Setup logging - self.set_logging(self.startup_options.log_level) - logging.debug('>>') - self.data_path = data_path - self.date = Date() - self.ddbb = None - # Checking profile - logging.debug('Checking configuration and profile...') - self.profile = Profile(self.data_path,self) - self.windowmain = None - self.ddbb = DDBB(self.profile) - logging.debug('connecting to DDBB') - self.ddbb.connect() + def __init__(self,filename = None, data_path = None): + #Version constants + self.version ="1.7.2_svn#622" + self.DB_version = 3 + #Process command line options + self.startup_options = self.get_options() + #Setup logging + self.set_logging(self.startup_options.log_level) + logging.debug('>>') + self.data_path = data_path + self.date = Date() + self.ddbb = None + # Checking profile + logging.debug('Checking configuration and profile...') + self.profile = Profile(self.data_path,self) + self.windowmain = None + self.ddbb = DDBB(self.profile) + logging.debug('connecting to DDBB') + self.ddbb.connect() - #Get user's DB version - currentDB_version = self.profile.getValue("pytraining","DB_version") - logging.debug("Current DB version: "+str(currentDB_version)) - # DB check can be triggered either via new version (mandatory) or as runtime parameter (--check) - if self.startup_options.check: # User requested check - self.sanityCheck() - elif currentDB_version is None: # No stored DB version - check DB etc - self.sanityCheck() - elif self.DB_version > int(currentDB_version): # DB version expected is newer than user's version - check DB etc - self.sanityCheck() - else: - logging.info('No sanity check requested') - self.record = Record(data_path,self) - pool_size = self.profile.getIntValue("pytraining","activitypool_size", default=1) - self.activitypool = ActivityPool(self, size=pool_size) - #preparamos la ventana principal - self.windowmain = Main(data_path,self,self.version, gpxDir=self.profile.gpxdir) - self.date = Date(self.windowmain.calendar) - self.waypoint = Waypoint(data_path,self) - self.extension = Extension(data_path, self) - self.plugins = Plugins(data_path, self) - self.importdata = Importdata(data_path, self, self.profile) - self.loadPlugins() - self.loadExtensions() - self.windowmain.setup() - self.windowmain.on_calendar_selected(None) - self.refreshMainSportList() - self.windowmain.run() - logging.debug('<<') + #Get user's DB version + currentDB_version = self.profile.getValue("pytraining","DB_version") + logging.debug("Current DB version: "+str(currentDB_version)) + # DB check can be triggered either via new version (mandatory) or as runtime parameter (--check) + if self.startup_options.check: # User requested check + self.sanityCheck() + elif currentDB_version is None: # No stored DB version - check DB etc + self.sanityCheck() + elif self.DB_version > int(currentDB_version): # DB version expected is newer than user's version - check DB etc + self.sanityCheck() + else: + logging.info('No sanity check requested') + self.record = Record(data_path,self) + pool_size = self.profile.getIntValue("pytraining","activitypool_size", default=1) + self.activitypool = ActivityPool(self, size=pool_size) + #preparamos la ventana principal + self.windowmain = Main(data_path,self,self.version, gpxDir=self.profile.gpxdir) + self.date = Date(self.windowmain.calendar) + self.waypoint = Waypoint(data_path,self) + self.extension = Extension(data_path, self) + self.plugins = Plugins(data_path, self) + self.importdata = Importdata(data_path, self, self.profile) + self.loadPlugins() + self.loadExtensions() + self.windowmain.setup() + self.windowmain.on_calendar_selected(None) + self.refreshMainSportList() + self.windowmain.run() + logging.debug('<<') - def get_options(self): - ''' - Define usage and accepted options for command line startup + def get_options(self): + ''' + Define usage and accepted options for command line startup - returns: options - dict with option: value pairs - ''' - usage = '''usage: %prog [options] + returns: options - dict with option: value pairs + ''' + usage = '''usage: %prog [options] - For more help on valid options try: - %prog -h ''' - parser = OptionParser(usage=usage) - parser.set_defaults(log_level=logging.ERROR, validate=False, gm3=True, testimport=False, equip=False) - parser.add_option("-d", "--debug", action="store_const", const=logging.DEBUG, dest="log_level", help="enable logging at debug level") - parser.add_option("-i", "--info", action="store_const", const=logging.INFO, dest="log_level", help="enable logging at info level") - parser.add_option("-w", "--warn", action="store_const", const=logging.WARNING, dest="log_level", help="enable logging at warning level") - parser.add_option("--valid", action="store_true", dest="validate", help="enable validation of files imported by plugins (details at info or debug logging level) - note plugin must support validation") - parser.add_option("--check", action="store_true", dest="check", help="triggers database (only sqlite based) and configuration file sanity checks, adding fields if necessary. Backup of database is done before any change. Details at info or debug logging level") - parser.add_option("--gmaps2", action="store_false", dest="gm3", help="Use old Google Maps API version (v2)") - parser.add_option("--testimport", action="store_true", dest="testimport", help="EXPERIMENTAL: show new import functionality - for testing only USE AT YOUR OWN RISK") - parser.add_option("--equip", action="store_false", dest="equip", help="EXPERIMENTAL: enable equipment management") - (options, args) = parser.parse_args() - return options + For more help on valid options try: + %prog -h ''' + parser = OptionParser(usage=usage) + parser.set_defaults(log_level=logging.ERROR, validate=False, gm3=True, testimport=True, equip=False, newgraph=False) + parser.add_option("-d", "--debug", action="store_const", const=logging.DEBUG, dest="log_level", help="enable logging at debug level") + parser.add_option("-i", "--info", action="store_const", const=logging.INFO, dest="log_level", help="enable logging at info level") + parser.add_option("-w", "--warn", action="store_const", const=logging.WARNING, dest="log_level", help="enable logging at warning level") + parser.add_option("--valid", action="store_true", dest="validate", help="enable validation of files imported by plugins (details at info or debug logging level) - note plugin must support validation") + parser.add_option("--check", action="store_true", dest="check", help="triggers database (only sqlite based) and configuration file sanity checks, adding fields if necessary. Backup of database is done before any change. Details at info or debug logging level") + parser.add_option("--gmaps2", action="store_false", dest="gm3", help="Use old Google Maps API version (v2)") + parser.add_option("--testimport", action="store_true", dest="testimport", help="EXPERIMENTAL: show new import functionality - for testing only USE AT YOUR OWN RISK") + parser.add_option("--equip", action="store_false", dest="equip", help="EXPERIMENTAL: enable equipment management") + parser.add_option("--newgraph", action="store_true", dest="newgraph", help="EXPERIMENTAL: new graphing approach") + (options, args) = parser.parse_args() + return options - def set_logging(self,level): - '''Setup rotating log file with customized format''' - PATH = os.environ['HOME']+"/.pytrainer" - if not os.path.exists(PATH): - os.mkdir(PATH) - LOG_FILENAME = PATH + "/log.out" - rotHandler = logging.handlers.RotatingFileHandler(LOG_FILENAME, maxBytes=100000, backupCount=5) - formatter = logging.Formatter('%(asctime)s|%(levelname)s|%(module)s|%(funcName)s|%(message)s') - rotHandler.setFormatter(formatter) - logging.getLogger('').addHandler(rotHandler) - self.set_logging_level(self.startup_options.log_level) + def set_logging(self,level): + '''Setup rotating log file with customized format''' + PATH = os.environ['HOME']+"/.pytrainer" + if not os.path.exists(PATH): + os.mkdir(PATH) + LOG_FILENAME = PATH + "/log.out" + rotHandler = logging.handlers.RotatingFileHandler(LOG_FILENAME, maxBytes=100000, backupCount=5) + formatter = logging.Formatter('%(asctime)s|%(levelname)s|%(module)s|%(funcName)s|%(message)s') + rotHandler.setFormatter(formatter) + logging.getLogger('').addHandler(rotHandler) + self.set_logging_level(self.startup_options.log_level) - def set_logging_level(self, level): - '''Set level of information written to log''' - logging.debug("Setting logger to level: "+ str(level)) - logging.getLogger('').setLevel(level) + def set_logging_level(self, level): + '''Set level of information written to log''' + logging.debug("Setting logger to level: "+ str(level)) + logging.getLogger('').setLevel(level) - def quit(self): - logging.debug('--') - logging.info("Exit!") - #self.webservice.stop() - self.windowmain.gtk_main_quit() - logging.shutdown() - sys.exit() # Any nonzero value is considered “abnormal termination” by shells and the like + def quit(self): + logging.debug('--') + logging.info("Exit!") + #self.webservice.stop() + self.windowmain.gtk_main_quit() + logging.shutdown() + sys.exit() # Any nonzero value is considered “abnormal termination” by shells and the like - def loadPlugins(self): - logging.debug('>>') - activeplugins = self.plugins.getActivePlugins() - if (len(activeplugins)<1): - logging.info("No active plugins") - else: - for plugin in activeplugins: - txtbutton = self.plugins.loadPlugin(plugin) - self.windowmain.addImportPlugin(txtbutton) - logging.debug('<<') + def loadPlugins(self): + logging.debug('>>') + activeplugins = self.plugins.getActivePlugins() + if (len(activeplugins)<1): + logging.info("No active plugins") + else: + for plugin in activeplugins: + txtbutton = self.plugins.loadPlugin(plugin) + self.windowmain.addImportPlugin(txtbutton) + logging.debug('<<') - def loadExtensions(self): - logging.debug('>>') - activeextensions = self.extension.getActiveExtensions() - if (len(activeextensions)<1): - logging.info("No active extensions") - else: - for extension in activeextensions: - txtbutton = self.extension.loadExtension(extension) - self.windowmain.addExtension(txtbutton) - logging.debug('<<') + def loadExtensions(self): + logging.debug('>>') + activeextensions = self.extension.getActiveExtensions() + if (len(activeextensions)<1): + logging.info("No active extensions") + else: + for extension in activeextensions: + txtbutton = self.extension.loadExtension(extension) + self.windowmain.addExtension(txtbutton) + logging.debug('<<') - def runPlugin(self,widget,pathPlugin): - logging.debug('>>') - self.pluginClass = self.plugins.importClass(pathPlugin) - pluginFiles = self.pluginClass.run() - if pluginFiles is not None: - logging.debug("Plugin returned %d files" % (len(pluginFiles)) ) - #process returned GPX files - for (pluginFile, sport) in pluginFiles: - if os.path.isfile(pluginFile): - logging.info('File exists. Size: %d. Sport: %s' % (os.path.getsize(pluginFile), sport)) - if self.record.importFromGPX(pluginFile, sport) is None: - logging.error("Error importing file "+pluginFile) - else: - logging.error('File '+pluginFile+' not valid') - else: - logging.debug("No files returned from Plugin") - self.refreshListRecords() - self.refreshGraphView("day") - logging.debug('<<') + def runPlugin(self,widget,pathPlugin): + logging.debug('>>') + self.pluginClass = self.plugins.importClass(pathPlugin) + pluginFiles = self.pluginClass.run() + if pluginFiles is not None: + logging.debug("Plugin returned %d files" % (len(pluginFiles)) ) + #process returned GPX files + for (pluginFile, sport) in pluginFiles: + if os.path.isfile(pluginFile): + logging.info('File exists. Size: %d. Sport: %s' % (os.path.getsize(pluginFile), sport)) + if self.record.importFromGPX(pluginFile, sport) is None: + logging.error("Error importing file "+pluginFile) + else: + logging.error('File '+pluginFile+' not valid') + else: + logging.debug("No files returned from Plugin") + self.refreshListRecords() + self.refreshGraphView("day") + logging.debug('<<') - def runExtension(self,extension,id): - logging.debug('>>') - print("Extension id: %s" % str(id)) - activity = self.activitypool.get_activity(id) - txtbutton,pathExtension,type = extension - self.extensionClass = self.extension.importClass(pathExtension) - self.extensionClass.run(id, activity) - #if type == "record": - # #Si es record le tenemos que crear el googlemaps, el gpx y darle el id de la bbdd - # alert = self.extension.runExtension(pathExtension,id) + def runExtension(self,extension,id): + logging.debug('>>') + print("Extension id: %s" % str(id)) + activity = self.activitypool.get_activity(id) + txtbutton,pathExtension,type = extension + self.extensionClass = self.extension.importClass(pathExtension) + self.extensionClass.run(id, activity) + #if type == "record": + # #Si es record le tenemos que crear el googlemaps, el gpx y darle el id de la bbdd + # alert = self.extension.runExtension(pathExtension,id) - logging.debug('<<') + logging.debug('<<') - def refreshMainSportList(self): - logging.debug('>>') - listSport = self.profile.getSportList() - self.windowmain.updateSportList(listSport) - logging.debug('<<') + def refreshMainSportList(self): + logging.debug('>>') + listSport = self.profile.getSportList() + self.windowmain.updateSportList(listSport) + logging.debug('<<') - def refreshGraphView(self, view, sport=None): - logging.debug('>>') - if self.windowmain is None: - logging.debug("First call to refreshGraphView") - logging.debug('<<') - return - date_selected = self.date.getDate() - if view=="record": - logging.debug('record view') - if self.windowmain.recordview.get_current_page()==0: - self.refreshRecordGraphView("info") - elif self.windowmain.recordview.get_current_page()==1: - self.refreshRecordGraphView("graphs") - elif self.windowmain.recordview.get_current_page()==2: - self.refreshRecordGraphView("map") - elif self.windowmain.recordview.get_current_page()==3: - self.refreshRecordGraphView("heartrate") - elif view=="day": - logging.debug('day view') - record_list = self.record.getrecordList(date_selected) - self.windowmain.actualize_dayview(record_list) - #selected,iter = self.windowmain.recordTreeView.get_selection().get_selected() - elif view=="week": - logging.debug('week view') - date_ini, date_end = self.date.getWeekInterval(date_selected, self.profile.prf_us_system) - sport = self.windowmain.getSportSelected() - record_list = self.record.getrecordPeriod(date_ini, date_end, sport) - self.windowmain.actualize_weekview(record_list, date_ini, date_end) - elif view=="month": - logging.debug('month view') - date_ini, date_end = self.date.getMonthInterval(date_selected) - sport = self.windowmain.getSportSelected() - record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport) - nameMonth, daysInMonth = self.date.getNameMonth(date_selected) - self.windowmain.actualize_monthview(record_list, nameMonth) - self.windowmain.actualize_monthgraph(record_list, daysInMonth) - elif view=="year": - logging.debug('year view') - date_ini, date_end = self.date.getYearInterval(date_selected) - sport = self.windowmain.getSportSelected() - year = self.date.getYear(date_selected) - record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport) - self.windowmain.actualize_yearview(record_list, year) - self.windowmain.actualize_yeargraph(record_list) - elif view=="listview": - logging.debug('list view') - self.refreshListView() - else: - print "Unknown view %s" % view - logging.debug('<<') + def refreshGraphView(self, view, sport=None): + logging.debug('>>') + if self.windowmain is None: + logging.debug("First call to refreshGraphView") + logging.debug('<<') + return + date_selected = self.date.getDate() + if view=="record": + logging.debug('record view') + if self.windowmain.recordview.get_current_page()==0: + self.refreshRecordGraphView("info") + elif self.windowmain.recordview.get_current_page()==1: + self.refreshRecordGraphView("graphs") + elif self.windowmain.recordview.get_current_page()==2: + self.refreshRecordGraphView("map") + elif self.windowmain.recordview.get_current_page()==3: + self.refreshRecordGraphView("heartrate") + elif view=="day": + logging.debug('day view') + record_list = self.record.getrecordList(date_selected) + self.windowmain.actualize_dayview(record_list) + #selected,iter = self.windowmain.recordTreeView.get_selection().get_selected() + elif view=="week": + logging.debug('week view') + date_ini, date_end = self.date.getWeekInterval(date_selected, self.profile.prf_us_system) + sport = self.windowmain.getSportSelected() + record_list = self.record.getrecordPeriod(date_ini, date_end, sport) + self.windowmain.actualize_weekview(record_list, date_ini, date_end) + elif view=="month": + logging.debug('month view') + date_ini, date_end = self.date.getMonthInterval(date_selected) + sport = self.windowmain.getSportSelected() + record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport) + nameMonth, daysInMonth = self.date.getNameMonth(date_selected) + self.windowmain.actualize_monthview(record_list, nameMonth) + self.windowmain.actualize_monthgraph(record_list, daysInMonth) + elif view=="year": + logging.debug('year view') + date_ini, date_end = self.date.getYearInterval(date_selected) + sport = self.windowmain.getSportSelected() + year = self.date.getYear(date_selected) + record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport) + self.windowmain.actualize_yearview(record_list, year) + self.windowmain.actualize_yeargraph(record_list) + elif view=="listview": + logging.debug('list view') + self.refreshListView() + else: + print "Unknown view %s" % view + logging.debug('<<') - def refreshRecordGraphView(self, view): - logging.debug('>>') - logging.info('Working on '+view+' graph') - selected,iter = self.windowmain.recordTreeView.get_selection().get_selected() - if iter: - id_record = selected.get_value(iter,0) - else: - id_record = None - view="info" - activity = self.activitypool.get_activity(id_record) - if view=="info": - self.windowmain.actualize_recordview(activity) - if view=="graphs": - self.windowmain.actualize_recordgraph(activity) - if view=="map": - self.refreshMapView() - if view=="heartrate": - self.windowmain.actualize_heartrategraph(activity) - self.windowmain.actualize_hrview(activity) - logging.debug('<<') + def refreshRecordGraphView(self, view): + logging.debug('>>') + logging.info('Working on '+view+' graph') + selected,iter = self.windowmain.recordTreeView.get_selection().get_selected() + if iter: + id_record = selected.get_value(iter,0) + else: + id_record = None + view="info" + activity = self.activitypool.get_activity(id_record) + if view=="info": + self.windowmain.actualize_recordview(activity) + if view=="graphs": + self.windowmain.actualize_recordgraph(activity) + if view=="map": + self.refreshMapView() + if view=="heartrate": + self.windowmain.actualize_heartrategraph(activity) + self.windowmain.actualize_hrview(activity) + logging.debug('<<') - def refreshMapView(self, full_screen=False): - logging.debug('>>') - if self.windowmain is None: - logging.debug('Called before windowmain initialisation') - logging.debug('<<') - return - selected,iter = self.windowmain.recordTreeView.get_selection().get_selected() - id_record = selected.get_value(iter,0) - activity = self.activitypool.get_activity(id_record) - logging.debug('Trying to show map for record '+str(id_record)) - self.windowmain.actualize_map(activity, full_screen) - logging.debug('<<') + def refreshMapView(self, full_screen=False): + logging.debug('>>') + if self.windowmain is None: + logging.debug('Called before windowmain initialisation') + logging.debug('<<') + return + selected,iter = self.windowmain.recordTreeView.get_selection().get_selected() + id_record = selected.get_value(iter,0) + activity = self.activitypool.get_ac... [truncated message content] |
From: <jb...@us...> - 2010-09-28 00:44:46
|
Revision: 623 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=623&view=rev Author: jblance Date: 2010-09-28 00:44:39 +0000 (Tue, 28 Sep 2010) Log Message: ----------- Split elevation code into separate class files Modified Paths: -------------- pytrainer/trunk/extensions/fixelevation/fixelevation.py pytrainer/trunk/pytrainer/main.py Added Paths: ----------- pytrainer/trunk/pytrainer/lib/srtmlayer.py pytrainer/trunk/pytrainer/lib/srtmtiff.py Modified: pytrainer/trunk/extensions/fixelevation/fixelevation.py =================================================================== --- pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-09-28 00:20:39 UTC (rev 622) +++ pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-09-28 00:44:39 UTC (rev 623) @@ -1,244 +1,15 @@ #!/usr/bin/env python -import os, stat, sys +import os #, stat, sys import logging import gtk - -import random, re, urllib2, zipfile -from math import floor, ceil -from cStringIO import StringIO -from optparse import OptionParser - -from osgeo import gdal, gdalnumeric +#import random, re, urllib2, zipfile +#from math import floor, ceil +#from cStringIO import StringIO +#from optparse import OptionParser +#from osgeo import gdal, gdalnumeric from lxml import etree +from pytrainer.lib.srtmlayer import SrtmLayer -""" -A list of servers providing SRTM data in GeoTIFF -""" -srtm_server_list = [ - {'url' : 'http://droppr.org/srtm/v4.1/6_5x5_TIFs/', 'ext' : '.zip', 'active' : True }, \ - {'url' : 'ftp://xftp.jrc.it/pub/srtmV4/tiff/' , 'ext' : '.zip', 'active' : True }, \ - {'url' : 'http://srtm.csi.cgiar.org/SRT-ZIP/SRTM_V41/SRTM_Data_GeoTiff/' , 'ext' : '.zip' , 'active' : True }, \ - {'url' : 'ftp://srtm.csi.cgiar.org/SRTM_V41/SRTM_Data_GeoTiff/' , 'ext' : '.zip' , 'active' : True }, \ - {'url' : 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/', 'ext' : '.ZIP', 'active' : False } - ] -srtm_server = srtm_server_list[0] - -# from gpxtools -def bilinear_interpolation(tl, tr, bl, br, a, b): - """ - Based on equation from: - http://en.wikipedia.org/wiki/Bilinear_interpolation - - :Parameters: - tl : int - top-left - tr : int - top-right - bl : int - buttom-left - br : int - bottom-right - a : float - x distance to top-left - b : float - y distance to top-right - - :Returns: (float) - interpolated value - """ - b1 = tl - b2 = bl - tl - b3 = tr - tl - b4 = tl - bl - tr + br - - return b1 + b2 * a + b3 * b + b4 * a * b - -class SrtmTiff(object): - """ - Provides an interface to SRTM elevation data stored in GeoTIFF file. - - Based on code from `eleserver` code by grahamjones139. - http://code.google.com/p/eleserver/ - """ - tile = {} - - def __init__(self, filename): - """ - Reads the GeoTIFF files into memory ready for processing. - """ - self.tile = self.load_tile(filename) - - def load_tile(self, filename): - """ - Loads a GeoTIFF tile from disk and returns a dictionary containing - the file data, plus metadata about the tile. - - The dictionary returned by this function contains the following data: - xsize - the width of the tile in pixels. - ysize - the height of the tile in pixels. - lat_origin - the latitude of the top left pixel in the tile. - lon_origin - the longitude of the top left pixel in the tile. - lat_pixel - the height of one pixel in degrees latitude. - lon_pixel - the width of one pixel in degrees longitude. - N, S, E, W - the bounding box for this tile in degrees. - data - a two dimensional array containing the tile data. - - """ - dataset = gdal.Open(filename) - geotransform = dataset.GetGeoTransform() - xsize = dataset.RasterXSize - ysize = dataset.RasterYSize - lon_origin = geotransform[0] - lat_origin = geotransform[3] - lon_pixel = geotransform[1] - lat_pixel = geotransform[5] - - retdict = { - 'xsize': xsize, - 'ysize': ysize, - 'lat_origin': lat_origin, - 'lon_origin': lon_origin, - 'lon_pixel': lon_pixel, - 'lat_pixel': lat_pixel, - 'N': lat_origin, - 'S': lat_origin + lat_pixel*ysize, - 'E': lon_origin + lon_pixel*xsize, - 'W': lon_origin, - 'dataset': dataset, - } - - return retdict - - def pos_from_lat_lon(self, lat, lon): - """ - Converts coordinates (lat,lon) into the appropriate (row,column) - position in the GeoTIFF tile data stored in td. - """ - td = self.tile - N = td['N'] - S = td['S'] - E = td['E'] - W = td['W'] - lat_pixel = td['lat_pixel'] - lon_pixel = td['lon_pixel'] - xsize = td['xsize'] - ysize = td['ysize'] - - rowno_f = (lat-N)/lat_pixel - colno_f = (lon-W)/lon_pixel - rowno = int(floor(rowno_f)) - colno = int(floor(colno_f)) - - # Error checking to correct any rounding errors. - if (rowno<0): - rowno = 0 - if (rowno>(xsize-1)): - rowno = xsize-1 - if (colno<0): - colno = 0 - if (colno>(ysize-1)): - colno = xsize-1 - - return (rowno, colno, rowno_f, colno_f) - - def get_elevation(self, lat, lon): - """ - Returns the elevation in metres of point (lat, lon). - - Uses bilinar interpolation to interpolate the SRTM data to the - required point. - """ - row, col, row_f, col_f = self.pos_from_lat_lon(lat, lon) - - # NOTE - THIS IS A FIDDLE TO STOP ERRORS AT THE EDGE OF - # TILES - IT IS NO CORRECT - WE SHOULD GET TWO POINTS - # FROM THE NEXT TILE. - if row==5999: row=5998 - if col==5999: col=5998 - - htarr = gdalnumeric.DatasetReadAsArray(self.tile['dataset'], col, row, 2, 2) - height = bilinear_interpolation(htarr[0][0], htarr[0][1], htarr[1][0], htarr[1][1], - row_f-row, col_f-col) - - return height - - -class SrtmLayer(object): - """ - Provides an interface to SRTM elevation data stored in GeoTIFF files. - Files are automaticly downloaded from mirror server and cached. - - Sample usage: - - >>> lat = 52.25 - >>> lon = 16.75 - >>> srtm = SrtmLayer() - >>> ele = srtm.get_elevation(lat, lon) - >>> round(ele, 4) - 63.9979 - - """ - _cache = {} - - def _download_srtm_tiff(self, srtm_filename): - """ - Download and unzip GeoTIFF file. - """ - #msg = _("Downloading SRTM Data from server. This might take some time...") - #md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, msg) - #md.set_title(_("Downloading SRTM Data")) - #md.set_modal(True) - #md.show() - - srtm_dir = os.path.expanduser('~/.pytrainer/SRTM_data') - if not os.path.isdir(srtm_dir): - os.mkdir(srtm_dir) - - logging.info('Downloading SRTM data file, it may take some time ...') - #url = 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/%s.ZIP' % srtm_filename[:-4] - url = '%s%s%s' % (srtm_server['url'], srtm_filename[:-4],srtm_server['ext'] ) - print "Attempting to get URL: %s" % url - zobj = StringIO() - zobj.write(urllib2.urlopen(url).read()) - z = zipfile.ZipFile(zobj) - - srtm_path = os.path.join(srtm_dir, srtm_filename) - out_file = open(srtm_path, 'w') - out_file.write(z.read(srtm_filename)) - - z.close() - out_file.close() - #md.destroy() - - - def get_srtm_filename(self, lat, lon): - """ - Filename of GeoTIFF file containing data with given coordinates. - """ - colmin = floor((6000 * (180 + lon)) / 5) - rowmin = floor((6000 * (60 - lat)) / 5) - - ilon = ceil(colmin / 6000.0) - ilat = ceil(rowmin / 6000.0) - - #return 'srtm_%02d_%02d.TIF' % (ilon, ilat) - return 'srtm_%02d_%02d.tif' % (ilon, ilat) - - def get_elevation(self, lat, lon): - """ - Returns the elevation in metres of point (lat, lon). - """ - srtm_filename = self.get_srtm_filename(lat, lon) - if srtm_filename not in self._cache: - srtm_path = os.path.join(os.path.expanduser('~/.pytrainer/SRTM_data'), srtm_filename) - if not os.path.isfile(srtm_path): - self._download_srtm_tiff(srtm_filename) - - self._cache[srtm_filename] = SrtmTiff(srtm_path) - - srtm = self._cache[srtm_filename] - return srtm.get_elevation(lat, lon) - class fixelevation: _data = None _srtm = SrtmLayer() Added: pytrainer/trunk/pytrainer/lib/srtmlayer.py =================================================================== --- pytrainer/trunk/pytrainer/lib/srtmlayer.py (rev 0) +++ pytrainer/trunk/pytrainer/lib/srtmlayer.py 2010-09-28 00:44:39 UTC (rev 623) @@ -0,0 +1,102 @@ +#!/usr/bin/env python +import os, stat, sys +import logging + +import random, re, urllib2, zipfile +from math import floor, ceil +from cStringIO import StringIO +from osgeo import gdal, gdalnumeric + +from pytrainer.lib.srtmtiff import SrtmTiff + +""" +A list of servers providing SRTM data in GeoTIFF +""" +srtm_server_list = [ + {'url' : 'http://droppr.org/srtm/v4.1/6_5x5_TIFs/', 'ext' : '.zip', 'active' : True }, \ + {'url' : 'ftp://xftp.jrc.it/pub/srtmV4/tiff/' , 'ext' : '.zip', 'active' : True }, \ + {'url' : 'http://srtm.csi.cgiar.org/SRT-ZIP/SRTM_V41/SRTM_Data_GeoTiff/' , 'ext' : '.zip' , 'active' : True }, \ + {'url' : 'ftp://srtm.csi.cgiar.org/SRTM_V41/SRTM_Data_GeoTiff/' , 'ext' : '.zip' , 'active' : True }, \ + {'url' : 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/', 'ext' : '.ZIP', 'active' : False } + ] +srtm_server = srtm_server_list[0] + + +class SrtmLayer(object): + """ + Provides an interface to SRTM elevation data stored in GeoTIFF files. + Files are automaticly downloaded from mirror server and cached. + + Sample usage: + + >>> lat = 52.25 + >>> lon = 16.75 + >>> srtm = SrtmLayer() + >>> ele = srtm.get_elevation(lat, lon) + >>> round(ele, 4) + 63.9979 + + """ + _cache = {} + + def _download_srtm_tiff(self, srtm_filename): + """ + Download and unzip GeoTIFF file. + """ + #msg = _("Downloading SRTM Data from server. This might take some time...") + #md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, msg) + #md.set_title(_("Downloading SRTM Data")) + #md.set_modal(True) + #md.show() + + srtm_dir = os.path.expanduser('~/.pytrainer/SRTM_data') + if not os.path.isdir(srtm_dir): + os.mkdir(srtm_dir) + + logging.info('Downloading SRTM data file, it may take some time ...') + #url = 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/%s.ZIP' % srtm_filename[:-4] + url = '%s%s%s' % (srtm_server['url'], srtm_filename[:-4],srtm_server['ext'] ) + print "Attempting to get URL: %s" % url + zobj = StringIO() + zobj.write(urllib2.urlopen(url).read()) + z = zipfile.ZipFile(zobj) + print "Got URL: %s" % url + + srtm_path = os.path.join(srtm_dir, srtm_filename) + out_file = open(srtm_path, 'w') + out_file.write(z.read(srtm_filename)) + + z.close() + out_file.close() + #md.destroy() + + + def get_srtm_filename(self, lat, lon): + """ + Filename of GeoTIFF file containing data with given coordinates. + """ + colmin = floor((6000 * (180 + lon)) / 5) + rowmin = floor((6000 * (60 - lat)) / 5) + + ilon = ceil(colmin / 6000.0) + ilat = ceil(rowmin / 6000.0) + + #return 'srtm_%02d_%02d.TIF' % (ilon, ilat) + return 'srtm_%02d_%02d.tif' % (ilon, ilat) + + def get_elevation(self, lat, lon): + """ + Returns the elevation in metres of point (lat, lon). + """ + srtm_filename = self.get_srtm_filename(lat, lon) + if srtm_filename not in self._cache: + srtm_path = os.path.join(os.path.expanduser('~/.pytrainer/SRTM_data'), srtm_filename) + if not os.path.isfile(srtm_path): + self._download_srtm_tiff(srtm_filename) + else: + print "File already downloaded (%s)" % srtm_filename + + self._cache[srtm_filename] = SrtmTiff(srtm_path) + + srtm = self._cache[srtm_filename] + return srtm.get_elevation(lat, lon) Added: pytrainer/trunk/pytrainer/lib/srtmtiff.py =================================================================== --- pytrainer/trunk/pytrainer/lib/srtmtiff.py (rev 0) +++ pytrainer/trunk/pytrainer/lib/srtmtiff.py 2010-09-28 00:44:39 UTC (rev 623) @@ -0,0 +1,145 @@ +#!/usr/bin/env python + +import logging +from math import floor +from osgeo import gdal, gdalnumeric + +# from gpxtools +def bilinear_interpolation(tl, tr, bl, br, a, b): + """ + Based on equation from: + http://en.wikipedia.org/wiki/Bilinear_interpolation + + :Parameters: + tl : int + top-left + tr : int + top-right + bl : int + buttom-left + br : int + bottom-right + a : float + x distance to top-left + b : float + y distance to top-right + + :Returns: (float) + interpolated value + """ + b1 = tl + b2 = bl - tl + b3 = tr - tl + b4 = tl - bl - tr + br + + return b1 + b2 * a + b3 * b + b4 * a * b + + +class SrtmTiff(object): + """ + Provides an interface to SRTM elevation data stored in GeoTIFF file. + + Based on code from `eleserver` code by grahamjones139. + http://code.google.com/p/eleserver/ + """ + tile = {} + + def __init__(self, filename): + """ + Reads the GeoTIFF files into memory ready for processing. + """ + self.tile = self.load_tile(filename) + + def load_tile(self, filename): + """ + Loads a GeoTIFF tile from disk and returns a dictionary containing + the file data, plus metadata about the tile. + + The dictionary returned by this function contains the following data: + xsize - the width of the tile in pixels. + ysize - the height of the tile in pixels. + lat_origin - the latitude of the top left pixel in the tile. + lon_origin - the longitude of the top left pixel in the tile. + lat_pixel - the height of one pixel in degrees latitude. + lon_pixel - the width of one pixel in degrees longitude. + N, S, E, W - the bounding box for this tile in degrees. + data - a two dimensional array containing the tile data. + + """ + dataset = gdal.Open(filename) + geotransform = dataset.GetGeoTransform() + xsize = dataset.RasterXSize + ysize = dataset.RasterYSize + lon_origin = geotransform[0] + lat_origin = geotransform[3] + lon_pixel = geotransform[1] + lat_pixel = geotransform[5] + + retdict = { + 'xsize': xsize, + 'ysize': ysize, + 'lat_origin': lat_origin, + 'lon_origin': lon_origin, + 'lon_pixel': lon_pixel, + 'lat_pixel': lat_pixel, + 'N': lat_origin, + 'S': lat_origin + lat_pixel*ysize, + 'E': lon_origin + lon_pixel*xsize, + 'W': lon_origin, + 'dataset': dataset, + } + + return retdict + + def pos_from_lat_lon(self, lat, lon): + """ + Converts coordinates (lat,lon) into the appropriate (row,column) + position in the GeoTIFF tile data stored in td. + """ + td = self.tile + N = td['N'] + S = td['S'] + E = td['E'] + W = td['W'] + lat_pixel = td['lat_pixel'] + lon_pixel = td['lon_pixel'] + xsize = td['xsize'] + ysize = td['ysize'] + + rowno_f = (lat-N)/lat_pixel + colno_f = (lon-W)/lon_pixel + rowno = int(floor(rowno_f)) + colno = int(floor(colno_f)) + + # Error checking to correct any rounding errors. + if (rowno<0): + rowno = 0 + if (rowno>(xsize-1)): + rowno = xsize-1 + if (colno<0): + colno = 0 + if (colno>(ysize-1)): + colno = xsize-1 + + return (rowno, colno, rowno_f, colno_f) + + def get_elevation(self, lat, lon): + """ + Returns the elevation in metres of point (lat, lon). + + Uses bilinar interpolation to interpolate the SRTM data to the + required point. + """ + row, col, row_f, col_f = self.pos_from_lat_lon(lat, lon) + + # NOTE - THIS IS A FIDDLE TO STOP ERRORS AT THE EDGE OF + # TILES - IT IS NO CORRECT - WE SHOULD GET TWO POINTS + # FROM THE NEXT TILE. + if row==5999: row=5998 + if col==5999: col=5998 + + htarr = gdalnumeric.DatasetReadAsArray(self.tile['dataset'], col, row, 2, 2) + height = bilinear_interpolation(htarr[0][0], htarr[0][1], htarr[1][0], htarr[1][1], + row_f-row, col_f-col) + + return height Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-09-28 00:20:39 UTC (rev 622) +++ pytrainer/trunk/pytrainer/main.py 2010-09-28 00:44:39 UTC (rev 623) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#622" + self.version ="1.7.2_svn#623" self.DB_version = 3 #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-09-28 21:32:02
|
Revision: 626 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=626&view=rev Author: jblance Date: 2010-09-28 21:31:55 +0000 (Tue, 28 Sep 2010) Log Message: ----------- Anonymise fixes for OSM extension from Arnd Modified Paths: -------------- pytrainer/trunk/extensions/openstreetmap/openstreetmap.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/extensions/openstreetmap/openstreetmap.py =================================================================== --- pytrainer/trunk/extensions/openstreetmap/openstreetmap.py 2010-09-28 21:22:07 UTC (rev 625) +++ pytrainer/trunk/extensions/openstreetmap/openstreetmap.py 2010-09-28 21:31:55 UTC (rev 626) @@ -13,277 +13,271 @@ import mimetools, mimetypes class openstreetmap: - def __init__(self, parent = None, pytrainer_main = None, conf_dir = None, options = None): - self.parent = parent - self.pytrainer_main = pytrainer_main - self.options = options - self.conf_dir = conf_dir - self.description = " " - self.tags = "" - self.visibility = "private" + def __init__(self, parent = None, pytrainer_main = None, conf_dir = None, options = None): + self.parent = parent + self.pytrainer_main = pytrainer_main + self.options = options + self.conf_dir = conf_dir + self.description = " " + self.tags = "" + self.visibility = "private" - def run(self, id, activity=None): #TODO Convert to use activity... - logging.debug(">>") - uri = "http://api.openstreetmap.org/api/0.6/gpx/create" #URI for uploading traces to OSM - if 'username' not in self.options or self.options['username'] == "" or 'password' not in self.options or self.options['password'] == "": - logging.error("Must have username and password configured") - msg = _("Must have username and password configured") - md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg) - md.set_title(_("Openstreetmap Extension Error")) - md.run() - md.destroy() - return - username = self.options['username'] - password = self.options['password'] - gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, id) - if os.path.isfile(gpx_file): - #GPX file is ok and found, so open it - logging.debug("GPX file: %s found, size: %d" % (gpx_file, os.path.getsize(gpx_file))) - f = open(gpx_file, 'r') - file_contents = f.read() - #TODO Fix to use etree functionality..... - if file_contents.find("<?xml version='1.0' encoding='ASCII'?>") != -1: - logging.debug("GPX file: %s has ASCII encoding - updating to UTF-8 for OSM support" % gpx_file) - f.close() #Close readonly file - f = open(gpx_file, 'w') #and open file for writing - file_contents = file_contents.replace("<?xml version='1.0' encoding='ASCII'?>","<?xml version='1.0' encoding='UTF-8'?>", 1) - f.write(file_contents) #Write new content - f.close() #Close - f = open(gpx_file, 'r') #Reopen in readonly mode - #Get extra info from user - response=self.display_options_window() - if not response==gtk.RESPONSE_ACCEPT: - f.close() - logging.debug("User abort") - return - if self.makeanon: - logging.debug("User requested anonymising of GPX data") - f.close() #Close standard gpxfile - gpx_file = self.make_gpx_private(gpx_file) - f = open(gpx_file, 'r') #Open anonymous gpxfile in readonly mode - fields = (("description",self.description), ("tags",self.tags), ("visibility",self.visibility)) - logging.debug("Added fields: %s" % str(fields)) - #Multipart encode the request - boundary, body = self.multipart_encode(fields=fields, files=(("file", f),)) - content_type = 'multipart/form-data; boundary=%s' % boundary - #Finished with the file so close it - f.close() - #Add the http headers to the request - h = httplib2.Http() - headers = { - 'Content-Type': content_type - } - #Add basic authentication credentials to the request - h.add_credentials(username, password) - #Show user something is happening - msg = _("Posting GPX trace to Openstreetmap\n\nPlease wait this could take several minutes") - md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, msg) - md.set_title(_("Openstreetmap Extension Processing")) - md.set_modal(True) - md.show() - while gtk.events_pending(): # This allows the GUI to update - gtk.main_iteration() # before completion of this entire action - logging.debug("before request posting") - #POST request to OSM - res, content = h.request(uri, 'POST', body=body, headers=headers) - logging.debug("after request posting") - logging.debug("Got response status: %s, reason: %s, content: %s" % (res.status, res.reason, content)) - if res.reason == 'OK': - res_msg = "Successfully posted to OSM.\nYou should get an email with the outcome of the upload soon\n\nTrace id is %s" % content - else: - res_msg = "Some error occured\nGot a status %s, reason %s\nContent was: %s" % (res.status, res.reason, content) - #Close 'Please wait' dialog - md.destroy() - #Show the user the result - md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, res_msg) - md.set_title(_("Openstreetmap Extension Upload Complete")) - md.set_modal(False) - md.run() - md.destroy() + def run(self, id, activity=None): #TODO Convert to use activity... + logging.debug(">>") + uri = "http://api.openstreetmap.org/api/0.6/gpx/create" #URI for uploading traces to OSM + if 'username' not in self.options or self.options['username'] == "" or 'password' not in self.options or self.options['password'] == "": + logging.error("Must have username and password configured") + msg = _("Must have username and password configured") + md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg) + md.set_title(_("Openstreetmap Extension Error")) + md.run() + md.destroy() + return + username = self.options['username'] + password = self.options['password'] + gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, id) + if os.path.isfile(gpx_file): + #GPX file is ok and found, so open it + logging.debug("GPX file: %s found, size: %d" % (gpx_file, os.path.getsize(gpx_file))) + f = open(gpx_file, 'r') + file_contents = f.read() + #TODO Fix to use etree functionality..... + if file_contents.find("<?xml version='1.0' encoding='ASCII'?>") != -1: + logging.debug("GPX file: %s has ASCII encoding - updating to UTF-8 for OSM support" % gpx_file) + f.close() #Close readonly file + f = open(gpx_file, 'w') #and open file for writing + file_contents = file_contents.replace("<?xml version='1.0' encoding='ASCII'?>","<?xml version='1.0' encoding='UTF-8'?>", 1) + f.write(file_contents) #Write new content + f.close() #Close + f = open(gpx_file, 'r') #Reopen in readonly mode + #Get extra info from user + response=self.display_options_window() + if not response==gtk.RESPONSE_ACCEPT: + f.close() + logging.debug("User abort") + return + if self.makeanon: + logging.debug("User requested anonymising of GPX data") + f.close() #Close standard gpxfile + gpx_file = self.make_gpx_private(gpx_file) + f = open(gpx_file, 'r') #Open anonymous gpxfile in readonly mode + fields = (("description",self.description), ("tags",self.tags), ("visibility",self.visibility)) + logging.debug("Added fields: %s" % str(fields)) + #Multipart encode the request + boundary, body = self.multipart_encode(fields=fields, files=(("file", f),)) + content_type = 'multipart/form-data; boundary=%s' % boundary + #Finished with the file so close it + f.close() + #Add the http headers to the request + h = httplib2.Http() + headers = { + 'Content-Type': content_type + } + #Add basic authentication credentials to the request + h.add_credentials(username, password) + #Show user something is happening + msg = _("Posting GPX trace to Openstreetmap\n\nPlease wait this could take several minutes") + md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, msg) + md.set_title(_("Openstreetmap Extension Processing")) + md.set_modal(True) + md.show() + while gtk.events_pending(): # This allows the GUI to update + gtk.main_iteration() # before completion of this entire action + logging.debug("before request posting") + #POST request to OSM + res, content = h.request(uri, 'POST', body=body, headers=headers) + logging.debug("after request posting") + logging.debug("Got response status: %s, reason: %s, content: %s" % (res.status, res.reason, content)) + if res.reason == 'OK': + res_msg = "Successfully posted to OSM.\nYou should get an email with the outcome of the upload soon\n\nTrace id is %s" % content + else: + res_msg = "Some error occured\nGot a status %s, reason %s\nContent was: %s" % (res.status, res.reason, content) + #Close 'Please wait' dialog + md.destroy() + #Show the user the result + md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, res_msg) + md.set_title(_("Openstreetmap Extension Upload Complete")) + md.set_modal(False) + md.run() + md.destroy() - else: - logging.error("GPX file: %s NOT found!!!" % (gpx_file)) - logging.debug("<<") + else: + logging.error("GPX file: %s NOT found!!!" % (gpx_file)) + logging.debug("<<") - def display_options_window(self): - self.prefwindow = gtk.Dialog(title=_("Please add any additional information for this upload"), parent=None, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)) - self.prefwindow.set_modal(False) - table = gtk.Table(1,2) - self.entryList = [] - #Add description - label = gtk.Label("<b>Description</b>") - label.set_use_markup(True) - entry = gtk.Entry() - self.entryList.append(entry) - table.attach(label,0,1,0,1) - table.attach(entry,1,2,0,1) - #Add tags - label = gtk.Label("<b>Tags</b>") - label.set_use_markup(True) - entry = gtk.Entry() - self.entryList.append(entry) - table.attach(label,0,1,1,2) - table.attach(entry,1,2,1,2) - #Add visibility - label = gtk.Label("<b>Visibility</b>") - label.set_use_markup(True) - combobox = gtk.combo_box_new_text() - combobox.append_text("private") - combobox.append_text("public") - combobox.append_text("trackable") - combobox.append_text("identifiable") - combobox.set_active(0) - table.attach(combobox,1,2,2,3) - self.entryList.append(combobox) - table.attach(label,0,1,2,3) - #Add anonymize GPX option - label = gtk.Label("<b>Anonymize GPX Data</b>") - label.set_use_markup(True) - table.attach(label,0,1,3,4) - checkbutton = gtk.CheckButton() - table.attach(checkbutton,1,2,3,4) - self.entryList.append(checkbutton) - #Buld dialog and show - self.prefwindow.vbox.pack_start(table) - self.prefwindow.show_all() - self.prefwindow.connect("response", self.on_options_ok_clicked) - response=self.prefwindow.run() - self.prefwindow.destroy() - return response + def display_options_window(self): + self.prefwindow = gtk.Dialog(title=_("Please add any additional information for this upload"), parent=None, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)) + self.prefwindow.set_modal(False) + table = gtk.Table(1,2) + self.entryList = [] + #Add description + label = gtk.Label("<b>Description</b>") + label.set_use_markup(True) + entry = gtk.Entry() + self.entryList.append(entry) + table.attach(label,0,1,0,1) + table.attach(entry,1,2,0,1) + #Add tags + label = gtk.Label("<b>Tags</b>") + label.set_use_markup(True) + entry = gtk.Entry() + self.entryList.append(entry) + table.attach(label,0,1,1,2) + table.attach(entry,1,2,1,2) + #Add visibility + label = gtk.Label("<b>Visibility</b>") + label.set_use_markup(True) + combobox = gtk.combo_box_new_text() + combobox.append_text("private") + combobox.append_text("public") + combobox.append_text("trackable") + combobox.append_text("identifiable") + combobox.set_active(0) + table.attach(combobox,1,2,2,3) + self.entryList.append(combobox) + table.attach(label,0,1,2,3) + #Add anonymize GPX option + label = gtk.Label("<b>Anonymize GPX Data</b>") + label.set_use_markup(True) + table.attach(label,0,1,3,4) + checkbutton = gtk.CheckButton() + table.attach(checkbutton,1,2,3,4) + self.entryList.append(checkbutton) + #Buld dialog and show + self.prefwindow.vbox.pack_start(table) + self.prefwindow.show_all() + self.prefwindow.connect("response", self.on_options_ok_clicked) + response=self.prefwindow.run() + self.prefwindow.destroy() + return response - def on_options_ok_clicked(self, widget, response_id): - if not response_id == gtk.RESPONSE_ACCEPT: - return response_id - self.description = self.entryList[0].get_text() - if self.description == "": - logging.debug("A description is required - setting to default") - self.description = "Uploaded from pytrainer" - self.tags = self.entryList[1].get_text() - self.visibility = self.entryList[2].get_active_text() - self.makeanon = self.entryList[3].get_active() - logging.debug("Description: %s, tags: %s, visibility: %s, makeanon: %s" % ( self.description, self.tags, self.visibility, self.makeanon) ) + def on_options_ok_clicked(self, widget, response_id): + if not response_id == gtk.RESPONSE_ACCEPT: + return response_id + self.description = self.entryList[0].get_text() + if self.description == "": + logging.debug("A description is required - setting to default") + self.description = "Uploaded from pytrainer" + self.tags = self.entryList[1].get_text() + self.visibility = self.entryList[2].get_active_text() + self.makeanon = self.entryList[3].get_active() + logging.debug("Description: %s, tags: %s, visibility: %s, makeanon: %s" % ( self.description, self.tags, self.visibility, self.makeanon) ) - def multipart_encode(self, fields, files, boundary = None, buffer = None): - ''' - Multipart encode data for posting - from examples at from http://odin.himinbi.org/MultipartPostHandler.py & http://bitworking.org/projects/httplib2/doc/html/libhttplib2.html - ''' - if boundary is None: - boundary = mimetools.choose_boundary() - if buffer is None: - buffer = '' - for (key, value) in fields: - buffer += '--%s\r\n' % boundary - buffer += 'Content-Disposition: form-data; name="%s"' % key - buffer += '\r\n\r\n' + value + '\r\n' - print files - for (key, fd) in files: - file_size = os.fstat(fd.fileno())[stat.ST_SIZE] - filename = os.path.basename(fd.name) - contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' - buffer += '--%s\r\n' % boundary - buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename) - buffer += 'Content-Type: %s\r\n' % contenttype - # buffer += 'Content-Length: %s\r\n' % file_size - fd.seek(0) - buffer += '\r\n' + fd.read() + '\r\n' - buffer += '--%s--\r\n\r\n' % boundary - return boundary, buffer - - def make_gpx_private(self, gpx_file=None): - ''' - wipes out private data from gpx files - converts laps to waypoints - ''' - logging.debug(">>") - if gpx_file is None: - return None - - filen = os.path.basename(gpx_file) - tmpdir = self.pytrainer_main.profile.tmpdir - anon_gpx_file = "%s/%s" % (tmpdir, filen) - - # Filtered home area, example Berlin - # corners NorthEast and SouthWest - #TODO This needs to be a config item.... - NE_LAT = 52.518 - NE_LON = 13.408 - SW_LAT = 52.4 - SW_LON = 13.3 + def multipart_encode(self, fields, files, boundary = None, buffer = None): + ''' + Multipart encode data for posting + from examples at from http://odin.himinbi.org/MultipartPostHandler.py & http://bitworking.org/projects/httplib2/doc/html/libhttplib2.html + ''' + if boundary is None: + boundary = mimetools.choose_boundary() + if buffer is None: + buffer = '' + for (key, value) in fields: + buffer += '--%s\r\n' % boundary + buffer += 'Content-Disposition: form-data; name="%s"' % key + buffer += '\r\n\r\n' + value + '\r\n' + print files + for (key, fd) in files: + file_size = os.fstat(fd.fileno())[stat.ST_SIZE] + filename = os.path.basename(fd.name) + contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' + buffer += '--%s\r\n' % boundary + buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename) + buffer += 'Content-Type: %s\r\n' % contenttype + # buffer += 'Content-Length: %s\r\n' % file_size + fd.seek(0) + buffer += '\r\n' + fd.read() + '\r\n' + buffer += '--%s--\r\n\r\n' % boundary + return boundary, buffer + + def make_gpx_private(self, gpx_file=None): + ''' + wipes out private data from gpx files + converts laps to waypoints + ''' + logging.debug(">>") + if gpx_file is None: + return None + + filen = os.path.basename(gpx_file) + tmpdir = self.pytrainer_main.profile.tmpdir + anon_gpx_file = "%s/%s" % (tmpdir, filen) + + # Filtered home area, example Berlin + # corners NorthEast and SouthWest + #TODO This needs to be a config item.... + NE_LAT = 52.518 + NE_LON = 13.408 + SW_LAT = 52.4 + SW_LON = 13.3 - # Config parameters, not used yet - FILTER_BOX = True - ERASE_TIME = True - LAP_TO_WAYPOINT = True + # Config parameters, not used yet + FILTER_BOX = True + ERASE_TIME = True + LAP_TO_WAYPOINT = True - tree = etree.parse(gpx_file) - _xmlns = tree.getroot().nsmap[None] - _trkpt_path = '{%s}trk/{%s}trkseg/{%s}trkpt' % (_xmlns, _xmlns, _xmlns) - # namespace of gpx files - NS = dict(ns='http://www.topografix.com/GPX/1/1') + tree = etree.parse(gpx_file) + _xmlns = tree.getroot().nsmap[None] + _trkpt_path = '{%s}trk/{%s}trkseg/{%s}trkpt' % (_xmlns, _xmlns, _xmlns) + # namespace of gpx files + NS = dict(ns='http://www.topografix.com/GPX/1/1') - myroot = tree.getroot() - gpxdataNS = string.Template(\ - ".//{http://www.cluetrust.com/XML/GPXDATA/1/0}$tag") - lapTag = gpxdataNS.substitute(tag="lap") - endPointTag = gpxdataNS.substitute(tag="endPoint") - triggerTag = gpxdataNS.substitute(tag="trigger") - laps = tree.findall(lapTag) + myroot = tree.getroot() + gpxdataNS = string.Template(\ + ".//{http://www.cluetrust.com/XML/GPXDATA/1/0}$tag") + lapTag = gpxdataNS.substitute(tag="lap") + endPointTag = gpxdataNS.substitute(tag="endPoint") + triggerTag = gpxdataNS.substitute(tag="trigger") + laps = tree.findall(lapTag) - #new_waypoints=[] - mygpx = tree.find('gpx') + mygpx = tree.find('gpx') - for lap in laps: - trigger = lap.find(triggerTag) - # Watch out for manually triggered laps - if trigger.text == 'manual': - endPoint = lap.find(endPointTag) - lat = endPoint.get("lat") - lon = endPoint.get("lon") - print lat,lon - #new_waypoints.append([lat,lon]) - #add waypoint - etree.SubElement(myroot, 'wpt', attrib= {'lat':lat, 'lon':lon}) + for lap in laps: + trigger = lap.find(triggerTag) + # Watch out for manually triggered laps + if trigger.text == 'manual': + endPoint = lap.find(endPointTag) + lat = endPoint.get("lat") + lon = endPoint.get("lon") + # Create waypt if not in home box + if not ((SW_LAT < float(lat) < NE_LAT) and (SW_LON < float(lon) < NE_LON)): + etree.SubElement(myroot, 'wpt', attrib= {'lat':lat, 'lon':lon}) + etree.strip_attributes(myroot, 'creator') - etree.strip_attributes(myroot, 'creator') + # Wipe out home box + for trkpt in tree.findall(_trkpt_path): + lat = float(trkpt.attrib['lat']) + lon = float(trkpt.attrib['lon']) + if (lat < NE_LAT) & (lon < NE_LON) & (lat > SW_LAT) & (lon > SW_LON): + par = trkpt.getparent() + par.remove(trkpt) - # Wipe out home box - for trkpt in tree.findall(_trkpt_path): - lat = float(trkpt.attrib['lat']) - lon = float(trkpt.attrib['lon']) - #print lat, lon - if (lat < NE_LAT) & (lon < NE_LON) & (lat > SW_LAT) & (lon > SW_LON): - #print lat,lon - par = trkpt.getparent() - par.remove(trkpt) + time = tree.xpath('//ns:trkpt/ns:time', namespaces=NS) + for i in time: + i.text = '1970-01-01T00:00:00+00:00' + # osm regards <time> as mandatory. gnaa. + ext = tree.xpath('//ns:gpx/ns:extensions', namespaces=NS) + for i in ext: + par = i.getparent() + par.remove(i) + meta = tree.xpath('//ns:gpx/ns:metadata', namespaces=NS) + for i in meta: + par = i.getparent() + par.remove(i) + ele = tree.xpath('//ns:trkpt/ns:ele', namespaces=NS) + for i in ele: + par = i.getparent() + par.remove(i) - time = tree.xpath('//ns:trkpt/ns:time', namespaces=NS) - for i in time: - i.text = '1970-01-01T00:00:00+00:00' - # osm regards <time> as mandatory. gnaa. + # test schema on cleaned xml-tree + # gpx.xsd from http://www.topografix.com/gpx.asp - ext = tree.xpath('//ns:gpx/ns:extensions', namespaces=NS) - for i in ext: - par = i.getparent() - par.remove(i) - meta = tree.xpath('//ns:gpx/ns:metadata', namespaces=NS) - for i in meta: - par = i.getparent() - par.remove(i) - ele = tree.xpath('//ns:trkpt/ns:ele', namespaces=NS) - for i in ele: - par = i.getparent() - par.remove(i) + #xmlschema = etree.XMLSchema(etree.parse('gpx.xsd')) + #xmlschema.validate(tree) - # test schema on cleaned xml-tree - # gpx.xsd from http://www.topografix.com/gpx.asp + # write new gpx file + tree.write(anon_gpx_file, pretty_print=False, xml_declaration=True, encoding='UTF-8') + logging.debug("<<") + return anon_gpx_file - #xmlschema = etree.XMLSchema(etree.parse('gpx.xsd')) - #xmlschema.validate(tree) - - # write new gpx file - tree.write(anon_gpx_file, pretty_print=False, xml_declaration=True, encoding='UTF-8') - logging.debug("<<") - return anon_gpx_file - Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-09-28 21:22:07 UTC (rev 625) +++ pytrainer/trunk/pytrainer/main.py 2010-09-28 21:31:55 UTC (rev 626) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#625" + self.version ="1.7.2_svn#626" self.DB_version = 3 #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-09-28 22:30:37
|
Revision: 627 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=627&view=rev Author: jblance Date: 2010-09-28 22:30:27 +0000 (Tue, 28 Sep 2010) Log Message: ----------- Elevation fixes - download progress indicator, auto server switch, cancel download Modified Paths: -------------- pytrainer/trunk/extensions/fixelevation/fixelevation.py pytrainer/trunk/pytrainer/lib/srtmlayer.py pytrainer/trunk/pytrainer/main.py Added Paths: ----------- pytrainer/trunk/pytrainer/lib/srtmdownload.py Modified: pytrainer/trunk/extensions/fixelevation/fixelevation.py =================================================================== --- pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-09-28 21:31:55 UTC (rev 626) +++ pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-09-28 22:30:27 UTC (rev 627) @@ -2,11 +2,6 @@ import os #, stat, sys import logging import gtk -#import random, re, urllib2, zipfile -#from math import floor, ceil -#from cStringIO import StringIO -#from optparse import OptionParser -#from osgeo import gdal, gdalnumeric from lxml import etree from pytrainer.lib.srtmlayer import SrtmLayer @@ -23,19 +18,19 @@ def run(self, id, activity=None): #TODO Convert to use activity... logging.debug(">>") gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, id) + ele_fixed = True + if os.path.isfile(gpx_file): # Backup original raw data as *.orig.gpx - orig_file = open(gpx_file, 'r') - orig_data = orig_file.read() - orig_file.close() - backup_file = open("%s/gpx/%s.orig.gpx" % (self.conf_dir, id), 'w') - backup_file.write(orig_data) - backup_file.close() + #orig_file = open(gpx_file, 'r') + #orig_data = orig_file.read() + #orig_file.close() + #backup_file = open("%s/gpx/%s.orig.gpx" % (self.conf_dir, id), 'w') + #backup_file.write(orig_data) + #backup_file.close() #GPX file is ok and found, so open it logging.debug("ELE GPX file: %s found, size: %d" % (gpx_file, os.path.getsize(gpx_file))) - - """ Parse GPX file to ElementTree instance. """ @@ -52,23 +47,27 @@ lon = float(trkpt.attrib['lon']) ele = trkpt.find('{%s}ele' % self._xmlns) + ele_new = self._srtm.get_elevation(lat, lon) + if not ele_new: + ele_fixed = False + break + if ele is not None: - ele.text = str(self._srtm.get_elevation(lat, lon)) + ele.text = str(ele_new) else: ele = etree.Element('ele') - ele.text = str(self._srtm.get_elevation(lat, lon)) - trkpt.append(ele) - """ - write out to original *.gpx. - """ - self._data.write( gpx_file, + ele.text = str(ele_new) + trkpt.append(ele) + if ele_fixed: + # Write out to original *.gpx. + self._data.write( gpx_file, encoding=self._data.docinfo.encoding, xml_declaration=True, pretty_print=False) + res_msg = "Elevation has been fixed." + else: + res_msg = "Elevation could not be fixed!" - - #print trkpt - res_msg = "Elevation has been fixed." #Show the user the result md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, res_msg) md.set_title(_("Elevation Correction Complete")) @@ -80,7 +79,3 @@ else: logging.error("ELE GPX file: %s NOT found!!!" % (gpx_file)) logging.debug("<<") - - - - Added: pytrainer/trunk/pytrainer/lib/srtmdownload.py =================================================================== --- pytrainer/trunk/pytrainer/lib/srtmdownload.py (rev 0) +++ pytrainer/trunk/pytrainer/lib/srtmdownload.py 2010-09-28 22:30:27 UTC (rev 627) @@ -0,0 +1,151 @@ +# -*- coding: iso-8859-1 -*- + +#This program is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public License +#as published by the Free Software Foundation; either version 2 +#of the License, or (at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import os +import gtk +import urllib2 +import zipfile +from cStringIO import StringIO +import logging + +""" +A list of servers providing SRTM data in GeoTIFF. +""" +srtm_server_list = [ + {'url' : 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/', 'ext' : '.ZIP', 'active' : False }, \ + {'url' : 'http://droppr.org/srtm/v4.1/6_5x5_TIFs/', 'ext' : '.zip', 'active' : True }, \ + {'url' : 'ftp://xftp.jrc.it/pub/srtmV4/tiff/' , 'ext' : '.zip', 'active' : True }, \ + {'url' : 'http://srtm.csi.cgiar.org/SRT-ZIP/SRTM_V41/SRTM_Data_GeoTiff/' , 'ext' : '.zip' , 'active' : True }, \ + {'url' : 'ftp://srtm.csi.cgiar.org/SRTM_V41/SRTM_Data_GeoTiff/' , 'ext' : '.zip' , 'active' : True }, \ + {'url' : 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/', 'ext' : '.ZIP', 'active' : False } + ] + +global loopActive + +class DownloadLoop: + """ + Download GeoTIFF in partial chunks. Between chunks check gtk.min_iteration + and update progressbar. Threadless Implementation. + """ + srtm_dir = os.path.expanduser('~/.pytrainer/SRTM_data') + + def __init__(self, progressbar, label, tile_name): + self.progressbar = progressbar + self.label = label + self.tile_name = tile_name + + def run(self): + logging.debug(">>") + global loopActive + + #print 'Loop started', loopActive + + srtm_filename = '%s.tif' % self.tile_name + if not os.path.isdir(self.srtm_dir): + os.mkdir(self.srtm_dir) + + urlfile = self.get_urlfile() + size_total = int(urlfile.info().getheader('Content-Length').strip()) + + if size_total == 0: + loopActive = False + #print 'Total size:', size_total + + size_chunk = 4096 #8192 + size_got = 0 + zobj = StringIO() + + while loopActive: + while gtk.events_pending(): + gtk.main_iteration(block = False) + chunk = urlfile.read(size_chunk) + size_got+= size_chunk + if chunk: + zobj.write( chunk ) + size_rel = min (1.0, size_got / (1.0 * size_total)) + #print "Read %s Percent." % (round(100*size_rel, 1)) + self.progressbar.set_fraction( size_rel ) + else: + loopActive = False + if size_rel == 1.0: + print "start unzip" + z = zipfile.ZipFile(zobj) + srtm_path = os.path.join(self.srtm_dir, srtm_filename) + out_file = open(srtm_path, 'w') + out_file.write(z.read(srtm_filename)) + z.close() + zobj.close + out_file.close() + logging.debug("<<") + return True # Hooray, got file + logging.debug("<<") + return False + + def get_urlfile(self): + """ Go through SRTM Servers """ + logging.debug('--') + for server in srtm_server_list: + url = '%s%s%s' % (server['url'], self.tile_name, server['ext']) + print "Attempting to get URL: %s" % url + logging.debug("Attempting to get URL: %s" % url) + try: + urlfile = urllib2.urlopen( url ) + self.label.set_text(str(url)) + return urlfile + except: + print '%s FAILED' % url + logging.debug('%s FAILED' % url) + pass + + +def main_quit(obj): + logging.debug("--") + global loopActive + print 'main_quit entered' + loopActive = False + +def download(tile_name): + logging.debug(">>") + global loopActive + loopActive = True + result = False + window = gtk.Dialog() + window.set_title('Download GeoTIFF') + labelH = gtk.Label('<b>Downloading Tile %s</b>' % tile_name) + labelH.set_use_markup(True) + labelH.set_alignment(0, 1) + + label = gtk.Label('Searching for Server ...') + progressbar = gtk.ProgressBar() + + window.connect('destroy', main_quit) + button = gtk.Button(stock=gtk.STOCK_CANCEL) + button.connect("clicked", main_quit) + + window.vbox.pack_start(labelH, expand=False, padding=3) + window.vbox.pack_start(label, expand=False, padding=3) + window.vbox.pack_start(progressbar, expand=False, padding=3) + window.action_area.pack_start(button, expand=False) + window.show_all() + + lp = DownloadLoop(progressbar, label, tile_name) + result = lp.run() + try: + window.destroy() + except: + pass + logging.debug("<<") + return result Modified: pytrainer/trunk/pytrainer/lib/srtmlayer.py =================================================================== --- pytrainer/trunk/pytrainer/lib/srtmlayer.py 2010-09-28 21:31:55 UTC (rev 626) +++ pytrainer/trunk/pytrainer/lib/srtmlayer.py 2010-09-28 22:30:27 UTC (rev 627) @@ -8,20 +8,8 @@ from osgeo import gdal, gdalnumeric from pytrainer.lib.srtmtiff import SrtmTiff +import srtmdownload -""" -A list of servers providing SRTM data in GeoTIFF -""" -srtm_server_list = [ - {'url' : 'http://droppr.org/srtm/v4.1/6_5x5_TIFs/', 'ext' : '.zip', 'active' : True }, \ - {'url' : 'ftp://xftp.jrc.it/pub/srtmV4/tiff/' , 'ext' : '.zip', 'active' : True }, \ - {'url' : 'http://srtm.csi.cgiar.org/SRT-ZIP/SRTM_V41/SRTM_Data_GeoTiff/' , 'ext' : '.zip' , 'active' : True }, \ - {'url' : 'ftp://srtm.csi.cgiar.org/SRTM_V41/SRTM_Data_GeoTiff/' , 'ext' : '.zip' , 'active' : True }, \ - {'url' : 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/', 'ext' : '.ZIP', 'active' : False } - ] -srtm_server = srtm_server_list[0] - - class SrtmLayer(object): """ Provides an interface to SRTM elevation data stored in GeoTIFF files. @@ -38,39 +26,7 @@ """ _cache = {} - - def _download_srtm_tiff(self, srtm_filename): - """ - Download and unzip GeoTIFF file. - """ - #msg = _("Downloading SRTM Data from server. This might take some time...") - #md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, msg) - #md.set_title(_("Downloading SRTM Data")) - #md.set_modal(True) - #md.show() - - srtm_dir = os.path.expanduser('~/.pytrainer/SRTM_data') - if not os.path.isdir(srtm_dir): - os.mkdir(srtm_dir) - - logging.info('Downloading SRTM data file, it may take some time ...') - #url = 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/%s.ZIP' % srtm_filename[:-4] - url = '%s%s%s' % (srtm_server['url'], srtm_filename[:-4],srtm_server['ext'] ) - print "Attempting to get URL: %s" % url - zobj = StringIO() - zobj.write(urllib2.urlopen(url).read()) - z = zipfile.ZipFile(zobj) - print "Got URL: %s" % url - - srtm_path = os.path.join(srtm_dir, srtm_filename) - out_file = open(srtm_path, 'w') - out_file.write(z.read(srtm_filename)) - - z.close() - out_file.close() - #md.destroy() - - + def get_srtm_filename(self, lat, lon): """ Filename of GeoTIFF file containing data with given coordinates. @@ -81,7 +37,6 @@ ilon = ceil(colmin / 6000.0) ilat = ceil(rowmin / 6000.0) - #return 'srtm_%02d_%02d.TIF' % (ilon, ilat) return 'srtm_%02d_%02d.tif' % (ilon, ilat) def get_elevation(self, lat, lon): @@ -92,7 +47,9 @@ if srtm_filename not in self._cache: srtm_path = os.path.join(os.path.expanduser('~/.pytrainer/SRTM_data'), srtm_filename) if not os.path.isfile(srtm_path): - self._download_srtm_tiff(srtm_filename) + result = srtmdownload.download( srtm_filename[:-4] ) + if not result: + return False else: print "File already downloaded (%s)" % srtm_filename Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-09-28 21:31:55 UTC (rev 626) +++ pytrainer/trunk/pytrainer/main.py 2010-09-28 22:30:27 UTC (rev 627) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#626" + self.version ="1.7.2_svn#627" self.DB_version = 3 #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-09-30 00:14:12
|
Revision: 631 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=631&view=rev Author: jblance Date: 2010-09-30 00:14:04 +0000 (Thu, 30 Sep 2010) Log Message: ----------- Change to startup script to _hopefully_ resolve the issue with multiple installs of xulrunner Modified Paths: -------------- pytrainer/trunk/bin/pytrainer pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/bin/pytrainer =================================================================== --- pytrainer/trunk/bin/pytrainer 2010-09-29 21:57:45 UTC (rev 630) +++ pytrainer/trunk/bin/pytrainer 2010-09-30 00:14:04 UTC (rev 631) @@ -25,9 +25,36 @@ import gtk import gtk.glade import os +import glob import commands +def _max(one, two): + '''Function to determine the max of two versions of format /xx/xxx/????-1.2.3 ''' + if one is None: + return two + elif two is None: + return one + one_v = os.path.basename(one).split('-')[1] + two_v = os.path.basename(two).split('-')[1] + one_v_nos = one_v.split('.') + two_v_nos = two_v.split('.') + + for index, no in enumerate(one_v_nos): + if index >= len(two_v_nos): + return one + elif no > two_v_nos[index]: + return one + elif no < two_v_nos[index]: + return two + else: + pass + if len(one_v_nos) >= len(two_v_nos): + return one + else: + return two + + bin_path = os.path.realpath(os.path.dirname(__file__)) # directory that the pytrainer script executes from e.g. /usr/bin or /usr/local/bin base_path = os.path.dirname(bin_path) @@ -47,13 +74,28 @@ #ensure pytrainer directory is included in import path sys.path.insert(0, site_path) - from pytrainer.main import pyTrainer -os.environ['MOZILLA_FIVE_HOME']=commands.getstatusoutput("find /usr/li* -name xulrunner -exec dirname {} \; 2>/dev/null")[1] +#Determine xulrunner location +xulrunners = glob.glob("/usr/li*/xulrunner*/xulrunner") +if len(xulrunners) == 0: + #Didnt find any - fall back to old approach + xul_env = commands.getstatusoutput("find /usr/li* -name xulrunner -exec dirname {} \; 2>/dev/null")[1] +elif len(xulrunners) == 1: + #Found just one location - use that + xul_env = os.path.dirname(xulrunners[0]) +else: + #Found more than one - need to choose one... + max_version = None + for item in xulrunners: + max_version = _max(max_version, item) + xul_env = max_version +print "Using xulrunner dir: %s" % xul_env +os.environ['MOZILLA_FIVE_HOME']=xul_env + def main(argv): - pytrainer = pyTrainer(None, data_path) + pytrainer = pyTrainer(None, data_path) if __name__ == "__main__": main(sys.argv[1:]) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-09-29 21:57:45 UTC (rev 630) +++ pytrainer/trunk/pytrainer/main.py 2010-09-30 00:14:04 UTC (rev 631) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#630" + self.version ="1.7.2_svn#631" self.DB_version = 3 #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-09-30 03:29:03
|
Revision: 634 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=634&view=rev Author: jblance Date: 2010-09-30 03:28:54 +0000 (Thu, 30 Sep 2010) Log Message: ----------- Updates to wordpress extension - removed separate googlemaps Modified Paths: -------------- pytrainer/trunk/extensions/wordpress/wordpress.py pytrainer/trunk/pytrainer/extensions/googlemaps.py pytrainer/trunk/pytrainer/main.py Removed Paths: ------------- pytrainer/trunk/extensions/wordpress/googlemaps.py Deleted: pytrainer/trunk/extensions/wordpress/googlemaps.py =================================================================== --- pytrainer/trunk/extensions/wordpress/googlemaps.py 2010-09-30 01:32:14 UTC (rev 633) +++ pytrainer/trunk/extensions/wordpress/googlemaps.py 2010-09-30 03:28:54 UTC (rev 634) @@ -1,98 +0,0 @@ -# -*- coding: iso-8859-1 -*- - -#Copyright (C) Fiz Vazquez vu...@si... - -#This program is free software; you can redistribute it and/or -#modify it under the terms of the GNU General Public License -#as published by the Free Software Foundation; either version 2 -#of the License, or (at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program; if not, write to the Free Software -#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -import os -import re -import sys -import fileinput -import shutil - -import pytrainer.lib.points as Points -from pytrainer.lib.gpx import Gpx -from pytrainer.lib.fileUtils import fileUtils - - -def drawMap(gpxfile,key,htmlpath): - #Not sure why need to process gpx file - cachefile = "/tmp/gpx.txt" - #trackdistance = 100 - #os.system("gpsbabel -t -i gpx -f %s -x position,distance=%sm -o gpx -F %s" %(gpxfile,trackdistance,cachefile)) - shutil.copy2(gpxfile, cachefile) - - # Test if file already contains gpxdata attribute - found = False - for line in fileinput.FileInput(cachefile,inplace=1): - if "xmlns:gpxdata" in line: - found = True - print line.rstrip('\n'); - # If file don't has gpxdata attribute: add namespace - if not found: - for line in fileinput.FileInput(cachefile,inplace=1): - if "xmlns:xsi" in line: - line=line.replace('xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"','xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gpxdata="http://www.cluetrust.com/XML/GPXDATA/1/0"') - print line.rstrip('\n'); - gpx = Gpx("",cachefile) - list_values = gpx.getTrackList() - pointlist = [] - for i in list_values: - pointlist.append((i[4],i[5])) - points,levels = Points.encodePoints(pointlist) - points = points.replace("\\","\\\\") - - createHtml(points,levels,pointlist[0],htmlpath,key) - -def createHtml(points,levels,init_point,htmlpath,key): - content = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n" - content += " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" - content += " <html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:v=\"urn:schemas-microsoft-com:vml\">\n" - content += " <head>\n" - content += " <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/>\n" - content += " <title>Google Maps JavaScript API Example</title>\n" - content += " <script id=\"googleapiimport\" src=\"http://maps.google.com/maps?file=api&v=2&key=%s\"\n" %key - content += " type=\"text/javascript\"></script>\n" - content += " <script type=\"text/javascript\">\n" - content += " //<![CDATA[\n" - content += " function load() {\n" - content += " if (GBrowserIsCompatible()) {\n" - content += " var map = new GMap2(document.getElementById(\"map\"));\n" - content += " map.addControl(new GLargeMapControl());\n" - content += " map.addControl(new GMapTypeControl());\n" - content += " map.setCenter(new GLatLng(%s,%s), 11);\n" %(init_point[0],init_point[1]) - content += " // Add an encoded polyline.\n" - content += " var encodedPolyline = new GPolyline.fromEncoded({\n" - content += " color: \"#3333cc\",\n" - content += " weight: 10,\n" - content += " points: \"%s\",\n" %points - content += " levels: \"%s\",\n" %levels - content += " zoomFactor: 32,\n" - content += " numLevels: 4\n" - content += " });\n" - content += " map.addOverlay(encodedPolyline);\n" - content += " }\n" - content += " }\n " - content += " //]]>\n" - content += " </script>\n" - content += " </head>\n" - content += " <body onload=\"load()\" onunload=\"GUnload()\">\n" - content += " <div id=\"map\" style=\"width: 460px; height: 460px\"></div>\n" - content += " </body>\n" - content += "</html>\n" - file = fileUtils(htmlpath,content) - file.run() - - Modified: pytrainer/trunk/extensions/wordpress/wordpress.py =================================================================== --- pytrainer/trunk/extensions/wordpress/wordpress.py 2010-09-30 01:32:14 UTC (rev 633) +++ pytrainer/trunk/extensions/wordpress/wordpress.py 2010-09-30 03:28:54 UTC (rev 634) @@ -24,59 +24,64 @@ import gtk import httplib2 -import wordpresslib #TODO remove need for this library -import googlemaps #TODO remove this separate googlemaps class +import wordpresslib #TODO remove need for this library +from pytrainer.extensions.googlemaps import Googlemaps import pytrainer.lib.points as Points from pytrainer.lib.date import Date class wordpress: - def __init__(self, parent = None, pytrainer_main = None, conf_dir = None, options = None): - #TODO could use some logging - self.parent = parent - self.pytrainer_main = pytrainer_main - self.options = options - self.conf_dir = conf_dir + def __init__(self, parent = None, pytrainer_main = None, conf_dir = None, options = None): + #TODO could use some logging + self.parent = parent + self.pytrainer_main = pytrainer_main + self.options = options + self.conf_dir = conf_dir + self.tmpdir = self.pytrainer_main.profile.tmpdir + self.data_path = self.pytrainer_main.profile.data_path + self.googlemaps = Googlemaps(data_path=self.data_path, pytrainer_main=pytrainer_main) + self.wp = None - def run(self, id, activity=None): - #Show user something is happening - msg = _("Posting to Wordpress blog") - md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, msg) - md.set_title(_("Wordpress Extension Processing")) - md.set_modal(True) - md.show() - while gtk.events_pending(): # This allows the GUI to update - gtk.main_iteration() # before completion of this entire action - logging.debug("before request posting") - options = self.options - self.wordpressurl = options["wordpressurl"] - self.user = options["wordpressuser"] - self.password = options["wordpresspass"] - self.gpxfile = "%s/gpx/%s.gpx" %(self.conf_dir,id) - self.googlekey = options["googlekey"] - self.idrecord = id - self.activity = activity - self.wordpresscategory = options["wordpresscategory"] - debug_msg = "%s, %s, %s, %s, %s, %s" % (self.wordpressurl, self.user, self.gpxfile, self.googlekey, self.idrecord, self.wordpresscategory) - logging.debug(debug_msg) - try: - self.wp = wordpresslib.WordPressClient(self.wordpressurl, self.user, self.password) #TODO remove need for wordpresslib?? - self.error = False - except: - self.error = True - self.log = "Url, user or pass are incorrect. Please, check your configuration" - self.loadRecordInfo() - if self.title is None: - self.title = "No Title" - blog_table = self.createTable() - blog_route = self.createRoute() - blog_body = self.createBody() + def run(self, id, activity=None): + #Show user something is happening + msg = _("Posting to Wordpress blog") + md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, msg) + md.set_title(_("Wordpress Extension Processing")) + md.set_modal(True) + md.show() + while gtk.events_pending(): # This allows the GUI to update + gtk.main_iteration() # before completion of this entire action + logging.debug("before request posting") + options = self.options + self.wordpressurl = options["wordpressurl"] + self.user = options["wordpressuser"] + self.password = options["wordpresspass"] + self.gpxfile = "%s/gpx/%s.gpx" %(self.conf_dir,id) + self.googlekey = options["googlekey"] + self.idrecord = id + self.activity = activity + self.wordpresscategory = options["wordpresscategory"] + debug_msg = "%s, %s, %s, %s, %s, %s" % (self.wordpressurl, self.user, self.gpxfile, self.googlekey, self.idrecord, self.wordpresscategory) + logging.debug(debug_msg) + try: + self.wp = wordpresslib.WordPressClient(self.wordpressurl, self.user, self.password) #TODO remove need for wordpresslib?? + self.error = False + except Exception as e: + print e + self.error = True + self.log = "Url, user or pass are incorrect. Please, check your configuration" + self.loadRecordInfo() + if self.title is None or self.title == "": + self.title = "Untitled Activity" + blog_table = self.createTable() + blog_route = self.createRoute() + blog_body = self.createBody() - blog_figureHR = self.createFigureHR() - blog_figureStage = self.createFigureStage() - blog_foot = self.createFoot() + blog_figureHR = self.createFigureHR() + blog_figureStage = self.createFigureStage() + blog_foot = self.createFoot() - self.description = "<![CDATA["+blog_body+blog_table+blog_route+blog_figureHR+blog_figureStage+blog_foot+"]]>" - xmlstuff = '''<methodCall> + self.description = "<![CDATA["+blog_body+blog_table+blog_route+blog_figureHR+blog_figureStage+blog_foot+"]]>" + xmlstuff = '''<methodCall> <methodName>metaWeblog.newPost</methodName> <params> <param> @@ -123,153 +128,156 @@ </methodCall> ''' % (self.user, self.password, self.wordpresscategory, self.description, self.title) - #POST request to Wordpress blog - h = httplib2.Http() - res, content = h.request(self.wordpressurl, 'POST', body=xmlstuff) - logging.debug("after request posting") - logging.debug("Got response status: %s, reason: %s, content: %s" % (res.status, res.reason, content)) - if res.reason == 'OK': - res_msg = "Successfully posted to Wordpress." - else: - res_msg = "Some error occured\nGot a status %s, reason %s\nContent was: %s" % (res.status, res.reason, content) - #Close 'Please wait' dialog - md.destroy() - #Show the user the result - md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, res_msg) - md.set_title(_("Wordpress Extension Upload Complete")) - md.set_modal(False) - md.run() - md.destroy() + #POST request to Wordpress blog + h = httplib2.Http() + res, content = h.request(self.wordpressurl, 'POST', body=xmlstuff) + logging.debug("after request posting") + logging.debug("Got response status: %s, reason: %s, content: %s" % (res.status, res.reason, content)) + if res.reason == 'OK': + res_msg = "Successfully posted to Wordpress." + else: + res_msg = "Some error occured\nGot a status %s, reason %s\nContent was: %s" % (res.status, res.reason, content) + #Close 'Please wait' dialog + md.destroy() + #Show the user the result + md = gtk.MessageDialog(self.pytrainer_main.windowmain.window1, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, res_msg) + md.set_title(_("Wordpress Extension Upload Complete")) + md.set_modal(False) + md.run() + md.destroy() - def createRoute(self): - gpxpath = "/tmp/gpstrace.gpx.txt" - htmlpath = "/tmp/index.html" #TODO fix to use correct tmp dir - kmlpath = "/tmp/gps.kml.txt" #TODO fix to use correct tmp dir - description_route = '' - if os.path.isfile(self.gpxfile): - #copy gpx file to new name - shutil.copy(self.gpxfile, gpxpath) - #create the html file - googlemaps.drawMap(self.gpxfile,self.googlekey,htmlpath) #TODO fix to use main googlemaps and remove extensions copy - #create the kml file - os.system("gpsbabel -t -i gpx -f %s -o kml,points=0,line_color=ff0000ff -F %s" %(self.gpxfile,kmlpath)) #TODO fix to remove gpsbabel + def createRoute(self): + gpxpath = "%s/gpstrace.gpx.txt" % self.tmpdir + #htmlpath = "%s/index.html" % self.tmpdir + kmlpath = "%s/gps.kml.txt" % self.tmpdir + description_route = '' + if os.path.isfile(self.gpxfile): + #copy gpx file to new name + shutil.copy(self.gpxfile, gpxpath) + #create the html file + #htmlpath = googlemaps.drawMap(self.gpxfile,self.googlekey,htmlpath) #TODO fix to use main googlemaps and remove extensions copy + htmlpath = self.googlemaps.drawMap(self.activity) + #create the kml file + os.system("gpsbabel -t -i gpx -f %s -o kml,points=0,line_color=ff0000ff -F %s" %(self.gpxfile,kmlpath)) #TODO fix to remove gpsbabel - #gfile = self.wp.newMediaObject(self.gpxfile) - gfile = self.wp.newMediaObject(gpxpath) - hfile = self.wp.newMediaObject(htmlpath) - kfile = self.wp.newMediaObject(kmlpath) + #gfile = self.wp.newMediaObject(self.gpxfile) + gfile = self.wp.newMediaObject(gpxpath) + hfile = self.wp.newMediaObject(htmlpath) + kfile = self.wp.newMediaObject(kmlpath) - description_route = '''<strong>Map: </strong> <br/> - <iframe width='480' height='480' src='%s'> Need frame support </iframe><br/> - <a href='%s'>Gpx-format</a> <a href='%s'>Kml-format (GoogleEarth)</a><br/><br/>''' %(hfile,gfile,kfile) - return description_route + description_route = '''<strong>Map: </strong> <br/> + <iframe width='480' height='480' src='%s'> Need frame support </iframe><br/> + <a href='%s'>Gpx-format</a> <a href='%s'>Kml-format (GoogleEarth)</a><br/><br/>''' %(hfile,gfile,kfile) + return description_route - def loadRecordInfo(self): - #date = Date() - #record = self.pytrainer_main.record.getrecordInfo(self.idrecord)[0] - #"sports.name,date,distance,time,beats,comments,average,calories,id_record,title,upositive,unegative,maxspeed,maxpace,pace,maxbeats,date_time_utc,date_time_local", - self.sport = self.activity.sport_name - self.date = self.activity.date - self.distance = self.activity.distance - self.time = "%d:%02d:%02d" % (self.activity.time_tuple) - print self.time - self.beats = self.activity.beats - self.comments = self.activity.comments - self.average = self.activity.average - self.calories = self.activity.calories - self.title = self.activity.title - self.upositive = self.activity.upositive - self.unegative = self.activity.unegative - self.maxspeed = self.activity.maxspeed - self.maxpace = self.activity.maxpace - self.pace = self.activity.pace - self.maxbeats = self.activity.maxbeats - self.distance_unit = self.activity.distance_unit - self.speed_unit = self.activity.speed_unit - self.pace_unit = self.activity.pace_unit - self.height_unit = self.activity.height_unit + def loadRecordInfo(self): + #date = Date() + #record = self.pytrainer_main.record.getrecordInfo(self.idrecord)[0] + #"sports.name,date,distance,time,beats,comments,average,calories,id_record,title,upositive,unegative,maxspeed,maxpace,pace,maxbeats,date_time_utc,date_time_local", + self.sport = self.activity.sport_name + self.date = self.activity.date + self.distance = self.activity.distance + self.time = "%d:%02d:%02d" % (self.activity.time_tuple) + self.beats = self.activity.beats + self.comments = self.activity.comments + self.average = self.activity.average + self.calories = self.activity.calories + self.title = self.activity.title + self.upositive = self.activity.upositive + self.unegative = self.activity.unegative + self.maxspeed = self.activity.maxspeed + self.maxpace = self.activity.maxpace + self.pace = self.activity.pace + self.maxbeats = self.activity.maxbeats + self.distance_unit = self.activity.distance_unit + self.speed_unit = self.activity.speed_unit + self.pace_unit = self.activity.pace_unit + self.height_unit = self.activity.height_unit - def createBody(self): - return '''<b> Description: </b><br/>%s<br/>''' %self.activity.comments + def createBody(self): + if self.comments is None or self.comments == "": + return "" + else: + return '''<b> Description: </b><br/>%s<br/>''' %self.comments - def createTable(self): - description_table = ''' - <br/> - <table border=0> - <tr> - <td><strong>Activity:</strong></td> - <td>%s</td> - <td><strong>Date:</strong></td> - <td>%s</td> - </tr> - <tr> - <td><strong>Distance (%s):</strong></td> - <td>%.2f</td> - <td><strong>Time (hh:mm:ss):</strong></td> - <td>%s</td> - </tr> - <tr> - <td><strong>Max speed (%s):</strong></td> - <td>%.2f</td> - <td><strong>Avg speed (%s):</strong></td> - <td>%.2f</td> - </tr> - <tr> - <td><strong>Max pace (%s):</strong></td> - <td>%.2f</td> - <td><strong>Avg pace (%s):</strong></td> - <td>%.2f</td> - </tr> - <tr> - <td><strong>Max pulse:</strong></td> - <td>%s</td> - <td><strong>Avg pulse:</strong></td> - <td>%s</td> - </tr> - <tr> - <td><strong>Acc elevation (+%s):</strong></td> - <td>%.2f</td> - <td><strong>Acc elevation (-%s):</strong></td> - <td>%.2f</td> - </tr> - </table> - ''' %( self.sport, self.date, self.distance_unit, self.distance, self.time, self.speed_unit, self.maxspeed, - self.speed_unit, self.average, self.pace_unit, self.maxpace,self.pace_unit, self.pace, - self.maxbeats, self.beats, self.height_unit, self.upositive, self.height_unit, self.unegative) - return description_table + def createTable(self): + description_table = ''' + <br/> + <table border=0> + <tr> + <td><strong>Activity:</strong></td> + <td>%s</td> + <td><strong>Date:</strong></td> + <td>%s</td> + </tr> + <tr> + <td><strong>Distance (%s):</strong></td> + <td>%.2f</td> + <td><strong>Time (hh:mm:ss):</strong></td> + <td>%s</td> + </tr> + <tr> + <td><strong>Max speed (%s):</strong></td> + <td>%.2f</td> + <td><strong>Avg speed (%s):</strong></td> + <td>%.2f</td> + </tr> + <tr> + <td><strong>Max pace (%s):</strong></td> + <td>%.2f</td> + <td><strong>Avg pace (%s):</strong></td> + <td>%.2f</td> + </tr> + <tr> + <td><strong>Max pulse:</strong></td> + <td>%s</td> + <td><strong>Avg pulse:</strong></td> + <td>%s</td> + </tr> + <tr> + <td><strong>Acc elevation (+%s):</strong></td> + <td>%.2f</td> + <td><strong>Acc elevation (-%s):</strong></td> + <td>%.2f</td> + </tr> + </table> + ''' %( self.sport, self.date, self.distance_unit, self.distance, self.time, self.speed_unit, self.maxspeed, + self.speed_unit, self.average, self.pace_unit, self.maxpace,self.pace_unit, self.pace, + self.maxbeats, self.beats, self.height_unit, self.upositive, self.height_unit, self.unegative) + return description_table - def createFigureHR(self): - hr_fig_path = "/tmp/hr.png" #TODO fix, correct tmp dir and ensure png exists - blog_figures = '' - # If there are no graphs, return empty string. - if os.path.isfile(hr_fig_path): - #the graph files are created because the graph tabs are automatically visited (which invokes graph generation) - hrfile = self.wp.newMediaObject(hr_fig_path) - blog_figures = '''<br/> <img src='%s' /> ''' %hrfile - return blog_figures + def createFigureHR(self): + hr_fig_path = "%s/hr.png" % self.tmpdir #TODO ensure png exists + blog_figures = '' + # If there are no graphs, return empty string. + if os.path.isfile(hr_fig_path): + #the graph files are created because the graph tabs are automatically visited (which invokes graph generation) + hrfile = self.wp.newMediaObject(hr_fig_path) + blog_figures = '''<br/> <img src='%s' /> ''' %hrfile + return blog_figures - def createFigureStage(self): - stage_fig_path = "/tmp/stage.png" #TODO fix, correct tmp dir and ensure png exists - blog_figures = '' - # If there are no graphs, return empty string. - if os.path.isfile(stage_fig_path): - #the graph files are created because the graph tabs are automatically visited (which invokes graph generation) - stagefile = self.wp.newMediaObject(stage_fig_path) - blog_figures = '''<br/> <img src='%s' /> ''' %stagefile - return blog_figures + def createFigureStage(self): + stage_fig_path = "/tmp/stage.png" #TODO fix, correct tmp dir and ensure png exists + blog_figures = '' + # If there are no graphs, return empty string. + if os.path.isfile(stage_fig_path): + #the graph files are created because the graph tabs are automatically visited (which invokes graph generation) + stagefile = self.wp.newMediaObject(stage_fig_path) + blog_figures = '''<br/> <img src='%s' /> ''' %stagefile + return blog_figures - def createFoot(self): - return ''' <br/><center>Powered by <a href='http://sourceforge.net/projects/pytrainer/'>Pytrainer</a></center>''' + def createFoot(self): + return ''' <br/><center>Powered by <a href='http://sourceforge.net/projects/pytrainer/'>Pytrainer</a></center>''' - def createTitle(self): - if self.title==None: - self.error = True - self.log = "A Title must be defined. Please, configure the record properly" - return self.title + def createTitle(self): + if self.title==None: + self.error = True + self.log = "A Title must be defined. Please, configure the record properly" + return self.title - def createCategory(self): - if self.wordpresscategory==None: - self.error = True - self.log = "A wordpress category must be defined. Please, configure the wordpress extension" - else: - return ([self.wordpresscategory]) + def createCategory(self): + if self.wordpresscategory==None: + self.error = True + self.log = "A wordpress category must be defined. Please, configure the wordpress extension" + else: + return ([self.wordpresscategory]) Modified: pytrainer/trunk/pytrainer/extensions/googlemaps.py =================================================================== --- pytrainer/trunk/pytrainer/extensions/googlemaps.py 2010-09-30 01:32:14 UTC (rev 633) +++ pytrainer/trunk/pytrainer/extensions/googlemaps.py 2010-09-30 03:28:54 UTC (rev 634) @@ -27,310 +27,314 @@ #from pytrainer.record import Record class Googlemaps: - def __init__(self, data_path = None, waypoint = None, pytrainer_main=None): - logging.debug(">>") - self.data_path = data_path - self.waypoint=waypoint - self.pytrainer_main = pytrainer_main - self.htmlfile = "%s/googlemaps.html" % (self.pytrainer_main.profile.tmpdir) - logging.debug("<<") + def __init__(self, data_path = None, waypoint = None, pytrainer_main=None): + logging.debug(">>") + self.data_path = data_path + self.waypoint=waypoint + self.pytrainer_main = pytrainer_main + self.htmlfile = "%s/googlemaps.html" % (self.pytrainer_main.profile.tmpdir) + logging.debug("<<") - def drawMap(self,activity): - '''Draw google map - create html file using Google API version?? - render using embedded Mozilla + def drawMap(self,activity): + '''Draw google map + create html file using Google API version?? + render using embedded Mozilla - info at http://www.pygtk.org/pygtkmozembed/class-gtkmozembed.html - ''' - logging.debug(">>") - points = [] - levels = [] - pointlist = [] - polyline = [] + info at http://www.pygtk.org/pygtkmozembed/class-gtkmozembed.html + ''' + logging.debug(">>") + points = [] + levels = [] + pointlist = [] + polyline = [] - list_values = activity.tracks - if list_values is not None and list_values != [] and len(list_values) > 0: - minlat, minlon = float(list_values[0][4]),float(list_values[0][5]) - maxlat=minlat - maxlon=minlon - for i in list_values: - lat, lon = float(i[4]), float(i[5]) - minlat = min(minlat, lat) - maxlat = max(maxlat, lat) - minlon = min(minlon, lon) - maxlon = max(maxlon, lon) - pointlist.append((lat,lon)) - polyline.append("new google.maps.LatLng(%s, %s)" % (lat, lon)) - logging.debug("minlat: %s, maxlat: %s" % (minlat, maxlat)) - logging.debug("minlon: %s, maxlon: %s" % (minlon, maxlon)) - points,levels = Points.encodePoints(pointlist) - points = points.replace("\\","\\\\") - if self.pytrainer_main.startup_options.gm3: - logging.debug("Using Google Maps version 3 API") - laps = activity.laps - timeHours = int(activity.time) / 3600 - timeMin = (float(activity.time) / 3600.0 - timeHours) * 60 - time = "%d%s %02d%s" % (timeHours, _("h"), timeMin, _("min")) - startinfo = "<div class='info_content'>%s: %s</div>" % (activity.sport_name, activity.title) - finishinfo = "<div class='info_content'>%s: %s<br>%s: %s%s</div>" % (_("Time"), time, _("Distance"), activity.distance, activity.distance_unit) - startinfo = startinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html - finishinfo = finishinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html - self.createHtml_api3(polyline, minlat, minlon, maxlat, maxlon, startinfo, finishinfo, laps) - else: - logging.debug("Using Google Maps version 2 API") - self.createHtml(points,levels,pointlist[0]) - else: - self.createErrorHtml() - return self.htmlfile - logging.debug("<<") + list_values = activity.tracks + if list_values is not None and list_values != [] and len(list_values) > 0: + minlat, minlon = float(list_values[0][4]),float(list_values[0][5]) + maxlat=minlat + maxlon=minlon + for i in list_values: + lat, lon = float(i[4]), float(i[5]) + minlat = min(minlat, lat) + maxlat = max(maxlat, lat) + minlon = min(minlon, lon) + maxlon = max(maxlon, lon) + pointlist.append((lat,lon)) + polyline.append("new google.maps.LatLng(%s, %s)" % (lat, lon)) + logging.debug("minlat: %s, maxlat: %s" % (minlat, maxlat)) + logging.debug("minlon: %s, maxlon: %s" % (minlon, maxlon)) + points,levels = Points.encodePoints(pointlist) + points = points.replace("\\","\\\\") + if self.pytrainer_main.startup_options.gm3: + logging.debug("Using Google Maps version 3 API") + laps = activity.laps + timeHours = int(activity.time) / 3600 + timeMin = (float(activity.time) / 3600.0 - timeHours) * 60 + time = "%d%s %02d%s" % (timeHours, _("h"), timeMin, _("min")) + startinfo = "<div class='info_content'>%s: %s</div>" % (activity.sport_name, activity.title) + finishinfo = "<div class='info_content'>%s: %s<br>%s: %s%s</div>" % (_("Time"), time, _("Distance"), activity.distance, activity.distance_unit) + startinfo = startinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html + finishinfo = finishinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html + self.createHtml_api3(polyline, minlat, minlon, maxlat, maxlon, startinfo, finishinfo, laps) + else: + logging.debug("Using Google Maps version 2 API") + self.createHtml(points,levels,pointlist[0]) + else: + self.createErrorHtml() + return self.htmlfile + logging.debug("<<") - def createHtml_api3(self,polyline, minlat, minlon, maxlat, maxlon, startinfo, finishinfo, laps): - ''' - Generate a Google maps html file using the v3 api - documentation at http://code.google.com/apis/maps/documentation/v3 - ''' - logging.debug(">>") - waypoints = self.waypoint.getAllWaypoints() - #TODO waypoints not supported in this function yet - #TODO sort polyline encoding (not supported in v3?) - #TODO check http://code.google.com/apis/maps/documentation/v3/overlays.html#Polylines for MVArray?? - content = ''' - <html> - <head> - <style type="text/css"> - div.info_content { font-family: sans-serif; font-size: 10px; } - </style> - <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> - <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> - <script type="text/javascript"> - function initialize() {\n''' - content += " var startlatlng = %s ;\n" % (polyline[0]) - content += " var centerlatlng = new google.maps.LatLng(%f, %f);\n" % ((minlat+maxlat)/2., (minlon+maxlon)/2.) - content += " var endlatlng = %s;\n" % (polyline[-1]) - content += " var swlatlng = new google.maps.LatLng(%f, %f);\n" % (minlat,minlon) - content += " var nelatlng = new google.maps.LatLng(%f, %f);\n" % (maxlat,maxlon) - content += " var startcontent = \"%s\";\n" % (startinfo) - content += " var finishcontent = \"%s\";\n" % (finishinfo) - content += " var startimageloc = \"%s/glade/start.png\";\n" % (os.path.abspath(self.data_path)) - content += " var finishimageloc = \"%s/glade/finish.png\";\n" % (os.path.abspath(self.data_path)) - content += " var lapimageloc = \"%s/glade/waypoint.png\";\n" % (os.path.abspath(self.data_path)) - content +=''' - var myOptions = { - zoom: 8, - center: centerlatlng, - scaleControl: true, - mapTypeId: google.maps.MapTypeId.ROADMAP - }; + def createHtml_api3(self,polyline, minlat, minlon, maxlat, maxlon, startinfo, finishinfo, laps): + ''' + Generate a Google maps html file using the v3 api + documentation at http://code.google.com/apis/maps/documentation/v3 + ''' + logging.debug(">>") + if self.waypoint is not None: + waypoints = self.waypoint.getAllWaypoints() + #TODO waypoints not supported in this function yet + #TODO sort polyline encoding (not supported in v3?) + #TODO check http://code.google.com/apis/maps/documentation/v3/overlays.html#Polylines for MVArray?? + content = ''' + <html> + <head> + <style type="text/css"> + div.info_content { font-family: sans-serif; font-size: 10px; } + </style> + <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> + <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> + <script type="text/javascript"> + function initialize() {\n''' + content += " var startlatlng = %s ;\n" % (polyline[0]) + content += " var centerlatlng = new google.maps.LatLng(%f, %f);\n" % ((minlat+maxlat)/2., (minlon+maxlon)/2.) + content += " var endlatlng = %s;\n" % (polyline[-1]) + content += " var swlatlng = new google.maps.LatLng(%f, %f);\n" % (minlat,minlon) + content += " var nelatlng = new google.maps.LatLng(%f, %f);\n" % (maxlat,maxlon) + content += " var startcontent = \"%s\";\n" % (startinfo) + content += " var finishcontent = \"%s\";\n" % (finishinfo) + content += " var startimageloc = \"%s/glade/start.png\";\n" % (os.path.abspath(self.data_path)) + content += " var finishimageloc = \"%s/glade/finish.png\";\n" % (os.path.abspath(self.data_path)) + content += " var lapimageloc = \"%s/glade/waypoint.png\";\n" % (os.path.abspath(self.data_path)) + content +=''' + var myOptions = { + zoom: 8, + center: centerlatlng, + scaleControl: true, + mapTypeId: google.maps.MapTypeId.ROADMAP + }; - var startimage = new google.maps.MarkerImage(startimageloc,\n - // This marker is 32 pixels wide by 32 pixels tall. - new google.maps.Size(32, 32), - // The origin for this image is 0,0. - new google.maps.Point(0,0), - // The anchor for this image is the base of the flagpole - new google.maps.Point(16, 32));\n\n - var finishimage = new google.maps.MarkerImage(finishimageloc,\n - // This marker is 32 pixels wide by 32 pixels tall. - new google.maps.Size(32, 32), - // The origin for this image is 0,0. - new google.maps.Point(0,0), - // The anchor for this image is the base of the flagpole - new google.maps.Point(16, 32));\n + var startimage = new google.maps.MarkerImage(startimageloc,\n + // This marker is 32 pixels wide by 32 pixels tall. + new google.maps.Size(32, 32), + // The origin for this image is 0,0. + new google.maps.Point(0,0), + // The anchor for this image is the base of the flagpole + new google.maps.Point(16, 32));\n\n + var finishimage = new google.maps.MarkerImage(finishimageloc,\n + // This marker is 32 pixels wide by 32 pixels tall. + new google.maps.Size(32, 32), + // The origin for this image is 0,0. + new google.maps.Point(0,0), + // The anchor for this image is the base of the flagpole + new google.maps.Point(16, 32));\n - var lapimage = new google.maps.MarkerImage(lapimageloc,\n - // This marker is 32 pixels wide by 32 pixels tall. - new google.maps.Size(32, 32), - // The origin for this image is 0,0. - new google.maps.Point(0,0), - // The anchor for this image is the base of the flagpole - new google.maps.Point(16, 32));\n + var lapimage = new google.maps.MarkerImage(lapimageloc,\n + // This marker is 32 pixels wide by 32 pixels tall. + new google.maps.Size(32, 32), + // The origin for this image is 0,0. + new google.maps.Point(0,0), + // The anchor for this image is the base of the flagpole + new google.maps.Point(16, 32));\n - var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); - var startmarker = new google.maps.Marker({ - position: startlatlng, - map: map, - icon: startimage, - title:"Start"}); + var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); + var startmarker = new google.maps.Marker({ + position: startlatlng, + map: map, + icon: startimage, + title:"Start"}); - var finishmarker = new google.maps.Marker({ - position: endlatlng, - icon: finishimage, - map: map, - title:"End"}); \n + var finishmarker = new google.maps.Marker({ + position: endlatlng, + icon: finishimage, + map: map, + title:"End"}); \n - //Add an infowindows - var startinfo = new google.maps.InfoWindow({ - content: startcontent - }); + //Add an infowindows + var startinfo = new google.maps.InfoWindow({ + content: startcontent + }); - var finishinfo = new google.maps.InfoWindow({ - content: finishcontent - }); + var finishinfo = new google.maps.InfoWindow({ + content: finishcontent + }); - google.maps.event.addListener(startmarker, 'click', function() { - startinfo.open(map,startmarker); - }); + google.maps.event.addListener(startmarker, 'click', function() { + startinfo.open(map,startmarker); + }); - google.maps.event.addListener(finishmarker, 'click', function() { - finishinfo.open(map,finishmarker); - });\n''' + google.maps.event.addListener(finishmarker, 'click', function() { + finishinfo.open(map,finishmarker); + });\n''' - #"id_lap, record, elapsed_time, distance, start_lat, start_lon, end_lat, end_lon, calories, lap_number", - for lap in laps: - lapNumber = int(lap['lap_number'])+1 - elapsedTime = float(lap['elapsed_time']) - elapsedTimeHours = int(elapsedTime/3600) - elapsedTimeMins = int((elapsedTime - (elapsedTimeHours * 3600)) / 60) - elapsedTimeSecs = elapsedTime - (elapsedTimeHours * 3600) - (elapsedTimeMins * 60) - if elapsedTimeHours > 0: - strElapsedTime = "%0.0dh:%0.2dm:%0.2fs" % (elapsedTimeHours, elapsedTimeMins, elapsedTimeSecs) - elif elapsedTimeMins > 0: - strElapsedTime = "%0.0dm:%0.2fs" % (elapsedTimeMins, elapsedTimeSecs) - else: - strElapsedTime = "%0.0fs" % (elapsedTimeSecs) - #process lat and lon for this lap - try: - lapLat = float(lap['end_lat']) - lapLon = float(lap['end_lon']) - content += "var lap%dmarker = new google.maps.Marker({position: new google.maps.LatLng(%f, %f), icon: lapimage, map: map, title:\"Lap%d\"}); \n " % (lapNumber, lapLat, lapLon, lapNumber) - content += "var lap%d = new google.maps.InfoWindow({content: \"<div class='info_content'>End of lap:%s<br>Elapsed time:%s<br>Distance:%0.2f km<br>Calories:%s</div>\" });\n" % (lapNumber, lapNumber, strElapsedTime, float(lap['distance'])/1000, lap['calories']) - content += "google.maps.event.addListener(lap%dmarker, 'click', function() { lap%d.open(map,lap%dmarker); });\n" % (lapNumber,lapNumber,lapNumber) - except Exception as e: - #Error processing lap lat or lon - #dont show this lap - logging.debug( "Error processing lap "+ str(lap) ) - logging.debug(str(e)) + #"id_lap, record, elapsed_time, distance, start_lat, start_lon, end_lat, end_lon, calories, lap_number", + for lap in laps: + lapNumber = int(lap['lap_number'])+1 + elapsedTime = float(lap['elapsed_time']) + elapsedTimeHours = int(elapsedTime/3600) + elapsedTimeMins = int((elapsedTime - (elapsedTimeHours * 3600)) / 60) + elapsedTimeSecs = elapsedTime - (elapsedTimeHours * 3600) - (elapsedTimeMins * 60) + if elapsedTimeHours > 0: + strElapsedTime = "%0.0dh:%0.2dm:%0.2fs" % (elapsedTimeHours, elapsedTimeMins, elapsedTimeSecs) + elif elapsedTimeMins > 0: + strElapsedTime = "%0.0dm:%0.2fs" % (elapsedTimeMins, elapsedTimeSecs) + else: + strElapsedTime = "%0.0fs" % (elapsedTimeSecs) + #process lat and lon for this lap + try: + lapLat = float(lap['end_lat']) + lapLon = float(lap['end_lon']) + content += "var lap%dmarker = new google.maps.Marker({position: new google.maps.LatLng(%f, %f), icon: lapimage, map: map, title:\"Lap%d\"}); \n " % (lapNumber, lapLat, lapLon, lapNumber) + content += "var lap%d = new google.maps.InfoWindow({content: \"<div class='info_content'>End of lap:%s<br>Elapsed time:%s<br>Distance:%0.2f km<br>Calories:%s</div>\" });\n" % (lapNumber, lapNumber, strElapsedTime, float(lap['distance'])/1000, lap['calories']) + content += "google.maps.event.addListener(lap%dmarker, 'click', function() { lap%d.open(map,lap%dmarker); });\n" % (lapNumber,lapNumber,lapNumber) + except Exception as e: + #Error processing lap lat or lon + #dont show this lap + logging.debug( "Error processing lap "+ str(lap) ) + logging.debug(str(e)) - content += ''' + content += ''' - var boundsBox = new google.maps.LatLngBounds(swlatlng, nelatlng );\n - map.fitBounds(boundsBox);\n - var polylineCoordinates = [\n''' - for point in polyline: - content += " %s,\n" % (point) - content += ''' ];\n - // Add a polyline.\n - var polyline = new google.maps.Polyline({\n - path: polylineCoordinates,\n - strokeColor: \"#3333cc\",\n - strokeOpacity: 0.6,\n - strokeWeight: 5,\n - });\n - polyline.setMap(map);\n - } + var boundsBox = new google.maps.LatLngBounds(swlatlng, nelatlng );\n + map.fitBounds(boundsBox);\n + var polylineCoordinates = [\n''' + for point in polyline: + content += " %s,\n" % (point) + content += ''' ];\n + // Add a polyline.\n + var polyline = new google.maps.Polyline({\n + path: polylineCoordinates,\n + strokeColor: \"#3333cc\",\n + strokeOpacity: 0.6,\n + strokeWeight: 5,\n + });\n + polyline.setMap(map);\n + } - </script> - </head> - <body onload="initialize()"> - <div id="map_canvas" style="width:100%; height:100%"></div> - </body> - </html>''' - file = fileUtils(self.htmlfile,content) - file.run() - logging.debug("<<") + </script> + </head> + <body onload="initialize()"> + <div id="map_canvas" style="width:100%; height:100%"></div> + </body> + </html>''' + file = fileUtils(self.htmlfile,content) + file.run() + logging.debug("<<") - def createHtml(self,points,levels,init_point): - logging.debug(">>") - waypoints = self.waypoint.getAllWaypoints() - content = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n" - content += " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" - content += " <html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:v=\"urn:schemas-microsoft-com:vml\">\n" - content += " <head>\n" - content += " <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/>\n" - content += " <title>Google Maps JavaScript API Example</title>\n" - content += " <script id=\"googleapiimport\" src=\"http://maps.google.com/maps?file=api&v=2\"\n" - content += " type=\"text/javascript\"></script>\n" - content += " <script type=\"text/javascript\">\n" - content += " //<![CDATA[\n" - i = 0 - arrayjs = "" - for point in waypoints: - content += "lon = '%f';\n"%point[2] - content += "lat = '%f';\n"%point[1] - content += "name = '%s';\n"%point[6] - content += "description = '%s';\n"%point[4] - content += "sym = '%s';\n"%point[7] - content += "id = '%d';\n"%point[0] - content += """waypoint%d = Array (lon,lat,name,description,sym,id);\n"""%i - if i>0: - arrayjs+="," - arrayjs +="waypoint%d"%i - i = i+1 - content += """waypointList = Array (%s);\n""" %arrayjs - content += """ - function createMarker(waypoint,map) { - var lon = waypoint[0]; - var lat = waypoint[1]; - var id = waypoint[5]; - var name = waypoint[2]; - var description = waypoint[3]; + def createHtml(self,points,levels,init_point): + logging.debug(">>") + if self.waypoint is not None: + waypoints = self.waypoint.getAllWaypoints() + else: + waypoints = [] + content = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n" + content += " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" + content += " <html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:v=\"urn:schemas-microsoft-com:vml\">\n" + content += " <head>\n" + content += " <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/>\n" + content += " <title>Google Maps JavaScript API Example</title>\n" + content += " <script id=\"googleapiimport\" src=\"http://maps.google.com/maps?file=api&v=2\"\n" + content += " type=\"text/javascript\"></script>\n" + content += " <script type=\"text/javascript\">\n" + content += " //<![CDATA[\n" + i = 0 + arrayjs = "" + for point in waypoints: + content += "lon = '%f';\n"%point[2] + content += "lat = '%f';\n"%point[1] + content += "name = '%s';\n"%point[6] + content += "description = '%s';\n"%point[4] + content += "sym = '%s';\n"%point[7] + content += "id = '%d';\n"%point[0] + content += """waypoint%d = Array (lon,lat,name,description,sym,id);\n"""%i + if i>0: + arrayjs+="," + arrayjs +="waypoint%d"%i + i = i+1 + content += """waypointList = Array (%s);\n""" %arrayjs + content += """ + function createMarker(waypoint,map) { + var lon = waypoint[0]; + var lat = waypoint[1]; + var id = waypoint[5]; + var name = waypoint[2]; + var description = waypoint[3]; - var point = new GLatLng(lat,lon); - var text = "<b>"+waypoint[2]+"</b><br/>"+waypoint[3]; + var point = new GLatLng(lat,lon); + var text = "<b>"+waypoint[2]+"</b><br/>"+waypoint[3]; - var icon = new GIcon(); - if (sym=="Summit") { - icon.image = \""""+os.path.abspath(self.data_path)+"""/glade/summit.png\"; - } - else { - icon.image = \""""+os.path.abspath(self.data_path)+"""/glade/waypoint.png\"; - } - icon.iconSize = new GSize(32, 32); - icon.iconAnchor = new GPoint(16, 16); - icon.infoWindowAnchor = new GPoint(5, 1); + var icon = new GIcon(); + if (sym=="Summit") { + icon.image = \""""+os.path.abspath(self.data_path)+"""/glade/summit.png\"; + } + else { + icon.image = \""""+os.path.abspath(self.data_path)+"""/glade/waypoint.png\"; + } + icon.iconSize = new GSize(32, 32); + icon.iconAnchor = new GPoint(16, 16); + icon.infoWindowAnchor = new GPoint(5, 1); - var markerD = new GMarker(point, {icon:icon, draggable: false}); - GEvent.addListener(markerD, "click", function() { - markerD.openInfoWindowHtml("<b>" + name + "</b><br/>"+description); - }); - map.addOverlay(markerD); + var markerD = new GMarker(point, {icon:icon, draggable: false}); + GEvent.addListener(markerD, "click", function() { + markerD.openInfoWindowHtml("<b>" + name + "</b><br/>"+description); + }); + map.addOverlay(markerD); - }""" + }""" - content += " function load() {\n" - content += " if (GBrowserIsCompatible()) {\n" - content += " var map = new GMap2(document.getElementById(\"map\"));\n" - content += " map.addControl(new GLargeMapControl());\n" - content += " map.addControl(new GMapTypeControl());\n" - content += " map.addControl(new GScaleControl());\n" - content += " map.setCenter(new GLatLng(%f,%f), 11);\n" %(float(init_point[0]),float(init_point[1])) - content += " ovMap=new GOverviewMapControl();\n" - content += " map.addControl(ovMap);\n" - content += " mini=ovMap.getOverviewMap();\n" - content += " //Dibujamos los waypoints\n" - content += " for (i=0; i<waypointList.length; i++){\n" - content += " createMarker(waypointList[i],map);\n" - content += " map.enableDragging();\n" - content += " }\n" - content += " document.getElementById('map').style.top='0px';\n" - content += " document.getElementById('map').style.left='0px';\n" - content += " document.getElementById('map').style.width='100%';\n" - content += " // Add an encoded polyline.\n" - content += " var encodedPolyline = new GPolyline.fromEncoded({\n" - content += " color: \"#3333cc\",\n" - content += " weight: 10,\n" - content += " points: \"%s\",\n" %points - content += " levels: \"%s\",\n" %levels - content += " zoomFactor: 32,\n" - content += " numLevels: 4\n" - content += " });\n" - content += " map.addOverlay(encodedPolyline);\n" - content += " }\n" - content += " }\n " - content += " //]]>\n" - content += " </script>\n" - content += " </head>\n" - content += " <body onload=\"load()\" onunload=\"GUnload()\">\n" - content += " <div id=\"map\" style=\"width: 520px; height: 480px\"></div>\n" - content += " </body>\n" - content += "</html>\n" - file = fileUtils(self.htmlfile,content) - file.run() - logging.debug("<<") + content += " function load() {\n" + content += " if (GBrowserIsCompatible()) {\n" + content += " var map = new GMap2(document.getElementById(\"map\"));\n" + content += " map.addControl(new GLargeMapControl());\n" + content += " map.addControl(new GMapTypeControl());\n" + content += " map.addControl(new GScaleControl());\n" + content += " map.setCenter(new GLatLng(%f,%f), 11);\n" %(float(init_point[0]),float(init_point[1])) + content += " ovMap=new GOverviewMapControl();\n" + content += " map.addControl(ovMap);\n" + content += " mini=ovMap.getOverviewMap();\n" + content += " //Dibujamos los waypoints\n" + content += " for (i=0; i<waypointList.length; i++){\n" + content += " createMarker(waypointList[i],map);\n" + content += " map.enableDragging();\n" + content += " }\n" + content += " document.getElementById('map').style.top='0px';\n" + content += " document.getElementById('map').style.left='0px';\n" + content += " document.getElementById('map').style.width='100%';\n" + content += " // Add an encoded polyline.\n" + content += " var encodedPolyline = new GPolyline.fromEncoded({\n" + content += " color: \"#3333cc\",\n" + content += " weight: 10,\n" + content += " points: \"%s\",\n" %points + content += " levels: \"%s\",\n" %levels + content += " zoomFactor: 32,\n" + content += " numLevels: 4\n" + content += " });\n" + content += " map.addOverlay(encodedPolyline);\n" + content += " }\n" + content += " }\n " + content += " //]]>\n" + content += " </script>\n" + content += " </head>\n" + content += " <body onload=\"load()\" onunload=\"GUnload()\">\n" + content += " <div id=\"map\" style=\"width: 520px; height: 480px\"></div>\n" + content += " </body>\n" + content += "</html>\n" + file = fileUtils(self.htmlfile,content) + file.run() + logging.debug("<<") - def createErrorHtml(self): - logging.debug(">>") - content = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + def createErrorHtml(self): + logging.debug(">>") + content = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"> <head> </head> @@ -338,7 +342,7 @@ No Gpx Data </body> </html> - ''' - file = fileUtils(self.htmlfile,content) - file.run() - logging.debug("<<") + ''' + file = fileUtils(self.htmlfile,content) + file.run() + logging.debug("<<") Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-09-30 01:32:14 UTC (rev 633) +++ pytrainer/trunk/pytrainer/main.py 2010-09-30 03:28:54 UTC (rev 634) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#632" + self.version ="1.7.2_svn#634" self.DB_version = 3 #Process command line options self.startup_options = self.get_options() @@ -191,7 +191,7 @@ def runExtension(self,extension,id): logging.debug('>>') - print("Extension id: %s" % str(id)) + #print("Extension id: %s" % str(id)) activity = self.activitypool.get_activity(id) txtbutton,pathExtension,type = extension self.extensionClass = self.extension.importClass(pathExtension) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-09-30 22:13:39
|
Revision: 638 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=638&view=rev Author: jblance Date: 2010-09-30 22:13:29 +0000 (Thu, 30 Sep 2010) Log Message: ----------- Implement per sport pace limits - display only in newgraph Modified Paths: -------------- pytrainer/trunk/glade/profile.glade pytrainer/trunk/pytrainer/gui/windowprofile.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/profile.py Modified: pytrainer/trunk/glade/profile.glade =================================================================== --- pytrainer/trunk/glade/profile.glade 2010-09-30 21:13:08 UTC (rev 637) +++ pytrainer/trunk/glade/profile.glade 2010-09-30 22:13:29 UTC (rev 638) @@ -780,7 +780,7 @@ <child> <widget class="GtkTable" id="table18"> <property name="visible">True</property> - <property name="n_rows">4</property> + <property name="n_rows">5</property> <property name="n_columns">3</property> <property name="column_spacing">5</property> <property name="row_spacing">5</property> @@ -884,8 +884,8 @@ </widget> <packing> <property name="right_attach">3</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> @@ -896,6 +896,36 @@ <child> <placeholder/> </child> + <child> + <placeholder/> + </child> + <child> + <widget class="GtkLabel" id="label-10"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Maximum Pace:</property> + </widget> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkEntry" id="newmaxpace"> + <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="y_options"></property> + </packing> + </child> </widget> <packing> <property name="position">0</property> @@ -1141,7 +1171,7 @@ <child> <widget class="GtkTable" id="table17"> <property name="visible">True</property> - <property name="n_rows">4</property> + <property name="n_rows">5</property> <property name="n_columns">2</property> <property name="column_spacing">5</property> <property name="row_spacing">5</property> @@ -1234,12 +1264,39 @@ </widget> <packing> <property name="right_attach">2</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label-9"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Maxiumum Pace</property> + </widget> + <packing> <property name="top_attach">3</property> <property name="bottom_attach">4</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> + <child> + <widget class="GtkEntry" id="editmaxpace"> + <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="y_options"></property> + </packing> + </child> </widget> <packing> <property name="position">0</property> Modified: pytrainer/trunk/pytrainer/gui/windowprofile.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowprofile.py 2010-09-30 21:13:08 UTC (rev 637) +++ pytrainer/trunk/pytrainer/gui/windowprofile.py 2010-09-30 22:13:29 UTC (rev 638) @@ -53,7 +53,7 @@ self.prf_ddbb.insert_text(i,self.ddbb_type[i]) #preparamos la lista sports: - column_names=[_("Sport"),_("MET"),_("Extra Weight")] + column_names=[_("Sport"),_("MET"),_("Extra Weight"), _("Maximum Pace")] for column_index, column_name in enumerate(column_names): column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) column.set_resizable(True) @@ -141,6 +141,7 @@ gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, + gobject.TYPE_STRING, object) for i in sport_list: if not i[1]: @@ -151,12 +152,22 @@ weight = i[2] else: weight = 0 + try: + max_pace = int(i[4]) + if max_pace is None or max_pace == 0: + max_pace = "" + except Exception as e: + #print type(e), e + max_pace = "" + + iter = store.append() store.set ( iter, 0, str(i[0]), - 1, i[1], - 2, i[2] + 1, met, + 2, weight, + 3, max_pace, ) self.sportTreeView.set_model(store) #self.sportlistbutton.hide() @@ -334,7 +345,8 @@ sport = self.newsportentry.get_text() met = self.newmetentry.get_text() weight = self.newweightentry.get_text() - self.parent.addNewSport(sport,met,weight) + maxpace = self.newmaxpace.get_text() + self.parent.addNewSport(sport,met,weight,maxpace) self.parent.actualize_mainsportlist() self.on_switch_page(None,None,2) self.hidesportsteps() @@ -364,11 +376,12 @@ selected,iter = self.sportTreeView.get_selection().get_selected() if iter: sport = selected.get_value(iter,0) - name,met,weight = self.parent.getSportInfo(sport) + name,met,weight,maxpace = self.parent.getSportInfo(sport) self.editsportentry.set_text(sport) self.sportnameedit.set_text(sport) self.editweightentry.set_text(str(weight)) self.editmetentry.set_text(str(met)) + self.editmaxpace.set_text(str(maxpace)) self.hidesportsteps() self.editsport.show() @@ -377,7 +390,8 @@ newnamesport = self.editsportentry.get_text() newmetsport = self.editmetentry.get_text() newweightsport = self.editweightentry.get_text() - self.parent.updateSport(oldnamesport,newnamesport,newmetsport,newweightsport) + newmaxpace = self.editmaxpace.get_text() + self.parent.updateSport(oldnamesport,newnamesport,newmetsport,newweightsport, newmaxpace) self.parent.actualize_mainsportlist() self.on_switch_page(None,None,2) self.hidesportsteps() Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-09-30 21:13:08 UTC (rev 637) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-09-30 22:13:29 UTC (rev 638) @@ -67,6 +67,7 @@ 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 + pace_limit - (int) maximum pace that is valid for this activity ''' def __init__(self, pytrainer_main = None, id = None): logging.debug(">>") @@ -86,6 +87,7 @@ self.has_data = False self.distance_data = {} self.time_data = {} + self.pace_limit = None if self.pytrainer_main.profile.getValue("pytraining","prf_us_system") == "True": self.us_system = True else: @@ -138,12 +140,15 @@ db_result = self.pytrainer_main.ddbb.select_dict("records,sports", ("sports.name","id_sports", "date","distance","time","beats","comments", "average","calories","id_record","title","upositive","unegative", - "maxspeed","maxpace","pace","maxbeats","date_time_utc","date_time_local"), + "maxspeed","maxpace","pace","maxbeats","date_time_utc","date_time_local", "sports.max_pace"), "id_record=\"%s\" and records.sport=sports.id_sports" %self.id) if len(db_result) == 1: dict = db_result[0] self.sport_name = dict['sports.name'] self.sport_id = dict['id_sports'] + self.pace_limit = dict['sports.max_pace'] + if self.pace_limit == 0 or self.pace_limit == "": + self.pace_limit = None self.title = dict['title'] self.date = dict['date'] self.time = self._int(dict['time']) @@ -297,8 +302,11 @@ for track in self.tracklist: try: pace = 60/track['velocity'] - #pace = 0 if pace > 90 else pace - except: + 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 #TODO this should be None when we move to newgraph... + except Exception as e: + #print type(e), e pace = 0 if self.us_system: self.distance_data['elevation'].addPoints(x=km2miles(track['elapsed_distance']), y=m2feet(track['ele'])) Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-09-30 21:13:08 UTC (rev 637) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-09-30 22:13:29 UTC (rev 638) @@ -140,6 +140,7 @@ "name":"varchar(100)", "weight":"float", "met":"float", + "max_pace":"integer", }, "waypoints":{ "id_waypoint":"integer primary key autoincrement", "lat":"float", Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-09-30 21:13:08 UTC (rev 637) +++ pytrainer/trunk/pytrainer/main.py 2010-09-30 22:13:29 UTC (rev 638) @@ -49,8 +49,8 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#635" - self.DB_version = 3 + self.version ="1.7.2_svn#638" + self.DB_version = 4 #Process command line options self.startup_options = self.get_options() #Setup logging Modified: pytrainer/trunk/pytrainer/profile.py =================================================================== --- pytrainer/trunk/pytrainer/profile.py 2010-09-30 21:13:08 UTC (rev 637) +++ pytrainer/trunk/pytrainer/profile.py 2010-09-30 22:13:29 UTC (rev 638) @@ -276,11 +276,11 @@ 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",None) + return self.pytrainer_main.ddbb.select("sports","name,met,weight,id_sports,max_pace",None) else: return connection - def addNewSport(self,sport,met,weight): + def addNewSport(self,sport,met,weight,maxpace): """31.08.2008 - dgranda It adds a new sport. arguments: @@ -289,9 +289,9 @@ weight: returns: id_sports from new sport""" logging.debug(">>") - logging.debug("Adding new sport: "+sport+"|"+weight+"|"+met) - sport = [sport,met,weight] - self.pytrainer_main.ddbb.insert("sports","name,met,weight",sport) + logging.debug("Adding new sport: "+sport+"|"+weight+"|"+met+"|"+maxpace) + sport = [sport,met,weight,maxpace] + self.pytrainer_main.ddbb.insert("sports","name,met,weight,max_pace",sport) sport_id = self.pytrainer_main.ddbb.select("sports","id_sports","name=\"%s\"" %(sport)) logging.debug("<<") return sport_id @@ -305,13 +305,13 @@ self.pytrainer_main.ddbb.delete("sports","id_sports=\"%d\""%id_sport) logging.debug("<<") - def updateSport(self,oldnamesport,newnamesport,newmetsport,newweightsport): + def updateSport(self,oldnamesport,newnamesport,newmetsport,newweightsport,newmaxpace=None): logging.debug("--") - self.pytrainer_main.ddbb.update("sports","name,met,weight",[newnamesport,newmetsport,newweightsport],"name=\"%s\""%oldnamesport) + self.pytrainer_main.ddbb.update("sports","name,met,weight,max_pace",[newnamesport,newmetsport,newweightsport, newmaxpace],"name=\"%s\""%oldnamesport) def getSportInfo(self,namesport): logging.debug("--") - return self.pytrainer_main.ddbb.select("sports","name,met,weight","name=\"%s\""%namesport)[0] + return self.pytrainer_main.ddbb.select("sports","name,met,weight,max_pace","name=\"%s\""%namesport)[0] def build_ddbb(self): 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-01 04:00:09
|
Revision: 639 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=639&view=rev Author: jblance Date: 2010-10-01 04:00:02 +0000 (Fri, 01 Oct 2010) Log Message: ----------- More changes to new graphing approach Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/drawGraph.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/activity.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-09-30 22:13:29 UTC (rev 638) +++ pytrainer/trunk/glade/pytrainer.glade 2010-10-01 04:00:02 UTC (rev 639) @@ -1198,6 +1198,9 @@ <child> <placeholder/> </child> + <child> + <placeholder/> + </child> </widget> <packing> <property name="expand">False</property> Modified: pytrainer/trunk/pytrainer/gui/drawGraph.py =================================================================== --- pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-09-30 22:13:29 UTC (rev 638) +++ pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-10-01 04:00:02 UTC (rev 639) @@ -66,8 +66,10 @@ canvas.show() #Display title etc - plt.xlabel(datalist.xlabel) - plt.title(title) + if datalist.xlabel is not None: + plt.xlabel(datalist.xlabel) + if title is not None: + plt.title(title) #Removed as now in legend #plt.ylabel(datalist.ylabel) @@ -80,6 +82,12 @@ elif datalist.graphType == "bar": plt.bar(datalist.x_values, datalist.y_values, datalist.bar_widths, datalist.bar_bottoms, color=datalist.linecolor, label=datalist.ylabel) #return figure + elif datalist.graphType == "vspan": + i = 0 + while i < len(datalist.x_values): + #print datalist.x_values[i] , datalist.bar_widths[i] + plt.axvspan(datalist.x_values[i], datalist.x_values[i]+datalist.bar_widths[i], alpha=0.15, facecolor=datalist.linecolor) + i += 1 else: print "Unknown/unimplemented graph type: %s" % datalist.graphType return figure @@ -205,6 +213,7 @@ figure = None datalist = [] count = 0 + if activity.x_axis == "distance": if activity.title is None or activity.title == "": _title = "%s%s of %s on %s" % (str(activity.distance), activity.distance_unit, activity.sport_name, activity.date) @@ -212,11 +221,13 @@ _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 - #TODO sort for x = time.... for item in activity.distance_data: if activity.distance_data[item].show_on_y1: count += 1 figure = self.draw(activity.distance_data[item], box=box, figure=figure, title=_title) + #Display lap divisions if required + if activity.show_laps: + figure = self.draw(activity.lap_distance, box=box, figure=figure) elif activity.x_axis == "time": _time = "%d:%02d:%02d" % (activity.time_tuple) @@ -228,6 +239,9 @@ if activity.time_data[item].show_on_y1: count += 1 figure = self.draw(activity.time_data[item], box=box, figure=figure, title=_title) + #Display lap divisions if required + if activity.show_laps: + figure = self.draw(activity.lap_time, box=box, figure=figure) if count == 0: logging.debug("No items to graph.. Removing graph") figure = self.draw(None, box=box, figure=figure) Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-09-30 22:13:29 UTC (rev 638) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-01 04:00:02 UTC (rev 639) @@ -311,18 +311,26 @@ y2Frame = gtk.Frame(label="Show on Y2 Axis") xvbox = gtk.VBox() y1box = gtk.Table() - y2vbox = gtk.VBox() + y2box = gtk.Table() #Populate X axis data - xdistancebutton = gtk.RadioButton(label="Distance") - xtimebutton = gtk.RadioButton(group=xdistancebutton, label="Time") + #Create x axis items + xdistancebutton = gtk.RadioButton(label=_("Distance")) + xtimebutton = gtk.RadioButton(group=xdistancebutton, label=_("Time")) + xlapsbutton = gtk.CheckButton(label=_("Laps")) + #Set state of buttons if activity.x_axis == "distance": xdistancebutton.set_active(True) elif activity.x_axis == "time": xtimebutton.set_active(True) + xlapsbutton.set_active(activity.show_laps) + #Connect handlers to buttons xdistancebutton.connect("toggled", self.on_xaxischange, "distance", activity) + xtimebutton.connect("toggled", self.on_xaxischange, "time", activity) + xlapsbutton.connect("toggled", self.on_xlapschange, activity) + #Add buttons to frame xvbox.add(xdistancebutton) - xtimebutton.connect("toggled", self.on_xaxischange, "time", activity) xvbox.add(xtimebutton) + xvbox.add(xlapsbutton) xFrame.add(xvbox) row = 0 @@ -355,19 +363,24 @@ #Second Y axis y2button = gtk.CheckButton(label=data[graphdata].title) - y2button.connect("toggled", self.on_y2change, y2vbox) - y2vbox.add(y2button) - + 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() + _color = gtk.gdk.color_parse(data[graphdata].linecolor) + y2color.set_color(_color) + y2color.connect("color-set", self.on_y1colorchange, y2box, graphdata, activity) + #Attach to container + y2box.attach(y2color, 1, 2, row, row+1) row += 1 y1Frame.add(y1box) - y2Frame.add(y2vbox) - self.graph_data_hbox.pack_start(xFrame, expand=False, fill=True, padding=0) + 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.show_all() - - self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) else: @@ -1035,8 +1048,14 @@ if widget.get_active(): activity.x_axis = data self.actualize_recordgraph(activity) - + 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''' logging.debug("Setting %s to color %s" % (graphdata, widget.get_color() ) ) @@ -1049,7 +1068,6 @@ def on_y1change(self, widget, box, graphdata, activity): '''Hander for changes to y1 selection''' - #TODO Need to deal with different x options, ie distance and time... logging.debug("Y1 selection toggled: %s" % graphdata) #Loop through all options at set data correctly for child in box.get_children(): @@ -1065,14 +1083,14 @@ activity.time_data[item].show_on_y1 = child.get_active() #Replot the activity self.grapher.drawMultiPlot(activity=activity, box=self.record_graph_vbox) - - def on_y2change(self, widget, box): + + def on_y2change(self, widget, box, graphdata, activity): '''Hander for changes to y2 selection''' print "Y2 selected: ", - for child in box.get_children(): - if child.get_active(): - print child.get_label(), - print + #for child in box.get_children(): + # if child.get_active(): + # print child.get_label(), + #print 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-09-30 22:13:29 UTC (rev 638) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-10-01 04:00:02 UTC (rev 639) @@ -67,6 +67,9 @@ 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 + show_laps - (bool) display laps on graphs + lap_distance - (graphdata) + lap_time - (graphdata) pace_limit - (int) maximum pace that is valid for this activity ''' def __init__(self, pytrainer_main = None, id = None): @@ -104,6 +107,7 @@ self._init_graph_data() self._generate_per_lap_graphs() self.x_axis = "distance" + self.show_laps = False logging.debug("<<") def _set_units(self): @@ -205,6 +209,13 @@ logging.debug("No laps to generate graphs from") logging.debug("<<") return + #Lap columns + self.lap_distance = GraphData() + self.lap_distance.set_color('#CCFF00') + self.lap_distance.graphType = "vspan" + self.lap_time = GraphData() + self.lap_time.set_color('#CCFF00') + self.lap_time.graphType = "vspan" #Pace title=_("Pace by Lap") xlabel="%s (%s)" % (_('Distance'), self.distance_unit) @@ -212,15 +223,24 @@ self.distance_data['pace_lap'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel) self.distance_data['pace_lap'].set_color('#99CCFF') self.distance_data['pace_lap'].graphType = "bar" + xlabel=_("Time (seconds)") + self.time_data['pace_lap'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel) + self.time_data['pace_lap'].set_color('#99CCFF') + self.time_data['pace_lap'].graphType = "bar" for lap in self.laps: time = float( lap['elapsed_time'].decode('utf-8') ) # time in sql is a unicode string dist = lap['distance']/1000 #distance in km pace = time/(60*dist) #min/km logging.debug("Time: %f, Dist: %f, Pace: %f" % (time, dist, pace) ) + self.lap_time.addBars(x=time, y=10) if self.us_system: + self.lap_distance.addBars(x=km2miles(dist), y=10) self.distance_data['pace_lap'].addBars(x=km2miles(dist), y=pacekm2miles(pace)) + self.time_data['pace_lap'].addBars(x=time, y=pacekm2miles(pace)) else: + self.lap_distance.addBars(x=dist, y=10) self.distance_data['pace_lap'].addBars(x=dist, y=pace) + self.time_data['pace_lap'].addBars(x=time, y=pace) logging.debug("<<") def _get_laps_from_gpx(self): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-10-04 04:31:30
|
Revision: 641 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=641&view=rev Author: jblance Date: 2010-10-04 04:31:23 +0000 (Mon, 04 Oct 2010) Log Message: ----------- Update garmintools schema to allow 0 calories, fix error in checkDB code Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/schemas/garmintools.xsd Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-04 00:59:52 UTC (rev 640) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2010-10-04 04:31:23 UTC (rev 641) @@ -28,20 +28,20 @@ def __init__(self, configuration, pytrainer_main=None): self.pytrainer_main = pytrainer_main self.configuration = configuration - self.ddbb_type = configuration.getValue("pytraining","prf_ddbb") + self.ddbb_type = self.configuration.getValue("pytraining","prf_ddbb") if self.ddbb_type == "mysql": #TODO no longer supported? from mysqlUtils import Sql else: from sqliteUtils import Sql - self.confdir = configuration.confdir + self.confdir = self.configuration.confdir self.ddbb_path = "%s/pytrainer.ddbb" %self.confdir - ddbb_host = configuration.getValue("pytraining","prf_ddbbhost") - ddbb = configuration.getValue("pytraining","prf_ddbbname") - ddbb_user = configuration.getValue("pytraining","prf_ddbbuser") - ddbb_pass = configuration.getValue("pytraining","prf_ddbbpass") - self.ddbbObject = Sql(ddbb_host,ddbb,ddbb_user,ddbb_pass,configuration) + ddbb_host = self.configuration.getValue("pytraining","prf_ddbbhost") + ddbb = self.configuration.getValue("pytraining","prf_ddbbname") + ddbb_user = self.configuration.getValue("pytraining","prf_ddbbuser") + ddbb_pass = self.configuration.getValue("pytraining","prf_ddbbpass") + 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 @@ -220,7 +220,7 @@ logging.debug("Found %d records in DB without date_time_local field populated" % (len(listOfRecords) ) ) for record in listOfRecords: try: - gpxfile = configuration.gpxdir+"/%s.gpx"%(record[0]) + gpxfile = self.configuration.gpxdir+"/%s.gpx"%(record[0]) dateFromUTC = Date().getDateTime(record[2]) if os.path.isfile(gpxfile) : #GPX file exists for this record - probably not a manual record date_time_local = str(dateFromUTC[1]) Modified: pytrainer/trunk/schemas/garmintools.xsd =================================================================== --- pytrainer/trunk/schemas/garmintools.xsd 2010-10-04 00:59:52 UTC (rev 640) +++ pytrainer/trunk/schemas/garmintools.xsd 2010-10-04 04:31:23 UTC (rev 641) @@ -27,7 +27,7 @@ <xsd:element name="begin_pos" type="position_type" minOccurs="0" /> <xsd:element name="end_pos" type="position_type" minOccurs="0" /> <xsd:element name="max_speed" type="xsd:float" minOccurs="0" /> - <xsd:element name="calories" type="xsd:positiveInteger" minOccurs="0" /> + <xsd:element name="calories" type="xsd:integer" minOccurs="0" /> <xsd:element name="avg_hr" type="xsd:positiveInteger" minOccurs="0" /> <xsd:element name="max_hr" type="xsd:positiveInteger" minOccurs="0" /> <xsd:element name="intensity" type="xsd:string" minOccurs="0" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-10-05 00:15:01
|
Revision: 643 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=643&view=rev Author: jblance Date: 2010-10-05 00:14:54 +0000 (Tue, 05 Oct 2010) Log Message: ----------- Fixes to edit record Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/drawGraph.py pytrainer/trunk/pytrainer/gui/windowrecord.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py Added Paths: ----------- pytrainer/trunk/schemas/pytrainer-0.1.xsd Modified: pytrainer/trunk/pytrainer/gui/drawGraph.py =================================================================== --- pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-10-04 04:50:08 UTC (rev 642) +++ pytrainer/trunk/pytrainer/gui/drawGraph.py 2010-10-05 00:14:54 UTC (rev 643) @@ -128,6 +128,7 @@ ''' Draw a plot style graph ''' + print "drawGraph 131: DEPRECIATED drawPlot called" #data = {'linewidth':3, 'x':(1,2,3), 'y':(3,9,1)} logging.debug('>>') if box is None: Modified: pytrainer/trunk/pytrainer/gui/windowrecord.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-10-04 04:50:08 UTC (rev 642) +++ pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-10-05 00:14:54 UTC (rev 643) @@ -28,549 +28,619 @@ from dateutil.tz import * # for tzutc() class WindowRecord(SimpleGladeApp): - def __init__(self, data_path = None, listSport = None, parent = None, date = None, title=None, distance=None, time=None, upositive=None, unegative=None, bpm=None, calories=None, comment=None, windowTitle=None): - self.parent = parent - self.data_path = data_path - glade_path="glade/newrecord.glade" - root = "newrecord" - domain = None - self.mode = "newrecord" - self.id_record = "" - self.store = None - self.active_row = None - self.activity_data = [] - SimpleGladeApp.__init__(self, data_path+glade_path, root, domain) - self.conf_options = [ - "rcd_date", - "rcd_sport", - "rcd_distance", - "rcd_beats", - "rcd_comments", - "rcd_average", - "rcd_calories", - "rcd_title", - "rcd_gpxfile", - "rcd_upositive", - "rcd_unegative", - "rcd_maxbeats", - "rcd_pace", - "rcd_maxpace", - "rcd_maxvel", - ] - self.listSport = {} - for i in listSport: - self.listSport[i[3]] = i[0] #Create dictionary using SportID as key (may be non sequential if sports have been deleted) - for i in self.listSport: - self.rcd_sport.insert_text(i,self.listSport[i]) - self.rcd_sport.set_active(0) + def __init__(self, data_path = None, listSport = None, parent = None, date = None, title=None, distance=None, time=None, upositive=None, unegative=None, bpm=None, calories=None, comment=None, windowTitle=None): + logging.debug(">>") + self.parent = parent + self.pytrainer_main = parent.pytrainer_main + self.data_path = data_path + glade_path="glade/newrecord.glade" + root = "newrecord" + domain = None + self.mode = "newrecord" + self.id_record = "" + self.store = None + self.active_row = None + self.activity_data = [] + SimpleGladeApp.__init__(self, data_path+glade_path, root, domain) + self.conf_options = [ + "rcd_date", + "rcd_sport", + "rcd_distance", + "rcd_beats", + "rcd_comments", + "rcd_average", + "rcd_calories", + "rcd_title", + "rcd_gpxfile", + "rcd_upositive", + "rcd_unegative", + "rcd_maxbeats", + "rcd_pace", + "rcd_maxpace", + "rcd_maxvel", + ] + self.listSport = {} + for i in listSport: + self.listSport[i[3]] = i[0] #Create dictionary using SportID as key (may be non sequential if sports have been deleted) + for i in self.listSport: + self.rcd_sport.insert_text(i,self.listSport[i]) + self.rcd_sport.set_active(0) - if windowTitle is not None: - self.newrecord.set_title(windowTitle) - if date != None: - self.setDate(date) - if title != None: - self.rcd_title.set_text(title) - if distance != None: - self.rcd_distance.set_text(distance) - if time != None: - self.setTime(time) - if distance!=None and time!=None: - self.on_calcaverage_clicked(None) - if upositive != None: - self.rcd_upositive.set_text(upositive) - if unegative != None: - self.rcd_unegative.set_text(unegative) - if calories != None: - self.rcd_calories.set_text(calories) - - def getActivityData(self): - return self.activity_data - - def populateMultiWindow(self, activities): - self.mode = "multiple_activities" - #activities (activity_id, start_time, distance, duration, sport, gpx_file, file_id) - self.activity_data = [] - #Make treeview - self.store = self.build_tree_view() - #Add data - for activity in activities: - iter = self.store.append() - self.store.set( - iter, - 0, activity[0], - 1, activity[1], - 2, activity[2], - 3, activity[3], - 4, activity[4], - 5, activity[5] - ) - details = {} - details["complete"] = False - details["rcd_distance"] = activity[2] - duration = activity[3] - if duration.count(":") == 2: - hours, mins, secs = duration.split(":") - else: - hours = mins = secs = 0 - #details["rcd_hour"] = float(hours) - #details["rcd_min"] = float(mins) - #details["rcd_second"] = float(secs) - #details["rcd_time"] = (((float(hours) * 60) + float(mins)) * 60) + float(secs) - details["activity_id"] = activity[0] - details["rcd_time"] = (float(hours), float(mins), float(secs)) - details["rcd_sport"] = activity[4] - details["rcd_gpxfile"] = activity[5] - details["file_id"] = activity[6] - self.activity_data.append(details) - self.scrolledwindowEntries.show_all() - #Hide some of the buttons - self.button25.hide() #GPX file "Open" button - self.button24.hide() #GPX file "Calculate Values" button - self.button10.hide() #Distance "Calculate" button - self.button11.hide() #Duration "Calculate" button - #self.button12.hide() #Velocity "Calculate" button - self.button43.hide() #Pace "Calculate" button - #Make GPX file 'unsensitive' - self.rcd_gpxfile.set_sensitive(0) - while gtk.events_pending(): # This allows the GUI to update - gtk.main_iteration() # before completion of this entire action - #Select first row and display details - self.treeviewEntries.set_cursor(0) - self.show_treeviewEntries_row(0) - - def build_tree_view(self): - store = gtk.ListStore( gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING ) - column_names=["id", _("Start Time"), _("Distance"),_("Duration"),_("Sport"), _("GPX File")] - for column_index, column_name in enumerate(column_names): - #Add columns - column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) - column.set_sort_column_id(column_index) - if column_name == "id": - column.set_visible(False) - column.set_resizable(True) - self.treeviewEntries.append_column(column) - self.treeviewEntries.set_headers_clickable(True) - self.treeviewEntries.set_model(store) - return store - - def on_accept_clicked(self,widget): - if self.mode == "multiple_activities": - #Check for edited data in comments - if self.active_row is not None: - buffer = self.rcd_comments.get_buffer() - start,end = buffer.get_bounds() - comments = buffer.get_text(start,end, True).replace("\"","'") - self.activity_data[self.active_row]["rcd_comments"] = comments - #Advanced tab items - self.activity_data[self.active_row]["rcd_maxpace"] = self.rcd_maxpace.get_text() - self.activity_data[self.active_row]["rcd_pace"] = self.rcd_pace.get_text() - self.activity_data[self.active_row]["rcd_upositive"] = self.rcd_upositive.get_text() - self.activity_data[self.active_row]["rcd_unegative"] = self.rcd_unegative.get_text() - self.activity_data[self.active_row]["rcd_maxbeats"] = self.rcd_maxbeats.get_text() - self.activity_data[self.active_row]["rcd_beats"] = self.rcd_beats.get_text() - self.activity_data[self.active_row]["rcd_calories"] = self.rcd_calories.get_text() - row = 0 - for activity in self.activity_data: - index = self.activity_data.index(activity) - if activity["complete"] is False: - #Did not view or modify this record - need to get all the details - print "Activity incomplete.. " + activity["rcd_gpxfile"] - self.update_activity_data(row, activity["rcd_gpxfile"], activity["rcd_sport"]) - activity["rcd_title"] = activity["rcd_title"].replace("\"","'") - #Add activity to DB etc - laps = activity.pop("laps", ()) - self.activity_data[index]["db_id"] = self.parent.insertRecord(activity, laps) - row += 1 - logging.debug("Processed %d rows of activity data" % row) - else: - list_options = {} - trackSummary = {} - for i in self.conf_options: - var = getattr(self,i) - if i == "rcd_title": - list_options[i] = var.get_text().replace("\"","'") - elif i != "rcd_sport" and i != "rcd_comments": - list_options[i] = var.get_text() - elif i == "rcd_sport": - list_options[i] = var.get_active_text() - elif i == "rcd_comments": - buffer = var.get_buffer() - start,end = buffer.get_bounds() - list_options[i] = buffer.get_text(start,end, True) - list_options[i] = list_options[i].replace("\"","'") - list_options["rcd_time"] = [self.rcd_hour.get_value_as_int(),self.rcd_min.get_value_as_int(),self.rcd_second.get_value_as_int()] - if self.mode == "newrecord": - logging.debug('Track data: '+str(list_options)) - if list_options["rcd_gpxfile"] != "": - logging.info('Adding new activity based on GPX file') - trackSummary=(list_options["rcd_sport"],"","") - self.parent.insertNewRecord(list_options["rcd_gpxfile"], trackSummary) - else: - logging.info('Adding new activity based on provided data') - #Manual entry, calculate time info - record_time = self.rcd_starttime.get_text() - record_date = self.rcd_date.get_text() - localtz = Date().getLocalTZ() - date = dateutil.parser.parse(record_date+" "+record_time+" "+localtz) - local_date = str(date) - utc_date = date.astimezone(tzutc()).strftime("%Y-%m-%dT%H:%M:%SZ") - list_options["date_time_utc"] = utc_date - list_options["date_time_local"] = local_date - self.parent.insertRecord(list_options) - elif self.mode == "editrecord": - self.parent.updateRecord(list_options, self.id_record) - self.close_window() - - def on_cancel_clicked(self,widget): - self.close_window() + if windowTitle is not None: + self.newrecord.set_title(windowTitle) + if date != None: + self.setDate(date) + if title != None: + self.rcd_title.set_text(title) + if distance != None: + self.rcd_distance.set_text(distance) + if time != None: + self.setTime(time) + if distance!=None and time!=None: + self.on_calcaverage_clicked(None) + if upositive != None: + self.rcd_upositive.set_text(upositive) + if unegative != None: + self.rcd_unegative.set_text(unegative) + if calories != None: + self.rcd_calories.set_text(calories) + logging.debug("<<") + + def getActivityData(self): + return self.activity_data + + def populateMultiWindow(self, activities): + logging.debug(">>") + self.mode = "multiple_activities" + #activities (activity_id, start_time, distance, duration, sport, gpx_file, file_id) + self.activity_data = [] + #Make treeview + self.store = self.build_tree_view() + #Add data + for activity in activities: + iter = self.store.append() + self.store.set( + iter, + 0, activity[0], + 1, activity[1], + 2, activity[2], + 3, activity[3], + 4, activity[4], + 5, activity[5] + ) + details = {} + details["complete"] = False + details["rcd_distance"] = activity[2] + duration = activity[3] + if duration.count(":") == 2: + hours, mins, secs = duration.split(":") + else: + hours = mins = secs = 0 + #details["rcd_hour"] = float(hours) + #details["rcd_min"] = float(mins) + #details["rcd_second"] = float(secs) + #details["rcd_time"] = (((float(hours) * 60) + float(mins)) * 60) + float(secs) + details["activity_id"] = activity[0] + details["rcd_time"] = (float(hours), float(mins), float(secs)) + details["rcd_sport"] = activity[4] + details["rcd_gpxfile"] = activity[5] + details["file_id"] = activity[6] + self.activity_data.append(details) + self.scrolledwindowEntries.show_all() + #Hide some of the buttons + self.button25.hide() #GPX file "Open" button + self.button24.hide() #GPX file "Calculate Values" button + self.button10.hide() #Distance "Calculate" button + self.button11.hide() #Duration "Calculate" button + #self.button12.hide() #Velocity "Calculate" button + self.button43.hide() #Pace "Calculate" button + #Make GPX file 'unsensitive' + self.rcd_gpxfile.set_sensitive(0) + while gtk.events_pending(): # This allows the GUI to update + gtk.main_iteration() # before completion of this entire action + #Select first row and display details + self.treeviewEntries.set_cursor(0) + self.show_treeviewEntries_row(0) + logging.debug("<<") + + def build_tree_view(self): + store = gtk.ListStore( gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING ) + column_names=["id", _("Start Time"), _("Distance"),_("Duration"),_("Sport"), _("GPX File")] + for column_index, column_name in enumerate(column_names): + #Add columns + column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index) + column.set_sort_column_id(column_index) + if column_name == "id": + column.set_visible(False) + column.set_resizable(True) + self.treeviewEntries.append_column(column) + self.treeviewEntries.set_headers_clickable(True) + self.treeviewEntries.set_model(store) + return store + + def on_accept_clicked(self,widget): + logging.debug(">>") + if self.mode == "multiple_activities": + logging.debug("multiple_activities") + #Check for edited data in comments + if self.active_row is not None: + buffer = self.rcd_comments.get_buffer() + start,end = buffer.get_bounds() + comments = buffer.get_text(start,end, True).replace("\"","'") + self.activity_data[self.active_row]["rcd_comments"] = comments + #Advanced tab items + self.activity_data[self.active_row]["rcd_maxpace"] = self.rcd_maxpace.get_text() + self.activity_data[self.active_row]["rcd_pace"] = self.rcd_pace.get_text() + self.activity_data[self.active_row]["rcd_upositive"] = self.rcd_upositive.get_text() + self.activity_data[self.active_row]["rcd_unegative"] = self.rcd_unegative.get_text() + self.activity_data[self.active_row]["rcd_maxbeats"] = self.rcd_maxbeats.get_text() + self.activity_data[self.active_row]["rcd_beats"] = self.rcd_beats.get_text() + self.activity_data[self.active_row]["rcd_calories"] = self.rcd_calories.get_text() + row = 0 + for activity in self.activity_data: + index = self.activity_data.index(activity) + if activity["complete"] is False: + #Did not view or modify this record - need to get all the details + print "Activity incomplete.. " + activity["rcd_gpxfile"] + self.update_activity_data(row, activity["rcd_gpxfile"], activity["rcd_sport"]) + activity["rcd_title"] = activity["rcd_title"].replace("\"","'") + #Add activity to DB etc + laps = activity.pop("laps", ()) + self.activity_data[index]["db_id"] = self.parent.insertRecord(activity, laps) + row += 1 + logging.debug("Processed %d rows of activity data" % row) + else: + logging.debug("Single activity") + list_options = {} + trackSummary = {} + list_options["rcd_date"] = self.rcd_date.get_text() + list_options["rcd_sport"] = self.rcd_sport.get_active_text() + list_options["rcd_distance"] = self.rcd_distance.get_text() + list_options["rcd_beats"] = self.rcd_beats.get_text() + list_options["rcd_average"] = self.rcd_average.get_text() + list_options["rcd_calories"] = self.rcd_calories.get_text() + list_options["rcd_title"] = self.rcd_title.get_text().replace("\"","'") + list_options["rcd_gpxfile"] = self.rcd_gpxfile.get_text() + list_options["rcd_upositive"] = self.rcd_upositive.get_text() + list_options["rcd_unegative"] = self.rcd_unegative.get_text() + list_options["rcd_maxbeats"] = self.rcd_maxbeats.get_text() + list_options["rcd_pace"] = self.rcd_pace.get_text() + list_options["rcd_maxpace"] = self.rcd_maxpace.get_text() + list_options["rcd_maxvel"] = self.rcd_maxvel.get_text() + list_options["rcd_time"] = [self.rcd_hour.get_value_as_int(),self.rcd_min.get_value_as_int(),self.rcd_second.get_value_as_int()] + buffer = self.rcd_comments.get_buffer() + start,end = buffer.get_bounds() + comment = buffer.get_text(start,end, True) + list_options["rcd_comments"] = comment.replace("\"","'") - def close_window(self, widget=None): - self.newrecord.hide() - #self.newrecord = None - self.quit() + if self.mode == "newrecord": + logging.debug('Track data: '+str(list_options)) + if list_options["rcd_gpxfile"] != "": + logging.info('Adding new activity based on GPX file') + trackSummary=(list_options["rcd_sport"],"","") + self.parent.insertNewRecord(list_options["rcd_gpxfile"], trackSummary) + else: + logging.info('Adding new activity based on provided data') + #Manual entry, calculate time info + record_time = self.rcd_starttime.get_text() + record_date = self.rcd_date.get_text() + localtz = Date().getLocalTZ() + date = dateutil.parser.parse(record_date+" "+record_time+" "+localtz) + local_date = str(date) + utc_date = date.astimezone(tzutc()).strftime("%Y-%m-%dT%H:%M:%SZ") + list_options["date_time_utc"] = utc_date + list_options["date_time_local"] = local_date + self.parent.insertRecord(list_options) + elif self.mode == "editrecord": + self.parent.updateRecord(list_options, self.id_record) + logging.debug("<<") + self.close_window() + + def on_cancel_clicked(self,widget): + self.close_window() - def on_calendar_clicked(self,widget): - calendardialog = WindowCalendar(self.data_path,self, date=self.rcd_date.get_text()) - calendardialog.run() + def close_window(self, widget=None): + self.newrecord.hide() + #self.newrecord = None + self.quit() - def setDate(self,date): - self.rcd_date.set_text(date) + def on_calendar_clicked(self,widget): + calendardialog = WindowCalendar(self.data_path,self, date=self.rcd_date.get_text()) + calendardialog.run() - def setTime(self,timeInSeconds): - time_in_hour = int(timeInSeconds)/3600.0 - hour = int(time_in_hour) - min = int((time_in_hour-hour)*60) - sec = (((time_in_hour-hour)*60)-min)*60 - self.rcd_hour.set_value(hour) - self.rcd_min.set_value(min) - self.rcd_second.set_value(sec) + def setDate(self,date): + self.rcd_date.set_text(date) - def setValue(self,var_name,value, format="%0.2f"): - var = getattr(self,var_name) - try: - valueString = format % value - var.set_text(valueString) - except Exception as e: - print var_name, value, e - pass - - def setValues(self,values): - #(24, u'2009-12-26', 4, 23.48, u'9979', 0.0, 8.4716666232200009, 2210, u'', None, u'', 573.0, 562.0, 11.802745244400001, 5.0499999999999998, 7.04, 0.0, u'2009-12-25T19:41:48Z', u'2009-12-26 08:41:48+13:00') - #(50, u'2006-10-13', 1, 25.0, u'5625', 0.0, 16.0, 0, u'', gpsfile, title,upositive,unegative,maxspeed|maxpace|pace|maxbeats - self.mode = "editrecord" - self.id_record = values[0] - self.setTime(values[4]) - self.rcd_date.set_text(str(values[1])) - self.setValue("rcd_distance",values[3]) - self.setValue("rcd_average",values[6]) - self.setValue("rcd_calories",values[7], "%0.0f") - self.setValue("rcd_beats",values[5], "%0.0f") - self.setValue("rcd_upositive",values[11]) - self.setValue("rcd_unegative",values[12]) - self.setValue("rcd_maxvel",values[13]) - self.setValue("rcd_maxpace",values[14]) - self.setValue("rcd_pace",values[15]) - self.setValue("rcd_maxbeats",values[16], "%0.0f") - self.rcd_title.set_text("%s"%values[10]) - - local_time = values[18] - if local_time is not None: - dateTime = dateutil.parser.parse(local_time) - sTime = dateTime.strftime("%X") - self.rcd_starttime.set_text("%s" % sTime) - sportID = values[2] - sportPosition = self.getSportPosition(sportID) - self.rcd_sport.set_active(sportPosition) - buffer = self.rcd_comments.get_buffer() - start,end = buffer.get_bounds() - buffer.set_text(values[8]) + def setTime(self,timeInSeconds): + time_in_hour = int(timeInSeconds)/3600.0 + hour = int(time_in_hour) + min = int((time_in_hour-hour)*60) + sec = (((time_in_hour-hour)*60)-min)*60 + self.rcd_hour.set_value(hour) + self.rcd_min.set_value(min) + self.rcd_second.set_value(sec) - def getSportPosition(self, sportID): - """ - Function to determine the position in the sport array for a given sport ID - Needed as once sports are deleted there are gaps in the list... - """ - count = 0 - for key, value in self.listSport.iteritems(): - if key == sportID: - return count - count +=1 - return 0 - - def getSportPositionByName(self, sport): - """ - Function to determine the position in the sport array for a given sport - Needed as once sports are deleted there are gaps in the list... - """ - count = 0 - for key, value in self.listSport.iteritems(): - if value == sport: - return count - count +=1 - return None - - def on_calctime_clicked(self,widget): - try: - distance = self.rcd_distance.get_text() - average = self.rcd_average.get_text() - time_in_hour = float(distance)/float(average) - self.set_recordtime(time_in_hour) - except: - pass + def setValue(self,var_name,value, format="%0.2f"): + var = getattr(self,var_name) + try: + valueString = format % value + var.set_text(valueString) + except Exception as e: + print var_name, value, e + pass + + def setValuesFromActivity(self, activity): + logging.debug(">>") + self.mode = "editrecord" + if activity is None: + logging.debug("activity is None") + logging.debug("<<") + return + self.id_record = activity.id_record + (h, m, s) = activity.time_tuple + self.rcd_hour.set_value(h) + self.rcd_min.set_value(m) + self.rcd_second.set_value(s) + self.rcd_date.set_text(activity.date) + self.rcd_distance.set_text("%.2f"%activity.distance) + self.rcd_average.set_text("%.2f"%activity.average) + self.rcd_calories.set_text("%s"%activity.calories) + self.rcd_beats.set_text("%s"%activity.beats) + self.rcd_upositive.set_text("%.2f"%activity.upositive) + self.rcd_unegative.set_text("%.2f"%activity.unegative) + self.rcd_maxvel.set_text("%.2f"%activity.maxspeed) + self.rcd_maxpace.set_text("%s"%self.parent.pace_from_float(activity.maxpace)) + self.rcd_pace.set_text("%s"%self.parent.pace_from_float(activity.pace)) + self.rcd_maxbeats.set_text("%s"%activity.maxbeats) + self.rcd_title.set_text(activity.title) + + if activity.starttime is not None: + self.rcd_starttime.set_text("%s" % activity.starttime) + sportPosition = self.getSportPosition(activity.sport_id) + self.rcd_sport.set_active(sportPosition) + buffer = self.rcd_comments.get_buffer() + start,end = buffer.get_bounds() + buffer.set_text(activity.comments) + if activity.gpx_file is not None: + self.rcd_gpxfile.set_text(activity.gpx_file) + self.frameGeneral.set_sensitive(0) #Currently record values not changed if a GPX file is present + self.frameVelocity.set_sensitive(0) #Greying out options to indicate this to user + logging.debug("<<") + + def setValues(self,values): + #(24, u'2009-12-26', 4, 23.48, u'9979', 0.0, 8.4716666232200009, 2210, u'', None, u'', 573.0, 562.0, 11.802745244400001, 5.0499999999999998, 7.04, 0.0, u'2009-12-25T19:41:48Z', u'2009-12-26 08:41:48+13:00') + #(50, u'2006-10-13', 1, 25.0, u'5625', 0.0, 16.0, 0, u'', gpsfile, title,upositive,unegative,maxspeed|maxpace|pace|maxbeats + print "windowrecord setValues called" + self.mode = "editrecord" + self.id_record = values[0] + self.setTime(values[4]) + self.rcd_date.set_text(str(values[1])) + self.setValue("rcd_distance",values[3]) + self.setValue("rcd_average",values[6]) + self.setValue("rcd_calories",values[7], "%0.0f") + self.setValue("rcd_beats",values[5], "%0.0f") + self.setValue("rcd_upositive",values[11]) + self.setValue("rcd_unegative",values[12]) + self.setValue("rcd_maxvel",values[13]) + self.setValue("rcd_maxpace",values[14]) + self.setValue("rcd_pace",values[15]) + self.setValue("rcd_maxbeats",values[16], "%0.0f") + self.rcd_title.set_text("%s"%values[10]) + + local_time = values[18] + if local_time is not None: + dateTime = dateutil.parser.parse(local_time) + sTime = dateTime.strftime("%X") + self.rcd_starttime.set_text("%s" % sTime) + sportID = values[2] + sportPosition = self.getSportPosition(sportID) + self.rcd_sport.set_active(sportPosition) + buffer = self.rcd_comments.get_buffer() + start,end = buffer.get_bounds() + buffer.set_text(values[8]) - def update_activity_data(self, row, gpx_file, sport): - self.activity_data[row]["rcd_comments"] = "" - gpx_summary, laps = self.parent.summaryFromGPX(gpx_file, (sport,"")) - local_time = gpx_summary['date_time_local'] - start_date = local_time.strftime("%Y-%m-%d") - start_time = local_time.strftime("%H:%M:%S") - self.activity_data[row]["rcd_date"] = start_date - self.activity_data[row]["rcd_starttime"] = start_time - self.activity_data[row]["date_time_local"] = gpx_summary['date_time_local'] - self.activity_data[row]["date_time_utc"] = gpx_summary['date_time_utc'] - self.activity_data[row]["rcd_average"] = gpx_summary["rcd_average"] - self.activity_data[row]["rcd_calories"] = gpx_summary["rcd_calories"] - self.activity_data[row]["rcd_beats"] = gpx_summary["rcd_beats"] - self.activity_data[row]["rcd_upositive"] = gpx_summary["rcd_upositive"] - self.activity_data[row]["rcd_unegative"] = gpx_summary["rcd_unegative"] - self.activity_data[row]["rcd_maxvel"] = gpx_summary["rcd_maxvel"] - self.activity_data[row]["rcd_maxpace"] = gpx_summary["rcd_maxpace"] - self.activity_data[row]["rcd_pace"] = gpx_summary["rcd_pace"] - self.activity_data[row]["rcd_maxbeats"] = gpx_summary["rcd_maxbeats"] - self.activity_data[row]["rcd_title"] = "" - self.activity_data[row]["laps"] = laps - self.activity_data[row]["complete"] = True + def getSportPosition(self, sportID): + """ + Function to determine the position in the sport array for a given sport ID + Needed as once sports are deleted there are gaps in the list... + """ + count = 0 + for key, value in self.listSport.iteritems(): + if key == sportID: + return count + count +=1 + return 0 + + def getSportPositionByName(self, sport): + """ + Function to determine the position in the sport array for a given sport + Needed as once sports are deleted there are gaps in the list... + """ + count = 0 + for key, value in self.listSport.iteritems(): + if value == sport: + return count + count +=1 + return None + + def on_calctime_clicked(self,widget): + try: + distance = self.rcd_distance.get_text() + average = self.rcd_average.get_text() + time_in_hour = float(distance)/float(average) + self.set_recordtime(time_in_hour) + except: + pass - - def show_treeviewEntries_row(self, row): - ''' - Show details of treeview entry - TODO need to maintain any changes and display those.... - ''' - self.active_row = row - #Get details from stored data - #set sport - sport = self.activity_data[row]["rcd_sport"] - sportPosition = self.getSportPositionByName(sport) - if sportPosition is not None: - self.rcd_sport.set_active(sportPosition) - #Set gpx file name - gpx_file = self.activity_data[row]["rcd_gpxfile"] - self.setValue("rcd_gpxfile", gpx_file, "%s") - #set duration - time = Date().time2second(self.activity_data[row]["rcd_time"]) #TODO Fix to use timeinseconds!! - self.setTime(time) #TODO Fix to use timeinseconds!! - #Set distance - self.setValue("rcd_distance",self.activity_data[row]["rcd_distance"], "%s") - #Set comments - buffer = self.rcd_comments.get_buffer() - start,end = buffer.get_bounds() - if "rcd_comments" not in self.activity_data[row]: - self.activity_data[row]["rcd_comments"] = "" - buffer.set_text(self.activity_data[row]["rcd_comments"]) - while gtk.events_pending(): # This allows the GUI to update - gtk.main_iteration() # before completion of this entire action - if self.activity_data[row]["complete"] is False: - #Haven't processed GPX file yet - #Blank values not yet known - self.setValue("rcd_date", "", "%s") - self.setValue("rcd_starttime", "", "%s") - self.setValue("rcd_average", "", "%s") - self.setValue("rcd_calories","", "%s") - self.setValue("rcd_beats", "", "%s") - self.setValue("rcd_upositive", "", "%s") - self.setValue("rcd_unegative", "", "%s") - self.setValue("rcd_maxvel", "", "%s") - self.rcd_maxpace.set_text("") - self.rcd_pace.set_text("") - self.setValue("rcd_maxbeats", "", "%s") - while gtk.events_pending(): # This allows the GUI to update - gtk.main_iteration() # before completion of this entire action - #Get some info from gpx file - self.update_activity_data(row, gpx_file, sport) - - self.setValue("rcd_date", self.activity_data[row]["rcd_date"], "%s") - self.setValue("rcd_starttime", self.activity_data[row]["rcd_starttime"], "%s") - self.setValue("rcd_average",self.activity_data[row]["rcd_average"]) - self.setValue("rcd_calories",self.activity_data[row]["rcd_calories"], "%s") - self.setValue("rcd_beats",self.activity_data[row]["rcd_beats"], "%s") - self.setValue("rcd_upositive",self.activity_data[row]["rcd_upositive"], "%s") - self.setValue("rcd_unegative",self.activity_data[row]["rcd_unegative"], "%s") - self.setValue("rcd_maxvel",self.activity_data[row]["rcd_maxvel"]) - self.rcd_maxpace.set_text(self.activity_data[row]["rcd_maxpace"]) - self.rcd_pace.set_text(self.activity_data[row]["rcd_pace"]) - self.setValue("rcd_maxbeats",self.activity_data[row]["rcd_maxbeats"], "%s") - self.rcd_title.set_text(self.activity_data[row]["rcd_title"]) - - - def on_rcd_title_changed(self, widget): - if self.mode == "multiple_activities" and self.active_row is not None: - self.activity_data[self.active_row]["rcd_title"] = self.rcd_title.get_text() - - def on_rcd_sport_changed(self, widget): - if self.mode == "multiple_activities" and self.active_row is not None: - sport = self.rcd_sport.get_active_text() - #Update sport in data store - self.activity_data[self.active_row]["rcd_sport"] = sport - #Update sport in treeview - self.store[self.active_row][4] = sport - - def on_rcd_distance_changed(self, widget): - if self.mode == "multiple_activities" and self.active_row is not None: - distance = self.rcd_distance.get_text() - #Update distance in data store - self.activity_data[self.active_row]["rcd_distance"] = distance - #Update distance in treeview - self.store[self.active_row][2] = distance - - def on_rcd_duration_value_changed(self, widget): - if self.mode == "multiple_activities" and self.active_row is not None: - hour = self.rcd_hour.get_value() - min = self.rcd_min.get_value() - sec = self.rcd_second.get_value() - #print hour, min, sec - #Update duration in data store - self.activity_data[self.active_row]["rcd_time"] = (hour, min, sec) - #Update duration in treeview - self.store[self.active_row][3] = "%d:%.2d:%.2d" % (int(hour), int(min), int(sec)) - - def on_rcd_date_changed(self, widget): - if self.mode == "multiple_activities" and self.active_row is not None: - #Update date in data store - self.activity_data[self.active_row]["rcd_date"] = self.rcd_date.get_text() - - def on_rcd_starttime_changed(self, widget): - if self.mode == "multiple_activities" and self.active_row is not None: - #Update start time in data store - self.activity_data[self.active_row]["rcd_starttime"] = self.rcd_starttime.get_text() - - def on_treeviewEntries_row_activated(self, treeview, event): - ''' - Callback to display details of different activity - ''' - #Check for edited data in previous row - if self.active_row is not None: - #Check for edited data in comments - buffer = self.rcd_comments.get_buffer() - start,end = buffer.get_bounds() - comments = buffer.get_text(start,end, True).replace("\"","'") - self.activity_data[self.active_row]["rcd_comments"] = comments - #Advanced tab items - self.activity_data[self.active_row]["rcd_maxpace"] = self.rcd_maxpace.get_text() - self.activity_data[self.active_row]["rcd_pace"] = self.rcd_pace.get_text() - self.activity_data[self.active_row]["rcd_upositive"] = self.rcd_upositive.get_text() - self.activity_data[self.active_row]["rcd_unegative"] = self.rcd_unegative.get_text() - self.activity_data[self.active_row]["rcd_maxbeats"] = self.rcd_maxbeats.get_text() - self.activity_data[self.active_row]["rcd_beats"] = self.rcd_beats.get_text() - self.activity_data[self.active_row]["rcd_calories"] = self.rcd_calories.get_text() - #Get row that was selected - 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) - while gtk.events_pending(): # This allows the GUI to update - gtk.main_iteration() # before completion of this entire action - self.show_treeviewEntries_row(path[0]) - - def on_calcaverage_clicked(self,widget): - try: - hour = self.rcd_hour.get_value_as_int() - min = self.rcd_min.get_value_as_int() - sec = self.rcd_second.get_value_as_int() - time = sec + (min*60) + (hour*3600) - time_in_hour = time/3600.0 - distance = float(self.rcd_distance.get_text()) - average = distance/time_in_hour - self.rcd_average.set_text("%0.2f" %average) - except: - pass - - def on_calcpace_clicked(self,widget): - hour = self.rcd_hour.get_value_as_int() - min = self.rcd_min.get_value_as_int() - sec = self.rcd_second.get_value_as_int() - time = sec + (min*60) + (hour*3600) - if time<1: - return False - time_in_min = time/60.0 - distance = float(self.rcd_distance.get_text()) - if distance<1: - return False - #Calc Pace - average = time_in_min/distance - #Tranform pace to mm.ss - min = int(average) - per_min = average - min - sec = float(per_min) * 60 / 100 - dec_pace = min + sec - #Transform pace to mm:ss - pace = self.parent.pace_from_float(dec_pace) - self.rcd_pace.set_text(pace) - - def on_calccalories_clicked(self,widget): - sport = self.rcd_sport.get_active_text() - hour = self.rcd_hour.get_value_as_int() - min = self.rcd_min.get_value_as_int() - sec = self.rcd_second.get_value_as_int() - hour += min/60 + sec/60/60 - weight = float("0%s"%self.parent.configuration.getValue("pytraining","prf_weight")) - met = self.parent.getSportMet(sport) - extraweight = self.parent.getSportWeight(sport) - if met: - calories = met*(weight+extraweight)*hour - self.rcd_calories.set_text(str(calories)) + def update_activity_data(self, row, gpx_file, sport): + self.activity_data[row]["rcd_comments"] = "" + gpx_summary, laps = self.parent.summaryFromGPX(gpx_file, (sport,"")) + local_time = gpx_summary['date_time_local'] + start_date = local_time.strftime("%Y-%m-%d") + start_time = local_time.strftime("%H:%M:%S") + self.activity_data[row]["rcd_date"] = start_date + self.activity_data[row]["rcd_starttime"] = start_time + self.activity_data[row]["date_time_local"] = gpx_summary['date_time_local'] + self.activity_data[row]["date_time_utc"] = gpx_summary['date_time_utc'] + self.activity_data[row]["rcd_average"] = gpx_summary["rcd_average"] + self.activity_data[row]["rcd_calories"] = gpx_summary["rcd_calories"] + self.activity_data[row]["rcd_beats"] = gpx_summary["rcd_beats"] + self.activity_data[row]["rcd_upositive"] = gpx_summary["rcd_upositive"] + self.activity_data[row]["rcd_unegative"] = gpx_summary["rcd_unegative"] + self.activity_data[row]["rcd_maxvel"] = gpx_summary["rcd_maxvel"] + self.activity_data[row]["rcd_maxpace"] = gpx_summary["rcd_maxpace"] + self.activity_data[row]["rcd_pace"] = gpx_summary["rcd_pace"] + self.activity_data[row]["rcd_maxbeats"] = gpx_summary["rcd_maxbeats"] + self.activity_data[row]["rcd_title"] = "" + self.activity_data[row]["laps"] = laps + self.activity_data[row]["complete"] = True - def on_calcdistance_clicked(self,widget): - try: - hour = self.rcd_hour.get_value_as_int() - min = self.rcd_min.get_value_as_int() - sec = self.rcd_second.get_value_as_int() - time = sec + (min*60) + (hour*3600) - time_in_hour = time/3600.0 - average = float(self.rcd_average.get_text()) - distance = average*time_in_hour - self.set_distance(distance) - except: - pass - - def set_distance(self,distance): - self.rcd_distance.set_text("%0.2f" %distance) - - def set_maxspeed(self,vel): - self.rcd_maxvel.set_text("%0.2f" %vel) - - def set_maxhr(self,hr): - self.rcd_maxbeats.set_text("%0.2f" %hr) - - def set_recordtime (self,time_in_hour): - hour = int(time_in_hour) - min = int((time_in_hour-hour)*60) - sec = (((time_in_hour-hour)*60)-min)*60 - self.rcd_hour.set_value(hour) - self.rcd_min.set_value(min) - self.rcd_second.set_value(sec) + + def show_treeviewEntries_row(self, row): + ''' + Show details of treeview entry + TODO need to maintain any changes and display those.... + ''' + self.active_row = row + #Get details from stored data + #set sport + sport = self.activity_data[row]["rcd_sport"] + sportPosition = self.getSportPositionByName(sport) + if sportPosition is not None: + self.rcd_sport.set_active(sportPosition) + #Set gpx file name + gpx_file = self.activity_data[row]["rcd_gpxfile"] + self.setValue("rcd_gpxfile", gpx_file, "%s") + #set duration + time = Date().time2second(self.activity_data[row]["rcd_time"]) #TODO Fix to use timeinseconds!! + self.setTime(time) #TODO Fix to use timeinseconds!! + #Set distance + self.setValue("rcd_distance",self.activity_data[row]["rcd_distance"], "%s") + #Set comments + buffer = self.rcd_comments.get_buffer() + start,end = buffer.get_bounds() + if "rcd_comments" not in self.activity_data[row]: + self.activity_data[row]["rcd_comments"] = "" + buffer.set_text(self.activity_data[row]["rcd_comments"]) + while gtk.events_pending(): # This allows the GUI to update + gtk.main_iteration() # before completion of this entire action + if self.activity_data[row]["complete"] is False: + #Haven't processed GPX file yet + #Blank values not yet known + self.setValue("rcd_date", "", "%s") + self.setValue("rcd_starttime", "", "%s") + self.setValue("rcd_average", "", "%s") + self.setValue("rcd_calories","", "%s") + self.setValue("rcd_beats", "", "%s") + self.setValue("rcd_upositive", "", "%s") + self.setValue("rcd_unegative", "", "%s") + self.setValue("rcd_maxvel", "", "%s") + self.rcd_maxpace.set_text("") + self.rcd_pace.set_text("") + self.setValue("rcd_maxbeats", "", "%s") + while gtk.events_pending(): # This allows the GUI to update + gtk.main_iteration() # before completion of this entire action + #Get some info from gpx file + self.update_activity_data(row, gpx_file, sport) + + self.setValue("rcd_date", self.activity_data[row]["rcd_date"], "%s") + self.setValue("rcd_starttime", self.activity_data[row]["rcd_starttime"], "%s") + self.setValue("rcd_average",self.activity_data[row]["rcd_average"]) + self.setValue("rcd_calories",self.activity_data[row]["rcd_calories"], "%s") + self.setValue("rcd_beats",self.activity_data[row]["rcd_beats"], "%s") + self.setValue("rcd_upositive",self.activity_data[row]["rcd_upositive"], "%s") + self.setValue("rcd_unegative",self.activity_data[row]["rcd_unegative"], "%s") + self.setValue("rcd_maxvel",self.activity_data[row]["rcd_maxvel"]) + self.rcd_maxpace.set_text(self.activity_data[row]["rcd_maxpace"]) + self.rcd_pace.set_text(self.activity_data[row]["rcd_pace"]) + self.setValue("rcd_maxbeats",self.activity_data[row]["rcd_maxbeats"], "%s") + self.rcd_title.set_text(self.activity_data[row]["rcd_title"]) + + + def on_rcd_title_changed(self, widget): + if self.mode == "multiple_activities" and self.active_row is not None: + self.activity_data[self.active_row]["rcd_title"] = self.rcd_title.get_text() + + def on_rcd_sport_changed(self, widget): + if self.mode == "multiple_activities" and self.active_row is not None: + sport = self.rcd_sport.get_active_text() + #Update sport in data store + self.activity_data[self.active_row]["rcd_sport"] = sport + #Update sport in treeview + self.store[self.active_row][4] = sport + + def on_rcd_distance_changed(self, widget): + if self.mode == "multiple_activities" and self.active_row is not None: + distance = self.rcd_distance.get_text() + #Update distance in data store + self.activity_data[self.active_row]["rcd_distance"] = distance + #Update distance in treeview + self.store[self.active_row][2] = distance + + def on_rcd_duration_value_changed(self, widget): + if self.mode == "multiple_activities" and self.active_row is not None: + hour = self.rcd_hour.get_value() + min = self.rcd_min.get_value() + sec = self.rcd_second.get_value() + #print hour, min, sec + #Update duration in data store + self.activity_data[self.active_row]["rcd_time"] = (hour, min, sec) + #Update duration in treeview + self.store[self.active_row][3] = "%d:%.2d:%.2d" % (int(hour), int(min), int(sec)) + + def on_rcd_date_changed(self, widget): + if self.mode == "multiple_activities" and self.active_row is not None: + #Update date in data store + self.activity_data[self.active_row]["rcd_date"] = self.rcd_date.get_text() + + def on_rcd_starttime_changed(self, widget): + if self.mode == "multiple_activities" and self.active_row is not None: + #Update start time in data store + self.activity_data[self.active_row]["rcd_starttime"] = self.rcd_starttime.get_text() + + def on_treeviewEntries_row_activated(self, treeview, event): + ''' + Callback to display details of different activity + ''' + #Check for edited data in previous row + if self.active_row is not None: + #Check for edited data in comments + buffer = self.rcd_comments.get_buffer() + start,end = buffer.get_bounds() + comments = buffer.get_text(start,end, True).replace("\"","'") + self.activity_data[self.active_row]["rcd_comments"] = comments + #Advanced tab items + self.activity_data[self.active_row]["rcd_maxpace"] = self.rcd_maxpace.get_text() + self.activity_data[self.active_row]["rcd_pace"] = self.rcd_pace.get_text() + self.activity_data[self.active_row]["rcd_upositive"] = self.rcd_upositive.get_text() + self.activity_data[self.active_row]["rcd_unegative"] = self.rcd_unegative.get_text() + self.activity_data[self.active_row]["rcd_maxbeats"] = self.rcd_maxbeats.get_text() + self.activity_data[self.active_row]["rcd_beats"] = self.rcd_beats.get_text() + self.activity_data[self.active_row]["rcd_calories"] = self.rcd_calories.get_text() + #Get row that was selected + 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) + while gtk.events_pending(): # This allows the GUI to update + gtk.main_iteration() # before completion of this entire action + self.show_treeviewEntries_row(path[0]) + + def on_calcaverage_clicked(self,widget): + try: + hour = self.rcd_hour.get_value_as_int() + min = self.rcd_min.get_value_as_int() + sec = self.rcd_second.get_value_as_int() + time = sec + (min*60) + (hour*3600) + time_in_hour = time/3600.0 + distance = float(self.rcd_distance.get_text()) + average = distance/time_in_hour + self.rcd_average.set_text("%0.2f" %average) + except: + pass + + def on_calcpace_clicked(self,widget): + hour = self.rcd_hour.get_value_as_int() + min = self.rcd_min.get_value_as_int() + sec = self.rcd_second.get_value_as_int() + time = sec + (min*60) + (hour*3600) + if time<1: + return False + time_in_min = time/60.0 + distance = float(self.rcd_distance.get_text()) + if distance<1: + return False + #Calc Pace + average = time_in_min/distance + #Tranform pace to mm.ss + min = int(average) + per_min = average - min + sec = float(per_min) * 60 / 100 + dec_pace = min + sec + #Transform pace to mm:ss + pace = self.parent.pace_from_float(dec_pace) + self.rcd_pace.set_text(pace) + + def on_calccalories_clicked(self,widget): + sport = self.rcd_sport.get_active_text() + hour = self.rcd_hour.get_value_as_int() + min = self.rcd_min.get_value_as_int() + sec = self.rcd_second.get_value_as_int() + hour += min/60 + sec/60/60 + weight = self.pytrainer_main.profile.getValue("pytraining","prf_weight") + if weight is None or weight == "" or weight == "None": + weight = 0 + else: + weight = float(weight) + met = self.parent.getSportMet(sport) + extraweight = self.parent.getSportWeight(sport) + if extraweight is None or extraweight == "" or extraweight == "None": + extraweight = 0 + else: + extraweight = float(extraweight) + if met: + calories = met*(weight+extraweight)*hour + self.rcd_calories.set_text(str(calories)) - def on_selectfile_clicked(self,widget): - self.filechooser = FileChooser(self.data_path,self,"set_gpxfile","open") - self.filechooser.run() + def on_calcdistance_clicked(self,widget): + try: + hour = self.rcd_hour.get_value_as_int() + min = self.rcd_min.get_value_as_int() + sec = self.rcd_second.get_value_as_int() + time = sec + (min*60) + (hour*3600) + time_in_hour = time/3600.0 + average = float(self.rcd_average.get_text()) + distance = average*time_in_hour + self.set_distance(distance) + except: + pass + + def set_distance(self,distance): + self.rcd_distance.set_text("%0.2f" %distance) + + def set_maxspeed(self,vel): + self.rcd_maxvel.set_text("%0.2f" %vel) + + def set_maxhr(self,hr): + self.rcd_maxbeats.set_text("%0.2f" %hr) + + def set_recordtime (self,time_in_hour): + hour = int(time_in_hour) + min = int((time_in_hour-hour)*60) + sec = (((time_in_hour-hour)*60)-min)*60 + self.rcd_hour.set_value(hour) + self.rcd_min.set_value(min) + self.rcd_second.set_value(sec) - def set_gpxfile(self): - namefile = self.filechooser.filename - self.rcd_gpxfile.set_text(namefile) + def on_selectfile_clicked(self,widget): + logging.debug(">>") + #self.filechooser = FileChooser(self.data_path,self,"set_gpxfile","open") + #self.filechooser.run() + from pytrainer.gui.dialogs import fileChooserDialog + selectedFile = fileChooserDialog(title="Choose a Google Earth file (.kml) to import", multiple=False).getFiles() + if selectedFile is not None: + self.rcd_gpxfile.set_text(selectedFile[0]) + logging.debug("<<") - def on_calculatevalues_clicked(self,widget): - gpxfile = self.rcd_gpxfile.get_text() - if os.path.isfile(gpxfile): - self.frameGeneral.set_sensitive(0) - self.frameVelocity.set_sensitive(0) - self.parent.actualize_fromgpx(gpxfile) + def set_gpxfile(self): + logging.debug(">>") + #namefile = self.filechooser.filename + #self.rcd_gpxfile.set_text(namefile) + logging.debug("<<") + def on_calculatevalues_clicked(self,widget): + gpxfile = self.rcd_gpxfile.get_text() + if os.path.isfile(gpxfile): + self.frameGeneral.set_sensitive(0) + self.frameVelocity.set_sensitive(0) + self.parent.actualize_fromgpx(gpxfile) + Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-10-04 04:50:08 UTC (rev 642) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-10-05 00:14:54 UTC (rev 643) @@ -58,6 +58,7 @@ date_time_local - (string) date and time of activity in local timezone date_time_utc - (string) date and time of activity in UTC timezone date_time - (datetime) date and time of activity in local timezone + starttime - (string) distance - (float) activity distance average - (float) average speed of activity upositive - (float) height climbed during activity @@ -91,6 +92,9 @@ self.distance_data = {} self.time_data = {} self.pace_limit = None + self.starttime = None + #self.upositive = 0 + #self.unegative = 0 if self.pytrainer_main.profile.getValue("pytraining","prf_us_system") == "True": self.us_system = True else: @@ -168,9 +172,11 @@ self.date_time_utc = dict['date_time_utc'] if self.date_time_local is not None: #Have a local time stored in DB self.date_time = dateutil.parser.parse(self.date_time_local) + self.starttime = self.date_time.strftime("%X") else: #No local time in DB tmpDateTime = dateutil.parser.parse(self.date_time_utc) self.date_time = tmpDateTime.astimezone(tzlocal()) #datetime with localtime offset (using value from OS) + self.starttime = self.date_time.strftime("%X") #Sort data that changes for the US etc if self.us_system: self.distance = km2miles(self._float(dict['distance'])) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-04 04:50:08 UTC (rev 642) +++ pytrainer/trunk/pytrainer/main.py 2010-10-05 00:14:54 UTC (rev 643) @@ -49,7 +49,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#640" + self.version ="1.7.2_svn#643" self.DB_version = 4 #Process command line options self.startup_options = self.get_options() @@ -407,7 +407,7 @@ list_sport = self.profile.getSportList() if date == None: date = self.date.getDate() - self.record.newRecord(list_sport, date, title, distance, time, upositive, unegative, bpm, calories, comment) + self.record.newRecord(list_sport, date, title, distance, time, upositive, unegative, bpm, calories, comment) self.refreshListRecords() logging.debug('<<') Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2010-10-04 04:50:08 UTC (rev 642) +++ pytrainer/trunk/pytrainer/record.py 2010-10-05 00:14:54 UTC (rev 643) @@ -56,6 +56,10 @@ def editRecord(self,id_record,list_sport): logging.debug('>>') + activity = self.pytrainer_main.activitypool.get_activity(id_record) + self.recordwindow = WindowRecord(self.data_path, list_sport, self, None, windowTitle=_("Edit Entry")) + self.recordwindow.setValuesFromActivity(activity) + ''' record = self.pytrainer_main.ddbb.select("records", "id_record, date, sport, distance, time, beats, average, calories, comments, gpslog, title, upositive, unegative, maxspeed, maxpace, pace, maxbeats, date_time_utc, date_time_local", "id_record=\"%s\"" %id_record) logging.debug('retrieving data from DB: '+str(record)) gpxfile = self.pytrainer_main.profile.gpxdir+"/%d.gpx"%int(id_record) @@ -67,6 +71,7 @@ self.recordwindow.frameVelocity.set_sensitive(0) #Greying out options to indicate this to user logging.debug('sending record info to window') self.recordwindow.setValues(record[0]) + ''' logging.debug('launching window') self.recordwindow.run() logging.debug('<<') @@ -106,9 +111,9 @@ self.parseFloatRecord(list_options["rcd_upositive"]), self.parseFloatRecord(list_options["rcd_unegative"]), self.parseFloatRecord(list_options["rcd_maxvel"]), - self.parseFloatRecord(list_options["rcd_maxpace"]), + self.pace_to_float(list_options["rcd_maxpace"]), self.pace_to_float(list_options["rcd_pace"]), - self.pace_to_float(list_options["rcd_maxbeats"]) + self.parseFloatRecord(list_options["rcd_maxbeats"]) ) logging.debug('<<') return cells,values @@ -190,8 +195,11 @@ if os.path.isfile(gpxOrig): gpxDest = self.pytrainer_main.profile.gpxdir gpxNew = gpxDest+"/%d.gpx"%id_record - shutil.move(gpxOrig, gpxNew) - logging.debug('Moving '+gpxOrig+' to '+gpxNew) + #Leave original file in place... + #shutil.move(gpxOrig, gpxNew) + #logging.debug('Moving '+gpxOrig+' to '+gpxNew) + shutil.copy(gpxOrig, gpxNew) + logging.debug('Copying '+gpxOrig+' to '+gpxNew) #self.parent.refreshListRecords() logging.debug('<<') return self.pytrainer_main.ddbb.lastRecord("records") Added: pytrainer/trunk/schemas/pytrainer-0.1.xsd =================================================================== --- pytrainer/trunk/schemas/pytrainer-0.1.xsd (rev 0) +++ pytrainer/trunk/schemas/pytrainer-0.1.xsd 2010-10-05 00:14:54 UTC (rev 643) @@ -0,0 +1,56 @@ +<?xml version = "1.0" encoding = "UTF-8"?> +<xsd:schema + xmlns="http://sourceforge.net.project/pytrainer/GPX/0/1" schemaLocation="http://sourceforge.net/apps/trac/pytrainer/raw-attachment/wiki/SampleGPX/pytrainer-0.1.xsd" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:gpx="http://www.topografix.com/GPX/1/1" + targetNamespace="http://sourceforge.net.project/pytrainer/GPX/0/1" + elementFormDefault="qualified"> + <xsd:annotation> + <xsd:documentation> + The pytrainer schema is an mix-in schema for use with the GPX 1.1 schema from Topografix. It holds data exclusively processed by pytrainer. + </xsd:documentation> + </xsd:annotation> + + <xsd:import namespace="http://www.topografix.com/GPX/1/1" + schemaLocation="http://www.topografix.com/GPX/1/1/gpx.xsd"/> + <xsd:element name="ele" type="eleType"> + <xsd:annotation> + <xsd:documentation> + Corrected elevation values. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:complexType name="eleType"> + <xsd:simpleContent> + <xsd:extension base="xsd:decimal"> + <xsd:attribute name="method" type="xsd:string" use="required"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:element name="method" type="methodType"> + <xsd:annotation> + <xsd:documentation> + Method used for correction or manipulation. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:complexType name="methodType"> + <xsd:all> + <xsd:element name="description" type="xsd:string"/> + </xsd:all> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="type" type="methtype" use="required"/> + <xsd:attribute name="version" type="xsd:string"/> + <xsd:attribute name="date" type="xsd:dateTime"/> + </xsd:complexType> + + <xsd:simpleType name="methtype"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="ele"/> + <!--<xsd:enumeration value="hr"/>--> + </xsd:restriction> + </xsd:simpleType> + +</xsd:schema> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-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. |
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-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-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-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-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-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-29 04:45:22
|
Revision: 669 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=669&view=rev Author: jblance Date: 2010-10-29 04:45:15 +0000 (Fri, 29 Oct 2010) Log Message: ----------- Minor fixes for us units Modified Paths: -------------- pytrainer/trunk/extensions/fixelevation/fixelevation.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/lib/gpx.py pytrainer/trunk/pytrainer/lib/unitsconversor.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/extensions/fixelevation/fixelevation.py =================================================================== --- pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/extensions/fixelevation/fixelevation.py 2010-10-29 04:45:15 UTC (rev 669) @@ -15,9 +15,10 @@ self.options = options self.conf_dir = conf_dir - def run(self, id, activity=None): #TODO Convert to use activity... + def run(self, aid, activity=None): #TODO Convert to use activity... + print activity logging.debug(">>") - gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, id) + gpx_file = "%s/gpx/%s.gpx" % (self.conf_dir, aid) ele_fixed = True if os.path.isfile(gpx_file): @@ -36,6 +37,9 @@ """ self._data = etree.parse(gpx_file) self._xmlns = self._data.getroot().nsmap[None] + nsmap = self._data.getroot().nsmap + pyt_ns = "http://sourceforge.net.project/pytrainer/GPX/0/1" + PYTRAINER = "{%s}" % pyt_ns self._trkpt_path = '{%s}trk/{%s}trkseg/{%s}trkpt' % (self._xmlns, self._xmlns, self._xmlns) """ @@ -48,16 +52,31 @@ ele = trkpt.find('{%s}ele' % self._xmlns) ele_new = self._srtm.get_elevation(lat, lon) + #Add new elevation to extension tag + ''' + <extensions> + <pytrainer:ele method="srtm_bilinear">31.1</pytrainer:ele> + </extensions> + ''' + ext = etree.Element("extensions") + py_ele = etree.SubElement(ext, PYTRAINER + "ele", method="srtm_bilinear") + py_ele.text = str(ele_new) + + #print etree.tostring(ext) + + if not ele_new: ele_fixed = False break - if ele is not None: - ele.text = str(ele_new) - else: - ele = etree.Element('ele') - ele.text = str(ele_new) - trkpt.append(ele) + #if ele is not None: + # #ele.text = str(ele_new) + # ele.append(ext) + #else: + # ele = etree.Element('ele') + # ele.append(py_ele) + trkpt.append(ext) + if ele_fixed: # Write out to original *.gpx. self._data.write( gpx_file, @@ -65,6 +84,8 @@ xml_declaration=True, pretty_print=False) res_msg = "Elevation has been fixed." + #TODO Expire activity out of pool - so get updated info + self.pytrainer_main.activitypool.remove_activity(aid) else: res_msg = "Elevation could not be fixed!" Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-10-29 04:45:15 UTC (rev 669) @@ -566,7 +566,7 @@ # self.recordview.set_sensitive(0) logging.debug("<<") - def actualize_dayview(self,record_list): + def actualize_dayview(self,record_list=None, activity_list=None): logging.debug(">>") if self.pytrainer_main.profile.getValue("pytraining","prf_us_system") == "True": self.d_distance_unit.set_text(_("miles")) Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-10-29 04:45:15 UTC (rev 669) @@ -125,6 +125,65 @@ self.y2_limits_u = (None, None) self.show_laps = False logging.debug("<<") + + def __str__(self): + return ''' + tracks (%s) + tracklist (%s) + laps (%s) + tree (%s) + us_system (%s) + distance_unit (%s) + speed_unit (%s) + distance_data (%s) + time_data (%s) + height_unit (%s) + pace_unit (%s) + gpx_file (%s) + gpx (%s) + sport_name (%s) + sport_id (%s) + title (%s) + date (%s) + time (%s) + time_tuple (%s) + beats (%s) + maxbeats (%s) + comments (%s) + calories (%s) + id_record (%s) + date_time_local (%s) + date_time_utc (%s) + date_time (%s) + starttime (%s) + distance (%s) + average (%s) + upositive (%s) + unegative (%s) + maxspeed (%s) + maxpace (%s) + pace (%s) + has_data (%s) + x_axis (%s) + x_limits (%s) + y1_limits (%s) + y2_limits (%s) + x_limits_u (%s) + y1_limits_u (%s) + y2_limits_u (%s) + show_laps (%s) + lap_distance (%s) + lap_time (%s) + pace_limit (%s) + ''' % ('self.tracks', self.tracklist, self.laps, self.tree, self.us_system, + self.distance_unit, self.speed_unit, self.distance_data, self.time_data, + self.height_unit, self.pace_unit, self.gpx_file, self.gpx, self.sport_name, + self.sport_id, self.title, self.date, self.time, self.time_tuple, self.beats, + self.maxbeats, self.comments, self.calories, self.id_record, self.date_time_local, + self.date_time_utc, self.date_time, self.starttime, self.distance, self.average, + self.upositive, self.unegative, self.maxspeed, self.maxpace, self.pace, self.has_data, + self.x_axis, self.x_limits, self.y1_limits, self.y2_limits, self.x_limits_u, self.y1_limits_u, + self.y2_limits_u, self.show_laps, self.lap_distance, self.lap_time, self.pace_limit) def _set_units(self): if self.us_system: @@ -163,25 +222,25 @@ "maxspeed","maxpace","pace","maxbeats","date_time_utc","date_time_local", "sports.max_pace"), "id_record=\"%s\" and records.sport=sports.id_sports" %self.id) if len(db_result) == 1: - dict = db_result[0] - self.sport_name = dict['sports.name'] - self.sport_id = dict['id_sports'] - self.pace_limit = dict['sports.max_pace'] + _dict = db_result[0] + self.sport_name = _dict['sports.name'] + self.sport_id = _dict['id_sports'] + self.pace_limit = _dict['sports.max_pace'] if self.pace_limit == 0 or self.pace_limit == "": self.pace_limit = None - self.title = dict['title'] - self.date = dict['date'] - self.time = self._int(dict['time']) + self.title = _dict['title'] + self.date = _dict['date'] + self.time = self._int(_dict['time']) self.time_tuple = Date().second2time(self.time) - self.beats = self._int(dict['beats']) - self.comments = dict['comments'] - self.calories = self._int(dict['calories']) - self.id_record = dict['id_record'] - self.maxbeats = self._int(dict['maxbeats']) + self.beats = self._int(_dict['beats']) + self.comments = _dict['comments'] + self.calories = self._int(_dict['calories']) + self.id_record = _dict['id_record'] + self.maxbeats = self._int(_dict['maxbeats']) #Sort time.... # ... use local time if available otherwise use date_time_utc and create a local datetime... - self.date_time_local = dict['date_time_local'] - self.date_time_utc = dict['date_time_utc'] + self.date_time_local = _dict['date_time_local'] + self.date_time_utc = _dict['date_time_utc'] if self.date_time_local is not None: #Have a local time stored in DB self.date_time = dateutil.parser.parse(self.date_time_local) self.starttime = self.date_time.strftime("%X") @@ -191,21 +250,21 @@ self.starttime = self.date_time.strftime("%X") #Sort data that changes for the US etc if self.us_system: - self.distance = km2miles(self._float(dict['distance'])) - self.average = km2miles(self._float(dict['average'])) - self.upositive = m2feet(self._float(dict['upositive'])) - self.unegative = m2feet(self._float(dict['unegative'])) - self.maxspeed = km2miles(self._float(dict['maxspeed'])) - self.maxpace = pacekm2miles(self._float(dict['maxpace'])) - self.pace = pacekm2miles(self._float(dict['pace'])) + self.distance = km2miles(self._float(_dict['distance'])) + self.average = km2miles(self._float(_dict['average'])) + self.upositive = m2feet(self._float(_dict['upositive'])) + self.unegative = m2feet(self._float(_dict['unegative'])) + self.maxspeed = km2miles(self._float(_dict['maxspeed'])) + self.maxpace = pacekm2miles(self._float(_dict['maxpace'])) + self.pace = pacekm2miles(self._float(_dict['pace'])) else: - self.distance = self._float(dict['distance']) - self.average = self._float(dict['average']) - self.upositive = self._float(dict['upositive']) - self.unegative = self._float(dict['unegative']) - self.maxspeed = self._float(dict['maxspeed']) - self.maxpace = self._float(dict['maxpace']) - self.pace = self._float(dict['pace']) + self.distance = self._float(_dict['distance']) + self.average = self._float(_dict['average']) + self.upositive = self._float(_dict['upositive']) + self.unegative = self._float(_dict['unegative']) + self.maxspeed = self._float(_dict['maxspeed']) + self.maxpace = self._float(_dict['maxpace']) + self.pace = self._float(_dict['pace']) self.has_data = True else: raise Exception( "Error - multiple results from DB for id: %s" % self.id ) @@ -306,6 +365,15 @@ self.time_data['elevation'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel) self.time_data['elevation'].set_color('#ff0000', '#ff0000') self.time_data['elevation'].show_on_y1 = True #Make graph show elevation by default + #Corrected Elevation... + title=_("Corrected Elevation") + xlabel="%s (%s)" % (_('Distance'), self.distance_unit) + ylabel="%s (%s)" % (_('Corrected Elevation'), self.height_unit) + self.distance_data['cor_elevation'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel) + self.distance_data['cor_elevation'].set_color('#993333', '#993333') + xlabel=_("Time (seconds)") + self.time_data['cor_elevation'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel) + self.time_data['cor_elevation'].set_color('#993333', '#993333') #Speed title=_("Speed") xlabel="%s (%s)" % (_('Distance'), self.distance_unit) @@ -353,20 +421,24 @@ pace = 0 if self.us_system: self.distance_data['elevation'].addPoints(x=km2miles(track['elapsed_distance']), y=m2feet(track['ele'])) + self.distance_data['cor_elevation'].addPoints(x=km2miles(track['elapsed_distance']), y=m2feet(track['correctedElevation'])) self.distance_data['speed'].addPoints(x=km2miles(track['elapsed_distance']), y=km2miles(track['velocity'])) self.distance_data['pace'].addPoints(x=km2miles(track['elapsed_distance']), y=pacekm2miles(pace)) self.distance_data['hr'].addPoints(x=km2miles(track['elapsed_distance']), y=track['hr']) self.distance_data['cadence'].addPoints(x=km2miles(track['elapsed_distance']), y=track['cadence']) self.time_data['elevation'].addPoints(x=track['time_elapsed'], y=m2feet(track['ele'])) + self.time_data['cor_elevation'].addPoints(x=track['time_elapsed'], y=m2feet(track['correctedElevation'])) self.time_data['speed'].addPoints(x=track['time_elapsed'], y=km2miles(track['velocity'])) self.time_data['pace'].addPoints(x=track['time_elapsed'], y=pacekm2miles(pace)) else: self.distance_data['elevation'].addPoints(x=track['elapsed_distance'], y=track['ele']) + self.distance_data['cor_elevation'].addPoints(x=track['elapsed_distance'], y=track['correctedElevation']) self.distance_data['speed'].addPoints(x=track['elapsed_distance'], y=track['velocity']) self.distance_data['pace'].addPoints(x=track['elapsed_distance'], y=pace) self.distance_data['hr'].addPoints(x=track['elapsed_distance'], y=track['hr']) self.distance_data['cadence'].addPoints(x=track['elapsed_distance'], y=track['cadence']) self.time_data['elevation'].addPoints(x=track['time_elapsed'], y=track['ele']) + self.time_data['cor_elevation'].addPoints(x=track['time_elapsed'], y=track['correctedElevation']) self.time_data['speed'].addPoints(x=track['time_elapsed'], y=track['velocity']) self.time_data['pace'].addPoints(x=track['time_elapsed'], y=pace) self.time_data['hr'].addPoints(x=track['time_elapsed'], y=track['hr']) Modified: pytrainer/trunk/pytrainer/lib/gpx.py =================================================================== --- pytrainer/trunk/pytrainer/lib/gpx.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/pytrainer/lib/gpx.py 2010-10-29 04:45:15 UTC (rev 669) @@ -48,6 +48,9 @@ elapsedTimeTag = gpxdataNS.substitute(tag="elapsedTime") distanceTag = gpxdataNS.substitute(tag="distance") +pytrainerNS = string.Template(".//{http://sourceforge.net.project/pytrainer/GPX/0/1}$tag") +pyt_eleTag = pytrainerNS.substitute(tag="ele") + class Gpx: def __init__(self, data_path = None, filename = None, trkname = None): logging.debug(">>") @@ -277,6 +280,18 @@ ele = None else: ele = None + + #Get corrected elevation if it exists + correctedEleResult = trkpoint.find(pyt_eleTag) + if correctedEleResult is not None: + try: + corEle = float(correctedEleResult.text) + #Calculate elevation change + except Exception as e: + logging.debug(str(e)) + corEle = None + else: + corEle = None #Calculate climb or decent amount #Allow for some 'jitter' in height here @@ -308,18 +323,18 @@ #This 'fills in' the data for situations where some times are missing from the GPX file if time_ is not None: if len(waiting_points) > 0: - for ((w_total_dist, w_dist, w_alt, w_total_time, w_lat, w_lon, w_hr, w_cadence)) in waiting_points: + for ((w_total_dist, w_dist, w_alt, w_total_time, w_lat, w_lon, w_hr, w_cadence, w_corEle)) in waiting_points: w_time = (w_dist/dist_elapsed) * time_elapsed w_vel = w_dist/((w_time)/3600.0) w_total_time += w_time - retorno.append((w_total_dist, w_alt, w_total_time, w_vel, w_lat, w_lon, w_hr, w_cadence)) + retorno.append((w_total_dist, w_alt, w_total_time, w_vel, w_lat, w_lon, w_hr, w_cadence, w_corEle)) waiting_points = [] dist_elapsed = 0 else: - retorno.append((total_dist,ele, self.total_time,vel,lat,lon,hr,cadence)) + retorno.append((total_dist,ele, self.total_time,vel,lat,lon,hr,cadence,corEle)) dist_elapsed = 0 else: # time_ is None - waiting_points.append((total_dist, dist_elapsed, ele, self.total_time, lat, lon, hr, cadence)) + waiting_points.append((total_dist, dist_elapsed, ele, self.total_time, lat, lon, hr, cadence, corEle)) #Add to dict of values to trkpoint list self.trkpoints.append({ 'id': i, @@ -335,6 +350,7 @@ 'distance_from_previous': dist, 'elapsed_distance': total_dist, 'velocity':vel, + 'correctedElevation':corEle, }) Modified: pytrainer/trunk/pytrainer/lib/unitsconversor.py =================================================================== --- pytrainer/trunk/pytrainer/lib/unitsconversor.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/pytrainer/lib/unitsconversor.py 2010-10-29 04:45:15 UTC (rev 669) @@ -17,25 +17,57 @@ #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. def km2miles(kilometers): - return kilometers*0.621371192 + try: + km = float(kilometers) + return km*0.621371192 + except Exception as e: + return 0.0 def miles2mk(miles): - return miles/0.621371192 + try: + m = float(miles) + return m/0.621371192 + except Exception as e: + return 0.0 def pacekm2miles(kilometers): - return kilometers/0.621371192 + try: + km = float(kilometers) + return km/0.621371192 + except Exception as e: + return 0.0 def pacemiles2mk(miles): - return miles*0.621371192 + try: + m = float(miles) + return m*0.621371192 + except Exception as e: + return 0.0 def m2feet(meter): - return meter*3.2808399 + try: + m = float(meter) + return m*3.2808399 + except Exception as e: + return 0.0 def feet2m(feet): - return feet/3.2808399 + try: + m = float(feet) + return m/3.2808399 + except Exception as e: + return 0.0 def kg2pound(kg): - return kg*2.20462262 + try: + m = float(kg) + return m*2.20462262 + except Exception as e: + return 0.0 def pound2kg(pound): - return pound/2.20462262 + try: + m = float(pound) + return m/2.20462262 + except Exception as e: + return 0.0 Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-10-28 23:38:47 UTC (rev 668) +++ pytrainer/trunk/pytrainer/main.py 2010-10-29 04:45:15 UTC (rev 669) @@ -231,7 +231,7 @@ elif view=="day": logging.debug('day view') record_list = self.record.getrecordList(date_selected) - self.windowmain.actualize_dayview(record_list) + self.windowmain.actualize_dayview(record_list=record_list) #selected,iter = self.windowmain.recordTreeView.get_selection().get_selected() elif view=="week": logging.debug('week view') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-01 23:06:40
|
Revision: 673 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=673&view=rev Author: jblance Date: 2010-11-01 23:06:33 +0000 (Mon, 01 Nov 2010) Log Message: ----------- Fix unified imported to accept Nokia exported GPX files - with sport support Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowrecord.py pytrainer/trunk/pytrainer/lib/activity.py Added Paths: ----------- pytrainer/trunk/import/file_gpxplusNokia.py pytrainer/trunk/schemas/Topografix_gpx11-Nokia.xsd Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-01 03:53:00 UTC (rev 672) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-01 23:06:33 UTC (rev 673) @@ -36,11 +36,12 @@ </child> <child> <widget class="GtkImageMenuItem" id="menu_importdata"> - <property name="label">_Import</property> + <property name="label" translatable="yes">_Import</property> <property name="visible">True</property> <property name="use_underline">True</property> <property name="use_stock">False</property> <signal name="activate" handler="on_menu_importdata_activate"/> + <accelerator key="i" signal="activate" modifiers="GDK_CONTROL_MASK"/> <child internal-child="image"> <widget class="GtkImage" id="image1"> <property name="visible">True</property> Added: pytrainer/trunk/import/file_gpxplusNokia.py =================================================================== --- pytrainer/trunk/import/file_gpxplusNokia.py (rev 0) +++ pytrainer/trunk/import/file_gpxplusNokia.py 2010-11-01 23:06:33 UTC (rev 673) @@ -0,0 +1,130 @@ +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Fiz Vazquez vu...@si... +# Modified by dgranda + +#This program is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public License +#as published by the Free Software Foundation; either version 2 +#of the License, or (at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import logging +import os +#import StringIO +from lxml import etree +from pytrainer.lib.date import Date + +class gpxplusNokia(): + def __init__(self, parent = None, data_path = None): + self.parent = parent + self.pytrainer_main = parent.parent + self.tmpdir = self.pytrainer_main.profile.tmpdir + self.main_data_path = data_path + self.data_path = os.path.dirname(__file__) + self.xmldoc = None + self.activitiesSummary = [] + + def getXmldoc(self): + ''' Function to return parsed xmlfile ''' + return self.xmldoc + + def getFileType(self): + return _("Nokia Export - GPS eXchange file") + + def getActivitiesSummary(self): + return self.activitiesSummary + + def testFile(self, filename): + logging.debug('>>') + logging.debug("Testing " + filename) + #Check if file is a GPX + try: + #parse as xml + xmldoc = etree.parse(filename) + #Parse XML schema + xmlschema_doc = etree.parse(self.main_data_path+"schemas/Topografix_gpx11-Nokia.xsd") + xmlschema = etree.XMLSchema(xmlschema_doc) + if (xmlschema.validate(xmldoc)): + #Valid gpx file + self.xmldoc = xmldoc + startTime = self.getDateTime(self.startTimeFromFile(xmldoc)) + indatabase = self.inDatabase(xmldoc, startTime) + sport = self.getSport(xmldoc) + duration = self.getDetails(xmldoc, startTime) + distance = "" + self.activitiesSummary.append( (0, + indatabase, + startTime[1].strftime("%Y-%m-%dT%H:%M:%S"), + distance , + str(duration), + sport, + ) ) + return True + except: + #Not gpx file + return False + return False + + def getDateTime(self, time_): + return Date().getDateTime(time_) + + def inDatabase(self, tree, startTime): + #comparing date and start time (sport may have been changed in DB after import) + time = startTime + if time is None: + return False + time = time[0].strftime("%Y-%m-%dT%H:%M:%SZ") + if self.parent.parent.ddbb.select("records","*","date_time_utc=\"%s\"" % (time)): + return True + else: + return False + + def getDetails(self, tree, startTime): + root = tree.getroot() + #Get all times from file + times = root.findall(".//{http://www.topografix.com/GPX/1/1}time") + time = times[-1].text + return self.getDateTime(time)[0]-startTime[0] + + def getSport(self, tree): + #No sport in GPX file + root = tree.getroot() + element = root.find(".//{http://www.topografix.com/GPX/1/1}metadata/{http://www.topografix.com/GPX/1/1}desc") + if element is not None: + return element.text + return None + + def startTimeFromFile(self, tree): + """ Function to return the first time element from a GPX 1.1 file """ + root = tree.getroot() + timeElement = root.find(".//{http://www.topografix.com/GPX/1/1}time") + if timeElement is not None: + return timeElement.text + return None + + def getGPXFile(self, ID, file_id): + """ + Generate GPX file based on activity ID + + Returns (sport, GPX filename) + """ + sport = None + gpxFile = None + if ID == "0": #Only one activity in file + gpxFile = "%s/gpx-%s-%s.gpx" % (self.tmpdir, file_id, ID) + sport = self.getSport(self.xmldoc) + self.createGPXfile(gpxFile, self.xmldoc) + return sport, gpxFile + + def createGPXfile(self, gpxfile, tree): + tree.write(gpxfile, xml_declaration=True, encoding='UTF-8') + Modified: pytrainer/trunk/pytrainer/gui/windowrecord.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-11-01 03:53:00 UTC (rev 672) +++ pytrainer/trunk/pytrainer/gui/windowrecord.py 2010-11-01 23:06:33 UTC (rev 673) @@ -387,6 +387,7 @@ self.activity_data[row]["rcd_starttime"] = start_time self.activity_data[row]["date_time_local"] = gpx_summary['date_time_local'] self.activity_data[row]["date_time_utc"] = gpx_summary['date_time_utc'] + self.activity_data[row]["rcd_distance"] = gpx_summary["rcd_distance"] self.activity_data[row]["rcd_average"] = gpx_summary["rcd_average"] self.activity_data[row]["rcd_calories"] = gpx_summary["rcd_calories"] self.activity_data[row]["rcd_beats"] = gpx_summary["rcd_beats"] @@ -447,7 +448,7 @@ gtk.main_iteration() # before completion of this entire action #Get some info from gpx file self.update_activity_data(row, gpx_file, sport) - + self.setValue("rcd_distance",self.activity_data[row]["rcd_distance"], "%s") self.setValue("rcd_date", self.activity_data[row]["rcd_date"], "%s") self.setValue("rcd_starttime", self.activity_data[row]["rcd_starttime"], "%s") self.setValue("rcd_average",self.activity_data[row]["rcd_average"]) Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-11-01 03:53:00 UTC (rev 672) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-11-01 23:06:33 UTC (rev 673) @@ -101,6 +101,7 @@ self.time_data = {} self.pace_limit = None self.starttime = None + self.gpx_distance = None #self.upositive = 0 #self.unegative = 0 if self.pytrainer_main.profile.getValue("pytraining","prf_us_system") == "True": @@ -210,6 +211,8 @@ self.tree = self.gpx.tree self.tracks = self.gpx.getTrackList() #TODO fix - this should removed and replaced with self.tracklist functionality self.tracklist = self.gpx.trkpoints + self.gpx_distance = self.gpx.total_dist + print "GPX Distance: %s" % self.gpx_distance logging.debug("<<") def _init_from_db(self): @@ -261,6 +264,8 @@ # self.pace = pacekm2miles(self._float(_dict['pace'])) #else: self.distance = self._float(_dict['distance']) + if not self.distance: + self.distance = self.gpx_distance self.average = self._float(_dict['average']) self.upositive = self._float(_dict['upositive']) self.unegative = self._float(_dict['unegative']) Added: pytrainer/trunk/schemas/Topografix_gpx11-Nokia.xsd =================================================================== --- pytrainer/trunk/schemas/Topografix_gpx11-Nokia.xsd (rev 0) +++ pytrainer/trunk/schemas/Topografix_gpx11-Nokia.xsd 2010-11-01 23:06:33 UTC (rev 673) @@ -0,0 +1,800 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.topografix.com/GPX/1/1" targetNamespace="http://www.topografix.com/GPX/1/1" elementFormDefault="qualified"> + +<xsd:annotation> + <xsd:documentation> + GPX schema version 1.1 - For more information on GPX and this schema, visit http://www.topografix.com/gpx.asp + + GPX uses the following conventions: all coordinates are relative to the WGS84 datum. All measurements are in metric units. + </xsd:documentation> +</xsd:annotation> + + <xsd:element name="gpx" type="gpxType"> + <xsd:annotation> + <xsd:documentation> + GPX is the root element in the XML file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:complexType name="gpxType"> + <xsd:annotation> + <xsd:documentation> + GPX documents contain a metadata header, followed by waypoints, routes, and tracks. You can add your own elements + to the extensions section of the GPX document. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="metadata" type="metadataType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Metadata about the file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="wpt" type="wptType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A list of waypoints. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="rte" type="rteType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A list of routes. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="trk" type="trkType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A list of tracks. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + + <xsd:attribute name="version" type="xsd:string" use="required" fixed="1.1"> + <xsd:annotation> + <xsd:documentation> + You must include the version number in your GPX document. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="creator" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation> + You must include the name or URL of the software that created your GPX document. This allows others to + inform the creator of a GPX instance document that fails to validate. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="metadataType"> + <xsd:annotation> + <xsd:documentation> + Information about the GPX file, author, and copyright restrictions goes in the metadata section. Providing rich, + meaningful information about your GPX files allows others to search for and use your GPS data. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="name" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The name of the GPX file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="desc" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + A description of the contents of the GPX file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="author" type="personType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The person or organization who created the GPX file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="copyright" type="copyrightType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Copyright and license information governing use of the file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="link" type="linkType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + URLs associated with the location described in the file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="time" type="xsd:dateTime" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The creation date of the file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="keywords" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Keywords associated with the file. Search engines or databases can use this information to classify the data. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="bounds" type="boundsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Minimum and maximum coordinates which describe the extent of the coordinates in the file. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="wptType"> + <xsd:annotation> + <xsd:documentation> + wpt represents a waypoint, point of interest, or named feature on a map. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <!-- Position info --> + <xsd:element name="ele" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Elevation (in meters) of the point. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <!-- Nokia export modifications --> + <xsd:element name="speed" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The speed as calculated by the device + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="course" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The direction? as calculated by the device + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="desc" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + A text description of the element. Holds additional information about the element intended for the user, not the GPS. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="time" type="xsd:dateTime" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Creation/modification timestamp for element. Date and time in are in Univeral Coordinated Time (UTC), not local time! Conforms to ISO 8601 specification for date/time representation. Fractional seconds are allowed for millisecond timing in tracklogs. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="magvar" type="degreesType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Magnetic variation (in degrees) at the point + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="geoidheight" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Height (in meters) of geoid (mean sea level) above WGS84 earth ellipsoid. As defined in NMEA GGA message. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <!-- Description info --> + <xsd:element name="name" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The GPS name of the waypoint. This field will be transferred to and from the GPS. GPX does not place restrictions on the length of this field or the characters contained in it. It is up to the receiving application to validate the field before sending it to the GPS. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="cmt" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS waypoint comment. Sent to GPS as comment. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="src" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Source of data. Included to give user some idea of reliability and accuracy of data. "Garmin eTrex", "USGS quad Boston North", e.g. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="link" type="linkType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + Link to additional information about the waypoint. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="sym" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Text of GPS symbol name. For interchange with other programs, use the exact spelling of the symbol as displayed on the GPS. If the GPS abbreviates words, spell them out. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="type" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Type (classification) of the waypoint. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <!-- Accuracy info --> + <xsd:element name="fix" type="fixType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Type of GPX fix. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="sat" type="xsd:nonNegativeInteger" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Number of satellites used to calculate the GPX fix. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="hdop" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Horizontal dilution of precision. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="vdop" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Vertical dilution of precision. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="pdop" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Position dilution of precision. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="ageofdgpsdata" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Number of seconds since last DGPS update. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="dgpsid" type="dgpsStationType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + ID of DGPS station used in differential correction. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + + <xsd:attribute name="lat" type="latitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The latitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="lon" type="longitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The latitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="rteType"> + <xsd:annotation> + <xsd:documentation> + rte represents route - an ordered list of waypoints representing a series of turn points leading to a destination. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="name" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS name of route. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="cmt" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS comment for route. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="desc" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Text description of route for user. Not sent to GPS. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="src" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Source of data. Included to give user some idea of reliability and accuracy of data. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="link" type="linkType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + Links to external information about the route. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="number" type="xsd:nonNegativeInteger" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS route number. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="type" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Type (classification) of route. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="rtept" type="wptType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A list of route points. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="trkType"> + <xsd:annotation> + <xsd:documentation> + trk represents a track - an ordered list of points describing a path. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="name" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS name of track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="cmt" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS comment for track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="desc" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + User description of track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="src" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Source of data. Included to give user some idea of reliability and accuracy of data. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="link" type="linkType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + Links to external information about track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="number" type="xsd:nonNegativeInteger" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + GPS track number. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="type" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Type (classification) of track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="trkseg" type="trksegType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A Track Segment holds a list of Track Points which are logically connected in order. To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off, start a new Track Segment for each continuous span of track data. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="extensionsType"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> + <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:any> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="trksegType"> + <xsd:annotation> + <xsd:documentation> + A Track Segment holds a list of Track Points which are logically connected in order. To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off, start a new Track Segment for each continuous span of track data. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="trkpt" type="wptType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + A Track Point holds the coordinates, elevation, timestamp, and metadata for a single point in a track. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + + <xsd:element name="extensions" type="extensionsType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + You can add extend GPX by adding your own elements from another schema here. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="copyrightType"> + <xsd:annotation> + <xsd:documentation> + Information about the copyright holder and any license governing use of this file. By linking to an appropriate license, + you may place your data into the public domain or grant additional usage rights. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="year" type="xsd:gYear" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Year of copyright. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="license" type="xsd:anyURI" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Link to external file containing license text. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="author" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation> + Copyright holder (TopoSoft, Inc.) + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="linkType"> + <xsd:annotation> + <xsd:documentation> + A link to an external resource (Web page, digital photo, video clip, etc) with additional information. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="text" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Text of hyperlink. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="type" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Mime type of content (image/jpeg) + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="href" type="xsd:anyURI" use="required"> + <xsd:annotation> + <xsd:documentation> + URL of hyperlink. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="emailType"> + <xsd:annotation> + <xsd:documentation> + An email address. Broken into two parts (id and domain) to help prevent email harvesting. + </xsd:documentation> + </xsd:annotation> + <xsd:attribute name="id" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation> + id half of email address (billgates2004) + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="domain" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation> + domain half of email address (hotmail.com) + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="personType"> + <xsd:annotation> + <xsd:documentation> + A person or organization. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="name" type="xsd:string" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Name of person or organization. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="email" type="emailType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Email address. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="link" type="linkType" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + Link to Web site or other external information about person. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="ptType"> + <xsd:annotation> + <xsd:documentation> + A geographic point with optional elevation and time. Available for use by other schemas. + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="ele" type="xsd:decimal" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The elevation (in meters) of the point. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="time" type="xsd:dateTime" minOccurs="0"> + <xsd:annotation> + <xsd:documentation> + The time that the point was recorded. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="lat" type="latitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The latitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="lon" type="longitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The latitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="ptsegType"> + <xsd:annotation> + <xsd:documentation> + An ordered sequence of points. (for polygons or polylines, e.g.) + </xsd:documentation> + </xsd:annotation> + <xsd:sequence> <!-- elements must appear in this order --> + <xsd:element name="pt" type="ptType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation> + Ordered list of geographic points. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="boundsType"> + <xsd:annotation> + <xsd:documentation> + Two lat/lon pairs defining the extent of an element. + </xsd:documentation> + </xsd:annotation> + <xsd:attribute name="minlat" type="latitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The minimum latitude. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="minlon" type="longitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The minimum longitude. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="maxlat" type="latitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The maximum latitude. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="maxlon" type="longitudeType" use="required"> + <xsd:annotation> + <xsd:documentation> + The maximum longitude. + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + + <xsd:simpleType name="latitudeType"> + <xsd:annotation> + <xsd:documentation> + The latitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + <xsd:restriction base="xsd:decimal"> + <xsd:minInclusive value="-90.0"/> + <xsd:maxInclusive value="90.0"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="longitudeType"> + <xsd:annotation> + <xsd:documentation> + The longitude of the point. Decimal degrees, WGS84 datum. + </xsd:documentation> + </xsd:annotation> + <xsd:restriction base="xsd:decimal"> + <xsd:minInclusive value="-180.0"/> + <xsd:maxExclusive value="180.0"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="degreesType"> + <xsd:annotation> + <xsd:documentation> + Used for bearing, heading, course. Units are decimal degrees, true (not magnetic). + </xsd:documentation> + </xsd:annotation> + <xsd:restriction base="xsd:decimal"> + <xsd:minInclusive value="0.0"/> + <xsd:maxExclusive value="360.0"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="fixType"> + <xsd:annotation> + <xsd:documentation> + Type of GPS fix. none means GPS had no fix. To signify "the fix info is unknown, leave out fixType entirely. pps = military signal used + </xsd:documentation> + </xsd:annotation> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="2d"/> + <xsd:enumeration value="3d"/> + <xsd:enumeration value="dgps"/> + <xsd:enumeration value="pps"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="dgpsStationType"> + <xsd:annotation> + <xsd:documentation> + Represents a differential GPS station. + </xsd:documentation> + </xsd:annotation> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="1023"/> + </xsd:restriction> + </xsd:simpleType> + +</xsd:schema> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-03 03:18:39
|
Revision: 674 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=674&view=rev Author: jblance Date: 2010-11-03 03:18:31 +0000 (Wed, 03 Nov 2010) Log Message: ----------- Add extra graph data to old graph, still need to migrate to newgraph (from Patrick). Remove Googlemaps API v2 as option (v3 only now), remove testimport options (is no longer experimental) Modified Paths: -------------- pytrainer/trunk/glade/profile.glade pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/extensions/googlemaps.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/gui/windowprofile.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py pytrainer/trunk/pytrainer/recordgraph.py Modified: pytrainer/trunk/glade/profile.glade =================================================================== --- pytrainer/trunk/glade/profile.glade 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/glade/profile.glade 2010-11-03 03:18:31 UTC (rev 674) @@ -1,4 +1,4 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="UTF-8"?> <glade-interface> <!-- interface-requires gtk+ 2.10 --> <!-- interface-naming-policy toplevel-contextual --> @@ -362,7 +362,7 @@ <widget class="GtkEntry" id="entry345"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">6</property> </widget> <packing> @@ -539,7 +539,7 @@ <property name="width_request">108</property> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="expand">False</property> @@ -788,7 +788,7 @@ <widget class="GtkEntry" id="newsportentry"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -824,7 +824,7 @@ <widget class="GtkEntry" id="newmetentry"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -851,7 +851,7 @@ <widget class="GtkEntry" id="newweightentry"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -891,15 +891,6 @@ </packing> </child> <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> <widget class="GtkLabel" id="label-10"> <property name="visible">True</property> <property name="xalign">0</property> @@ -916,7 +907,7 @@ <widget class="GtkEntry" id="newmaxpace"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -926,6 +917,15 @@ <property name="y_options"></property> </packing> </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> </widget> <packing> <property name="position">0</property> @@ -1190,7 +1190,7 @@ <widget class="GtkEntry" id="editsportentry"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -1215,7 +1215,7 @@ <widget class="GtkEntry" id="editmetentry"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -1242,7 +1242,7 @@ <widget class="GtkEntry" id="editweightentry"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -1287,7 +1287,7 @@ <widget class="GtkEntry" id="editmaxpace"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> </widget> <packing> <property name="left_attach">1</property> @@ -1469,7 +1469,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">4</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> </widget> <packing> @@ -1484,7 +1484,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="max_length">4</property> - <property name="invisible_char">●</property> + <property name="invisible_char">●</property> <property name="width_chars">4</property> </widget> <packing> @@ -1850,100 +1850,6 @@ </packing> </child> <child> - <widget class="GtkLabel" id="labelGM3"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="ypad">5</property> - <property name="label" translatable="yes">Googlemaps v3</property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - </packing> - </child> - <child> - <widget class="GtkCheckButton" id="checkbuttonGM3"> - <property name="label">--gmaps2*</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="xalign">0</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_checkbuttonGM3_toggled"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_padding">10</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelGM3Description"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="ypad">5</property> - <property name="label" translatable="yes"><small>Is the Googlemaps API version 3 in use?</small></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelUnifiedImport"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="ypad">5</property> - <property name="label" translatable="yes">Unified Import</property> - </widget> - <packing> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - </packing> - </child> - <child> - <widget class="GtkCheckButton" id="checkbuttonUnifiedImport"> - <property name="label">--testimport</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="xalign">0</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_checkbuttonUnifiedImport_toggled"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="x_padding">10</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="labelUnifiedImportDescription"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="label" translatable="yes"><small>Is the Unified Importer active?</small></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - </packing> - </child> - <child> <widget class="GtkLabel" id="labelEquip"> <property name="visible">True</property> <property name="xalign">0</property> @@ -2033,6 +1939,24 @@ <property name="bottom_attach">7</property> </packing> </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> </widget> </child> </widget> @@ -2058,18 +1982,7 @@ </packing> </child> <child> - <widget class="GtkLabel" id="labelNote"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="yalign">0</property> - <property name="xpad">5</property> - <property name="ypad">5</property> - <property name="label" translatable="yes"><small>* Note Googlemaps API version 3 is on by default, use --gmaps2 to switch it off</small></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="position">2</property> - </packing> + <placeholder/> </child> </widget> <packing> Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-03 03:18:31 UTC (rev 674) @@ -1111,7 +1111,9 @@ Speed Pace Heart Rate -Cadence</property> +Cadence +Percentage +Zone</property> <signal name="changed" handler="on_day_combovalue_changed"/> </widget> <packing> Modified: pytrainer/trunk/pytrainer/extensions/googlemaps.py =================================================================== --- pytrainer/trunk/pytrainer/extensions/googlemaps.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/extensions/googlemaps.py 2010-11-03 03:18:31 UTC (rev 674) @@ -16,15 +16,12 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -import gtkmozembed import os import re import logging -#from pytrainer.lib.gpx import Gpx import pytrainer.lib.points as Points from pytrainer.lib.fileUtils import fileUtils -#from pytrainer.record import Record class Googlemaps: def __init__(self, data_path = None, waypoint = None, pytrainer_main=None): @@ -37,7 +34,7 @@ def drawMap(self,activity): '''Draw google map - create html file using Google API version?? + create html file using Google API version3 render using embedded Mozilla info at http://www.pygtk.org/pygtkmozembed/class-gtkmozembed.html @@ -65,20 +62,16 @@ logging.debug("minlon: %s, maxlon: %s" % (minlon, maxlon)) points,levels = Points.encodePoints(pointlist) points = points.replace("\\","\\\\") - if self.pytrainer_main.startup_options.gm3: - logging.debug("Using Google Maps version 3 API") - laps = activity.laps - timeHours = int(activity.time) / 3600 - timeMin = (float(activity.time) / 3600.0 - timeHours) * 60 - time = "%d%s %02d%s" % (timeHours, _("h"), timeMin, _("min")) - startinfo = "<div class='info_content'>%s: %s</div>" % (activity.sport_name, activity.title) - finishinfo = "<div class='info_content'>%s: %s<br>%s: %s%s</div>" % (_("Time"), time, _("Distance"), activity.distance, activity.distance_unit) - startinfo = startinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html - finishinfo = finishinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html - self.createHtml_api3(polyline, minlat, minlon, maxlat, maxlon, startinfo, finishinfo, laps) - else: - logging.debug("Using Google Maps version 2 API") - self.createHtml(points,levels,pointlist[0]) + logging.debug("Using Google Maps version 3 API") + laps = activity.laps + timeHours = int(activity.time) / 3600 + timeMin = (float(activity.time) / 3600.0 - timeHours) * 60 + time = "%d%s %02d%s" % (timeHours, _("h"), timeMin, _("min")) + startinfo = "<div class='info_content'>%s: %s</div>" % (activity.sport_name, activity.title) + finishinfo = "<div class='info_content'>%s: %s<br>%s: %s%s</div>" % (_("Time"), time, _("Distance"), activity.distance, activity.distance_unit) + startinfo = startinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html + finishinfo = finishinfo.encode('ascii', 'xmlcharrefreplace') #Encode for html + self.createHtml_api3(polyline, minlat, minlon, maxlat, maxlon, startinfo, finishinfo, laps) else: self.createErrorHtml() return self.htmlfile @@ -230,108 +223,6 @@ file.run() logging.debug("<<") - def createHtml(self,points,levels,init_point): - logging.debug(">>") - if self.waypoint is not None: - waypoints = self.waypoint.getAllWaypoints() - else: - waypoints = [] - content = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n" - content += " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" - content += " <html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:v=\"urn:schemas-microsoft-com:vml\">\n" - content += " <head>\n" - content += " <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/>\n" - content += " <title>Google Maps JavaScript API Example</title>\n" - content += " <script id=\"googleapiimport\" src=\"http://maps.google.com/maps?file=api&v=2\"\n" - content += " type=\"text/javascript\"></script>\n" - content += " <script type=\"text/javascript\">\n" - content += " //<![CDATA[\n" - i = 0 - arrayjs = "" - for point in waypoints: - content += "lon = '%f';\n"%point[2] - content += "lat = '%f';\n"%point[1] - content += "name = '%s';\n"%point[6] - content += "description = '%s';\n"%point[4] - content += "sym = '%s';\n"%point[7] - content += "id = '%d';\n"%point[0] - content += """waypoint%d = Array (lon,lat,name,description,sym,id);\n"""%i - if i>0: - arrayjs+="," - arrayjs +="waypoint%d"%i - i = i+1 - content += """waypointList = Array (%s);\n""" %arrayjs - content += """ - function createMarker(waypoint,map) { - var lon = waypoint[0]; - var lat = waypoint[1]; - var id = waypoint[5]; - var name = waypoint[2]; - var description = waypoint[3]; - - var point = new GLatLng(lat,lon); - var text = "<b>"+waypoint[2]+"</b><br/>"+waypoint[3]; - - var icon = new GIcon(); - if (sym=="Summit") { - icon.image = \""""+os.path.abspath(self.data_path)+"""/glade/summit.png\"; - } - else { - icon.image = \""""+os.path.abspath(self.data_path)+"""/glade/waypoint.png\"; - } - icon.iconSize = new GSize(32, 32); - icon.iconAnchor = new GPoint(16, 16); - icon.infoWindowAnchor = new GPoint(5, 1); - - var markerD = new GMarker(point, {icon:icon, draggable: false}); - GEvent.addListener(markerD, "click", function() { - markerD.openInfoWindowHtml("<b>" + name + "</b><br/>"+description); - }); - map.addOverlay(markerD); - - }""" - - content += " function load() {\n" - content += " if (GBrowserIsCompatible()) {\n" - content += " var map = new GMap2(document.getElementById(\"map\"));\n" - content += " map.addControl(new GLargeMapControl());\n" - content += " map.addControl(new GMapTypeControl());\n" - content += " map.addControl(new GScaleControl());\n" - content += " map.setCenter(new GLatLng(%f,%f), 11);\n" %(float(init_point[0]),float(init_point[1])) - content += " ovMap=new GOverviewMapControl();\n" - content += " map.addControl(ovMap);\n" - content += " mini=ovMap.getOverviewMap();\n" - content += " //Dibujamos los waypoints\n" - content += " for (i=0; i<waypointList.length; i++){\n" - content += " createMarker(waypointList[i],map);\n" - content += " map.enableDragging();\n" - content += " }\n" - content += " document.getElementById('map').style.top='0px';\n" - content += " document.getElementById('map').style.left='0px';\n" - content += " document.getElementById('map').style.width='100%';\n" - content += " // Add an encoded polyline.\n" - content += " var encodedPolyline = new GPolyline.fromEncoded({\n" - content += " color: \"#3333cc\",\n" - content += " weight: 10,\n" - content += " points: \"%s\",\n" %points - content += " levels: \"%s\",\n" %levels - content += " zoomFactor: 32,\n" - content += " numLevels: 4\n" - content += " });\n" - content += " map.addOverlay(encodedPolyline);\n" - content += " }\n" - content += " }\n " - content += " //]]>\n" - content += " </script>\n" - content += " </head>\n" - content += " <body onload=\"load()\" onunload=\"GUnload()\">\n" - content += " <div id=\"map\" style=\"width: 520px; height: 480px\"></div>\n" - content += " </body>\n" - content += "</html>\n" - file = fileUtils(self.htmlfile,content) - file.run() - logging.debug("<<") - def createErrorHtml(self): logging.debug(">>") content = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-03 03:18:31 UTC (rev 674) @@ -82,7 +82,6 @@ self.listsearch = ListSearch(self, self.pytrainer_main) def new(self): - self.testimport = self.pytrainer_main.startup_options.testimport self.menublocking = 0 self.selected_view="day" self.window1.set_title ("pyTrainer %s" % self.version) @@ -132,9 +131,6 @@ self.allRecordTreeView.set_search_column(1) self.notebook.set_current_page(1) - #Disable import menu item unless specified on startup - self.set_unified_import(self.testimport) - #Set correct map viewer if self.pytrainer_main.profile.getValue("pytraining","default_viewer") == "1": self.radiobuttonOSM.set_active(1) @@ -160,10 +156,6 @@ page = self.notebook.get_current_page() self.on_page_change(None,None,page) - def set_unified_import(self, status=False): - self.menu_importdata.set_sensitive(status) - self.parent.testimport = status - def _createXmlListView(self,file): menufile = XMLParser(file) savedOptions = [] @@ -214,7 +206,7 @@ self.parent.runExtension(extension,id) def createGraphs(self,RecordGraph,DayGraph,WeekGraph, MonthGraph,YearGraph,HeartRateGraph): - self.drawarearecord = RecordGraph(self.record_graph_vbox, self.window1, self.record_combovalue, self.record_combovalue2, self.btnShowLaps, self.tableConfigY1) + self.drawarearecord = RecordGraph(self.record_graph_vbox, self.window1, self.record_combovalue, self.record_combovalue2, self.btnShowLaps, self.tableConfigY1, pytrainer_main=self.pytrainer_main) self.drawareaheartrate = HeartRateGraph(self.heartrate_vbox, self.window1, self.heartrate_vbox2, pytrainer_main=self.pytrainer_main) #self.drawareaday = DayGraph(self.day_vbox, self.day_combovalue) self.day_vbox.hide() Modified: pytrainer/trunk/pytrainer/gui/windowprofile.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowprofile.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/gui/windowprofile.py 2010-11-03 03:18:31 UTC (rev 674) @@ -200,19 +200,7 @@ self.checkbuttonCheck.set_active(True) else: self.checkbuttonCheck.set_active(False) - - #Show if using Googlemaps API v3 - if self.pytrainer_main.startup_options.gm3: - self.checkbuttonGM3.set_active(True) - else: - self.checkbuttonGM3.set_active(False) - #Show if unified import activated - if self.pytrainer_main.startup_options.testimport: - self.checkbuttonUnifiedImport.set_active(True) - else: - self.checkbuttonUnifiedImport.set_active(False) - #Show if new graph activated if self.pytrainer_main.startup_options.newgraph: self.checkbuttonNewGraph.set_active(True) @@ -254,32 +242,6 @@ else: logging.debug("Check deactivated") self.pytrainer_main.startup_options.check = False - - def on_checkbuttonGM3_toggled(self, widget): - if self.checkbuttonGM3.get_active(): - logging.debug("GM3 activated") - self.pytrainer_main.startup_options.gm3 = True - else: - logging.debug("GM3 deactivated") - self.pytrainer_main.startup_options.gm3 = False - - def on_checkbuttonUnifiedImport_toggled(self, widget): - if self.checkbuttonUnifiedImport.get_active(): - logging.debug("Unified Import activated") - if self.pytrainer_main.startup_options.testimport is not True: - #Need to enable unified import - logging.debug("Need to enable unified import") - self.pytrainer_main.windowmain.set_unified_import(True) - else: - #No change - logging.debug("No change to unified import") - else: - logging.debug("Unified Import deactivated") - if self.pytrainer_main.startup_options.testimport is True: - logging.debug("Need to deactivate unified import") - self.pytrainer_main.windowmain.set_unified_import(False) - else: - logging.debug("No change to unified import") def on_checkbuttonNewGraph_toggled(self, widget): if self.checkbuttonNewGraph.get_active(): Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-11-03 03:18:31 UTC (rev 674) @@ -212,7 +212,7 @@ self.tracks = self.gpx.getTrackList() #TODO fix - this should removed and replaced with self.tracklist functionality self.tracklist = self.gpx.trkpoints self.gpx_distance = self.gpx.total_dist - print "GPX Distance: %s" % self.gpx_distance + logging.debug("GPX Distance: %s" % self.gpx_distance) logging.debug("<<") def _init_from_db(self): Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/main.py 2010-11-03 03:18:31 UTC (rev 674) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#672" + self.version ="1.7.2_svn#674" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() @@ -113,14 +113,12 @@ For more help on valid options try: %prog -h ''' parser = OptionParser(usage=usage) - parser.set_defaults(log_level=logging.ERROR, validate=False, gm3=True, testimport=True, equip=False, newgraph=False) + parser.set_defaults(log_level=logging.ERROR, validate=False, equip=False, newgraph=False) parser.add_option("-d", "--debug", action="store_const", const=logging.DEBUG, dest="log_level", help="enable logging at debug level") parser.add_option("-i", "--info", action="store_const", const=logging.INFO, dest="log_level", help="enable logging at info level") parser.add_option("-w", "--warn", action="store_const", const=logging.WARNING, dest="log_level", help="enable logging at warning level") parser.add_option("--valid", action="store_true", dest="validate", help="enable validation of files imported by plugins (details at info or debug logging level) - note plugin must support validation") parser.add_option("--check", action="store_true", dest="check", help="triggers database (only sqlite based) and configuration file sanity checks, adding fields if necessary. Backup of database is done before any change. Details at info or debug logging level") - parser.add_option("--gmaps2", action="store_false", dest="gm3", help="Use old Google Maps API version (v2)") - parser.add_option("--testimport", action="store_true", dest="testimport", help="EXPERIMENTAL: show new import functionality - for testing only USE AT YOUR OWN RISK") parser.add_option("--equip", action="store_false", dest="equip", help="EXPERIMENTAL: enable equipment management") parser.add_option("--newgraph", action="store_true", dest="newgraph", help="EXPERIMENTAL: new graphing approach") (options, args) = parser.parse_args() @@ -231,19 +229,20 @@ self.refreshRecordGraphView("heartrate") elif view=="day": logging.debug('day view') - record_list = self.record.getrecordList(date_selected) + sport = self.windowmain.activeSport + record_list = self.record.getrecordList(date_selected, sport) self.windowmain.actualize_dayview(record_list=record_list) #selected,iter = self.windowmain.recordTreeView.get_selection().get_selected() elif view=="week": logging.debug('week view') date_ini, date_end = self.date.getWeekInterval(date_selected, self.profile.prf_us_system) - sport = self.windowmain.getSportSelected() + sport = self.windowmain.activeSport record_list = self.record.getrecordPeriod(date_ini, date_end, sport) self.windowmain.actualize_weekview(record_list, date_ini, date_end) elif view=="month": logging.debug('month view') date_ini, date_end = self.date.getMonthInterval(date_selected) - sport = self.windowmain.getSportSelected() + sport = self.windowmain.activeSport record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport) nameMonth, daysInMonth = self.date.getNameMonth(date_selected) self.windowmain.actualize_monthview(record_list, nameMonth) @@ -251,7 +250,7 @@ elif view=="year": logging.debug('year view') date_ini, date_end = self.date.getYearInterval(date_selected) - sport = self.windowmain.getSportSelected() + sport = self.windowmain.activeSport year = self.date.getYear(date_selected) record_list = self.record.getrecordPeriodSport(date_ini, date_end,sport) self.windowmain.actualize_yearview(record_list, year) @@ -310,10 +309,11 @@ self.refreshListView(self.windowmain.listsearch.condition) #Refresh list records date = self.date.getDate() - record_ids = self.record.getrecordList(date) + id_sport = self.windowmain.activeSport + record_ids = self.record.getrecordList(date, id_sport) self.windowmain.actualize_recordTreeView(record_ids) #Mark the monthly calendar to show which days have activity? - record_list = self.record.getRecordDayList(date) + record_list = self.record.getRecordDayList(date, id_sport) self.windowmain.actualize_calendar(record_list) logging.debug('<<') Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/record.py 2010-11-03 03:18:31 UTC (rev 674) @@ -324,11 +324,16 @@ "sports.name,date,distance,time,beats,comments,average,calories,id_record,title,upositive,unegative,maxspeed,maxpace,pace,maxbeats,date_time_utc,date_time_local", "id_record=\"%s\" and records.sport=sports.id_sports" %id_record) - def getrecordList(self,date): + def getrecordList(self,date, id_sport=None): logging.debug('--') - return self.pytrainer_main.ddbb.select("records,sports", + if not id_sport: + return self.pytrainer_main.ddbb.select("records,sports", "sports.name,date,distance,time,beats,comments,average,calories,id_record,maxspeed,maxbeats,date_time_utc,date_time_local", "date=\"%s\" and records.sport=sports.id_sports" %date) + else: + return self.pytrainer_main.ddbb.select("records,sports", + "sports.name,date,distance,time,beats,comments,average,calories,id_record,maxspeed,maxbeats,date_time_utc,date_time_local", + "date=\"%s\" and sports.id_sports=\"%s\" and records.sport=sports.id_sports" %(date,id_sport)) def getLaps(self, id_record): logging.debug('--') @@ -449,12 +454,15 @@ "date,distance,average,title,sports.name,id_record,time,beats,calories", "sports.id_sports = records.sport and %s" %condition) - def getRecordDayList(self,date): + def getRecordDayList(self,date, id_sport=None): logging.debug('>>') year,month,day = date.split("-") logging.debug('Retrieving data for '+year+'.'+month+'.'+day) # Why is looking for all days of the same month? - records = self.pytrainer_main.ddbb.select("records","date","date LIKE '"+year+"-"+month+"-%'") + if not id_sport: + records = self.pytrainer_main.ddbb.select("records","date","date LIKE '"+year+"-"+month+"-%'") + else: + records = self.ddbb.select("records","date","date LIKE \"%s-%s-%%\" and sport=\"%s\"" %(year,month,id_sport)) logging.debug('Found '+str(len(records))+' entries') day_list = [] for i in records: Modified: pytrainer/trunk/pytrainer/recordgraph.py =================================================================== --- pytrainer/trunk/pytrainer/recordgraph.py 2010-11-01 23:06:33 UTC (rev 673) +++ pytrainer/trunk/pytrainer/recordgraph.py 2010-11-03 03:18:31 UTC (rev 674) @@ -18,153 +18,170 @@ import logging from gui.drawArea import DrawArea + import gtk class RecordGraph: - def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None, btnShowLaps = None, tableConfig = None): - logging.debug(">>") - self.drawarea = DrawArea(vbox, window) - self.combovalue = combovalue - self.combovalue2 = combovalue2 - self.showLaps = btnShowLaps - self.config_table = tableConfig - logging.debug("<<") + def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None, btnShowLaps = None, tableConfig = None, pytrainer_main=None): + logging.debug(">>") + self.pytrainer_main = pytrainer_main + self.drawarea = DrawArea(vbox, window) + self.combovalue = combovalue + self.combovalue2 = combovalue2 + self.showLaps = btnShowLaps + self.config_table = tableConfig + logging.debug("<<") - def drawgraph(self,values,laps=None, y1limits=None, y1color=None, y1_linewidth=1): - logging.debug(">>") - #Get the config options - for child in self.config_table.get_children(): - if child.get_name() == "spinbuttonY1Max": - spinbuttonY1Max = child - elif child.get_name() == "spinbuttonY1Min": - spinbuttonY1Min = child - elif child.get_name() == "colorbuttonY1LineColor": - colorbuttonY1LineColor = child - elif child.get_name() == "spinbuttonY1LineWeight": - spinbuttonY1LineWeight = child + def drawgraph(self,values,laps=None, y1limits=None, y1color=None, y1_linewidth=1): + logging.debug(">>") + #Get the config options + for child in self.config_table.get_children(): + if child.get_name() == "spinbuttonY1Max": + spinbuttonY1Max = child + elif child.get_name() == "spinbuttonY1Min": + spinbuttonY1Min = child + elif child.get_name() == "colorbuttonY1LineColor": + colorbuttonY1LineColor = child + elif child.get_name() == "spinbuttonY1LineWeight": + spinbuttonY1LineWeight = child - xval = [] - yval = [] - xlab = [] - ylab = [] - tit = [] - col = [] - value_selected = self.combovalue.get_active() - logging.debug("Value selected 1: "+ str(value_selected)) - value_selected2 = self.combovalue2.get_active() - logging.debug("Value selected 2: "+ str(value_selected2)) - showLaps = self.showLaps.get_active() - logging.debug("Show laps: "+ str(showLaps)) - #Determine left and right lap boundaries - if laps is not None and showLaps: - lapValues = [] - lastPoint = 0.0 - for lap in laps: - thisPoint = float(lap['distance'])/1000.0 + lastPoint - lapValues.append((lastPoint, thisPoint)) - lastPoint = thisPoint - else: - lapValues = None + xval = [] + yval = [] + xlab = [] + ylab = [] + tit = [] + col = [] + value_selected = self.combovalue.get_active() + logging.debug("Value selected 1: "+ str(value_selected)) + value_selected2 = self.combovalue2.get_active() + logging.debug("Value selected 2: "+ str(value_selected2)) + showLaps = self.showLaps.get_active() + logging.debug("Show laps: "+ str(showLaps)) + #Determine left and right lap boundaries + if laps is not None and showLaps: + lapValues = [] + lastPoint = 0.0 + for lap in laps: + thisPoint = float(lap['distance'])/1000.0 + lastPoint + lapValues.append((lastPoint, thisPoint)) + lastPoint = thisPoint + else: + lapValues = None - if value_selected < 0: - self.combovalue.set_active(0) - value_selected = 0 + if value_selected < 0: + self.combovalue.set_active(0) + value_selected = 0 - if value_selected2 < 0: - self.combovalue2.set_active(0) - value_selected2 = 0 - xvalues, yvalues = self.get_values(values,value_selected) - max_yvalue = max(yvalues) - min_yvalue = min(yvalues) - xlabel,ylabel,title,color = self.get_value_params(value_selected) - if y1color is not None: - _color = gtk.gdk.Color(y1color) - color = y1color - else: - _color = gtk.gdk.Color(color) + if value_selected2 < 0: + self.combovalue2.set_active(0) + value_selected2 = 0 + xvalues, yvalues = self.get_values(values,value_selected) + max_yvalue = max(yvalues) + min_yvalue = min(yvalues) + xlabel,ylabel,title,color = self.get_value_params(value_selected) + if y1color is not None: + _color = gtk.gdk.Color(y1color) + color = y1color + else: + _color = gtk.gdk.Color(color) - xval.append(xvalues) - yval.append(yvalues) - if value_selected2 > 0: - xlab.append("") - else: - xlab.append(xlabel) - ylab.append(ylabel) - tit.append(title) - col.append(color) + xval.append(xvalues) + yval.append(yvalues) + if value_selected2 > 0: + xlab.append("") + else: + xlab.append(xlabel) + ylab.append(ylabel) + tit.append(title) + col.append(color) - #_color = gtk.gdk.Color(color) - colorbuttonY1LineColor.set_color(_color) + #_color = gtk.gdk.Color(color) + colorbuttonY1LineColor.set_color(_color) - if value_selected2 > 0: - value_selected2 = value_selected2-1 - xlabel,ylabel,title,color = self.get_value_params(value_selected2) - xvalues,yvalues = self.get_values(values,value_selected2) - max_yvalue=max(max(yvalues), max_yvalue) - min_yvalue=min(min(yvalues), min_yvalue) - xval.append(xvalues) - yval.append(yvalues) - xlab.append(xlabel) - ylab.append(ylabel) - tit.append("") - col.append(color) - logging.info("To show: tit: "+str(tit)+" | col: "+str(col)+" | xlab: "+str(xlab)+" | ylab: "+str(ylab)) - #self.drawPlot(xvalues,yvalues,xlabel,ylabel,title,color,zones) - plot_stats = self.drawarea.drawPlot(xval,yval,xlab,ylab,tit,col,None,lapValues, ylimits=y1limits, y1_linewidth=y1_linewidth) - ymin = plot_stats['y1_min'] - ymax = plot_stats['y1_max'] - y1_linewidth = plot_stats['y1_linewidth'] + if value_selected2 > 0: + value_selected2 = value_selected2-1 + xlabel,ylabel,title,color = self.get_value_params(value_selected2) + xvalues,yvalues = self.get_values(values,value_selected2) + max_yvalue=max(max(yvalues), max_yvalue) + min_yvalue=min(min(yvalues), min_yvalue) + xval.append(xvalues) + yval.append(yvalues) + xlab.append(xlabel) + ylab.append(ylabel) + tit.append("") + col.append(color) + logging.info("To show: tit: "+str(tit)+" | col: "+str(col)+" | xlab: "+str(xlab)+" | ylab: "+str(ylab)) + #self.drawPlot(xvalues,yvalues,xlabel,ylabel,title,color,zones) + plot_stats = self.drawarea.drawPlot(xval,yval,xlab,ylab,tit,col,None,lapValues, ylimits=y1limits, y1_linewidth=y1_linewidth) + ymin = plot_stats['y1_min'] + ymax = plot_stats['y1_max'] + y1_linewidth = plot_stats['y1_linewidth'] - max_yvalue = max(max_yvalue, ymax) - min_yvalue = min(min_yvalue, ymin) - adjY1Min = gtk.Adjustment(value=ymin, lower=min_yvalue,upper=max_yvalue, step_incr=1, page_incr=10) - adjY1Max = gtk.Adjustment(value=ymax, lower=min_yvalue,upper=max_yvalue, step_incr=1, page_incr=10) - spinbuttonY1Min.set_adjustment(adjY1Min) - spinbuttonY1Max.set_adjustment(adjY1Max) - spinbuttonY1Min.set_value(ymin) - spinbuttonY1Max.set_value(ymax) - spinbuttonY1LineWeight.set_value(y1_linewidth) + max_yvalue = max(max_yvalue, ymax) + min_yvalue = min(min_yvalue, ymin) + adjY1Min = gtk.Adjustment(value=ymin, lower=min_yvalue,upper=max_yvalue, step_incr=1, page_incr=10) + adjY1Max = gtk.Adjustment(value=ymax, lower=min_yvalue,upper=max_yvalue, step_incr=1, page_incr=10) + spinbuttonY1Min.set_adjustment(adjY1Min) + spinbuttonY1Max.set_adjustment(adjY1Max) + spinbuttonY1Min.set_value(ymin) + spinbuttonY1Max.set_value(ymax) + spinbuttonY1LineWeight.set_value(y1_linewidth) - logging.debug("<<") + logging.debug("<<") - def get_value_params(self,value): - if value == 0: - return _("Distance (km)"),_("Height (m)"),_("Stage Profile"),"#000000" - if value == 1: - return _("Distance (km)"),_("Speed (Km/h)"),_("Speed"),"#00ff00" - if value == 2: - return _("Distance (km)"),_("Pace (min/km)"),_("Pace"),"#0000ff" - if value == 3: - return _("Distance (km)"),_("Beats (bpm)"),_("Heart Rate"),"#ff0000" - if value == 4: - return _("Distance (km)"),_("Cadence (rpm)"),_("Cadence"),"#7B3F00" + def get_value_params(self,value): + if value == 0: + return _("Distance (km)"),_("Height (m)"),_("Stage Profile"),"#000000" + if value == 1: + return _("Distance (km)"),_("Speed (Km/h)"),_("Speed"),"#00ff00" + if value == 2: + return _("Distance (km)"),_("Pace (min/km)"),_("Pace"),"#0000ff" + if value == 3: + return _("Distance (km)"),_("Beats (bpm)"),_("Heart Rate"),"#ff0000" + if value == 4: + return _("Distance (km)"),_("Cadence (rpm)"),_("Cadence"),"#7B3F00" + if value == 5: + return _("Distance (km)"),_("Beats (%)"),_("Beats"),"#ff0000" + if value == 6: + return _("Distance (km)"),_("Zone"),_("Zone"),"#ff0000" - def get_values(self,values, value_selected): - logging.debug(">>") - xvalue = [] - yvalue = [] - for value in values: - xvalue.append(value[0]) - if value_selected==0: - yvalue.append(value[1]) - if value_selected==1: - yvalue.append(value[3]) - if value_selected==2: - try: - yvalue.append(60/value[3]) - except: - yvalue.append(0) - if value_selected==3: - yvalue.append(value[6]) - if value_selected==4: - yvalue.append(value[7]) - logging.debug("<<") - return xvalue,yvalue + def get_values(self,values, value_selected): + logging.debug(">>") + xvalue = [] + yvalue = [] + zones = self.pytrainer_main.profile.getZones() + for value in values: + xvalue.append(value[0]) + if value_selected==0: + yvalue.append(value[1]) + if value_selected==1: + yvalue.append(value[3]) + if value_selected==2: + try: + yvalue.append(60/value[3]) + except: + yvalue.append(0) + if value_selected==3: + yvalue.append(value[6]) + if value_selected==4: + yvalue.append(value[7]) + if value_selected==5: + if value[6] <= zones[4][0]: + yvalue.append(50.0*value[6]/zones[4][0]) + else: + yvalue.append(50.0+50.0*((value[6]-zones[4][0])/(zones[0][1]-zones[4][0]))) + if value_selected==6: + if value[6] <= zones[4][0]: + yvalue.append(1.0*value[6]/zones[4][0]) + else: + yvalue.append(1.0+5.0*((value[6]-zones[4][0])/(zones[0][1]-zones[4][0]))) + logging.debug("<<") + return xvalue,yvalue - def getFloatValue(self, value): - try: - return float(value) - except: - return float(0) + def getFloatValue(self, value): + try: + return float(value) + except: + return float(0) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jb...@us...> - 2010-11-04 01:46:44
|
Revision: 677 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=677&view=rev Author: jblance Date: 2010-11-04 01:46:37 +0000 (Thu, 04 Nov 2010) Log Message: ----------- Modification of activity to better support value conversion Modified Paths: -------------- pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-03 08:36:49 UTC (rev 676) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-04 01:46:37 UTC (rev 677) @@ -816,74 +816,6 @@ </packing> </child> <child> - <widget class="GtkHBox" id="hbox37"> - <property name="visible">True</property> - <child> - <widget class="GtkLabel" id="record_hour"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label">00</property> - </widget> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label11132"> - <property name="visible">True</property> - <property name="label">:</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="record_minute"> - <property name="visible">True</property> - <property name="label">00</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">2</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label11133"> - <property name="visible">True</property> - <property name="label">:</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">3</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="record_second"> - <property name="visible">True</property> - <property name="xalign">1</property> - <property name="label">00</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">4</property> - </packing> - </child> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> <widget class="GtkLabel" id="r_speed_unit"> <property name="visible">True</property> <property name="xalign">0</property> @@ -964,6 +896,18 @@ <child> <placeholder/> </child> + <child> + <widget class="GtkLabel" id="record_duration"> + <property name="visible">True</property> + <property name="xalign">1</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> </widget> <packing> <property name="expand">False</property> Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-03 08:36:49 UTC (rev 676) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2010-11-04 01:46:37 UTC (rev 677) @@ -275,6 +275,26 @@ def actualize_recordview(self,activity): logging.debug(">>") if activity.id is None: + #Blank out fields + self.record_distance.set_text("") + self.record_upositive.set_text("") + self.record_unegative.set_text("") + self.record_average.set_text("") + self.record_maxspeed.set_text("") + self.record_pace.set_text("") + self.record_maxpace.set_text("") + self.record_sport.set_text("") + self.record_date.set_text("") + self.record_time.set_text("") + self.record_duration.set_text("") + #self.record_minute.set_text("") + #self.record_second.set_text("") + self.record_calories.set_text("") + self.record_title.set_text("") + com_buffer = self.record_comments.get_buffer() + start,end = com_buffer.get_bounds() + com_buffer.set_text("") + #Move to main record page and grey out self.recordview.set_current_page(0) self.recordview.set_sensitive(0) logging.debug("<<") @@ -297,23 +317,19 @@ recordTime = dateTime.strftime("%X") recordDateTimeOffset = dateTime.strftime("%z") - self.record_distance.set_text("%0.2f" %activity.get_value('distance')) - self.record_upositive.set_text("%0.2f" %activity.get_value('upositive')) - self.record_unegative.set_text("%0.2f" %activity.get_value('unegative')) - self.record_average.set_text("%0.2f" %activity.get_value('average')) - self.record_maxspeed.set_text("%0.2f" %activity.get_value('maxspeed')) - self.record_pace.set_text(activity.get_value('pace')) - self.record_maxpace.set_text(activity.get_value('maxpace')) + self.record_distance.set_text(activity.get_value_f('distance', "%0.2f")) + self.record_upositive.set_text(activity.get_value_f('upositive', "%0.2f")) + self.record_unegative.set_text(activity.get_value_f('unegative', "%0.2f")) + self.record_average.set_text(activity.get_value_f('average', "%0.2f")) + self.record_maxspeed.set_text(activity.get_value_f('maxspeed', "%0.2f")) + self.record_pace.set_text(activity.get_value_f('pace', "%s")) + self.record_maxpace.set_text(activity.get_value_f('maxpace', "%s")) self.record_sport.set_text(activity.sport_name) - #self.record_date.set_text(str(date)) self.record_date.set_text(recordDate) self.record_time.set_text(recordTime) - hour,min,sec=self.parent.date.second2time(int(activity.time)) - self.record_hour.set_text("%d" %hour) - self.record_minute.set_text("%02d" %min) - self.record_second.set_text("%02d" %sec) - self.record_calories.set_text("%0.0f" %activity.calories) + self.record_duration.set_text(activity.get_value_f('time', '%s')) + self.record_calories.set_text(activity.get_value_f('calories', "%0.0f")) self.record_title.set_text(activity.title) buffer = self.record_comments.get_buffer() start,end = buffer.get_bounds() Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2010-11-03 08:36:49 UTC (rev 676) +++ pytrainer/trunk/pytrainer/lib/activity.py 2010-11-04 01:46:37 UTC (rev 677) @@ -199,6 +199,7 @@ self.speed_unit = _("km/h") self.pace_unit = _("min/km") self.height_unit = _("m") + self.units = { 'distance': self.distance_unit, 'average': self.speed_unit, 'upositive': self.height_unit, 'unegative': self.height_unit, 'maxspeed': self.speed_unit, 'pace': self.pace_unit, 'maxpace': self.pace_unit } def _init_from_gpx_file(self): ''' @@ -492,6 +493,25 @@ result = 0 return result + def get_value_f(self, param, format=None, with_units=False): + ''' Function to return a value formated as a string + - takes into account US/metric + - also appends units if required + ''' + value = self.get_value(param) + if not value: + #Return blank string if value is None or 0 + return "" + if format is not None: + result = format % value + else: + result = str(value) + if with_units: + if param in self.units: + result += self.units[param] + #print "activity: 509", result + return result + def get_value(self, param): ''' Function to get the value of various params in this activity instance Automatically returns values converted to imperial if needed @@ -531,8 +551,19 @@ return self.pace_from_float(pacekm2miles(self.pace)) else: return self.pace_from_float(self.pace) + elif param == 'calories': + return self.calories + elif param == 'time': + if not self.time: + return "" + _hour,_min,_sec=self.pytrainer_main.date.second2time(self.time) + if _hour == 0: + return "%02d:%02d" % (_min, _sec) + else: + return "%0d:%02d:%02d" % (_hour, _min, _sec) else: print "Unable to provide value for unknown parameter (%s) for activity" % param + return None def set_value(self, param, value): ''' Function to set the value of various params in this activity instance @@ -592,6 +623,8 @@ def pace_from_float(self, value): '''Helper to generate mm:ss from float representation mm.ss (or mm,ss?)''' #Check that value supplied is a float + if not value: + return "" try: _value = "%0.2f" % float(value) except ValueError: Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2010-11-03 08:36:49 UTC (rev 676) +++ pytrainer/trunk/pytrainer/main.py 2010-11-04 01:46:37 UTC (rev 677) @@ -50,7 +50,7 @@ class pyTrainer: def __init__(self,filename = None, data_path = None): #Version constants - self.version ="1.7.2_svn#676" + self.version ="1.7.2_svn#677" self.DB_version = 6 #Process command line options self.startup_options = self.get_options() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dg...@us...> - 2010-11-06 09:49:52
|
Revision: 678 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=678&view=rev Author: dgranda Date: 2010-11-06 09:49:44 +0000 (Sat, 06 Nov 2010) Log Message: ----------- Basic equipment management - thx to ncjones Modified Paths: -------------- pytrainer/trunk/glade/newrecord.glade pytrainer/trunk/glade/profile.glade pytrainer/trunk/glade/pytrainer.glade pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/gui/windowprofile.py pytrainer/trunk/pytrainer/gui/windowrecord.py pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py Added Paths: ----------- pytrainer/trunk/glade/equipment.glade pytrainer/trunk/pytrainer/equipment.py pytrainer/trunk/pytrainer/gui/equipment.py pytrainer/trunk/test/ pytrainer/trunk/test/pytrainer/ pytrainer/trunk/test/pytrainer/equipment_test.py pytrainer/trunk/test/pytrainer/gui/ pytrainer/trunk/test/pytrainer/gui/equipment_test.py Added: pytrainer/trunk/glade/equipment.glade =================================================================== --- pytrainer/trunk/glade/equipment.glade (rev 0) +++ pytrainer/trunk/glade/equipment.glade 2010-11-06 09:49:44 UTC (rev 678) @@ -0,0 +1,642 @@ +<?xml version="1.0"?> +<interface> + <!-- interface-requires gtk 2.6 --> + <!-- interface-naming-policy project-wide --> + <object class="GtkNotebook" id="notebookEquipment"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="show_tabs">False</property> + <property name="show_border">False</property> + <child> + <object class="GtkFrame" id="frameEquipmentList"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignmentEquipmentList"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <object class="GtkVBox" id="vboxEquipmentList"> + <property name="visible">True</property> + <property name="border_width">5</property> + <child> + <object class="GtkScrolledWindow" id="scrolledwindowEquipmentList"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="treeviewEquipmentList"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hboxEquipmentListButtons"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="buttonEquipmentDelete"> + <property name="label">gtk-delete</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="delete_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="buttonEquipmentEdit"> + <property name="label">gtk-edit</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="edit_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="buttonEquipmentAdd"> + <property name="label">gtk-add</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="add_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="labelEquipmentList"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Equipment List</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="tab_expand">True</property> + </packing> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <object class="GtkFrame" id="frameEquipmentAdd"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignmentEquipmentAdd"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <object class="GtkVBox" id="vboxEquipmentAdd"> + <property name="visible">True</property> + <property name="border_width">5</property> + <child> + <object class="GtkHBox" id="hboxEquipmentAddDetails"> + <property name="visible">True</property> + <child> + <object class="GtkTable" id="tableEquipmentAddDetails"> + <property name="visible">True</property> + <property name="n_rows">4</property> + <property name="n_columns">2</property> + <property name="row_spacing">5</property> + <child> + <object class="GtkLabel" id="labelEquipmentAddDescription"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="xpad">5</property> + <property name="label" translatable="yes">Description</property> + </object> + <packing> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entryEquipmentAddDescription"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + <property name="width_chars">35</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkLabel" id="labelEquipmentAddLifeExpectancy"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="xpad">5</property> + <property name="label" translatable="yes">Life Expectancy</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkAlignment" id="alignment3"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xscale">0</property> + <child> + <object class="GtkEntry" id="entryEquipmentAddLifeExpectancy"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + <property name="width_chars">8</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="checkbuttonEquipmentAddActive"> + <property name="label" translatable="yes">Active</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkAlignment" id="alignment6"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkLabel" id="labelEquipmentAddNotes"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="yalign">0</property> + <property name="xpad">5</property> + <property name="ypad">5</property> + <property name="label" translatable="yes">Notes</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTextView" id="textviewEquipmentAddNotes"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hboxEquipmentAddButtons"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="buttonEquipmentAddCancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="cancel_add_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="buttonEquipmentAddConfirm"> + <property name="label">gtk-add</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="confirm_add_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="labelEquipmentAdd"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Add New Equipment</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <object class="GtkFrame" id="frameEquipmentEdit"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignmentEquipmentEdit"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <object class="GtkVBox" id="vboxEquipmentEdit"> + <property name="visible">True</property> + <property name="border_width">5</property> + <child> + <object class="GtkHBox" id="hboxEquipmentEditDetails"> + <property name="visible">True</property> + <child> + <object class="GtkTable" id="tableEquipmentEditDetails"> + <property name="visible">True</property> + <property name="n_rows">4</property> + <property name="n_columns">2</property> + <property name="row_spacing">5</property> + <child> + <object class="GtkLabel" id="labelEquipmentEditDescription"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="xpad">5</property> + <property name="label" translatable="yes">Description</property> + </object> + <packing> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entryEquipmentEditDescription"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + <property name="width_chars">35</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkLabel" id="labelEquipmentEditLifeExpectancy"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="xpad">5</property> + <property name="label" translatable="yes">Life Expectancy</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xscale">0</property> + <child> + <object class="GtkEntry" id="entryEquipmentEditLifeExpectancy"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + <property name="width_chars">8</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="checkbuttonEquipmentEditActive"> + <property name="label" translatable="yes">Active</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkAlignment" id="alignment8"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkLabel" id="labelEquipmentEditNotes"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="yalign">0</property> + <property name="xpad">5</property> + <property name="ypad">5</property> + <property name="label" translatable="yes">Notes</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTextView" id="textviewEquipmentEditNotes"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hboxEquipmentEditButtons"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="buttonEquipmentEditCancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="cancel_edit_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="buttonEquipmentEditConfirm"> + <property name="label">gtk-save</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="confirm_edit_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="labelEquipmentEdit"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Edit Equipment</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <object class="GtkFrame" id="frameEquipmentDelete"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignmentEquipmentDelete"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <object class="GtkVBox" id="vboxEquipmentDelete"> + <property name="visible">True</property> + <property name="border_width">5</property> + <child> + <object class="GtkLabel" id="labelEquipmentDeleteConfirm"> + <property name="visible">True</property> + <property name="label" translatable="yes">Really delete the equipment item?</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonboxEquipmentDeleteButtons"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="buttonEquipmentDeleteCancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="cancel_delete_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="buttonEquipmentDeleteConfirm"> + <property name="label">gtk-ok</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="confirm_delete_equipment_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="labelEquipmentDelete"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Delete Equipment</b></property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="position">3</property> + </packing> + </child> + <child type="tab"> + <placeholder/> + </child> + </object> +</interface> Modified: pytrainer/trunk/glade/newrecord.glade =================================================================== --- pytrainer/trunk/glade/newrecord.glade 2010-11-04 01:46:37 UTC (rev 677) +++ pytrainer/trunk/glade/newrecord.glade 2010-11-06 09:49:44 UTC (rev 678) @@ -1100,6 +1100,68 @@ <property name="type">tab</property> </packing> </child> + <child> + <widget class="GtkFrame" id="frameRecordEquipment"> + <property name="visible">True</property> + <property name="border_width">5</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <widget class="GtkAlignment" id="alignmentRecordEquipment"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <widget class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="border_width">5</property> + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="border_width">5</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <property name="shadow_type">in</property> + <child> + <widget class="GtkTreeView" id="treeviewRecordEquipment"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + <property name="headers_clickable">False</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Associated Equipment</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="position">3</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="record_equipment_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Equipment</property> + </widget> + <packing> + <property name="position">3</property> + <property name="tab_fill">False</property> + <property name="type">tab</property> + </packing> + </child> </widget> <packing> <property name="expand">False</property> Modified: pytrainer/trunk/glade/profile.glade =================================================================== --- pytrainer/trunk/glade/profile.glade 2010-11-04 01:46:37 UTC (rev 677) +++ pytrainer/trunk/glade/profile.glade 2010-11-06 09:49:44 UTC (rev 678) @@ -1420,6 +1420,28 @@ </packing> </child> <child> + <widget class="GtkAlignment" id="equipment_container"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="position">5</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="labelEquipment"> + <property name="visible">True</property> + <property name="label" translatable="yes">Equipment</property> + </widget> + <packing> + <property name="position">5</property> + <property name="tab_fill">False</property> + <property name="type">tab</property> + </packing> + </child> + <child> <widget class="GtkVBox" id="vbox25"> <property name="visible">True</property> <child> Modified: pytrainer/trunk/glade/pytrainer.glade =================================================================== --- pytrainer/trunk/glade/pytrainer.glade 2010-11-04 01:46:37 UTC (rev 677) +++ pytrainer/trunk/glade/pytrainer.glade 2010-11-06 09:49:44 UTC (rev 678) @@ -57,7 +57,7 @@ </child> <child> <widget class="GtkImageMenuItem" id="export_csv"> - <property name="label">_Export as Text Separated by Commas</property> + <property name="label" translatable="yes">_Export as Text Separated by Commas</property> <property name="visible">True</property> <property name="use_underline">True</property> <property name="use_stock">False</property> @@ -342,7 +342,7 @@ <child> <widget class="GtkTable" id="table13"> <property name="visible">True</property> - <property name="n_rows">10</property> + <property name="n_rows">11</property> <property name="n_columns">6</property> <property name="column_spacing">3</property> <property name="row_spacing">6</property> @@ -480,8 +480,8 @@ <property name="use_markup">True</property> </widget> <packing> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> + <property name="top_attach">7</property> + <property name="bottom_attach">8</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> @@ -796,8 +796,8 @@ </widget> <packing> <property name="right_attach">6</property> - <property name="top_attach">7</property> - <property name="bottom_attach">8</property> + <property name="top_attach">8</property> + <property name="bottom_attach">9</property> </packing> </child> <child> @@ -831,6 +831,35 @@ </packing> </child> <child> + <widget class="GtkLabel" id="label26"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="label" translatable="yes"><b>Equipment:</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_record_equipment"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="label" translatable="yes"></property> + <property name="use_markup">True</property> + <property name="wrap">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">6</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + </packing> + </child> + <child> <placeholder/> </child> <child> @@ -5973,7 +6002,7 @@ <widget class="GtkMenu" id="popup"> <child> <widget class="GtkImageMenuItem" id="edit_record1"> - <property name="label">Edit Record</property> + <property name="label" translatable="yes">Edit Record</property> <property name="visible">True</property> <property name="use_stock">False</property> <signal name="activate" handler="on_editrecord_activate"/> Added: pytrainer/trunk/pytrainer/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/equipment.py (rev 0) +++ pytrainer/trunk/pytrainer/equipment.py 2010-11-06 09:49:44 UTC (rev 678) @@ -0,0 +1,203 @@ +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#This program is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public License +#as published by the Free Software Foundation; either version 2 +#of the License, or (at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import logging + +class Equipment(object): + + """An equipment item that can be used during an activity, such as a pair of running shoes.""" + + def __init__(self): + self._id = None + self.description = u"" + self.active = True + self.life_expectancy = 0 + self.notes = u"" + + def _get_id(self): + return self._id + + def _set_id(self, id): + self._id = int(id) + + id = property(_get_id, _set_id) + + def _get_description(self): + return self._description + + def _set_description(self, description): + if not isinstance(description, unicode): + raise TypeError("Description must be unicode string, not {0}.".format(type(description).__name__)) + self._description = description + + description = property(_get_description, _set_description) + + def _get_active(self): + return self._active + + def _set_active(self, active): + if not isinstance(active, bool): + raise TypeError("Active must be boolean, not {0}.".format(type(active).__name__)) + self._active = active + + active = property(_get_active, _set_active) + + def _get_life_expectancy(self): + return self._life_expectancy + + def _set_life_expectancy(self, life_expectancy): + self._life_expectancy = int(life_expectancy) + + life_expectancy = property(_get_life_expectancy, _set_life_expectancy) + + def _get_notes(self): + return self._notes + + def _set_notes(self, notes): + if not isinstance(notes, unicode): + raise TypeError("Notes must be unicode string, not {0}.".format(type(notes).__name__)) + self._notes = notes + + notes = property(_get_notes, _set_notes) + + def __eq__(self, o): + if isinstance(o, Equipment): + if self.id is not None and o.id is not None: + return self.id == o.id + return False + + def __hash__(self): + if self.id is not None: + return self.id + else: + return object.__hash__(self) + +_TABLE_NAME = "equipment" + +_UPDATE_COLUMNS = "description,active,life_expectancy,notes" + +_ALL_COLUMNS = "id," + _UPDATE_COLUMNS + +def _create_row(equipment): + return [equipment.description, + 1 if equipment.active else 0, + equipment.life_expectancy, + equipment.notes] + +class EquipmentServiceException(Exception): + + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) + +class EquipmentService(object): + + """Provides access to stored equipment items.""" + + def __init__(self, ddbb): + self._ddbb = ddbb + + def get_all_equipment(self): + """Get all equipment items.""" + return self._get_equipment(None) + + def get_active_equipment(self): + """Get all the active equipment items.""" + return self._get_equipment("active = 1") + + def _get_equipment(self, condition): + logging.debug("Retrieving all equipment (condition: '{0}').".format(condition)) + resultSet = self._ddbb.select(_TABLE_NAME, _ALL_COLUMNS, condition) + equipmentList = [] + for result in resultSet: + equipmentList.append(self._create_equipment_item(result)) + return equipmentList + + def get_equipment_item(self, item_id): + """Get an individual equipment item by id. + + If no item with the given id exists then None is returned. + """ + resultSet = self._ddbb.select(_TABLE_NAME, _ALL_COLUMNS, "id = {0}".format(item_id)) + if len(resultSet) == 0: + return None + else: + return self._create_equipment_item(resultSet[0]) + + def _create_equipment_item(self, row): + equipment = Equipment() + (id, description, active, life_expectancy, notes) = row + equipment.id = id + equipment.description = description + equipment.active = bool(active) + equipment.life_expectancy = life_expectancy + equipment.notes = notes + return equipment + + def store_equipment(self, equipment): + """Store a new or update an existing equipment item. + + The stored object is returned.""" + logging.debug("Storing equipment item.") + item_id = None + if equipment.id != None: + item_id = self._update_equipment(equipment) + else: + item_id = self._store_new_equipment(equipment) + return self.get_equipment_item(item_id) + + def _update_equipment(self, equipment): + logging.debug("Updating existing equipment item.") + self._assert_exists(equipment) + self._ddbb.update(_TABLE_NAME, _UPDATE_COLUMNS, _create_row(equipment), "id = {0}".format(equipment.id)) + return equipment.id + + def _assert_exists(self, equipment): + if self.get_equipment_item(equipment.id) == None: + raise EquipmentServiceException("No equipment item exists with id '{0}'".format(equipment.id)) + logging.debug("Asserted item exists with id: '{0}'.".format(equipment.id)) + + def _store_new_equipment(self, equipment): + logging.debug("Storing new equipment item.") + self._assert_unique(equipment) + self._ddbb.insert(_TABLE_NAME, _UPDATE_COLUMNS, _create_row(equipment)) + return self._ddbb.select(_TABLE_NAME, "id", "description = \"{0}\"".format(equipment.description))[0][0] + + def _assert_unique(self, equipment): + result = self._ddbb.select(_TABLE_NAME, "id", "description = \"{0}\"".format(equipment.description)) + if len(result) > 0: + raise EquipmentServiceException("An equipment item already exists with description '{0}'".format(equipment.description)) + logging.debug("Asserted description is unique: '{0}'.".format(equipment.description)) + + def remove_equipment(self, equipment): + """Remove an existing equipment item.""" + logging.debug("Deleting equipment item with id: '{0}'".format(equipment.id)) + self._ddbb.delete("record_equipment", "equipment_id=\"{0}\"".format(equipment.id)) + self._ddbb.delete(_TABLE_NAME, "id=\"{0}\"".format(equipment.id)) + + def get_equipment_usage(self, equipment): + """Get the total use of the given equipment.""" + result = self._ddbb.select("records inner join record_equipment " + "on records.id_record = record_equipment.record_id", + "sum(distance)", + "record_equipment.equipment_id = {0}".format(equipment.id)) + usage = result[0][0] + return 0 if usage == None else usage + Added: pytrainer/trunk/pytrainer/gui/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/gui/equipment.py (rev 0) +++ pytrainer/trunk/pytrainer/gui/equipment.py 2010-11-06 09:49:44 UTC (rev 678) @@ -0,0 +1,186 @@ +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#This program is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public License +#as published by the Free Software Foundation; either version 2 +#of the License, or (at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import gtk +from pytrainer.equipment import Equipment + +class EquipmentStore(gtk.ListStore): + + def __init__(self, equipment_service): + super(EquipmentStore, self).__init__(int, str, float, str, bool) + self._equipment_service = equipment_service + for equipment in equipment_service.get_all_equipment(): + self._append_row(equipment) + + def _append_row(self, equipment): + self.append(self._create_tuple(equipment)) + + def _create_tuple(self, equipment): + usage = self._equipment_service.get_equipment_usage(equipment) + return (equipment.id, + equipment.description, + self._calculate_usage_percent(usage, equipment.life_expectancy), + str(int(round(usage))) + " / " + str(equipment.life_expectancy), + equipment.active) + + def _calculate_usage_percent(self, usage, life_expectancy): + if life_expectancy == 0: + return 0 + else: + return 100.0 * usage / life_expectancy + + def add_equipment(self, equipment): + added_equipment = self._equipment_service.store_equipment(equipment) + self._append_row(added_equipment) + + def get_equipment_item(self, item_path): + item_id = self.get_value(self.get_iter(item_path), 0) + return self._equipment_service.get_equipment_item(item_id) + + def edit_equipment(self, item_path, equipment): + updated_item = self._equipment_service.store_equipment(equipment) + for (column_index, value) in enumerate(self._create_tuple(updated_item)): + self.set(self.get_iter(item_path), column_index, value) + + def remove_equipment(self, item_path): + item = self.get_equipment_item(item_path) + self._equipment_service.remove_equipment(item) + self.remove(self.get_iter(item_path)) + +class EquipmentUi(gtk.HBox): + + def __init__(self, glade_conf_dir, equipment_service): + gtk.HBox.__init__(self) + self._equipment_store = EquipmentStore(equipment_service) + self._builder = gtk.Builder() + self._builder.add_from_file(glade_conf_dir + "/equipment.glade") + self._init_tree_view() + self._init_signals() + self.add(self._get_notebook()) + self.set_property('visible', True) + + def _get_notebook(self): + return self._builder.get_object("notebookEquipment") + + def _get_tree_view(self): + return self._builder.get_object("treeviewEquipmentList") + + def _init_tree_view(self): + tree_view = self._get_tree_view() + column = gtk.TreeViewColumn("Description", gtk.CellRendererText(), text=1) + column.set_resizable(True) + tree_view.append_column(column) + tree_view.append_column(gtk.TreeViewColumn("Usage", gtk.CellRendererProgress(), value=2, text=3)) + tree_view.append_column(gtk.TreeViewColumn("Active", gtk.CellRendererToggle(), active=4)) + # add filler column + tree_view.append_column(gtk.TreeViewColumn()) + tree_view.set_model(self._equipment_store) + + def _init_signals(self): + self._builder.connect_signals({ + "add_equipment_clicked": self._add_equipment_clicked, + "cancel_add_equipment_clicked": self._cancel_add_equipment_clicked, + "confirm_add_equipment_clicked": self._confirm_add_equipment_clicked, + "edit_equipment_clicked": self._edit_equipment_clicked, + "cancel_edit_equipment_clicked": self._cancel_edit_equipment_clicked, + "confirm_edit_equipment_clicked": self._confirm_edit_equipment_clicked, + "delete_equipment_clicked": self._delete_equipment_clicked, + "cancel_delete_equipment_clicked": self._cancel_delete_equipment_clicked, + "confirm_delete_equipment_clicked": self._confirm_delete_equipment_clicked}) + + def _get_selected_equipment_path(self): + (path, _) = self._get_tree_view().get_cursor() + return path + + def _get_selected_equipment_item(self): + return self._equipment_store.get_equipment_item(self._get_selected_equipment_path()) + + def clear_add_equipment_fields(self): + self._builder.get_object("entryEquipmentAddDescription").set_text("") + self._builder.get_object("entryEquipmentAddLifeExpectancy").set_text("0") + self._builder.get_object("checkbuttonEquipmentAddActive").set_active(True) + self._builder.get_object("textviewEquipmentAddNotes").get_buffer().set_text("") + + def show_page_equipment_list(self): + self._get_notebook().set_current_page(0) + + def show_page_equipment_add(self): + self._get_notebook().set_current_page(1) + self._builder.get_object("entryEquipmentAddDescription").grab_focus() + + def show_page_equipment_edit(self): + self._get_notebook().set_current_page(2) + + def show_page_equipment_delete(self): + self._get_notebook().set_current_page(3) + ... [truncated message content] |