Exemplo n.º 1
0
 def setUp(self):
     self.ddbb = DDBB()
     self.ddbb.connect()
     self.ddbb.create_tables(add_default=True)
     main = mock.Mock()
     main.ddbb = self.ddbb
     main.startup_options = mock.Mock()
     main.profile = mock.Mock()
     main.profile.plugindir = 'plugins'
     plugins = Plugins(parent=main)
     self.plugin = plugins.importClass('plugins/garmin-tcxv2')
     tree = etree.parse('pytrainer/test/imports/sample.tcx')
     self.activity = self.plugin.getActivities(tree)[0]
Exemplo n.º 2
0
 def __init__(self, sport_service, data_path = None, parent=None, config=None, pytrainer_main=None):
     self._sport_service = sport_service
     self.data_path = data_path
     self.glade_path=data_path+"glade/importdata.glade"
     self.root = "win_importdata"
     self.domain = None
     self.parent = parent
     self.pytrainer_main = pytrainer_main
     self.configuration = config
     self.activities_store = None # gtk.ListStore containing gtk.TreeModelRow, see build_activities_tree_view
     self.files_store = None # gtk.ListStore containing gtk.TreeModelRow, see build_files_tree_view
     self.processClasses = []
     self.plugins = Plugins(data_path, self.parent.parent)
     SimpleGladeApp.__init__(self, self.glade_path, self.root, self.domain)
Exemplo n.º 3
0
 def __init__(self,
              sport_service,
              data_path=None,
              parent=None,
              config=None,
              pytrainer_main=None):
     self._sport_service = sport_service
     self.data_path = data_path
     self.parent = parent
     self.pytrainer_main = pytrainer_main
     self.configuration = config
     self.activities_store = None  # Gtk.ListStore containing Gtk.TreeModelRow, see build_activities_tree_view
     self.files_store = None  # Gtk.ListStore containing Gtk.TreeModelRow, see build_files_tree_view
     self.processClasses = []
     self.plugins = Plugins(data_path, self.parent.parent)
     SimpleBuilderApp.__init__(self, "importdata.ui")
Exemplo n.º 4
0
 def __init__(self, sport_service, data_path = None, parent=None, config=None, pytrainer_main=None):
     self._sport_service = sport_service
     self.data_path = data_path
     self.glade_path=data_path+"glade/importdata.glade"
     self.root = "win_importdata"
     self.domain = None
     self.parent = parent
     self.pytrainer_main = pytrainer_main
     self.configuration = config
     self.activities_store = None
     self.files_store = None
     self.processClasses = []
     self.plugins = Plugins(data_path, self.parent.parent)
     SimpleGladeApp.__init__(self, self.glade_path, self.root, self.domain)
