Пример #1
0
 def __init__(self,filename = None, data_path = None):
     #Version constants
     self.version ="1.10.0-dev"
     #Process command line options
     self.startup_options = self.get_options()
     #Setup logging
     self.environment = Environment(platform.get_platform(), self.startup_options.conf_dir)
     self.environment.create_directories()
     self.set_logging(self.startup_options.log_level, self.startup_options.log_type)
     logging.debug('>>')
     logging.debug("PyTrainer version %s" % (self.version))
     self.data_path = data_path
     self.date = Date()
     self.ddbb = None
     # Checking profile
     logging.debug('Checking configuration and profile...')
     self.profile = Profile(self.environment, self.data_path,self)
     self.uc = UC()
     self.windowmain = None
     self.ddbb = DDBB(self.profile, self)
     logging.debug('connecting to DDBB')
     self.ddbb.connect()
     
     initialize_data(self.ddbb, self.environment.conf_dir)
         
     self._sport_service = SportService(self.ddbb)
     self.record = Record(self._sport_service, data_path, self)
     self.athlete = Athlete(data_path,self)
     self.stats = Stats(self._sport_service, 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(self._sport_service, 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(self._sport_service, 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('<<')
Пример #2
0
 def __init__(self, sport_service, data_path=None, parent=None):
     logging.debug(">>")
     self._sport_service = sport_service
     self.parent = parent
     self.pytrainer_main = parent
     self._equipment_service = EquipmentService(self.pytrainer_main.ddbb)
     self.data_path = data_path
     logging.debug("setting date...")
     self.date = Date()
     logging.debug("<<")
Пример #3
0
class Record:
    def __init__(self, sport_service, data_path=None, parent=None):
        logging.debug(">>")
        self._sport_service = sport_service
        self.parent = parent
        self.pytrainer_main = parent
        self._equipment_service = EquipmentService(self.pytrainer_main.ddbb)
        self.data_path = data_path
        logging.debug("setting date...")
        self.date = Date()
        logging.debug("<<")

    def newRecord(
        self,
        date,
        title=None,
        distance=None,
        time=None,
        upositive=None,
        unegative=None,
        bpm=None,
        calories=None,
        comment=None,
    ):
        logging.debug(">>")
        sports = self._sport_service.get_all_sports()
        self.recordwindow = WindowRecord(
            self._equipment_service,
            self.data_path,
            sports,
            self,
            self.format_date(date),
            title,
            distance,
            time,
            upositive,
            unegative,
            bpm,
            calories,
            comment,
        )
        self.recordwindow.run()
        logging.debug("<<")

    def newMultiRecord(self, activities):
        logging.debug(">>")
        sports = self._sport_service.get_all_sports()
        self.recordwindow = WindowRecord(
            self._equipment_service,
            self.data_path,
            sports,
            parent=self,
            windowTitle=_("Modify details before importing"),
        )
        self.recordwindow.populateMultiWindow(activities)
        self.recordwindow.run()
        return self.recordwindow.getActivityData()
        logging.debug("<<")

    def editRecord(self, id_record):
        logging.debug(">>")
        activity = self.pytrainer_main.activitypool.get_activity(id_record)
        record_equipment = self.get_record_equipment(id_record)
        sports = self._sport_service.get_all_sports()
        self.recordwindow = WindowRecord(
            self._equipment_service,
            self.data_path,
            sports,
            self,
            None,
            windowTitle=_("Edit Entry"),
            equipment=record_equipment,
        )
        self.recordwindow.setValuesFromActivity(activity)
        logging.debug("launching window")
        self.recordwindow.run()
        logging.debug("<<")

    def removeRecord(self, id_record):
        logging.debug(">>")
        record = self.pytrainer_main.ddbb.delete("records", 'id_record="%s"' % id_record)
        laps = self.pytrainer_main.ddbb.delete("laps", 'record="%s"' % id_record)
        logging.debug("removed record " + str(id_record) + " (and associated laps) from DB")
        gpxfile = self.pytrainer_main.profile.gpxdir + "/%d.gpx" % int(id_record)
        if os.path.isfile(gpxfile):
            os.remove(gpxfile)
            logging.debug("removed gpxfile " + gpxfile)
        logging.debug("<<")

    def pace_to_float(self, value):
        """Take a mm:ss or mm.ss and return float"""
        try:
            value = float(value)
        except:
            if ":" in value:  # 'mm:ss' found
                mins, sec = value.split(":")
                value = float(mins + "." + "%02d" % round(int(sec) * 5 / 3))
            elif "," in value:
                value = float(value.replace(",", "."))
            else:
                logging.error("Wrong value provided: %s" % value)
                value = None
        return value

    def pace_from_float(self, value, fromDB=False):
        """Helper to generate mm:ss from float representation mm.ss (or mm,ss?)"""
        # Check that value supplied is a float
        try:
            _value = "%0.2f" % float(value)
        except ValueError:
            _value = str(value)
        if fromDB:  # paces in DB are stored in mixed format -> 4:30 as 4.3 (NOT as 4.5 aka 'decimal')
            pace = _value
        else:
            mins, sec_dec = _value.split(".")
            pace = mins + ":" + "%02d" % round(int(sec_dec) * 3 / 5)
        return pace

    def _formatRecordNew(self, list_options):
        """20.07.2008 - dgranda
		New records handle date_time_utc field which is transparent when updating, so logic method has been splitted
		args: list with keys and values without valid format
		returns: keys and values matching DB schema"""
        logging.debug(">>")
        time = self.date.time2second(list_options["rcd_time"])
        average = self.parseFloatRecord(list_options["rcd_average"])
        keys = "date,sport,distance,time,beats,comments,average,calories,title,upositive,unegative,maxspeed,maxpace,pace,maxbeats,date_time_utc,date_time_local, duration"
        if list_options["rcd_beats"] == "":
            list_options["rcd_beats"] = 0

            # retrieving sport id (adding sport if it doesn't exist yet)
        sport_id = self.getSportId(list_options["rcd_sport"], add=True)

        values = (
            list_options["rcd_date"],
            sport_id,
            self.parseFloatRecord(list_options["rcd_distance"]),
            time,
            self.parseFloatRecord(list_options["rcd_beats"]),
            list_options["rcd_comments"],
            average,
            self.parseFloatRecord(list_options["rcd_calories"]),
            list_options["rcd_title"],
            self.parseFloatRecord(list_options["rcd_upositive"]),
            self.parseFloatRecord(list_options["rcd_unegative"]),
            self.parseFloatRecord(list_options["rcd_maxvel"]),
            self.pace_to_float(list_options["rcd_maxpace"]),
            self.pace_to_float(list_options["rcd_pace"]),
            self.parseFloatRecord(list_options["rcd_maxbeats"]),
            list_options["date_time_utc"],
            list_options["date_time_local"],
            time,
        )
        logging.debug("<<")
        return keys, values

    def insertRecord(self, list_options, laps=None, equipment=None):
        logging.debug(">>")
        # Create entry for activity in records table
        if list_options is None:
            logging.info("No data provided, abort adding entry")
            return None
        logging.debug("list_options: " + str(list_options))
        cells, values = self._formatRecordNew(list_options)
        self.pytrainer_main.ddbb.insert("records", cells, values)
        logging.debug("DB updated: " + str(cells) + " | " + str(values))
        id_record = self.pytrainer_main.ddbb.lastRecord("records")
        # Create entry(s) for activity in laps table
        if laps is not None:
            for lap in laps:
                lap["record"] = id_record  # Add reference to entry in record table
                lap_keys = ", ".join(map(str, lap.keys()))
                lap_values = lap.values()
                self.insertLaps(lap_keys, lap.values())
        if equipment is not None:
            for equipment_id in equipment:
                self._insert_record_equipment(id_record, equipment_id)
        gpxOrig = list_options["rcd_gpxfile"]
        if os.path.isfile(gpxOrig):
            gpxDest = self.pytrainer_main.profile.gpxdir
            gpxNew = gpxDest + "/%d.gpx" % id_record
            # 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")

    def insertNewRecord(self, gpxOrig, entry):  # TODO consolidate with insertRecord
        """29.03.2008 - dgranda
		Moves GPX file to store destination and updates database
		args: path to source GPX file"""
        logging.debug("--")
        (list_options, gpx_laps) = self.summaryFromGPX(gpxOrig, entry)
        if list_options is None:
            return None
        return self.insertRecord(list_options, laps=gpx_laps)

    def lapsFromGPX(self, gpx):
        logging.debug(">>")
        laps = []
        gpxLaps = gpx.getLaps()
        for lap in gpxLaps:
            lap_number = gpxLaps.index(lap)
            tmp_lap = {}
            tmp_lap["record"] = ""
            tmp_lap["lap_number"] = lap_number
            tmp_lap["elapsed_time"] = lap[0]
            tmp_lap["distance"] = lap[4]
            tmp_lap["start_lat"] = lap[5]
            tmp_lap["start_lon"] = lap[6]
            tmp_lap["end_lat"] = lap[1]
            tmp_lap["end_lon"] = lap[2]
            tmp_lap["calories"] = lap[3]
            tmp_lap["intensity"] = lap[7]
            tmp_lap["avg_hr"] = lap[8]
            tmp_lap["max_hr"] = lap[9]
            tmp_lap["max_speed"] = lap[10]
            tmp_lap["laptrigger"] = lap[11]
            tmp_lap["comments"] = ""
            laps.append(tmp_lap)
        logging.debug("<<")
        return laps

    def summaryFromGPX(self, gpxOrig, entry):
        """29.03.2008 - dgranda
		Retrieves info which will be stored in DB from GPX file
		args: path to source GPX file
		returns: list with fields and values, list of laps
		"""
        logging.debug(">>")
        gpx = Gpx(self.data_path, gpxOrig)
        distance, time, maxspeed, maxheartrate = gpx.getMaxValues()
        # if time == 0: #invalid record
        # 	print "Invalid record"
        # 	return (None, None)
        upositive, unegative = gpx.getUnevenness()
        if time > 0:
            speed = distance * 3600 / time
            time_hhmmss = [time // 3600, (time / 60) % 60, time % 60]
        else:
            speed = 0
            time_hhmmss = [0, 0, 0]
        summaryRecord = {}
        summaryRecord["rcd_gpxfile"] = gpxOrig
        summaryRecord["rcd_sport"] = entry[0]
        summaryRecord["rcd_date"] = gpx.getDate()
        summaryRecord["rcd_calories"] = gpx.getCalories()
        summaryRecord["rcd_comments"] = ""
        summaryRecord["rcd_title"] = ""
        summaryRecord["rcd_time"] = time_hhmmss  # ToDo: makes no sense to work with arrays
        summaryRecord["rcd_distance"] = "%0.2f" % distance
        if speed == 0:
            summaryRecord["rcd_pace"] = "0"
        else:
            summaryRecord["rcd_pace"] = "%d.%02d" % ((3600 / speed) / 60, (3600 / speed) % 60)
        if maxspeed == 0:
            summaryRecord["rcd_maxpace"] = "0"
        else:
            summaryRecord["rcd_maxpace"] = "%d.%02d" % ((3600 / maxspeed) / 60, (3600 / maxspeed) % 60)
        summaryRecord["rcd_average"] = speed
        summaryRecord["rcd_maxvel"] = maxspeed
        summaryRecord["rcd_beats"] = gpx.getHeartRateAverage()
        summaryRecord["rcd_maxbeats"] = maxheartrate
        summaryRecord["rcd_upositive"] = upositive
        summaryRecord["rcd_unegative"] = unegative
        if entry[1] == "":  # coming from new track dialog (file opening)												#TODO This if-else needs checking
            summaryRecord["date_time_utc"], summaryRecord["date_time_local"] = gpx.getStartTimeFromGPX(gpxOrig)  #
        else:  # coming from GPS device																				#
            summaryRecord["date_time_utc"] = entry[1]  #
            summaryRecord["date_time_local"] = entry[1]  #
            print "#TODO fix record summaryRecord local and utc time..."  #
        logging.debug("summary: " + str(summaryRecord))
        laps = self.lapsFromGPX(gpx)
        logging.debug("<<")
        return summaryRecord, laps

    def updateRecord(
        self, list_options, id_record, equipment=None
    ):  # ToDo: update only fields that can change if GPX file is present
        logging.debug(">>")
        # Remove activity from pool so data is updated
        self.pytrainer_main.activitypool.remove_activity(id_record)
        gpxfile = self.pytrainer_main.profile.gpxdir + "/%d.gpx" % int(id_record)
        gpxOrig = list_options["rcd_gpxfile"]
        if os.path.isfile(gpxOrig):
            if gpxfile != gpxOrig:
                shutil.copy2(gpxOrig, gpxfile)
        else:
            if list_options["rcd_gpxfile"] == "":
                logging.debug("Activity not based in GPX file")  # ein?
        logging.debug("Updating bbdd")
        cells, values = self._formatRecordNew(list_options)
        self.pytrainer_main.ddbb.update("records", cells, values, " id_record=%d" % int(id_record))
        if equipment is not None:
            self._update_record_equipment(id_record, equipment)
        self.pytrainer_main.refreshListView()
        logging.debug("<<")

    def parseFloatRecord(self, string):
        logging.debug("--")
        if string != "":
            try:
                return float(string.replace(",", ","))
            except:
                return float(string)
        else:
            return 0

    def getrecordInfo(self, id_record):
        logging.debug("--")
        if id_record is None or id_record == "":
            return []
        return self.pytrainer_main.ddbb.select(
            "records,sports",
            "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 format_date(self, date):
        return date.strftime("%Y-%m-%d")

    def getrecordList(self, date, id_sport=None):
        logging.debug("--")
        if not id_sport:
            # outer join on sport id to workaround bug where sport reference is null on records from GPX import
            return self.pytrainer_main.ddbb.select(
                "records left outer join sports on records.sport=sports.id_sports",
                "sports.name,date,distance,time,beats,comments,average,calories,id_record,maxspeed,maxbeats,date_time_utc,date_time_local,upositive,unegative",
                'date="%s" ' % self.format_date(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,upositive,unegative",
                'date="%s" and sports.id_sports="%s" and records.sport=sports.id_sports'
                % (self.format_date(date), id_sport),
            )

    def getLaps(self, id_record):
        logging.debug("--")
        laps = self.pytrainer_main.ddbb.select(
            "laps",
            "id_lap, record, elapsed_time, distance, start_lat, start_lon, end_lat, end_lon, calories, lap_number, intensity, max_speed, avg_hr, max_hr, laptrigger, comments",
            'record="%s"' % id_record,
        )
        if laps is None or laps == []:  # No laps stored - update DB
            logging.debug("No laps in DB for record %d" % id_record)
            # print ("No laps in DB for record %d" % id_record)
            gpx_dest = self.pytrainer_main.profile.gpxdir
            gpxfile = gpx_dest + "/%d.gpx" % id_record
            gpx = Gpx(self.data_path, gpxfile)
            laps = self.lapsFromGPX(gpx)
            if laps is not None:
                for lap in laps:
                    lap["record"] = id_record  # Add reference to entry in record table
                    lap_keys = ", ".join(map(str, lap.keys()))
                    lap_values = lap.values()
                    self.insertLaps(lap_keys, lap.values())
                    # Try to get lap info again #TODO? refactor
            laps = self.pytrainer_main.ddbb.select(
                "laps",
                "id_lap, record, elapsed_time, distance, start_lat, start_lon, end_lat, end_lon, calories, lap_number, intensity, max_speed, avg_hr, max_hr, laptrigger, comments",
                'record="%s"' % id_record,
            )
        return laps

    def insertLaps(self, cells, values):
        logging.debug("--")
        logging.debug("Adding lap information: " + ", ".join(map(str, values)))
        self.pytrainer_main.ddbb.insert("laps", cells, values)

    def _insert_record_equipment(self, record_id, equipment_id):
        self.pytrainer_main.ddbb.insert("record_equipment", "record_id, equipment_id", [record_id, equipment_id])

    def _update_record_equipment(self, record_id, equipment_ids):
        self.pytrainer_main.ddbb.delete("record_equipment", "record_id={0}".format(record_id))
        for id in equipment_ids:
            self._insert_record_equipment(record_id, id)

    def get_record_equipment(self, record_id):
        record_equipment = []
        results = self.pytrainer_main.ddbb.select("record_equipment", "equipment_id", "record_id={0}".format(record_id))
        for row in results:
            id = row[0]
            equipment_item = self._equipment_service.get_equipment_item(id)
            record_equipment.append(equipment_item)
        return record_equipment

    def getrecordPeriod(self, date_range, sport=None):
        # TODO This is essentially the same as getrecordPeriodSport (except date ranges) - need to look at merging the two
        date_ini = self.format_date(date_range.start_date)
        date_end = self.format_date(date_range.end_date)
        tables = "records,sports"
        if not sport:
            condition = 'date>="%s" and date<="%s" and records.sport=sports.id_sports' % (date_ini, date_end)
        else:
            condition = 'date>="%s" and date<="%s" and records.sport=sports.id_sports and sports.id_sports="%s"' % (
                date_ini,
                date_end,
                sport,
            )

        return self.pytrainer_main.ddbb.select(
            tables,
            "date,distance,time,beats,comments,average,calories,maxspeed,maxbeats, sports.name,upositive,unegative",
            condition,
        )

    def getrecordPeriodSport(self, date_ini, date_end, sport):
        if not sport:
            tables = "records"
            condition = 'date>"%s" and date<"%s"' % (date_ini, date_end)
        else:
            tables = "records,sports"
            condition = 'date>"%s" and date<"%s" and records.sport=sports.id_sports and sports.id_sports="%s"' % (
                date_ini,
                date_end,
                sport,
            )

        return self.pytrainer_main.ddbb.select(
            tables,
            "date,distance,time,beats,comments,average,calories,maxspeed,maxbeats,upositive,unegative",
            condition,
        )

    def _get_sport(self, sport_name):
        return self._sport_service.get_sport_by_name(sport_name)

    def getSportMet(self, sport_name):
        """Deprecated: use sport.met"""
        logging.debug("--")
        return self._get_sport(sport_name).met

    def getSportWeight(self, sport_name):
        """Deprecated: use sport.weight"""
        logging.debug("--")
        return self._get_sport(sport_name).weight

    def getSportId(self, sport_name, add=None):
        """Deprecated: use sport_service.get_sport_by_name()
		
		Get the id of a sport by name, optionally adding a new sport if
		none exists with the given name.
		arguments:
			sport_name: sport's name to get id for
			add: whether the sport should be added if not found
		returns: id for sport with given name or None"""
        if sport_name is None:
            return None
        sport = self._get_sport(sport_name)
        if sport is None:
            logging.debug("No sport with name: '%s'", str(sport_name))
            if add is not None:
                logging.debug("Adding sport '%s'", str(sport_name))
                new_sport = Sport()
                new_sport.name = unicode(sport_name)
                sport = self._sport_service.store_sport(new_sport)
        return None if sport is None else sport.id

    def getAllrecord(self):
        logging.debug("--")
        return self.pytrainer_main.ddbb.select("records", "date,distance,time,beats,comments,average,calories")

    def getAllRecordList(self):
        logging.debug("--")
        return self.pytrainer_main.ddbb.select(
            "records,sports",
            "date,distance,average,title,sports.name,id_record,time,beats,calories",
            "sports.id_sports = records.sport order by date desc",
        )

    def getRecordListByCondition(self, condition):
        logging.debug("--")
        if condition is None:
            return self.getAllRecordList()
        else:
            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 order by date desc" % condition,
            )

    def getRecordDayList(self, date, id_sport=None):
        logging.debug(">>")
        logging.debug("Retrieving data for " + str(date))
        # Why is looking for all days of the same month?
        if not id_sport:
            records = self.pytrainer_main.ddbb.select(
                "records", "date", "date LIKE '" + str(date.year) + "-" + date.strftime("%m") + "-%'"
            )
        else:
            records = self.pytrainer_main.ddbb.select(
                "records", "date", 'date LIKE "%d-%0.2d-%%" and sport="%s"' % (date.year, date.month, id_sport)
            )
        logging.debug("Found " + str(len(records)) + " entries")
        day_list = []
        for i in records:
            record = str(i[0]).split("-")
            logging.debug("date:" + str(i[0]))
            day_list.append(record[2])
        logging.debug("<<")
        return day_list

    def actualize_fromgpx(self, gpxfile):  # TODO remove? - should never have multiple tracks per GPX file
        logging.debug(">>")
        logging.debug("loading file: " + gpxfile)
        gpx = Gpx(self.data_path, gpxfile)
        tracks = gpx.getTrackRoutes()

        if len(tracks) == 1:
            logging.debug("Just 1 track")
            self._actualize_fromgpx(gpx)
        elif len(tracks) > 1:
            logging.debug("Found " + str(len(tracks)) + " tracks")
            self._select_trkfromgpx(gpxfile, tracks)
        else:
            msg = _("pytrainer can't import data from your gpx file")
            from gui.warning import Warning

            warning = Warning(self.data_path)
            warning.set_text(msg)
            warning.run()
        logging.debug("<<")

    def _actualize_fromgpx(self, gpx):
        logging.debug(">>")
        distance, time, maxspeed, maxheartrate = gpx.getMaxValues()
        upositive, unegative = gpx.getUnevenness()
        heartrate = gpx.getHeartRateAverage()
        date = gpx.getDate()
        calories = gpx.getCalories()
        start_time = gpx.getStart_time()

        self.recordwindow.rcd_date.set_text(date)
        self.recordwindow.rcd_starttime.set_text(start_time)
        self.recordwindow.rcd_upositive.set_text(str(upositive))
        self.recordwindow.rcd_unegative.set_text(str(unegative))
        self.recordwindow.rcd_beats.set_text(str(heartrate))
        self.recordwindow.rcd_calories.set_text(str(calories))
        self.recordwindow.set_distance(distance)
        self.recordwindow.set_maxspeed(maxspeed)
        self.recordwindow.set_maxhr(maxheartrate)
        self.recordwindow.set_recordtime(time / 60.0 / 60.0)
        self.recordwindow.on_calcavs_clicked(None)
        self.recordwindow.on_calccalories_clicked(None)
        self.recordwindow.rcd_maxpace.set_text("%d.%02d" % ((3600 / maxspeed) / 60, (3600 / maxspeed) % 60))
        logging.debug("<<")

    def __actualize_fromgpx(self, gpxfile, name=None):
        logging.debug(">>")
        gpx = Gpx(self.data_path, gpxfile, name)
        self._actualize_fromgpx(gpx)
        logging.debug("<<")

    def _select_trkfromgpx(self, gpxfile, tracks):  # TODO remove? - should never have multiple tracks per GPX file
        logging.debug(">>")
        logging.debug("Track dialog " + self.data_path + "|" + gpxfile)
        selectrckdialog = DialogSelectTrack(self.data_path, tracks, self.__actualize_fromgpx, gpxfile)
        logging.debug("Launching window...")
        selectrckdialog.run()
        logging.debug("<<")

    def importFromGPX(self, gpxFile, sport):
        """
		Add a record from a valid pytrainer type GPX file
		"""
        logging.debug(">>")
        entry_id = None
        if not os.path.isfile(gpxFile):
            logging.error("Invalid file: " + gpxFile)
        else:
            logging.info("Retrieving data from " + gpxFile)
            if not sport:
                sport = "import"
            entry = [sport, ""]
            entry_id = self.insertNewRecord(gpxFile, entry)
            if entry_id is None:
                logging.error("Entry not created for file %s" % gpxFile)
            else:
                logging.info("Entry %d has been added" % entry_id)
        logging.debug("<<")
        return entry_id
Пример #4
0
class pyTrainer:
    def __init__(self,filename = None, data_path = None):
        #Version constants
        self.version ="1.10.0-dev"
        #Process command line options
        self.startup_options = self.get_options()
        #Setup logging
        self.environment = Environment(platform.get_platform(), self.startup_options.conf_dir)
        self.environment.create_directories()
        self.set_logging(self.startup_options.log_level, self.startup_options.log_type)
        logging.debug('>>')
        logging.debug("PyTrainer version %s" % (self.version))
        self.data_path = data_path
        self.date = Date()
        self.ddbb = None
        # Checking profile
        logging.debug('Checking configuration and profile...')
        self.profile = Profile(self.environment, self.data_path,self)
        self.uc = UC()
        self.windowmain = None
        self.ddbb = DDBB(self.profile, self)
        logging.debug('connecting to DDBB')
        self.ddbb.connect()
        
        initialize_data(self.ddbb, self.environment.conf_dir)
            
        self._sport_service = SportService(self.ddbb)
        self.record = Record(self._sport_service, data_path, self)
        self.athlete = Athlete(data_path,self)
        self.stats = Stats(self._sport_service, 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(self._sport_service, 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(self._sport_service, 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

        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, equip=False, newgraph=True, conf_dir=None, log_type="file")
        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("--oldgraph", action="store_false", dest="newgraph", help="Turn off new graphing approach")
        parser.add_option("--newgraph", action="store_true", dest="newgraph", help="Deprecated Option: Turn on new graphing approach")
        parser.add_option("--confdir", dest="conf_dir", help="Specify the directory where application configuration will be stored.")
        parser.add_option("--logtype", dest="log_type", metavar="TYPE",  type="choice" , choices=["file", "console"], help="Specify where logging should be output to. TYPE is one of 'file' (default), or 'console'.")
        (options, args) = parser.parse_args()
        return options

    def set_logging(self, level, log_type):
        '''Setup rotating log file with customized format'''
        if("console" == log_type):
            handler = logging.StreamHandler(sys.stdout)
        else:
            handler = logging.handlers.RotatingFileHandler(self.environment.log_file, maxBytes=100000, backupCount=5)
        formatter = logging.Formatter('%(asctime)s|%(levelname)s|%(module)s|%(funcName)s|%(message)s')
        handler.setFormatter(formatter)
        logging.getLogger('').addHandler(handler)
        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 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 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 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('<<')

    def refreshMainSportList(self):
        logging.debug('>>')
        sports = self._sport_service.get_all_sports()
        self.windowmain.updateSportList(sports)
        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 self.windowmain.recordview.get_current_page()==4:
                self.refreshRecordGraphView("analytics")
        elif view=="day":
             logging.debug('day view')
             sport = self.windowmain.activeSport
             sport_id = self.record.getSportId(sport)
             record_list = self.record.getrecordList(date_selected, sport_id)
             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_range = DateRange.for_week_containing(date_selected)
             sport = self.windowmain.activeSport
             sport_id = self.record.getSportId(sport)
             record_list = self.record.getrecordPeriod(date_range, sport_id)
             self.windowmain.actualize_weekview(record_list, date_range)
        elif view=="month":
             logging.debug('month view')
             date_range = DateRange.for_month_containing(date_selected)
             sport = self.windowmain.activeSport
             sport_id = self.record.getSportId(sport)
             record_list = self.record.getrecordPeriod(date_range, sport_id)
             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_range = DateRange.for_year_containing(date_selected)
             sport = self.windowmain.activeSport
             sport_id = self.record.getSportId(sport)
             record_list = self.record.getrecordPeriod(date_range, sport_id)
             self.windowmain.actualize_yearview(record_list, date_selected.year)
             self.windowmain.actualize_yeargraph(record_list)
        elif view=="listview":
            logging.debug('list view')
            self.refreshListView()
        elif view=="athlete":
            logging.debug('athlete view')
            self.windowmain.on_athleteview_activate()
        elif view=="stats":
            logging.debug('stats view')
            self.windowmain.on_statsview_activate()
        else:
            print "Unknown view %s" % view
        logging.debug('<<')
        
    def refreshRecordGraphView(self, view, id_record=None):
        logging.debug('>>')
        logging.info('Working on '+view+' graph')
        if id_record is not None:
			#Refresh called for a specific record
            #Select correct record in treeview
            model = self.windowmain.recordTreeView.get_model()
            #Loop through all records in treeview looking for the correct one to highlight
            for i,row in enumerate(model):
				if row[0] == id_record:
					self.windowmain.recordTreeView.set_cursor(i)
        else:
            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)
        if view=="analytics":
             self.windowmain.actualize_analytics(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 refreshListRecords(self):
        logging.debug('>>')
        #Refresh list view
        #self.refreshListView() # old variant
        self.refreshListView(self.windowmain.listsearch.condition)
        #Refresh list records
        date = self.date.getDate()
        sport = self.windowmain.activeSport
        id_sport = self.record.getSportId(sport)
        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, id_sport)
        self.windowmain.actualize_calendar(record_list)
        logging.debug('<<')

    def refreshAthleteView(self):
        logging.debug('>>')
        self.athlete.refresh()
        self.windowmain.actualize_athleteview(self.athlete)
        logging.debug('<<')

    def refreshStatsView(self):
        logging.debug('>>')
        self.stats.refresh()
        self.windowmain.actualize_statsview(self.stats, self.record.getAllRecordList())
        logging.debug('<<')

    def refreshListView(self,condition=None):
        logging.debug('>>')
        record_list = self.record.getRecordListByCondition(condition)
        self.windowmain.actualize_listview(record_list)
        logging.debug('<<')

    def refreshWaypointView(self,default_waypoint=None,redrawmap=1):
        logging.debug('>>')
        waypoint_list = self.waypoint.getAllWaypoints()
        self.windowmain.actualize_waypointview(waypoint_list,default_waypoint,redrawmap)
        logging.debug('<<')

    def editExtensions(self):
        logging.debug('>>')
        before = self.extension.getActiveExtensions()
        self.extension.manageExtensions()
        after = self.extension.getActiveExtensions()
        self.setExtensions(before, after)
        logging.debug('<<')

    def importData(self):
        logging.debug('>>')
        activeplugins_before = self.plugins.getActivePlugins()
        self.importdata.runImportdata()
        activeplugins_after = self.plugins.getActivePlugins()
        #Need to check for plugins that have been disabled (were active and now are not)
        self.setMenuPlugins(activeplugins_before, activeplugins_after)
        self.refreshListRecords()
        self.refreshGraphView(self.windowmain.selected_view)
        logging.debug('<<')

    def editGpsPlugins(self):
        logging.debug('>>')
        activeplugins_before = self.plugins.getActivePlugins()
        self.plugins.managePlugins()
        activeplugins_after = self.plugins.getActivePlugins()
        #Need to check for plugins that have been disabled (were active and now are not)
        self.setMenuPlugins(activeplugins_before, activeplugins_after)
        logging.debug('<<')

    def setMenuPlugins(self, activeplugins_before, activeplugins_after):
        logging.debug('>>')
        #Need to check for plugins that have been disabled (were active and now are not)
        for plugin in activeplugins_before:
            if plugin not in activeplugins_after:
                #disabled plugin -> need to unload plugin
                txtbutton = self.plugins.loadPlugin(plugin)
                self.windowmain.removeImportPlugin(txtbutton)
        #Need to check for plugins that have been enabled (were not active and now are)
        for plugin in activeplugins_after:
            if plugin not in activeplugins_before:
                #new active plugin -> need to load plugin
                txtbutton = self.plugins.loadPlugin(plugin)
                self.windowmain.addImportPlugin(txtbutton)
        logging.debug('<<')

    def setExtensions(self, before, after):
        logging.debug('>>')
        #Need to check for extensions that have been disabled (were active and now are not)
        for extension in before:
            if extension not in after:
                #disabled extension -> need to unload extension
                print "Need to disable extension %s " % extension
                txtbutton = self.extension.loadExtension(extension)
                self.windowmain.removeExtension(txtbutton)
        #Need to check for plugins that have been enabled (were not active and now are)
        for extension in after:
            if extension not in before:
                #new active extension -> need to load extension
                logging.debug("Enabling extension %s " % extension)
                txtbutton = self.extension.loadExtension(extension)
                self.windowmain.addExtension(txtbutton)
        logging.debug('<<')

    def newRecord(self,title=None,distance=None,time=None,upositive=None,unegative=None,bpm=None,calories=None,comment=None,view=None):
        logging.debug('>>')
        date = self.date.getDate()
        self.record.newRecord(date, title, distance, time, upositive, unegative, bpm, calories, comment)
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def editRecord(self, id_record, view=None):
        logging.debug("Editing record with id: '%s'", id_record)
        self.record.editRecord(id_record)
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def removeRecord(self, id_record, confirm = False, view=None):
        logging.debug('>>')
        if confirm:
             self.record.removeRecord(id_record)
        else:
             msg = _("Delete this database entry?")
             params = [id_record,True]
             warning = Warning(self.data_path,self.removeRecord,params)
             warning.set_text(msg)
             warning.run()
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def removeWaypoint(self,id_waypoint, confirm = False):
        logging.debug('>>')
        if confirm:
             self.waypoint.removeWaypoint(id_waypoint)
             self.refreshWaypointView()
        else:
             msg = _("Delete this waypoint?")
             params = [id_waypoint,True]
             warning = Warning(self.data_path,self.removeWaypoint,params)
             warning.set_text(msg)
             warning.run()
        logging.debug('<<')

    def updateWaypoint(self,id_waypoint,lat,lon,name,desc,sym):
        logging.debug('>>')
        self.waypoint.updateWaypoint(id_waypoint,lat,lon,name,desc,sym)
        self.refreshWaypointView(id_waypoint)
        logging.debug('<<')

    def exportCsv(self):
        logging.debug('>>')
        from save import Save
        save = Save(self.data_path, self.record)
        save.run()
        logging.debug('<<')

    def editProfile(self):
        logging.debug('>>')
        self.profile.editProfile(self._sport_service)
        self.activitypool.clear_pool()
        self.windowmain.setup()
        logging.debug('<<')
Пример #5
0
class Record:
    def __init__(self, sport_service, data_path=None, parent=None):
        logging.debug('>>')
        self._sport_service = sport_service
        self.parent = parent
        self.pytrainer_main = parent
        self._equipment_service = EquipmentService(self.pytrainer_main.ddbb)
        self.data_path = data_path
        logging.debug('setting date...')
        self.date = Date()
        logging.debug('<<')

    def newRecord(self,
                  date,
                  title=None,
                  distance=None,
                  time=None,
                  upositive=None,
                  unegative=None,
                  bpm=None,
                  calories=None,
                  comment=None):
        logging.debug('>>')
        sports = self._sport_service.get_all_sports()
        self.recordwindow = WindowRecord(self._equipment_service,
                                         self.data_path, sports, self,
                                         self.format_date(date), title,
                                         distance, time, upositive, unegative,
                                         bpm, calories, comment)
        self.recordwindow.run()
        logging.debug('<<')

    def newMultiRecord(self, activities):
        logging.debug('>>')
        sports = self._sport_service.get_all_sports()
        self.recordwindow = WindowRecord(
            self._equipment_service,
            self.data_path,
            sports,
            parent=self,
            windowTitle=_("Modify details before importing"))
        self.recordwindow.populateMultiWindow(activities)
        self.recordwindow.run()
        return self.recordwindow.getActivityData()
        logging.debug('<<')

    def editRecord(self, id_record):
        logging.debug('>>')
        activity = self.pytrainer_main.activitypool.get_activity(id_record)
        record_equipment = self.get_record_equipment(id_record)
        sports = self._sport_service.get_all_sports()
        self.recordwindow = WindowRecord(self._equipment_service,
                                         self.data_path,
                                         sports,
                                         self,
                                         None,
                                         windowTitle=_("Edit Entry"),
                                         equipment=record_equipment)
        self.recordwindow.setValuesFromActivity(activity)
        logging.debug('launching window')
        self.recordwindow.run()
        logging.debug('<<')

    def removeRecord(self, id_record):
        logging.debug('>>')
        record = self.pytrainer_main.ddbb.delete(
            "records", "id_record=\"%s\"" % id_record)
        laps = self.pytrainer_main.ddbb.delete("laps",
                                               "record=\"%s\"" % id_record)
        logging.debug('removed record ' + str(id_record) +
                      ' (and associated laps) from DB')
        gpxfile = self.pytrainer_main.profile.gpxdir + "/%d.gpx" % int(
            id_record)
        if os.path.isfile(gpxfile):
            os.remove(gpxfile)
            logging.debug('removed gpxfile ' + gpxfile)
        logging.debug('<<')

    def pace_to_float(self, value):
        '''Take a mm:ss or mm.ss and return float'''
        try:
            value = float(value)
        except:
            if ":" in value:  # 'mm:ss' found
                mins, sec = value.split(":")
                value = float(mins + "." + "%02d" % round(int(sec) * 5 / 3))
            elif "," in value:
                value = float(value.replace(',', '.'))
            else:
                logging.error("Wrong value provided: %s" % value)
                value = None
        return value

    def pace_from_float(self, value, fromDB=False):
        '''Helper to generate mm:ss from float representation mm.ss (or mm,ss?)'''
        #Check that value supplied is a float
        try:
            _value = "%0.2f" % float(value)
        except ValueError:
            _value = str(value)
        if fromDB:  # paces in DB are stored in mixed format -> 4:30 as 4.3 (NOT as 4.5 aka 'decimal')
            pace = _value
        else:
            mins, sec_dec = _value.split(".")
            pace = mins + ":" + "%02d" % round(int(sec_dec) * 3 / 5)
        return pace

    def _formatRecordNew(self, list_options):
        """20.07.2008 - dgranda
		New records handle date_time_utc field which is transparent when updating, so logic method has been splitted
		args: list with keys and values without valid format
		returns: keys and values matching DB schema"""
        logging.debug('>>')
        time = self.date.time2second(list_options["rcd_time"])
        average = self.parseFloatRecord(list_options["rcd_average"])
        keys = "date,sport,distance,time,beats,comments,average,calories,title,upositive,unegative,maxspeed,maxpace,pace,maxbeats,date_time_utc,date_time_local, duration"
        if (list_options["rcd_beats"] == ""):
            list_options["rcd_beats"] = 0

        #retrieving sport id (adding sport if it doesn't exist yet)
        sport_id = self.getSportId(list_options["rcd_sport"], add=True)

        values = (
            list_options["rcd_date"],
            sport_id,
            self.parseFloatRecord(list_options["rcd_distance"]),
            time,
            self.parseFloatRecord(list_options["rcd_beats"]),
            list_options["rcd_comments"],
            average,
            self.parseFloatRecord(list_options["rcd_calories"]),
            list_options["rcd_title"],
            self.parseFloatRecord(list_options["rcd_upositive"]),
            self.parseFloatRecord(list_options["rcd_unegative"]),
            self.parseFloatRecord(list_options["rcd_maxvel"]),
            self.pace_to_float(list_options["rcd_maxpace"]),
            self.pace_to_float(list_options["rcd_pace"]),
            self.parseFloatRecord(list_options["rcd_maxbeats"]),
            list_options["date_time_utc"],
            list_options["date_time_local"],
            time,
        )
        logging.debug('<<')
        return keys, values

    def insertRecord(self, list_options, laps=None, equipment=None):
        logging.debug('>>')
        #Create entry for activity in records table
        if list_options is None:
            logging.info('No data provided, abort adding entry')
            return None
        logging.debug('list_options: ' + str(list_options))
        cells, values = self._formatRecordNew(list_options)
        self.pytrainer_main.ddbb.insert("records", cells, values)
        logging.debug('DB updated: ' + str(cells) + ' | ' + str(values))
        id_record = self.pytrainer_main.ddbb.lastRecord("records")
        #Create entry(s) for activity in laps table
        if laps is not None:
            for lap in laps:
                lap['record'] = id_record  #Add reference to entry in record table
                lap_keys = ", ".join(map(str, lap.keys()))
                lap_values = lap.values()
                self.insertLaps(lap_keys, lap.values())
        if equipment is not None:
            for equipment_id in equipment:
                self._insert_record_equipment(id_record, equipment_id)
        gpxOrig = list_options["rcd_gpxfile"]
        if os.path.isfile(gpxOrig):
            gpxDest = self.pytrainer_main.profile.gpxdir
            gpxNew = gpxDest + "/%d.gpx" % id_record
            #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")

    def insertNewRecord(self, gpxOrig,
                        entry):  #TODO consolidate with insertRecord
        """29.03.2008 - dgranda
		Moves GPX file to store destination and updates database
		args: path to source GPX file"""
        logging.debug('--')
        (list_options, gpx_laps) = self.summaryFromGPX(gpxOrig, entry)
        if list_options is None:
            return None
        return self.insertRecord(list_options, laps=gpx_laps)

    def lapsFromGPX(self, gpx):
        logging.debug('>>')
        laps = []
        gpxLaps = gpx.getLaps()
        for lap in gpxLaps:
            lap_number = gpxLaps.index(lap)
            tmp_lap = {}
            tmp_lap['record'] = ""
            tmp_lap['lap_number'] = lap_number
            tmp_lap['elapsed_time'] = lap[0]
            tmp_lap['distance'] = lap[4]
            tmp_lap['start_lat'] = lap[5]
            tmp_lap['start_lon'] = lap[6]
            tmp_lap['end_lat'] = lap[1]
            tmp_lap['end_lon'] = lap[2]
            tmp_lap['calories'] = lap[3]
            tmp_lap['intensity'] = lap[7]
            tmp_lap['avg_hr'] = lap[8]
            tmp_lap['max_hr'] = lap[9]
            tmp_lap['max_speed'] = lap[10]
            tmp_lap['laptrigger'] = lap[11]
            tmp_lap['comments'] = ""
            laps.append(tmp_lap)
        logging.debug('<<')
        return laps

    def summaryFromGPX(self, gpxOrig, entry):
        """29.03.2008 - dgranda
		Retrieves info which will be stored in DB from GPX file
		args: path to source GPX file
		returns: list with fields and values, list of laps
		"""
        logging.debug('>>')
        gpx = Gpx(self.data_path, gpxOrig)
        distance, time, maxspeed, maxheartrate = gpx.getMaxValues()
        #if time == 0: #invalid record
        #	print "Invalid record"
        #	return (None, None)
        upositive, unegative = gpx.getUnevenness()
        if time > 0:
            speed = distance * 3600 / time
            time_hhmmss = [time // 3600, (time / 60) % 60, time % 60]
        else:
            speed = 0
            time_hhmmss = [0, 0, 0]
        summaryRecord = {}
        summaryRecord['rcd_gpxfile'] = gpxOrig
        summaryRecord['rcd_sport'] = entry[0]
        summaryRecord['rcd_date'] = gpx.getDate()
        summaryRecord['rcd_calories'] = gpx.getCalories()
        summaryRecord['rcd_comments'] = ''
        summaryRecord['rcd_title'] = ''
        summaryRecord[
            'rcd_time'] = time_hhmmss  #ToDo: makes no sense to work with arrays
        summaryRecord['rcd_distance'] = "%0.2f" % distance
        if speed == 0:
            summaryRecord['rcd_pace'] = "0"
        else:
            summaryRecord['rcd_pace'] = "%d.%02d" % ((3600 / speed) / 60,
                                                     (3600 / speed) % 60)
        if maxspeed == 0:
            summaryRecord['rcd_maxpace'] = "0"
        else:
            summaryRecord['rcd_maxpace'] = "%d.%02d" % ((3600 / maxspeed) / 60,
                                                        (3600 / maxspeed) % 60)
        summaryRecord['rcd_average'] = speed
        summaryRecord['rcd_maxvel'] = maxspeed
        summaryRecord['rcd_beats'] = gpx.getHeartRateAverage()
        summaryRecord['rcd_maxbeats'] = maxheartrate
        summaryRecord['rcd_upositive'] = upositive
        summaryRecord['rcd_unegative'] = unegative
        if entry[
                1] == "":  # coming from new track dialog (file opening)												#TODO This if-else needs checking
            summaryRecord['date_time_utc'], summaryRecord[
                'date_time_local'] = gpx.getStartTimeFromGPX(gpxOrig)  #
        else:  # coming from GPS device																				#
            summaryRecord['date_time_utc'] = entry[1]  #
            summaryRecord['date_time_local'] = entry[1]  #
            print "#TODO fix record summaryRecord local and utc time..."  #
        logging.debug('summary: ' + str(summaryRecord))
        laps = self.lapsFromGPX(gpx)
        logging.debug('<<')
        return summaryRecord, laps

    def updateRecord(
        self,
        list_options,
        id_record,
        equipment=None
    ):  # ToDo: update only fields that can change if GPX file is present
        logging.debug('>>')
        #Remove activity from pool so data is updated
        self.pytrainer_main.activitypool.remove_activity(id_record)
        gpxfile = self.pytrainer_main.profile.gpxdir + "/%d.gpx" % int(
            id_record)
        gpxOrig = list_options["rcd_gpxfile"]
        if os.path.isfile(gpxOrig):
            if gpxfile != gpxOrig:
                shutil.copy2(gpxOrig, gpxfile)
        else:
            if (list_options["rcd_gpxfile"] == ""):
                logging.debug('Activity not based in GPX file')  # ein?
        logging.debug('Updating bbdd')
        cells, values = self._formatRecordNew(list_options)
        self.pytrainer_main.ddbb.update("records", cells, values,
                                        " id_record=%d" % int(id_record))
        if equipment is not None:
            self._update_record_equipment(id_record, equipment)
        self.pytrainer_main.refreshListView()
        logging.debug('<<')

    def parseFloatRecord(self, string):
        logging.debug('--')
        if string != "":
            try:
                return float(string.replace(",", ","))
            except:
                return float(string)
        else:
            return 0

    def getrecordInfo(self, id_record):
        logging.debug('--')
        if id_record is None or id_record == "":
            return []
        return self.pytrainer_main.ddbb.select(
            "records,sports",
            "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 format_date(self, date):
        return date.strftime("%Y-%m-%d")

    def getrecordList(self, date, id_sport=None):
        logging.debug('--')
        if not id_sport:
            # outer join on sport id to workaround bug where sport reference is null on records from GPX import
            return self.pytrainer_main.ddbb.select(
                "records left outer join sports on records.sport=sports.id_sports",
                "sports.name,date,distance,time,beats,comments,average,calories,id_record,maxspeed,maxbeats,date_time_utc,date_time_local,upositive,unegative",
                "date=\"%s\" " % self.format_date(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,upositive,unegative",
                "date=\"%s\" and sports.id_sports=\"%s\" and records.sport=sports.id_sports"
                % (self.format_date(date), id_sport))

    def getLaps(self, id_record):
        logging.debug('--')
        laps = self.pytrainer_main.ddbb.select(
            "laps",
            "id_lap, record, elapsed_time, distance, start_lat, start_lon, end_lat, end_lon, calories, lap_number, intensity, max_speed, avg_hr, max_hr, laptrigger, comments",
            "record=\"%s\"" % id_record)
        if laps is None or laps == []:  #No laps stored - update DB
            logging.debug("No laps in DB for record %d" % id_record)
            #print ("No laps in DB for record %d" % id_record)
            gpx_dest = self.pytrainer_main.profile.gpxdir
            gpxfile = gpx_dest + "/%d.gpx" % id_record
            gpx = Gpx(self.data_path, gpxfile)
            laps = self.lapsFromGPX(gpx)
            if laps is not None:
                for lap in laps:
                    lap['record'] = id_record  #Add reference to entry in record table
                    lap_keys = ", ".join(map(str, lap.keys()))
                    lap_values = lap.values()
                    self.insertLaps(lap_keys, lap.values())
            #Try to get lap info again #TODO? refactor
            laps = self.pytrainer_main.ddbb.select(
                "laps",
                "id_lap, record, elapsed_time, distance, start_lat, start_lon, end_lat, end_lon, calories, lap_number, intensity, max_speed, avg_hr, max_hr, laptrigger, comments",
                "record=\"%s\"" % id_record)
        return laps

    def insertLaps(self, cells, values):
        logging.debug('--')
        logging.debug("Adding lap information: " + ", ".join(map(str, values)))
        self.pytrainer_main.ddbb.insert("laps", cells, values)

    def _insert_record_equipment(self, record_id, equipment_id):
        self.pytrainer_main.ddbb.insert("record_equipment",
                                        "record_id, equipment_id",
                                        [record_id, equipment_id])

    def _update_record_equipment(self, record_id, equipment_ids):
        self.pytrainer_main.ddbb.delete("record_equipment",
                                        "record_id={0}".format(record_id))
        for id in equipment_ids:
            self._insert_record_equipment(record_id, id)

    def get_record_equipment(self, record_id):
        record_equipment = []
        results = self.pytrainer_main.ddbb.select(
            "record_equipment", "equipment_id",
            "record_id={0}".format(record_id))
        for row in results:
            id = row[0]
            equipment_item = self._equipment_service.get_equipment_item(id)
            record_equipment.append(equipment_item)
        return record_equipment

    def getrecordPeriod(self, date_range, sport=None):
        #TODO This is essentially the same as getrecordPeriodSport (except date ranges) - need to look at merging the two
        date_ini = self.format_date(date_range.start_date)
        date_end = self.format_date(date_range.end_date)
        tables = "records,sports"
        if not sport:
            condition = "date>=\"%s\" and date<=\"%s\" and records.sport=sports.id_sports" % (
                date_ini, date_end)
        else:
            condition = "date>=\"%s\" and date<=\"%s\" and records.sport=sports.id_sports and sports.id_sports=\"%s\"" % (
                date_ini, date_end, sport)

        return self.pytrainer_main.ddbb.select(
            tables,
            "date,distance,time,beats,comments,average,calories,maxspeed,maxbeats, sports.name,upositive,unegative",
            condition)

    def getrecordPeriodSport(self, date_ini, date_end, sport):
        if not sport:
            tables = "records"
            condition = "date>\"%s\" and date<\"%s\"" % (date_ini, date_end)
        else:
            tables = "records,sports"
            condition = "date>\"%s\" and date<\"%s\" and records.sport=sports.id_sports and sports.id_sports=\"%s\"" % (
                date_ini, date_end, sport)

        return self.pytrainer_main.ddbb.select(
            tables,
            "date,distance,time,beats,comments,average,calories,maxspeed,maxbeats,upositive,unegative",
            condition)

    def _get_sport(self, sport_name):
        return self._sport_service.get_sport_by_name(sport_name)

    def getSportMet(self, sport_name):
        """Deprecated: use sport.met"""
        logging.debug('--')
        return self._get_sport(sport_name).met

    def getSportWeight(self, sport_name):
        """Deprecated: use sport.weight"""
        logging.debug('--')
        return self._get_sport(sport_name).weight

    def getSportId(self, sport_name, add=None):
        """Deprecated: use sport_service.get_sport_by_name()
		
		Get the id of a sport by name, optionally adding a new sport if
		none exists with the given name.
		arguments:
			sport_name: sport's name to get id for
			add: whether the sport should be added if not found
		returns: id for sport with given name or None"""
        if sport_name is None:
            return None
        sport = self._get_sport(sport_name)
        if sport is None:
            logging.debug("No sport with name: '%s'", str(sport_name))
            if add is not None:
                logging.debug("Adding sport '%s'", str(sport_name))
                new_sport = Sport()
                new_sport.name = unicode(sport_name)
                sport = self._sport_service.store_sport(new_sport)
        return None if sport is None else sport.id

    def getAllrecord(self):
        logging.debug('--')
        return self.pytrainer_main.ddbb.select(
            "records", "date,distance,time,beats,comments,average,calories")

    def getAllRecordList(self):
        logging.debug('--')
        return self.pytrainer_main.ddbb.select(
            "records,sports",
            "date,distance,average,title,sports.name,id_record,time,beats,calories",
            "sports.id_sports = records.sport order by date desc")

    def getRecordListByCondition(self, condition):
        logging.debug('--')
        if condition is None:
            return self.getAllRecordList()
        else:
            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 order by date desc" %
                condition)

    def getRecordDayList(self, date, id_sport=None):
        logging.debug('>>')
        logging.debug('Retrieving data for ' + str(date))
        # Why is looking for all days of the same month?
        if not id_sport:
            records = self.pytrainer_main.ddbb.select(
                "records", "date", "date LIKE '" + str(date.year) + "-" +
                date.strftime("%m") + "-%'")
        else:
            records = self.pytrainer_main.ddbb.select(
                "records", "date",
                "date LIKE \"%d-%0.2d-%%\" and sport=\"%s\"" %
                (date.year, date.month, id_sport))
        logging.debug('Found ' + str(len(records)) + ' entries')
        day_list = []
        for i in records:
            record = str(i[0]).split("-")
            logging.debug('date:' + str(i[0]))
            day_list.append(record[2])
        logging.debug('<<')
        return day_list

    def actualize_fromgpx(
        self, gpxfile
    ):  #TODO remove? - should never have multiple tracks per GPX file
        logging.debug('>>')
        logging.debug('loading file: ' + gpxfile)
        gpx = Gpx(self.data_path, gpxfile)
        tracks = gpx.getTrackRoutes()

        if len(tracks) == 1:
            logging.debug('Just 1 track')
            self._actualize_fromgpx(gpx)
        elif len(tracks) > 1:
            logging.debug('Found ' + str(len(tracks)) + ' tracks')
            self._select_trkfromgpx(gpxfile, tracks)
        else:
            msg = _("pytrainer can't import data from your gpx file")
            from gui.warning import Warning
            warning = Warning(self.data_path)
            warning.set_text(msg)
            warning.run()
        logging.debug('<<')

    def _actualize_fromgpx(self, gpx):
        logging.debug('>>')
        distance, time, maxspeed, maxheartrate = gpx.getMaxValues()
        upositive, unegative = gpx.getUnevenness()
        heartrate = gpx.getHeartRateAverage()
        date = gpx.getDate()
        calories = gpx.getCalories()
        start_time = gpx.getStart_time()

        self.recordwindow.rcd_date.set_text(date)
        self.recordwindow.rcd_starttime.set_text(start_time)
        self.recordwindow.rcd_upositive.set_text(str(upositive))
        self.recordwindow.rcd_unegative.set_text(str(unegative))
        self.recordwindow.rcd_beats.set_text(str(heartrate))
        self.recordwindow.rcd_calories.set_text(str(calories))
        self.recordwindow.set_distance(distance)
        self.recordwindow.set_maxspeed(maxspeed)
        self.recordwindow.set_maxhr(maxheartrate)
        self.recordwindow.set_recordtime(time / 60.0 / 60.0)
        self.recordwindow.on_calcavs_clicked(None)
        self.recordwindow.on_calccalories_clicked(None)
        self.recordwindow.rcd_maxpace.set_text(
            "%d.%02d" % ((3600 / maxspeed) / 60, (3600 / maxspeed) % 60))
        logging.debug('<<')

    def __actualize_fromgpx(self, gpxfile, name=None):
        logging.debug('>>')
        gpx = Gpx(self.data_path, gpxfile, name)
        self._actualize_fromgpx(gpx)
        logging.debug('<<')

    def _select_trkfromgpx(
        self, gpxfile, tracks
    ):  #TODO remove? - should never have multiple tracks per GPX file
        logging.debug('>>')
        logging.debug('Track dialog ' + self.data_path + '|' + gpxfile)
        selectrckdialog = DialogSelectTrack(self.data_path, tracks,
                                            self.__actualize_fromgpx, gpxfile)
        logging.debug('Launching window...')
        selectrckdialog.run()
        logging.debug('<<')

    def importFromGPX(self, gpxFile, sport):
        """
		Add a record from a valid pytrainer type GPX file
		"""
        logging.debug('>>')
        entry_id = None
        if not os.path.isfile(gpxFile):
            logging.error("Invalid file: " + gpxFile)
        else:
            logging.info('Retrieving data from ' + gpxFile)
            if not sport:
                sport = "import"
            entry = [sport, ""]
            entry_id = self.insertNewRecord(gpxFile, entry)
            if entry_id is None:
                logging.error("Entry not created for file %s" % gpxFile)
            else:
                logging.info("Entry %d has been added" % entry_id)
        logging.debug('<<')
        return entry_id
Пример #6
0
class pyTrainer:
    def __init__(self, filename=None, data_path=None):
        #Version constants
        self.version = "1.10.0-dev"
        #Process command line options
        self.startup_options = self.get_options()
        #Setup logging
        self.environment = Environment(platform.get_platform(),
                                       self.startup_options.conf_dir)
        self.environment.create_directories()
        self.set_logging(self.startup_options.log_level,
                         self.startup_options.log_type)
        logging.debug('>>')
        logging.debug("PyTrainer version %s" % (self.version))
        self.data_path = data_path
        self.date = Date()
        self.ddbb = None
        # Checking profile
        logging.debug('Checking configuration and profile...')
        self.profile = Profile(self.environment, self.data_path, self)
        self.uc = UC()
        self.windowmain = None
        self.ddbb = DDBB(self.profile, self)
        logging.debug('connecting to DDBB')
        self.ddbb.connect()

        initialize_data(self.ddbb, self.environment.conf_dir)

        self._sport_service = SportService(self.ddbb)
        self.record = Record(self._sport_service, data_path, self)
        self.athlete = Athlete(data_path, self)
        self.stats = Stats(self._sport_service, 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(self._sport_service,
                               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(self._sport_service, 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

        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,
                            equip=False,
                            newgraph=True,
                            conf_dir=None,
                            log_type="file")
        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("--oldgraph",
                          action="store_false",
                          dest="newgraph",
                          help="Turn off new graphing approach")
        parser.add_option(
            "--newgraph",
            action="store_true",
            dest="newgraph",
            help="Deprecated Option: Turn on new graphing approach")
        parser.add_option(
            "--confdir",
            dest="conf_dir",
            help=
            "Specify the directory where application configuration will be stored."
        )
        parser.add_option(
            "--logtype",
            dest="log_type",
            metavar="TYPE",
            type="choice",
            choices=["file", "console"],
            help=
            "Specify where logging should be output to. TYPE is one of 'file' (default), or 'console'."
        )
        (options, args) = parser.parse_args()
        return options

    def set_logging(self, level, log_type):
        '''Setup rotating log file with customized format'''
        if ("console" == log_type):
            handler = logging.StreamHandler(sys.stdout)
        else:
            handler = logging.handlers.RotatingFileHandler(
                self.environment.log_file, maxBytes=100000, backupCount=5)
        formatter = logging.Formatter(
            '%(asctime)s|%(levelname)s|%(module)s|%(funcName)s|%(message)s')
        handler.setFormatter(formatter)
        logging.getLogger('').addHandler(handler)
        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 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 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 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('<<')

    def refreshMainSportList(self):
        logging.debug('>>')
        sports = self._sport_service.get_all_sports()
        self.windowmain.updateSportList(sports)
        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 self.windowmain.recordview.get_current_page() == 4:
                self.refreshRecordGraphView("analytics")
        elif view == "day":
            logging.debug('day view')
            sport = self.windowmain.activeSport
            sport_id = self.record.getSportId(sport)
            record_list = self.record.getrecordList(date_selected, sport_id)
            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_range = DateRange.for_week_containing(date_selected)
            sport = self.windowmain.activeSport
            sport_id = self.record.getSportId(sport)
            record_list = self.record.getrecordPeriod(date_range, sport_id)
            self.windowmain.actualize_weekview(record_list, date_range)
        elif view == "month":
            logging.debug('month view')
            date_range = DateRange.for_month_containing(date_selected)
            sport = self.windowmain.activeSport
            sport_id = self.record.getSportId(sport)
            record_list = self.record.getrecordPeriod(date_range, sport_id)
            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_range = DateRange.for_year_containing(date_selected)
            sport = self.windowmain.activeSport
            sport_id = self.record.getSportId(sport)
            record_list = self.record.getrecordPeriod(date_range, sport_id)
            self.windowmain.actualize_yearview(record_list, date_selected.year)
            self.windowmain.actualize_yeargraph(record_list)
        elif view == "listview":
            logging.debug('list view')
            self.refreshListView()
        elif view == "athlete":
            logging.debug('athlete view')
            self.windowmain.on_athleteview_activate()
        elif view == "stats":
            logging.debug('stats view')
            self.windowmain.on_statsview_activate()
        else:
            print "Unknown view %s" % view
        logging.debug('<<')

    def refreshRecordGraphView(self, view, id_record=None):
        logging.debug('>>')
        logging.info('Working on ' + view + ' graph')
        if id_record is not None:
            #Refresh called for a specific record
            #Select correct record in treeview
            model = self.windowmain.recordTreeView.get_model()
            #Loop through all records in treeview looking for the correct one to highlight
            for i, row in enumerate(model):
                if row[0] == id_record:
                    self.windowmain.recordTreeView.set_cursor(i)
        else:
            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)
        if view == "analytics":
            self.windowmain.actualize_analytics(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 refreshListRecords(self):
        logging.debug('>>')
        #Refresh list view
        #self.refreshListView() # old variant
        self.refreshListView(self.windowmain.listsearch.condition)
        #Refresh list records
        date = self.date.getDate()
        sport = self.windowmain.activeSport
        id_sport = self.record.getSportId(sport)
        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, id_sport)
        self.windowmain.actualize_calendar(record_list)
        logging.debug('<<')

    def refreshAthleteView(self):
        logging.debug('>>')
        self.athlete.refresh()
        self.windowmain.actualize_athleteview(self.athlete)
        logging.debug('<<')

    def refreshStatsView(self):
        logging.debug('>>')
        self.stats.refresh()
        self.windowmain.actualize_statsview(self.stats,
                                            self.record.getAllRecordList())
        logging.debug('<<')

    def refreshListView(self, condition=None):
        logging.debug('>>')
        record_list = self.record.getRecordListByCondition(condition)
        self.windowmain.actualize_listview(record_list)
        logging.debug('<<')

    def refreshWaypointView(self, default_waypoint=None, redrawmap=1):
        logging.debug('>>')
        waypoint_list = self.waypoint.getAllWaypoints()
        self.windowmain.actualize_waypointview(waypoint_list, default_waypoint,
                                               redrawmap)
        logging.debug('<<')

    def editExtensions(self):
        logging.debug('>>')
        before = self.extension.getActiveExtensions()
        self.extension.manageExtensions()
        after = self.extension.getActiveExtensions()
        self.setExtensions(before, after)
        logging.debug('<<')

    def importData(self):
        logging.debug('>>')
        activeplugins_before = self.plugins.getActivePlugins()
        self.importdata.runImportdata()
        activeplugins_after = self.plugins.getActivePlugins()
        #Need to check for plugins that have been disabled (were active and now are not)
        self.setMenuPlugins(activeplugins_before, activeplugins_after)
        self.refreshListRecords()
        self.refreshGraphView(self.windowmain.selected_view)
        logging.debug('<<')

    def editGpsPlugins(self):
        logging.debug('>>')
        activeplugins_before = self.plugins.getActivePlugins()
        self.plugins.managePlugins()
        activeplugins_after = self.plugins.getActivePlugins()
        #Need to check for plugins that have been disabled (were active and now are not)
        self.setMenuPlugins(activeplugins_before, activeplugins_after)
        logging.debug('<<')

    def setMenuPlugins(self, activeplugins_before, activeplugins_after):
        logging.debug('>>')
        #Need to check for plugins that have been disabled (were active and now are not)
        for plugin in activeplugins_before:
            if plugin not in activeplugins_after:
                #disabled plugin -> need to unload plugin
                txtbutton = self.plugins.loadPlugin(plugin)
                self.windowmain.removeImportPlugin(txtbutton)
        #Need to check for plugins that have been enabled (were not active and now are)
        for plugin in activeplugins_after:
            if plugin not in activeplugins_before:
                #new active plugin -> need to load plugin
                txtbutton = self.plugins.loadPlugin(plugin)
                self.windowmain.addImportPlugin(txtbutton)
        logging.debug('<<')

    def setExtensions(self, before, after):
        logging.debug('>>')
        #Need to check for extensions that have been disabled (were active and now are not)
        for extension in before:
            if extension not in after:
                #disabled extension -> need to unload extension
                print "Need to disable extension %s " % extension
                txtbutton = self.extension.loadExtension(extension)
                self.windowmain.removeExtension(txtbutton)
        #Need to check for plugins that have been enabled (were not active and now are)
        for extension in after:
            if extension not in before:
                #new active extension -> need to load extension
                logging.debug("Enabling extension %s " % extension)
                txtbutton = self.extension.loadExtension(extension)
                self.windowmain.addExtension(txtbutton)
        logging.debug('<<')

    def newRecord(self,
                  title=None,
                  distance=None,
                  time=None,
                  upositive=None,
                  unegative=None,
                  bpm=None,
                  calories=None,
                  comment=None,
                  view=None):
        logging.debug('>>')
        date = self.date.getDate()
        self.record.newRecord(date, title, distance, time, upositive,
                              unegative, bpm, calories, comment)
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def editRecord(self, id_record, view=None):
        logging.debug("Editing record with id: '%s'", id_record)
        self.record.editRecord(id_record)
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def removeRecord(self, id_record, confirm=False, view=None):
        logging.debug('>>')
        if confirm:
            self.record.removeRecord(id_record)
        else:
            msg = _("Delete this database entry?")
            params = [id_record, True]
            warning = Warning(self.data_path, self.removeRecord, params)
            warning.set_text(msg)
            warning.run()
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def removeWaypoint(self, id_waypoint, confirm=False):
        logging.debug('>>')
        if confirm:
            self.waypoint.removeWaypoint(id_waypoint)
            self.refreshWaypointView()
        else:
            msg = _("Delete this waypoint?")
            params = [id_waypoint, True]
            warning = Warning(self.data_path, self.removeWaypoint, params)
            warning.set_text(msg)
            warning.run()
        logging.debug('<<')

    def updateWaypoint(self, id_waypoint, lat, lon, name, desc, sym):
        logging.debug('>>')
        self.waypoint.updateWaypoint(id_waypoint, lat, lon, name, desc, sym)
        self.refreshWaypointView(id_waypoint)
        logging.debug('<<')

    def exportCsv(self):
        logging.debug('>>')
        from save import Save
        save = Save(self.data_path, self.record)
        save.run()
        logging.debug('<<')

    def editProfile(self):
        logging.debug('>>')
        self.profile.editProfile(self._sport_service)
        self.activitypool.clear_pool()
        self.windowmain.setup()
        logging.debug('<<')