Exemplo n.º 5
0
class WindowImportdata(SimpleBuilderApp):
    def __init__(self,
                 sport_service,
                 data_path=None,
                 parent=None,
                 config=None,
                 pytrainer_main=None):
        self._sport_service = sport_service
        self.data_path = data_path
        self.parent = parent
        self.pytrainer_main = pytrainer_main
        self.configuration = config
        self.activities_store = None  # Gtk.ListStore containing Gtk.TreeModelRow, see build_activities_tree_view
        self.files_store = None  # Gtk.ListStore containing Gtk.TreeModelRow, see build_files_tree_view
        self.processClasses = []
        self.plugins = Plugins(data_path, self.parent.parent)
        SimpleBuilderApp.__init__(self, "importdata.ui")

    def new(self):
        logging.debug(">>")
        try:
            self.defaulttab = self.configuration.getValue(
                "pytraining", "import_default_tab")
            self.defaulttab = int(self.defaulttab)
        except Exception as e:
            logging.debug("Exception: %s", str(e))
            self.defaulttab = 0
        self.auto_launch = self.configuration.getValue(
            "pytraining", "auto_launch_file_selection")
        if self.auto_launch == "True":
            self.auto_launch = True
        else:
            self.auto_launch = False
        logging.debug("Default tab: %s, Auto launch: %s", self.defaulttab,
                      self.auto_launch)
        self.init_all_tabs()
        self.notebookMainTabs.set_current_page(self.defaulttab)
        self.init_tab(self.defaulttab,
                      first=True)  #TODO fix so dont need to re-call init_tab
        logging.debug("<<")

    def init_all_tabs(self):
        logging.debug(">>")
        tabs = (0, 1, 2, 3, 4)
        for tab in tabs:
            self.init_tab(tab)

    def init_tab(self, page, first=False):
        ''' Initialise tab '''
        logging.debug(">>")
        logging.debug("page: %d first: %s" % (page, first))
        if page == 0:
            #'Import from GPS Device' tab
            self.init_gpsdevice_tab()
        elif page == 1:
            #'Import from File' tab
            self.init_file_tab(first)
        elif page == 2:
            #'Plugins' tab
            self.init_plugins_tab()
        elif page == 3:
            #'Options' tab
            self.init_options_tab()
        elif page == 4:
            #'CSV Import' tab
            self.init_csvimport_tab()
        else:
            #unknown tab
            logging.error("Unknown page %d passed to init_tab" % page)

    def updateStatusbar(self, statusbar, text, context_id=None):
        ''' Help function to set the text of the statusbar '''
        logging.debug("Setting statusbar %s to %s" %
                      (statusbar.get_name(), text))
        if context_id is None:
            context_id = statusbar.get_context_id(text)
        statusbar.push(context_id, text)
        return context_id

    def init_gpsdevice_tab(self):
        logging.debug(">>")
        logging.error("GPS Device import not yet implemented")
        logging.debug("<<")
        return

    def init_file_tab(self, first=False):
        logging.debug(">>")
        self.updateStatusbar(self.statusbarImportFile, _("No file selected"))
        self.processClasses = []
        if self.activities_store is None:
            self.activities_store = self.build_activities_tree_view()
        else:
            self.activities_store.clear()
        if self.files_store is None:
            self.files_store = self.build_files_tree_view()
        else:
            self.files_store.clear()
        self.buttonRemoveSelectedFiles.set_sensitive(0)
        self.buttonFileImport.set_sensitive(0)
        if first and self.auto_launch:
            while Gtk.events_pending():  # This allows the GUI to update
                Gtk.main_iteration()  # before completion of this entire action
            logging.debug("autolaunch active")
            self.buttonSelectFiles.clicked()
        logging.debug(">>")
        return

    def init_plugins_tab(self):
        logging.debug(">>")
        #Remove components in vbox - in case of re-detection
        for child in self.vboxPlugins.get_children():
            if isinstance(child, Gtk.Table):
                self.vboxPlugins.remove(child)
        pluginList = self.plugins.getPluginsList()
        logging.debug(pluginList)
        for plugin in pluginList:
            #Store plugin details
            pluginClass = plugin[0]
            pluginName = plugin[1]
            pluginDescription = plugin[2]
            #Build frame with name and description
            pluginFrame = Gtk.Frame(label="<b>" + pluginName + "</b>")
            pluginFrameLabel = pluginFrame.get_label_widget()
            pluginFrameLabel.set_use_markup(True)
            description = Gtk.Label(label="<small>" + pluginDescription +
                                    "</small>")
            description.set_alignment(0, 0)
            description.set_use_markup(True)
            description.set_line_wrap(True)
            pluginFrame.add(description)
            #Get plugin information
            name, description, status = self.plugins.getPluginInfo(pluginClass)
            #Create labels and buttons
            configButton = Gtk.Button(label=_("Configure"))
            #Connect button handlers
            configButton.connect('clicked',
                                 self.on_pluginsButton_Configure_clicked,
                                 pluginClass)
            if status == 0 or status == "0":
                #Plugin disabled
                pluginFrame.set_sensitive(0)
                statusLabel = Gtk.Label(label=_("Disabled"))
            else:
                statusLabel = Gtk.Label(label=_("Enabled"))

            #Create a table for the frame and button
            pluginTable = Gtk.Table()
            pluginTable.attach(pluginFrame,
                               0,
                               1,
                               0,
                               1,
                               xoptions=Gtk.AttachOptions.EXPAND
                               | Gtk.AttachOptions.FILL,
                               xpadding=5)
            pluginTable.attach(statusLabel,
                               1,
                               2,
                               0,
                               1,
                               xoptions=Gtk.AttachOptions.FILL,
                               yoptions=Gtk.AttachOptions.SHRINK,
                               xpadding=5,
                               ypadding=5)
            pluginTable.attach(configButton,
                               2,
                               3,
                               0,
                               1,
                               xoptions=Gtk.AttachOptions.FILL,
                               yoptions=Gtk.AttachOptions.SHRINK,
                               xpadding=5,
                               ypadding=5)
            #Add frame to tab
            self.vboxPlugins.pack_start(pluginTable,
                                        expand=False,
                                        fill=False,
                                        padding=5)
        self.win_importdata.show_all()
        logging.debug("<<")
        return

    def init_options_tab(self):
        logging.debug(">>")
        logging.debug("Default tab %s", self.defaulttab)
        #Set correct radiobutton based on saved preference
        if self.defaulttab == 1:
            self.radiobuttonFile.set_active(1)
            self.checkbuttonAutoLaunch.set_sensitive(1)
        elif self.defaulttab == 2:
            self.radiobuttonPlugins.set_active(1)
        else:
            self.radiobuttonTabGPSDevice.set_active(1)
        if self.auto_launch:
            self.checkbuttonAutoLaunch.set_active(1)
        logging.debug("<<")
        return

    def init_csvimport_tab(self):
        logging.debug(">>")
        #Populate Force Sport to combobox
        sport_list = self._sport_service.get_all_sports()
        #Remove placeholder item (needed to ensure correct model for combobox)
        self.comboCSVForceSport.remove(0)
        for sport in sport_list:
            logging.debug('Adding sport: %s' % sport.name)
            self.comboCSVForceSport.append_text(sport.name)
        self.comboCSVForceSport.set_active(0)
        logging.debug("<<")
        return

    def detect_tools(self):
        '''
            Iterate through all tool files from import directory
            Each file contains information on a particular tool
            and knows how to determine if the tool is present on the system
            and what configuration options are needed for the tool

            Currently displays the tool info and config grayed out if tool is not present
        '''
        logging.debug('>>')
        self.updateStatusbar(self.statusbarDevice, _("Checking for tools"))
        #Remove all components in vbox - in case of re-detection
        for child in self.vboxImportTools.get_children():
            self.vboxImportTools.remove(child)
        #Get import tool_* files
        fileList = glob.glob(self.data_path + "imports/tool_*.py")
        logging.debug("Tools filelist: %s" % fileList)
        for toolFile in fileList:
            index = fileList.index(toolFile)
            directory, filename = os.path.split(toolFile)
            filename = filename.rstrip('.py')
            classname = filename.lstrip('tool_')
            #Import module
            sys.path.insert(0, self.data_path + "import")
            module = __import__(filename)
            toolMain = getattr(module, classname)
            #Instantiate module
            toolClass = toolMain(self.parent, self.data_path)
            #Get info from class
            toolName = toolClass.getName()
            toolTable = Gtk.Table()
            toolFrame = Gtk.Frame(label=toolName)
            toolFrame.add(toolTable)
            if toolClass.isPresent():
                version = Gtk.Label(label="Version: " + toolClass.getVersion())
                version.set_alignment(0, 0)
                if toolClass.deviceExists():
                    deviceExists = Gtk.Label(label=_("GPS device found"))
                    deviceExists.set_alignment(0, 0)
                else:
                    deviceExists = Gtk.Label(
                        label=_("GPS device <b>not</b> found"))
                    deviceExists.set_alignment(0, 0)
                    deviceExists.set_use_markup(True)
                toolTable.attach(version,
                                 0,
                                 1,
                                 0,
                                 1,
                                 xoptions=Gtk.AttachOptions.EXPAND
                                 | Gtk.AttachOptions.FILL,
                                 xpadding=5)
                toolTable.attach(deviceExists,
                                 0,
                                 1,
                                 1,
                                 2,
                                 xoptions=Gtk.AttachOptions.EXPAND
                                 | Gtk.AttachOptions.FILL,
                                 xpadding=5)
                toolFrame.set_sensitive(1)
            else:
                info = Gtk.Label(
                    label=_("This tool was not found on the system"))
                info.set_alignment(0, 0.5)
                location = Gtk.LinkButton(toolClass.getSourceLocation(),
                                          toolName + _(" Homepage"))
                info.set_sensitive(0)
                toolTable.attach(info,
                                 0,
                                 1,
                                 0,
                                 1,
                                 xoptions=Gtk.AttachOptions.EXPAND
                                 | Gtk.AttachOptions.FILL,
                                 xpadding=5)
                toolTable.attach(location,
                                 1,
                                 2,
                                 0,
                                 1,
                                 xoptions=Gtk.AttachOptions.EXPAND
                                 | Gtk.AttachOptions.FILL,
                                 xpadding=5)
                #toolFrame.set_sensitive(0)
            self.vboxImportTools.pack_start(toolFrame,
                                            expand=False,
                                            fill=False,
                                            padding=5)
        self.win_importdata.show_all()
        logging.debug('<<')

    def validateFile(self, import_filename):
        '''
            Iterate through all supported types of file by reading processing files from import directory
            Each processing file understands one type of file

            If a processing file is found that recognises the selected file:
                 returns the instantiated class
            otherwise:
                 returns None
        '''
        logging.debug('>>')
        self.updateStatusbar(self.statusbarImportFile,
                             _("Checking file type for: ") + import_filename)
        #Get imports files_* files
        fileList = glob.glob(self.data_path + "imports/file_*.py")
        fileList.sort()
        logging.debug("File filelist: %s" % fileList)
        for processingFile in fileList:
            directory, filename = os.path.split(processingFile)
            filename = filename.rstrip('.py')
            logging.debug("Trying: %s" % filename)
            classname = filename.lstrip('file_')
            #Import module
            sys.path.insert(0, self.data_path + "imports")
            module = __import__(filename)
            processMain = getattr(module, classname)
            #Instantiate module
            processClass = processMain(self.parent, self.data_path)
            isValid = processClass.testFile(import_filename)
            if isValid:
                logging.debug('<<')
                return processClass
            else:
                processClass = None
        logging.debug('<<')
        return processClass

    def build_files_tree_view(self):
        ''' Build tree view to hold files from which the activities are read '''
        logging.debug('>>')
        store = Gtk.ListStore(
            GObject.TYPE_STRING,
            GObject.TYPE_BOOLEAN,
            GObject.TYPE_STRING,
            GObject.TYPE_STRING,
            GObject.TYPE_STRING,
        )
        column_names = ["id", "", _("File"), _("Type"), _("Activities")]
        for column_index, column_name in enumerate(column_names):
            if column_index == 1:
                #Add button column
                self.renderer1 = Gtk.CellRendererToggle()
                self.renderer1.set_property('activatable', True)
                self.renderer1.connect(
                    'toggled', self.treeviewImportFiles_toggled_checkbox,
                    store)
                column = Gtk.TreeViewColumn(column_name, self.renderer1)
                column.add_attribute(self.renderer1, "active", column_index)
                column.set_sort_column_id(-1)
            else:
                #Add other columns
                column = Gtk.TreeViewColumn(column_name,
                                            Gtk.CellRendererText(),
                                            text=column_index)
                column.set_sort_column_id(column_index)
            if column_name == "id":
                column.set_visible(False)
            column.set_resizable(True)
            self.treeviewImportFiles.append_column(column)
        self.treeviewImportFiles.set_headers_clickable(True)
        self.treeviewImportFiles.set_model(store)
        logging.debug('<<')
        return store

    def build_activities_tree_view(self):
        ''' Build tree view to hold activities that can be selected for import '''
        logging.debug('>>')
        store = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_BOOLEAN,
                              GObject.TYPE_STRING, GObject.TYPE_STRING,
                              GObject.TYPE_STRING, GObject.TYPE_STRING,
                              GObject.TYPE_STRING, GObject.TYPE_STRING,
                              GObject.TYPE_BOOLEAN)
        column_names = [
            "id", "",
            _("Start Time"),
            _("Distance"),
            _("Duration"),
            _("Sport"),
            _("Notes"), "file_id", "in_db"
        ]
        for column_index, column_name in enumerate(column_names):
            if column_index == 1:
                #Add checkbox column
                self.renderer1 = Gtk.CellRendererToggle()
                self.renderer1.set_property('activatable', True)
                self.renderer1.connect(
                    'toggled', self.treeviewImportEvents_toggled_checkbox,
                    store)
                column = Gtk.TreeViewColumn(column_name, self.renderer1)
                column.add_attribute(self.renderer1, "active", column_index)
                column.set_sort_column_id(-1)
                column.connect('clicked',
                               self.treeviewImportEvents_header_checkbox,
                               store)
            else:
                #Add other columns
                column = Gtk.TreeViewColumn(column_name,
                                            Gtk.CellRendererText(),
                                            text=column_index)
                column.set_sort_column_id(column_index)
            if column_name == "id" or column_name == "file_id" or column_name == "in_db":
                column.set_visible(False)
            column.set_resizable(True)
            self.treeviewImportEvents.append_column(column)
        self.treeviewImportEvents.set_headers_clickable(True)
        self.treeviewImportEvents.set_model(store)
        logging.debug('<<')
        return store

    def checkTreestoreForSelection(self, store):
        '''
            Function iterates over store checking if any items are selected
            returns True if at least one item is selected, False otherwise
            Checks item in position 1 only
        '''
        for item in store:
            if item[1]:
                return True
        return False

    def treeviewImportFiles_toggled_checkbox(self, cell, path, store):
        '''
            Sets the state of the checkbox to true or false.
        '''
        store[path][1] = not store[path][1]
        self.buttonRemoveSelectedFiles.set_sensitive(
            self.checkTreestoreForSelection(store))

    def treeviewImportEvents_toggled_checkbox(self, cell, path, store):
        '''
            Sets the state of the checkbox to true or false.
        '''
        store[path][1] = not store[path][1]
        self.buttonFileImport.set_sensitive(
            self.checkTreestoreForSelection(store))

    def treeviewImportEvents_setCheckboxes(self, state):
        '''
            Sets or unsets all checkboxes
        '''
        if self.activities_store is None or len(self.activities_store) == 0:
            return
        for item in self.activities_store:
            item[1] = state
        if state:
            self.buttonFileImport.set_sensitive(1)
        else:
            self.buttonFileImport.set_sensitive(0)

    def saveOptions(self):
        '''
            Save options selected in options tab
        '''
        self.autoLaunchFileSelection = "False"
        #Default tab option
        if self.radiobuttonTabGPSDevice.get_active():
            self.defaulttab = "0"
        elif self.radiobuttonFile.get_active():
            self.defaulttab = "1"
            if self.checkbuttonAutoLaunch.get_active():
                self.autoLaunchFileSelection = "True"
        elif self.radiobuttonPlugins.get_active():
            self.defaulttab = "2"
        logging.debug("Saving default tab: %s, auto launch: %s",
                      self.defaulttab, self.autoLaunchFileSelection)
        self.configuration.setValue("pytraining", "import_default_tab",
                                    self.defaulttab)
        self.configuration.setValue("pytraining", "auto_launch_file_selection",
                                    self.autoLaunchFileSelection)

    def removeSelectedFiles(self):
        '''
            Function to determine which files are selected
            * remove them from the list
            * remove the associated activities from the list also
        '''
        if self.files_store is None:
            return
        file_index = 0
        file_iters = []
        activity_iters = []
        for item in self.files_store:
            if item[1] is True:  #Checkbox is True, file for removal
                file_id = item[0]
                activity_index = 0
                for activity in self.activities_store:
                    if activity[
                            7] == file_id:  #Activity relates to file to be removed
                        activity_iters.append(
                            self.activities_store.get_iter(activity_index))
                    activity_index += 1
                file_iters.append(self.files_store.get_iter(file_index))
            file_index += 1
        logging.debug("Removing %d activities from activity tree view" %
                      len(activity_iters))
        for activity_iter in activity_iters:
            self.activities_store.remove(activity_iter)
        self.buttonFileImport.set_sensitive(
            self.checkTreestoreForSelection(
                self.activities_store))  #Set correct state for import button
        logging.debug("Removing %d files from file tree view" %
                      len(file_iters))
        for file_iter in file_iters:
            self.files_store.remove(file_iter)

    def getSelectedActivities(self):
        """
            Function to determine which activities are selected

            Returns array of the ids of the selected activities
        """
        selectedActivities = []
        if self.activities_store is None:
            logging.debug("activities_store is empty")
            return None
        for item in self.activities_store:
            if item[1] is True:  #Checkbox is True (selected)
                logging.debug("Added activity %s to selected list" % item)
                file_id = int(item[7])
                activity_id = item[0]
                start_time = item[2]
                distance = item[3]
                duration = item[4]
                sport = item[5]
                gpx_file = self.processClasses[file_id].getGPXFile(
                    activity_id, file_id)[1]
                in_db = item[8]
                selectedActivities.append(
                    (activity_id, start_time, distance, duration, sport,
                     gpx_file, file_id, in_db))
        logging.debug("Found %d selected activities to import" %
                      len(selectedActivities))
        return selectedActivities

    def importSelectedActivities(self, activities):
        """
            Function to import selected activity
        """
        logging.debug(
            "Checking if activities are already present in database...")
        for activity in activities:
            if activity[7]:
                logging.debug(
                    "Activity from %s (%s) already in database. Skipping import."
                    % (activity[1], activity[5]))
                activities.remove(activity)
                self.updateActivity(activity[0], activity[6], status=False)

        if len(activities) > 0:
            logging.debug("Importing %d activities" % len(activities))
            result = self.pytrainer_main.record.newMultiRecord(activities)
            for activity in result:
                if "db_id" in activity.keys() and type(
                        activity["db_id"]) is int:
                    #Activity imported correctly
                    duration = "%0.0f:%0.0f:%02.0f" % (
                        float(activity["rcd_time"][0]),
                        float(activity["rcd_time"][1]),
                        float(activity["rcd_time"][2]))
                    self.updateActivity(activity["activity_id"],
                                        activity["file_id"],
                                        status=False,
                                        notes=_("Imported into database"),
                                        sport=activity["rcd_sport"],
                                        distance=activity["rcd_distance"],
                                        duration=duration,
                                        in_db=True)
        else:
            logging.debug("No activities to import")
        return len(activities)

    def updateActivity(self,
                       activityID,
                       file_id,
                       status=None,
                       notes=None,
                       sport=None,
                       distance=None,
                       duration=None,
                       in_db=None):
        path = 0
        for item in self.activities_store:
            if item[0] == activityID and item[7] == str(file_id):
                if status is not None:
                    self.activities_store[path][1] = status
                if notes is not None:
                    self.activities_store[path][6] = notes
                if sport is not None:
                    self.activities_store[path][5] = sport
                if distance is not None:
                    self.activities_store[path][3] = distance
                if duration is not None:
                    self.activities_store[path][4] = duration
                if in_db is not None:
                    self.activities_store[path][8] = in_db
            path += 1

    def close_window(self):
        logging.debug('--')
        self.win_importdata.hide()
        self.quit()

    ############################
    ## Window signal handlers ##
    ############################

    def on_radiobuttonFile_toggled(self, *args):
        logging.debug("radio button toggled")

    def on_pluginsButton_Configure_clicked(self, button, pluginClass):
        '''
            Handler for plugin Buttons
        '''
        name, description, status = self.plugins.getPluginInfo(pluginClass)
        prefs = self.plugins.getPluginConfParams(pluginClass)

        self.prefwindow = Gtk.Window()
        self.prefwindow.set_border_width(20)
        self.prefwindow.set_title(_("%s settings" % name))
        self.prefwindow.set_modal(True)

        table = Gtk.Table(1, 2)
        i = 0
        self.entryList = []
        for pref in prefs:
            label = Gtk.Label(label="<b>%s</b>" % pref[0])
            label.set_use_markup(True)
            if pref[0] != "status":
                entry = Gtk.Entry()
                entry.set_text(pref[1])
                self.entryList.append(entry)
                table.attach(entry, 1, 2, i, i + 1)
            else:
                combobox = Gtk.ComboBoxText()
                combobox.append_text(_("Disable"))
                combobox.append_text(_("Enable"))
                combobox.set_active(int(pref[1]))
                table.attach(combobox, 1, 2, i, i + 1)
                self.entryList.append(combobox)
            table.attach(label, 0, 1, i, i + 1)
            i += 1

        button = Gtk.Button(_("Ok"))
        button.connect("clicked", self.on_pluginAcceptSettings_clicked,
                       pluginClass)
        table.attach(button, 0, 2, i, i + 1)
        self.prefwindow.add(table)
        self.prefwindow.show_all()

    def on_pluginAcceptSettings_clicked(self, widget, pluginClass):
        '''
            Duplicate of plugin settings accept handler
        '''
        logging.debug('>>')
        prefs = self.plugins.getPluginConfParams(pluginClass)
        savedOptions = []
        i = 0
        for pref in prefs:
            try:
                savedOptions.append(
                    (pref[0], gtk_str(self.entryList[i].get_text())))
            except:
                combobox = self.entryList[i]
                index = combobox.get_active()
                savedOptions.append((pref[0], "%s" % index))
            i += 1
        self.prefwindow.hide()
        self.prefwindow = None
        self.plugins.setPluginConfParams(pluginClass, savedOptions)
        self.init_plugins_tab()
        logging.debug('<<')

    def treeviewImportEvents_header_checkbox(self, column, store):
        '''
            Handler for click on checkbox column
        '''
        logging.debug('--')
        if store is None:
            return
        for item in store:
            if item[1]:
                self.treeviewImportEvents_setCheckboxes(False)
                return
        self.treeviewImportEvents_setCheckboxes(True)

    def on_win_importdata_delete_event(self, widget, window):
        ''' Window closed '''
        logging.debug('--')
        self.close_window()

    def on_notebookMainTabs_switch_page(self, notebook, page, new_page):
        logging.debug('--')
        #self.init_tab(new_page)

    def on_buttonOptionsSave_clicked(self, widget):
        logging.debug('>>')
        self.updateStatusbar(self.statusbarOptions, _("Saving options"))
        self.saveOptions()
        self.updateStatusbar(self.statusbarOptions, _("Options saved"))
        logging.debug('<<')

    def on_buttonOptionsReset_clicked(self, widget):
        logging.debug('>>')
        #GPS Device is default
        self.defaulttab = 0
        #Redisplay tab
        self.init_options_tab()
        self.updateStatusbar(self.statusbarOptions, "")
        logging.debug('<<')

    def on_buttonRemoveSelectedFiles_clicked(self, widget):
        ''' Remove selected files and associated activities from list '''
        logging.debug('>>')
        self.removeSelectedFiles()
        self.updateStatusbar(self.statusbarOptions, "")
        logging.debug('<<')

    def on_buttonFileImport_clicked(self, widget):
        ''' Import selected activities '''
        logging.debug('>>')
        selectedActivities = self.getSelectedActivities()
        selectedCount = len(selectedActivities)
        if selectedCount > 0:
            if selectedCount == 1:
                msgImporting = _("Importing one activity")
            else:
                msgImporting = _("Importing %d activities") % selectedCount
            self.updateStatusbar(self.statusbarImportFile, msgImporting)
            logging.debug(msgImporting)
            while Gtk.events_pending():  # This allows the GUI to update
                Gtk.main_iteration()  # before completion of this entire action
            importedActivities = self.importSelectedActivities(
                selectedActivities)
            # Preparing feedback for user
            if importedActivities == 0:
                msgImported = _("No activity has been imported")
            elif importedActivities == 1:
                msgImported = _("Imported one activity")
            elif importedActivities > 1:
                msgImported = _("Imported %d activities") % importedActivities
            discardedActivities = selectedCount - importedActivities
            if discardedActivities > 0:
                if discardedActivities == 1:
                    msgImported += _(
                        " Activity selected was already present in DB")
                else:
                    msgImported += _(
                        " %d selected activities were already present in DB"
                    ) % discardedActivities
            self.updateStatusbar(self.statusbarImportFile, msgImported)
            logging.debug(msgImported)
        self.buttonFileImport.set_sensitive(0)  #Disable import button
        logging.debug('<<')

    def on_buttonSelectFiles_clicked(self, widget):
        logging.debug('>>')
        selectedFiles = fileChooserDialog(
            title=_("Choose a file (or files) to import activities from"),
            multiple=True).getFiles()
        while Gtk.events_pending():  # This allows the GUI to update
            Gtk.main_iteration()  # before completion of this entire action
        if selectedFiles is None or len(selectedFiles) == 0:
            #Nothing selected
            logging.debug("No files selected")
            logging.debug('<<')
            return
        logging.debug("%s files selected" % len(selectedFiles))
        for filename in selectedFiles:  #Multiple files
            class_index = len(self.processClasses)
            #Validate file
            self.processClasses.append(self.validateFile(filename))
            if self.processClasses[class_index] is not None:
                filetype = self.processClasses[class_index].getFileType()
                self.updateStatusbar(self.statusbarImportFile,
                                     _("Found file of type: %s") % filetype)
                logging.debug("Found file of type: %s" % filetype)
                activitiesSummary = self.processClasses[
                    class_index].getActivitiesSummary()
                activity_count = len(activitiesSummary)
                logging.debug("%s activities in file: %s", activity_count,
                              filename)
                #Add file to files treeview
                iter = self.files_store.append()
                self.files_store.set(
                    iter, 0, str(class_index), 1, True, 2, filename, 3,
                    self.processClasses[class_index].getFileType(), 4,
                    str(activity_count))
                #File valid, so enable remove button
                self.buttonRemoveSelectedFiles.set_sensitive(1)
                #Get activities in file
                for activity in activitiesSummary:
                    #Add activity details to TreeView store to display
                    if not activity[1]:
                        #Activity selected, so enable import button
                        self.buttonFileImport.set_sensitive(1)
                        note = ""
                    else:
                        note = _("Found in database")
                    activity_iter = self.activities_store.append()
                    # Status (#1) can be changed by user (via checkbox), we need another field to know if activity is in DB
                    self.activities_store.set(
                        activity_iter,
                        0,
                        str(activity[0]),
                        1,
                        not activity[1],
                        2,
                        activity[2],
                        3,
                        activity[3],
                        4,
                        activity[4],
                        5,
                        activity[5],
                        6,
                        note,
                        7,
                        str(class_index),
                        8,
                        activity[1],
                    )
            else:  #Selected file not understood by any of the process files
                #Display error
                logging.debug(
                    "File %s is of unknown or unsupported file type" %
                    filename)
                msg = _("File %s is of unknown or unsupported file type"
                        ) % filename
                md = Gtk.MessageDialog(self.win_importdata,
                                       Gtk.DialogFlags.DESTROY_WITH_PARENT,
                                       Gtk.MessageType.ERROR,
                                       Gtk.ButtonsType.CLOSE, msg)
                md.set_title("Error")
                md.run()
                md.destroy()
                self.updateStatusbar(self.statusbarImportFile, "")
        logging.debug('<<')

    def on_buttonFileClose_clicked(self, widget):
        logging.debug('--')
        self.close_window()

    def on_buttonDeviceClose_clicked(self, widget):
        logging.debug('--')
        self.close_window()

    def on_buttonOptionsClose_clicked(self, widget):
        logging.debug('--')
        self.close_window()

    def on_buttonPluginsClose_clicked(self, widget):
        logging.debug('--')
        self.close_window()

    def on_buttonDeviceToolRescan_clicked(self, widget):
        logging.debug('--')
        self.detect_tools()

    def on_comboboxDevice_changed(self, widget):
        logging.debug('--')
        self.detect_tools()

    def on_filechooserCSVImport_file_set(self, widget):
        logging.debug('--')
        filename = widget.get_filename()
        if not os.path.isfile(filename):
            return
        self.updateStatusbar(self.statusbarCSVImport,
                             _("Got file: ") + filename)
        #Enable buttons
        self.buttonCSVProcess.set_sensitive(True)
        self.buttonCSVImport.set_sensitive(True)

    def on_buttonCSVProcess_clicked(self, widget):
        logging.debug('>>')
        #Get selected file
        self.CSVfilename = self.filechooserCSVImport.get_filename()
        if not os.path.isfile(self.CSVfilename):
            return
        #Determine delimiter
        if self.rbCSVTab.get_active():
            self.delimiter = "\t"
        elif self.rbCSVComma.get_active():
            self.delimiter = ","
        elif self.rbCSVOther.get_active():
            self.delimiter = gtk_str(self.entryCSVOther.get_text())
        else:
            self.delimiter = " "

        #Read as delimited file
        csvfile = open(self.CSVfilename, 'rb')
        #See if file has header row
        self.has_header = csv.Sniffer().has_header(csvfile.read(1024))
        csvfile.seek(0)
        reader = csv.DictReader(csvfile, delimiter=self.delimiter)
        #Read file to determine fields (must be a better way of doing this)
        for row in reader:
            pass
        #Build array of column names
        if self.has_header:
            #If the file has a header row, use the actual column names
            columns = reader.fieldnames
        else:
            #Otherwise just label them with numbers
            logging.debug(len(reader.fieldnames))
            columns = [
                _("Column %d") % x for x in range(0, len(reader.fieldnames))
            ]

        for column in columns:
            self.cbCSVDate.append_text(column)
            self.cbCSVDistance.append_text(column)
            self.cbCSVDuration.append_text(column)
            self.cbCSVTitle.append_text(column)
            self.cbCSVSport.append_text(column)
            self.cbCSVAvgSpeed.append_text(column)
            self.cbCSVMaxSpeed.append_text(column)
            self.cbCSVCal.append_text(column)
            self.cbCSVAccent.append_text(column)
            self.cbCSVDescent.append_text(column)
            self.cbCSVHR.append_text(column)
            self.cbCSVMaxHR.append_text(column)
            self.cbCSVPace.append_text(column)
            self.cbCSVMaxPace.append_text(column)
            self.cbCSVComments.append_text(column)
        self.cbCSVDate.set_active(0)
        self.cbCSVDistance.set_active(0)
        self.cbCSVDuration.set_active(0)
        self.cbCSVTitle.set_active(0)
        self.cbCSVSport.set_active(0)
        self.cbCSVAvgSpeed.set_active(0)
        self.cbCSVMaxSpeed.set_active(0)
        self.cbCSVCal.set_active(0)
        self.cbCSVAccent.set_active(0)
        self.cbCSVDescent.set_active(0)
        self.cbCSVHR.set_active(0)
        self.cbCSVMaxHR.set_active(0)
        self.cbCSVPace.set_active(0)
        self.cbCSVMaxPace.set_active(0)
        self.cbCSVComments.set_active(0)
        logging.debug('<<')

    def on_buttonCSVImport_clicked(self, widget):
        logging.debug('>>')
        #Determine values
        dateCol = self.cbCSVDate.get_active()
        distanceCol = self.cbCSVDistance.get_active()
        durationCol = self.cbCSVDuration.get_active()
        titleCol = self.cbCSVTitle.get_active()
        sportCol = self.cbCSVSport.get_active()
        avgspeedCol = self.cbCSVAvgSpeed.get_active()
        maxspeedCol = self.cbCSVMaxSpeed.get_active()
        calCol = self.cbCSVCal.get_active()
        accCol = self.cbCSVAccent.get_active()
        desCol = self.cbCSVDescent.get_active()
        hrCol = self.cbCSVHR.get_active()
        maxHRCol = self.cbCSVMaxHR.get_active()
        paceCol = self.cbCSVPace.get_active()
        maxPaceCol = self.cbCSVMaxPace.get_active()
        commentsCol = self.cbCSVComments.get_active()

        if dateCol == 0:
            #Error need to have at least a date
            self.updateStatusbar(
                self.statusbarCSVImport,
                _("ERROR: Must define at least a date column"))
            return

        #Import...
        #Get selected file
        if not os.path.isfile(self.CSVfilename):
            return
        #Read as delimited file
        csvfile = open(self.CSVfilename, 'rb')
        reader = csv.reader(csvfile, delimiter=self.delimiter)
        #Process File

        for i, row in enumerate(reader):
            if self.has_header and i == 0:
                #Ignore first row
                continue
            if not row:
                continue
            data = Activity()
            #Determine dates
            _date = getDateTime(row[dateCol - 1])
            #year, month, day = date.split("-")
            date = _date[1].strftime("%Y-%m-%d")
            zuluDateTime = _date[0].strftime("%Y-%m-%dT%H:%M:%SZ")
            localDateTime = str(_date[1])
            data.date = _date[1].date()
            data.date_time_utc = zuluDateTime
            data.date_time_local = localDateTime
            if distanceCol:
                try:
                    data.distance = locale.atof(row[distanceCol - 1])
                except:
                    data.distance = 0
            else:
                data.distance = 0
            if durationCol:
                #calculate duration in sec...
                try:
                    _duration = row[durationCol - 1]
                except:
                    _duration = 0
                if _duration.count(':') == 2:
                    #Have 00:00:00 duration
                    h, m, s = _duration.split(':')
                    try:
                        durationSec = int(h) * 3600 + int(m) * 60 + int(s)
                    except:
                        logging.debug("Error calculating duration for '%s'" %
                                      _duration)
                        durationSec = None
                else:
                    try:
                        durationSec = locale.atoi(_duration)
                    except:
                        #Unknown duration
                        logging.debug("Could not determine duration for '%s'" %
                                      _duration)
                        durationSec = None
                if durationSec is not None:
                    data.duration = durationSec
                    data.time = str(durationSec)
            if titleCol:
                try:
                    data.title = row[titleCol - 1]
                except:
                    pass
            if self.checkbCSVForceSport.get_active():
                sport = self.pytrainer_main.record.getSport(gtk_str(
                    self.comboCSVForceSport.get_active_text()),
                                                            add=True)
                data.sport = sport
            elif sportCol:
                #retrieving sport id (adding sport if it doesn't exist yet)
                sport = self.pytrainer_main.record.getSport(row[sportCol - 1],
                                                            add=True)
                data.sport = sport
            else:
                self.comboCSVForceSport.set_active(0)
                sport = self.pytrainer_main.record.getSport(gtk_str(
                    self.comboCSVForceSport.get_active_text()),
                                                            add=True)
                data.sport = sport

            if avgspeedCol:
                #
                try:
                    data.average = locale.atof(row[avgspeedCol - 1])
                except:
                    pass
            if maxspeedCol:
                try:
                    data.maxspeed = locale.atof(row[maxspeedCol - 1])
                except:
                    pass
            if calCol:
                try:
                    data.calories = locale.atoi(row[calCol - 1])
                except:
                    pass
            if accCol:
                try:
                    data.upositive = locale.atof(row[accCol - 1])
                except:
                    pass
            if desCol:
                try:
                    data.unegative = locale.atof(row[desCol - 1])
                except:
                    pass
            if hrCol:
                try:
                    data.beats = locale.atof(row[hrCol - 1])
                except:
                    pass
            if maxHRCol:
                try:
                    data.maxbeats = locale.atof(row[maxHRCol - 1])
                except:
                    pass
            if paceCol:
                try:
                    data.pace = locale.atof(row[paceCol - 1])
                except:
                    pass
            if maxPaceCol:
                try:
                    data.maxpace = locale.atof(row[maxPaceCol - 1])
                except:
                    pass
            if commentsCol:
                try:
                    data.comments = row[commentsCol - -1]
                except:
                    pass

            #Insert into DB
            self.pytrainer_main.ddbb.session.add(data)
            self.pytrainer_main.ddbb.session.commit()
        #Display message....
        self.updateStatusbar(self.statusbarCSVImport,
                             _("Import completed. %d rows processed") % i)
        #Disable import button
        self.buttonCSVImport.set_sensitive(0)
        logging.debug('<<')
Exemplo n.º 6
0
class WindowImportdata(SimpleGladeApp):
    def __init__(self, sport_service, data_path = None, parent=None, config=None, pytrainer_main=None):
        self._sport_service = sport_service
        self.data_path = data_path
        self.glade_path=data_path+"glade/importdata.glade"
        self.root = "win_importdata"
        self.domain = None
        self.parent = parent
        self.pytrainer_main = pytrainer_main
        self.configuration = config
        self.activities_store = None
        self.files_store = None
        self.processClasses = []
        self.plugins = Plugins(data_path, self.parent.parent)
        SimpleGladeApp.__init__(self, self.glade_path, self.root, self.domain)

    #def run(self):
    #   SimpleGladeApp.__init__(self, self.glade_path, self.root, self.domain)

    def new(self):
        logging.debug(">>")
        try:
            self.defaulttab = self.configuration.getValue("pytraining","import_default_tab")
            self.defaulttab = int(self.defaulttab)
        except Exception as e:
            logging.debug("Exception: %s", str(e))
            self.defaulttab = 0
        self.auto_launch = self.configuration.getValue("pytraining","auto_launch_file_selection")
        if self.auto_launch == "True":
            self.auto_launch = True
        else:
            self.auto_launch = False
        logging.debug("Default tab: %s, Auto launch: %s" % (str(self.defaulttab), str(self.auto_launch)))
        self.init_all_tabs()
        self.notebookMainTabs.set_current_page(self.defaulttab)
        self.init_tab(self.defaulttab, first=True)          #TODO fix so dont need to re-call init_tab
        logging.debug("<<")

    def init_all_tabs(self):
        logging.debug(">>")
        tabs = (0,1,2,3,4)
        for tab in tabs:
            self.init_tab(tab)

    def init_tab(self, page, first=False):
        ''' Initialise tab '''
        logging.debug(">>")
        logging.debug("page: %d first: %s" % (page, first))
        if page == 0:
            #'Import from GPS Device' tab
            self.init_gpsdevice_tab()
        elif page == 1:
            #'Import from File' tab
            self.init_file_tab(first)
        elif page == 2:
            #'Plugins' tab
            self.init_plugins_tab()
        elif page == 3:
            #'Options' tab
            self.init_options_tab()
        elif page == 4:
            #'CSV Import' tab
            self.init_csvimport_tab()
        else:
            #unknown tab
            logging.error("Unknown page %d passed to init_tab" % page)

    def updateStatusbar(self, statusbar, text, context_id = None):
        ''' Help function to set the text of the statusbar '''
        logging.debug("Setting statusbar %s to %s" % (statusbar.get_name(), text) )
        if context_id is None:
            context_id = statusbar.get_context_id(text)
        statusbar.push(context_id, text)
        return context_id

    def init_gpsdevice_tab(self):
        logging.debug(">>")
        logging.error("GPS Device import not yet implemented")
        logging.debug("<<")
        return

    def init_file_tab(self, first=False):
        logging.debug(">>")
        self.updateStatusbar(self.statusbarImportFile, _("No file selected") )
        self.processClasses = []
        if self.activities_store is None:
            self.activities_store = self.build_activities_tree_view()
        else:
            self.activities_store.clear()
        if self.files_store is None:
            self.files_store = self.build_files_tree_view()
        else:
            self.files_store.clear()
        self.buttonRemoveSelectedFiles.set_sensitive(0)
        self.buttonFileImport.set_sensitive(0)
        if first and self.auto_launch:
            while gtk.events_pending(): # This allows the GUI to update
                gtk.main_iteration()    # before completion of this entire action
            logging.debug("autolaunch active")
            self.buttonSelectFiles.clicked()
        logging.debug(">>")
        return

    def init_plugins_tab(self):
        logging.debug(">>")
        #Remove components in vbox - in case of re-detection
        for child in self.vboxPlugins.get_children():
            if isinstance(child, gtk.Table):
                self.vboxPlugins.remove(child)
        pluginList = self.plugins.getPluginsList()
        logging.debug(pluginList)
        for plugin in pluginList:
            #Store plugin details
            pluginClass = plugin[0]
            pluginName = plugin[1]
            pluginDescription = plugin[2]
            #Build frame with name and description
            pluginFrame = gtk.Frame(label="<b>"+pluginName+"</b>")
            pluginFrameLabel = pluginFrame.get_label_widget()
            pluginFrameLabel.set_use_markup(True)
            description = gtk.Label("<small>"+pluginDescription+"</small>")
            description.set_alignment(0,0)
            description.set_use_markup(True)
            description.set_line_wrap(True)
            pluginFrame.add(description)
            #Get plugin information
            name,description,status = self.plugins.getPluginInfo(pluginClass)
            #Create labels and buttons
            configButton = gtk.Button(label=_("Configure"))
            runButton = gtk.Button(label=_("Run"))
            #Connect button handlers
            configButton.connect('clicked', self.on_pluginsButton_Configure_clicked, pluginClass)
            runButton.connect('clicked', self.on_pluginsButton_Run_clicked, pluginClass)
            if status == 0 or status == "0":
                #Plugin disabled
                pluginFrame.set_sensitive(0)
                runButton.set_sensitive(0)
                statusLabel = gtk.Label(_("Disabled"))
            else:
                statusLabel = gtk.Label(_("Enabled"))

            #Create a table for the frame and button
            pluginTable = gtk.Table()
            pluginTable.attach(pluginFrame, 0, 1, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5)
            pluginTable.attach(statusLabel, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.SHRINK, xpadding=5, ypadding=5)
            pluginTable.attach(configButton, 2, 3, 0, 1, xoptions=gtk.FILL, yoptions=gtk.SHRINK, xpadding=5, ypadding=5)
            pluginTable.attach(runButton, 3, 4, 0, 1, xoptions=gtk.FILL, yoptions=gtk.SHRINK, xpadding=5, ypadding=5)
            #Add frame to tab
            self.vboxPlugins.pack_start(pluginTable, expand=False, fill=False, padding=5)
        self.win_importdata.show_all()
        logging.debug("<<")
        return

    def init_options_tab(self):
        logging.debug(">>")
        logging.debug("Default tab %s" % str(self.defaulttab) )
        #Set correct radiobutton based on saved preference
        if self.defaulttab == 1:
            self.radiobuttonFile.set_active(1)
            self.checkbuttonAutoLaunch.set_sensitive(1)
        elif self.defaulttab == 2:
            self.radiobuttonPlugins.set_active(1)
        else:
            self.radiobuttonTabGPSDevice.set_active(1)
        if self.auto_launch:
            self.checkbuttonAutoLaunch.set_active(1)
        logging.debug("<<")
        return

    def init_csvimport_tab(self):
        logging.debug(">>")
        #Populate Force Sport to combobox
        sport_list = self._sport_service.get_all_sports()
        #Remove placeholder item (needed to ensure correct model for combobox)
        self.comboCSVForceSport.remove_text(0)
        for sport in sport_list:
            logging.debug('Adding sport: %s' % sport.name)
            self.comboCSVForceSport.append_text(sport.name)
        self.comboCSVForceSport.set_active(0)
        logging.debug("<<")
        return

    def detect_tools(self):
        '''
            Iterate through all tool files from import directory
            Each file contains information on a particular tool
            and knows how to determine if the tool is present on the system
            and what configuration options are needed for the tool

            Currently displays the tool info and config grayed out if tool is not present
        '''
        logging.debug('>>')
        self.updateStatusbar(self.statusbarDevice, "Checking for tools")
        #Remove all components in vbox - in case of re-detection
        for child in self.vboxImportTools.get_children():
            self.vboxImportTools.remove(child)
        #Get import tool_* files
        fileList = glob.glob(self.data_path+"import/tool_*.py")
        logging.debug("Tools filelist: %s" % fileList)
        for toolFile in fileList:
            index = fileList.index(toolFile)
            directory, filename = os.path.split(toolFile)
            filename = filename.rstrip('.py')
            classname = filename.lstrip('tool_')
            #Import module
            sys.path.insert(0, self.data_path+"import")
            module = __import__(filename)
            toolMain = getattr(module, classname)
            #Instantiate module
            toolClass = toolMain(self.parent, self.data_path)
            #Get info from class
            toolName = toolClass.getName()
            toolTable = gtk.Table()
            toolFrame = gtk.Frame(label=toolName)
            toolFrame.add(toolTable)
            if toolClass.isPresent():
                version = gtk.Label("Version: " + toolClass.getVersion())
                version.set_alignment(0,0)
                if toolClass.deviceExists():
                    deviceExists = gtk.Label(_("GPS device found") )
                    deviceExists.set_alignment(0,0)
                else:
                    deviceExists = gtk.Label(_("GPS device <b>not</b> found"))
                    deviceExists.set_alignment(0,0)
                    deviceExists.set_use_markup(True)
                toolTable.attach(version, 0, 1, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5)
                toolTable.attach(deviceExists, 0, 1, 1, 2, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5)
                toolFrame.set_sensitive(1)
            else:
                info = gtk.Label(_("This tool was not found on the system") )
                info.set_alignment(0,0.5)
                location = gtk.LinkButton(toolClass.getSourceLocation(), toolName +_(" Homepage"))
                info.set_sensitive(0)
                toolTable.attach(info, 0, 1, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5)
                toolTable.attach(location, 1, 2, 0, 1, xoptions=gtk.EXPAND|gtk.FILL, xpadding=5)
                #toolFrame.set_sensitive(0)
            self.vboxImportTools.pack_start(toolFrame, expand=False, fill=False, padding=5)
        self.win_importdata.show_all()
        logging.debug('<<')

    def validateFile(self, import_filename):
        '''
            Iterate through all supported types of file by reading processing files from import directory
            Each processing file understands one type of file

            If a processing file is found that recognises the selected file:
                 returns the instantiated class
            otherwise:
                 returns None
        '''
        logging.debug('>>')
        self.updateStatusbar(self.statusbarImportFile, "Checking file type for: " + import_filename)
        #Get import files_* files
        fileList = glob.glob(self.data_path+"import/file_*.py")
        fileList.sort()
        logging.debug("File filelist: %s" % fileList)
        for processingFile in fileList:
            directory, filename = os.path.split(processingFile)
            filename = filename.rstrip('.py')
            logging.debug("Trying: %s" % filename)
            classname = filename.lstrip('file_')
            #Import module
            sys.path.insert(0, self.data_path+"import")
            module = __import__(filename)
            processMain = getattr(module, classname)
            #Instantiate module
            processClass = processMain(self.parent, self.data_path)
            isValid = processClass.testFile(import_filename)
            if isValid:
                logging.debug('<<')
                return processClass
            else:
                processClass = None
        logging.debug('<<')
        return processClass

    def build_files_tree_view(self):
        ''' Build tree view to hold files from which the activities are read '''
        logging.debug('>>')
        store = gtk.ListStore(  gobject.TYPE_STRING,
                                gobject.TYPE_BOOLEAN,
                                gobject.TYPE_STRING,
                                gobject.TYPE_STRING,
                                gobject.TYPE_STRING, )
        column_names=["id", "", _("File"), _("Type"), _("Activities")]
        for column_index, column_name in enumerate(column_names):
            if column_index == 1:
                #Add button column
                self.renderer1 = gtk.CellRendererToggle()
                self.renderer1.set_property('activatable', True)
                self.renderer1.connect( 'toggled', self.treeviewImportFiles_toggled_checkbox, store )
                column = gtk.TreeViewColumn(column_name, self.renderer1 )
                column.add_attribute( self.renderer1, "active", column_index)
                column.set_sort_column_id(-1)
                #column.connect('clicked', self.treeviewImportFiles_header_checkbox, store)
            else:
                #Add other columns
                column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index)
                column.set_sort_column_id(column_index)
            if column_name == "id":
                column.set_visible(False)
            column.set_resizable(True)
            self.treeviewImportFiles.append_column(column)
        self.treeviewImportFiles.set_headers_clickable(True)
        self.treeviewImportFiles.set_model(store)
        logging.debug('<<')
        return store

    def build_activities_tree_view(self):
        ''' Build tree view to hold activities that can be selected for import '''
        logging.debug('>>')
        store = gtk.ListStore(  gobject.TYPE_STRING,
                                gobject.TYPE_BOOLEAN,
                                gobject.TYPE_STRING,
                                gobject.TYPE_STRING,
                                gobject.TYPE_STRING,
                                gobject.TYPE_STRING,
                                gobject.TYPE_STRING,
                                gobject.TYPE_STRING )
        column_names=["id", "", _("Start Time"), _("Distance"),_("Duration"),_("Sport"), _("Notes"), "file_id"]
        for column_index, column_name in enumerate(column_names):
            if column_index == 1:
                #Add checkbox column
                self.renderer1 = gtk.CellRendererToggle()
                self.renderer1.set_property('activatable', True)
                self.renderer1.connect( 'toggled', self.treeviewImportEvents_toggled_checkbox, store )
                column = gtk.TreeViewColumn(column_name, self.renderer1 )
                column.add_attribute( self.renderer1, "active", column_index)
                column.set_sort_column_id(-1)
                column.connect('clicked', self.treeviewImportEvents_header_checkbox, store)
            else:
                #Add other columns
                column = gtk.TreeViewColumn(column_name, gtk.CellRendererText(), text=column_index)
                column.set_sort_column_id(column_index)
            if column_name == "id" or column_name == "file_id":
                column.set_visible(False)
            column.set_resizable(True)
            self.treeviewImportEvents.append_column(column)
        self.treeviewImportEvents.set_headers_clickable(True)
        self.treeviewImportEvents.set_model(store)
        logging.debug('<<')
        return store

    def checkTreestoreForSelection(self, store):
        '''
            Function iterates over store checking if any items are selected
            returns True if at least one item is selected, False otherwise
            Checks item in position 1 only
        '''
        for item in store:
            if item[1]:
                return True
        return False

    def treeviewImportFiles_toggled_checkbox(self, cell, path, store):
        '''
            Sets the state of the checkbox to true or false.
        '''
        store[path][1] = not store[path][1]
        self.buttonRemoveSelectedFiles.set_sensitive(self.checkTreestoreForSelection(store))

    def treeviewImportEvents_toggled_checkbox(self, cell, path, store):
        '''
            Sets the state of the checkbox to true or false.
        '''
        store[path][1] = not store[path][1]
        self.buttonFileImport.set_sensitive(self.checkTreestoreForSelection(store))

    def treeviewImportEvents_setCheckboxes(self, state):
        '''
            Sets or unsets all checkboxes
        '''
        if self.activities_store is None or len(self.activities_store) == 0:
            return
        for item in self.activities_store:
            item[1] = state
        if state:
            self.buttonFileImport.set_sensitive(1)
        else:
            self.buttonFileImport.set_sensitive(0)

    def saveOptions(self):
        '''
            Save options selected in options tab
        '''
        self.autoLaunchFileSelection = "False"
        #Default tab option
        if self.radiobuttonTabGPSDevice.get_active():
            self.defaulttab = "0"
        elif self.radiobuttonFile.get_active():
            self.defaulttab = "1"
            if self.checkbuttonAutoLaunch.get_active():
                self.autoLaunchFileSelection = "True"
        elif self.radiobuttonPlugins.get_active():
            self.defaulttab = "2"
        logging.debug("Saving default tab: %s, auto launch: %s" % (str(self.defaulttab), str(self.autoLaunchFileSelection)))
        self.configuration.setValue("pytraining","import_default_tab",self.defaulttab)
        self.configuration.setValue("pytraining","auto_launch_file_selection",self.autoLaunchFileSelection)
        #option

    def removeSelectedFiles(self):
        '''
            Function to determine which files are selected
            * remove them from the list
            * remove the associated activities from the list also
        '''
        if self.files_store is None:
            return
        file_index = 0
        file_iters = []
        activity_iters = []
        for item in self.files_store:
            if item[1] is True: #Checkbox is True, file for removal
                file_id = item[0]
                activity_index = 0
                for activity in self.activities_store:
                    if activity[7] == file_id: #Activity relates to file to be removed
                        activity_iters.append(self.activities_store.get_iter(activity_index))
                    activity_index += 1
                file_iters.append( self.files_store.get_iter(file_index))
            file_index += 1
        logging.debug("Removing %d activities from activity tree view" % len(activity_iters) )
        for activity_iter in activity_iters:
            self.activities_store.remove(activity_iter)
        self.buttonFileImport.set_sensitive(self.checkTreestoreForSelection(self.activities_store)) #Set correct state for import button
        logging.debug("Removing %d files from file tree view" % len(file_iters) )
        for file_iter in file_iters:
            self.files_store.remove(file_iter)

    def getSelectedActivities(self):
        """
            Function to determine which activities are selected

            Returns array of the ids of the selected activities
        """
        selectedActivities = []
        if self.activities_store is None:
            logging.debug("activities_store is empty")
            return None
        for item in self.activities_store:
            if item[1] is True: #Checkbox is True
                logging.debug("Added activity %s to selected list" % item)
                file_id = int(item[7])
                activity_id = item[0]
                start_time = item[2]
                distance = item[3]
                duration = item[4]
                sport = item[5]
                gpx_file = self.processClasses[file_id].getGPXFile(activity_id, file_id)[1]
                selectedActivities.append((activity_id, start_time, distance, duration, sport, gpx_file, file_id))
        logging.debug( "Found %d selected activities to import" % len(selectedActivities) )
        return selectedActivities

    def importSelectedActivities(self, activities):
        """
            Function to import selected activity
        """
        logging.debug( "Importing %d activities" % len(activities))
        result = self.pytrainer_main.record.newMultiRecord(activities)
        for activity in result:
            if "db_id" in activity.keys() and type(activity["db_id"]) is types.IntType:
                #Activity imported correctly
                duration = "%0.0f:%0.0f:%02.0f" % (float(activity["rcd_time"][0]), float(activity["rcd_time"][1]), float(activity["rcd_time"][2]))
                self.updateActivity(activity["activity_id"], activity["file_id"],
                                    status = False,
                                    notes = _("Imported into database"),
                                    sport = activity["rcd_sport"],
                                    distance = activity["rcd_distance"],
                                    duration = duration)
                #print "updating activity %s " % (str(activity))

    def updateActivity(self, activityID, file_id, status = None, notes = None, sport = None, distance = None, duration = None):
        path = 0
        for item in self.activities_store:
            if item[0] == activityID and item[7] == str(file_id):
                if status is not None:
                    self.activities_store[path][1] = status
                if notes is not None:
                    self.activities_store[path][6] = notes
                if sport is not None:
                    self.activities_store[path][5] = sport
                if distance is not None:
                    self.activities_store[path][3] = distance
                if duration is not None:
                    self.activities_store[path][4] = duration
            path +=1

    def close_window(self):
        logging.debug('--')
        self.win_importdata.hide()
        #self.win_importdata.destroy()
        self.quit()

    ############################
    ## Window signal handlers ##
    ############################

    def on_radiobuttonFile_toggled(self, *args):
        print "radio button toggled"

    def on_pluginsButton_Configure_clicked(self, button, pluginClass):
        '''
            Handler for plugin Buttons
        '''
        name,description,status = self.plugins.getPluginInfo(pluginClass)
        prefs = self.plugins.getPluginConfParams(pluginClass)

        self.prefwindow = gtk.Window()
        self.prefwindow.set_border_width(20)
        self.prefwindow.set_title(_("%s settings" %name))

        table = gtk.Table(1,2)
        i=0
        self.entryList = []
        for pref in prefs:
            label = gtk.Label("<b>%s</b>"%pref[0])
            label.set_use_markup(True)
            if pref[0] != "status":
                entry = gtk.Entry()
                entry.set_text(pref[1])
                self.entryList.append(entry)
                table.attach(entry,1,2,i,i+1)
            else:
                combobox = gtk.combo_box_new_text()
                combobox.append_text(_("Disable"))
                combobox.append_text(_("Enable"))
                combobox.set_active(int(pref[1]))
                table.attach(combobox,1,2,i,i+1)
                self.entryList.append(combobox)
            table.attach(label,0,1,i,i+1)
            i+=1

        button = gtk.Button(_("Ok"))
        button.connect("clicked", self.on_pluginAcceptSettings_clicked, pluginClass)
        table.attach(button,0,2,i,i+1)
        self.prefwindow.add(table)
        self.prefwindow.show_all()

    def on_pluginsButton_Run_clicked(self, button, pluginClass):
        '''
            Handler for plugin Buttons
        '''
        logging.debug('>>')
        self.pytrainer_main.runPlugin(button,pluginClass)
        logging.debug('<<')

    def on_pluginAcceptSettings_clicked(self, widget, pluginClass):
        '''
            Duplicate of plugin settings accept handler
        '''
        logging.debug('>>')
        prefs = self.plugins.getPluginConfParams(pluginClass)
        savedOptions = []
        i = 0
        for pref in prefs:
            try:
                savedOptions.append((pref[0],self.entryList[i].get_text()))
            except:
                combobox = self.entryList[i]
                index = combobox.get_active()
                savedOptions.append((pref[0],"%s" %index))
            i+=1
        self.prefwindow.hide()
        self.prefwindow = None
        self.plugins.setPluginConfParams(pluginClass,savedOptions)
        self.init_plugins_tab()
        logging.debug('<<')

    def treeviewImportEvents_header_checkbox(self, column, store):
        '''
            Handler for click on checkbox column
        '''
        logging.debug('--')
        if store is None:
            return
        for item in store:
            if item[1]:
                self.treeviewImportEvents_setCheckboxes(False)
                return
        self.treeviewImportEvents_setCheckboxes(True)

    def on_win_importdata_delete_event(self, widget, window):
        ''' Window closed '''
        logging.debug('--')
        self.close_window()

    def on_notebookMainTabs_switch_page(self, notebook, page, new_page):
        logging.debug('--')
        #self.init_tab(new_page)

    def on_buttonOptionsSave_clicked(self, widget):
        logging.debug('>>')
        self.updateStatusbar(self.statusbarOptions, _("Saving options"))
        self.saveOptions()
        self.updateStatusbar(self.statusbarOptions, _("Options saved"))
        logging.debug('<<')

    def on_buttonOptionsReset_clicked(self, widget):
        logging.debug('>>')
        #GPS Device is default
        self.defaulttab = 0
        #Redisplay tab
        self.init_options_tab()
        self.updateStatusbar(self.statusbarOptions, "")
        logging.debug('<<')

    def on_buttonRemoveSelectedFiles_clicked(self, widget):
        ''' Remove selected files and associated activities from list '''
        logging.debug('>>')
        self.removeSelectedFiles()
        logging.debug('<<')

    def on_buttonFileImport_clicked(self, widget):
        ''' Import selected activities '''
        logging.debug('>>')
        selectedActivities = self.getSelectedActivities()
        selectedCount = len(selectedActivities)
        if selectedCount > 0:
            if selectedCount == 1:
                msgImporting = _("Importing one activity")
                msgImported = _("Imported one activity")
            else:
                msgImporting = _("Importing %d activities" % selectedCount)
                msgImported = _("Imported %d activities" % selectedCount)
            self.updateStatusbar(self.statusbarImportFile, msgImporting)
            logging.debug(msgImporting)
            while gtk.events_pending(): # This allows the GUI to update
                gtk.main_iteration()    # before completion of this entire action
            #for activity in selectedActivities:
            self.importSelectedActivities(selectedActivities)
            self.updateStatusbar(self.statusbarImportFile, msgImported)
            logging.debug(msgImported)
            #Display informational dialog box
            #md = gtk.MessageDialog(self.win_importdata, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, msgImported)
            #md.set_title(_("Import Success"))
            #md.run()
            #md.destroy()
        self.buttonFileImport.set_sensitive(0) #Disable import button
        logging.debug('<<')

    def on_buttonSelectFiles_clicked(self, widget):
        logging.debug('>>')
        selectedFiles = fileChooserDialog(title=_("Choose a file (or files) to import activities from"), multiple=True).getFiles()
        while gtk.events_pending(): # This allows the GUI to update
            gtk.main_iteration()    # before completion of this entire action
        if selectedFiles is None or len(selectedFiles) == 0:
            #Nothing selected
            logging.debug("No files selected")
            logging.debug('<<')
            return
        logging.debug("%s files selected" % len(selectedFiles))
        for filename in selectedFiles: #Multiple files
            class_index = len(self.processClasses)
            #Validate file
            self.processClasses.append(self.validateFile(filename))
            if self.processClasses[class_index] is not None:
                filetype = self.processClasses[class_index].getFileType()
                self.updateStatusbar(self.statusbarImportFile, _("Found file of type: %s") % filetype )
                logging.debug(_("Found file of type: %s") % filetype)
                activitiesSummary = self.processClasses[class_index].getActivitiesSummary()
                activity_count = len(activitiesSummary)
                logging.debug("%s activities in file: %s" % (str(activity_count), filename) )
                #Add file to files treeview
                iter = self.files_store.append()
                self.files_store.set(
                    iter,
                    0, class_index,
                    1, True,
                    2, filename,
                    3, self.processClasses[class_index].getFileType(),
                    4, activity_count
                    )
                #File valid, so enable remove button
                self.buttonRemoveSelectedFiles.set_sensitive(1)
                #Get activities in file
                for activity in activitiesSummary:
                    #Add activity details to TreeView store to display
                    if not activity[1]:
                        #Activity selected, so enable import button
                        self.buttonFileImport.set_sensitive(1)
                        note = ""
                    else:
                        note = _("Found in database")
                    activity_iter = self.activities_store.append()
                    self.activities_store.set(
                        activity_iter,
                        0, activity[0],
                        1, not activity[1],
                        2, activity[2],
                        3, activity[3],
                        4, activity[4],
                        5, activity[5],
                        6, note,
                        7, class_index,
                        )
            else: #Selected file not understood by any of the process files
                #Display error
                logging.debug(_("File %s is of unknown or unsupported file type" % filename))
                msg = _("File %s is of unknown or unsupported file type" % filename)
                md = gtk.MessageDialog(self.win_importdata, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg)
                md.set_title("Error")
                md.run()
                md.destroy()
        logging.debug('<<')

    def on_buttonFileClose_clicked(self, widget):
        logging.debug('--')
        self.close_window()

    def on_buttonDeviceClose_clicked(self, widget):
        logging.debug('--')
        self.close_window()

    def on_buttonOptionsClose_clicked(self, widget):
        logging.debug('--')
        self.close_window()

    def on_buttonPluginsClose_clicked(self, widget):
        logging.debug('--')
        self.close_window()

    def on_buttonDeviceToolRescan_clicked(self, widget):
        logging.debug('--')
        self.detect_tools()

    def on_comboboxDevice_changed(self, widget):
        logging.debug('--')
        self.detect_tools()

    def on_filechooserCSVImport_file_set(self, widget):
        logging.debug('--')
        filename = widget.get_filename()
        if not os.path.isfile(filename):
            return
        self.updateStatusbar(self.statusbarCSVImport, "Got file: " + filename)
        #Enable buttons
        self.buttonCSVProcess.set_sensitive(True)
        self.buttonCSVImport.set_sensitive(True)

    def on_buttonCSVProcess_clicked(self, widget):
        logging.debug('>>')
        #Get selected file
        self.CSVfilename = self.filechooserCSVImport.get_filename()
        if not os.path.isfile(self.CSVfilename):
            return
        #Determine delimiter
        if self.rbCSVTab.get_active():
            self.delimiter = "\t"
        elif self.rbCSVComma.get_active():
            self.delimiter = ","
        elif self.rbCSVOther.get_active():
            self.delimiter = self.entryCSVOther.get_text()
        else:
            self.delimiter = " "

        #Read as delimited file
        csvfile = open(self.CSVfilename, 'rb')
        #See if file has header row
        self.has_header = csv.Sniffer().has_header(csvfile.read(1024))
        csvfile.seek(0)
        reader = csv.DictReader(csvfile, delimiter=self.delimiter)
        #Read file to determine fields (must be a better way of doing this)
        for row in reader:
            pass
        #Build array of column names
        if self.has_header:
            #If the file has a header row, use the actual column names
            columns = reader.fieldnames
        else:
            #Otherwise just label them with numbers
            print len(reader.fieldnames)
            columns = [_("Column %d") % x for x in range(0, len(reader.fieldnames))]
        #print columns

        for column in columns:
            self.cbCSVDate.append_text(column)
            self.cbCSVDistance.append_text(column)
            self.cbCSVDuration.append_text(column)
            self.cbCSVTitle.append_text(column)
            self.cbCSVSport.append_text(column)
            self.cbCSVAvgSpeed.append_text(column)
            self.cbCSVMaxSpeed.append_text(column)
            self.cbCSVCal.append_text(column)
            self.cbCSVAccent.append_text(column)
            self.cbCSVDescent.append_text(column)
            self.cbCSVHR.append_text(column)
            self.cbCSVMaxHR.append_text(column)
            self.cbCSVPace.append_text(column)
            self.cbCSVMaxPace.append_text(column)
            self.cbCSVComments.append_text(column)
        self.cbCSVDate.set_active(0)
        self.cbCSVDistance.set_active(0)
        self.cbCSVDuration.set_active(0)
        self.cbCSVTitle.set_active(0)
        self.cbCSVSport.set_active(0)
        self.cbCSVAvgSpeed.set_active(0)
        self.cbCSVMaxSpeed.set_active(0)
        self.cbCSVCal.set_active(0)
        self.cbCSVAccent.set_active(0)
        self.cbCSVDescent.set_active(0)
        self.cbCSVHR.set_active(0)
        self.cbCSVMaxHR.set_active(0)
        self.cbCSVPace.set_active(0)
        self.cbCSVMaxPace.set_active(0)
        self.cbCSVComments.set_active(0)
        logging.debug('<<')


    def on_buttonCSVImport_clicked(self, widget):
        logging.debug('>>')
        #Determine values
        dateCol = self.cbCSVDate.get_active()
        distanceCol = self.cbCSVDistance.get_active()
        durationCol = self.cbCSVDuration.get_active()
        titleCol = self.cbCSVTitle.get_active()
        sportCol = self.cbCSVSport.get_active()
        avgspeedCol = self.cbCSVAvgSpeed.get_active()
        maxspeedCol = self.cbCSVMaxSpeed.get_active()
        calCol = self.cbCSVCal.get_active()
        accCol = self.cbCSVAccent.get_active()
        desCol = self.cbCSVDescent.get_active()
        hrCol = self.cbCSVHR.get_active()
        maxHRCol = self.cbCSVMaxHR.get_active()
        paceCol = self.cbCSVPace.get_active()
        maxPaceCol = self.cbCSVMaxPace.get_active()
        commentsCol = self.cbCSVComments.get_active()

        #print dateCol, distanceCol, durationCol, titleCol, sportCol, avgspeedCol, maxspeedCol, calCol, accCol, desCol, hrCol, maxHRCol, paceCol, maxPaceCol, commentsCol

        if dateCol == 0:
            #Error need to have at least a date
            self.updateStatusbar(self.statusbarCSVImport, "ERROR: Must define at least a date column")
            return

        #Import...
        #Get selected file
        if not os.path.isfile(self.CSVfilename):
            return
        #Read as delimited file
        csvfile = open(self.CSVfilename, 'rb')
        reader = csv.reader(csvfile, delimiter=self.delimiter)
        #Process File

        for i, row in enumerate(reader):
            if self.has_header and i==0:
                #Ignore first row
                continue
            if not row:
                continue
            data = {}
            #Determine dates
            _date = Date().getDateTime(row[dateCol-1])
            #year, month, day = date.split("-")
            date = _date[1].strftime("%Y-%m-%d")
            zuluDateTime = _date[0].strftime("%Y-%m-%dT%H:%M:%SZ")
            localDateTime = str(_date[1])
            data['date'] = date
            data['date_time_utc'] = zuluDateTime
            data['date_time_local'] = localDateTime
            if distanceCol:
                try:
                    data['distance'] = locale.atof(row[distanceCol-1])
                except:
                    data['distance'] = 0
            else:
                data['distance'] = 0
            if durationCol:
                #calculate duration in sec...
                try:
                    _duration = row[durationCol-1]
                except:
                    _duration = 0
                if _duration.count(':') == 2:
                    #Have 00:00:00 duration
                    h, m, s = _duration.split(':')
                    try:
                        durationSec = int(h)*3600 + int(m)*60 + int(s)
                    except:
                        logging.debug("Error calculating duration for '%s'" % _duration)
                        #print("Error calculating duration for '%s'" % _duration)
                        durationSec = None
                else:
                    try:
                        durationSec = locale.atoi(_duration)
                    except:
                        #Unknown duration
                        logging.debug("Could not determine duration for '%s'" % _duration)
                        #print("Could not determine duration for '%s'" % _duration)
                        durationSec = None
                if durationSec is not None:
                    data['duration'] = durationSec
                    data['time'] = str(durationSec)
            if titleCol:
                try:
                    data['title'] = row[titleCol-1]
                except:
                    pass
            if self.checkbCSVForceSport.get_active():
                sport_id = self.pytrainer_main.record.getSportId(self.comboCSVForceSport.get_active_text(),add=True)
                data['sport'] = sport_id
            elif sportCol:
                #retrieving sport id (adding sport if it doesn't exist yet)
                sport_id = self.pytrainer_main.record.getSportId(row[sportCol-1],add=True)
                data['sport'] = sport_id
            else:
                self.comboCSVForceSport.set_active(0)
                sport_id = self.pytrainer_main.record.getSportId(self.comboCSVForceSport.get_active_text(),add=True)
                data['sport'] = sport_id

            if avgspeedCol:
                #
                try:
                    data['average'] = locale.atof(row[avgspeedCol-1])
                except:
                    pass
            if maxspeedCol:
                try:
                    data['maxspeed'] = locale.atof(row[maxspeedCol-1])
                except:
                    pass
            if calCol:
                try:
                    data['calories'] = locale.atoi(row[calCol-1])
                except:
                    pass
            if accCol:
                try:
                    data['upositive'] = locale.atof(row[accCol-1])
                except:
                    pass
            if desCol:
                try:
                    data['unegative'] = locale.atof(row[desCol-1])
                except:
                    pass
            if hrCol:
                try:
                    data['beats'] = locale.atof(row[hrCol-1])
                except:
                    pass
            if maxHRCol:
                try:
                    data['maxbeats'] = locale.atof(row[maxHRCol-1])
                except:
                    pass
            if paceCol:
                try:
                    data['pace'] = locale.atof(row[paceCol-1])
                except:
                    pass
            if maxPaceCol:
                try:
                    data['maxpace'] = locale.atof(row[maxPaceCol-1])
                except:
                    pass
            if commentsCol:
                try:
                    data['comments'] = row[commentsCol--1]
                except:
                    pass

            #Insert into DB
            logging.debug("Data", data)
            self.pytrainer_main.ddbb.insert_dict('records', data)
        #Display message....
        self.updateStatusbar(self.statusbarCSVImport, "Import completed. %d rows processed" % i)
        #Disable import button
        self.buttonCSVImport.set_sensitive(0)

        logging.debug('<<')