コード例 #1
0
 def changeDate(self, date=QDate.currentDate()):
     '''Actions to conduct when date is changed, e.g. check if date exists in
     database, load existing food log'''
        
     self.foodLogModel = FoodLogModel(self.db, date, self)
     self.foodLogToday.setModel(self.foodLogModel)
コード例 #2
0
class MainWindow(QMainWindow, Ui_MainWindow):
    """
    The primary GUI class for the Tracker programme.
    """
    
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        
        self.settings = QSettings()
        openRecent = self.settings.value('AppSettings/OpenRecent', '0')
        if int(openRecent) == int(Qt.Checked):
            self.filename = self.settings.value('AppSettings/LastOpenFile', None)
            print self.filename
            self.currentFilename.setText(self.filename)
        else:
            self.filename = None
        
        if self.filename == None:
            self.filename = self.fileBrowser()
            
        self.db = TrackerDB(self.filename)
        
        # User tab =============================================================
        self.browseFiles.clicked.connect(self.fileBrowser)
        self.userName.editingFinished.connect(self.userNameUpdate)
        self.currentAge.valueChanged.connect(self.calculateBMR)
        self.currentHeight.valueChanged.connect(self.calculateBMR)
        self.currentWeight.valueChanged.connect(self.calculateBMR)
        self.sex.currentIndexChanged.connect(self.calculateBMR)
        self.activity.currentIndexChanged.connect(self.calculateMCN)
        self.goal.currentIndexChanged.connect(self.calculateTCN)
        self.dietMacro.currentIndexChanged.connect(self.calculateSplit)
        self.loadUserData()
        
        # Foods tab ============================================================
        self.foodModel = Foodmodel(self.db, self)
        self.foodView.setModel(self.foodModel)
        
        self.foodView.doubleClicked.connect(self.foodViewEdit)
        self.addFoodButton.clicked.connect(self.editFood)
        self.deleteFoodButton.clicked.connect(self.foodViewDelete)
        
        # Food log tab =========================================================
        self.foodProxyModel = QSortFilterProxyModel(self)
        self.foodProxyModel.setSourceModel(self.foodModel)
        self.foodProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.foodProxyModel.setDynamicSortFilter(True)
        self.foodLogList.setModel(self.foodProxyModel)
        self.filterText.textChanged.connect(self.filterFoodProxyModel)
        
        self.setFoodLogDate()
        
        self.todayButton.clicked.connect(self.setFoodLogDate)
        self.yesterdayButton.clicked.connect(self.setFoodLogYesterday)
        self.nextDayButton.clicked.connect(self.setFoodLogNextDay)
        self.previousDayButton.clicked.connect(self.setFoodLogPreviousDay)
        self.dateEdit.dateChanged.connect(self.changeDate)
        self.removeFoodButton.clicked.connect(self.deleteFoodLogItem)
        self.addFoodtoLog.clicked.connect(self.quantityEditButton)
        
        self.foodLogList.doubleClicked.connect(self.quantityEdit)
        self.foodLogToday.doubleClicked.connect(self.existingQuantityEdit)
        
        self.clearFilterButton.clicked.connect(self.clearFilter)
        
        # Load today's data:
        self.changeDate()
                
        # Weight log tab =======================================================
        self.setWeightLogDate()
        self.todayButton_2.clicked.connect(self.setWeightLogDate)
        self.yesterdayButton_2.clicked.connect(self.setWeightLogYesterday)
        self.nextDayButton_2.clicked.connect(self.setWeightLogNextDay)
        self.previousDayButton_2.clicked.connect(self.setWeightLogPreviousDay)
        self.dateEdit_2.dateChanged.connect(self.changeWeightDate)
        self.weight.valueChanged.connect(self.weightChanged)
        self.changeWeightDate() # set to today's weight
        
        # Exercise log tab =====================================================
        self.setExerciseLogDate()
        self.exerciseTodayButton.clicked.connect(self.setExerciseLogDate)
        self.exerciseYesterdayButton.clicked.connect(self.setExerciseLogYesterday)
        self.exerciseNextDayButton.clicked.connect(self.setExerciseLogNextDay)
        self.exercisePreviousDayButton.clicked.connect(self.setExerciseLogPreviousDay)
        self.exerciseDateEdit.dateChanged.connect(self.changeExerciseDate)
        
        self.exerciseModel = Exercisemodel(self.db, self)
        self.exerciseList.setModel(self.exerciseModel)
        self.exerciseList.doubleClicked.connect(self.logExercise)
        
        self.logExerciseButton.clicked.connect(self.logExerciseClick)
        #self.unlogExerciseButton.clicked.connect()
        self.addExercise.clicked.connect(self.createExercise)
        self.editExercise.clicked.connect(self.modifyExercise)
        self.deleteExercise.clicked.connect(self.removeExercise)
        
        self.changeExerciseDate()
        
        # Saved settings =======================================================
        self.loadState()
    
    def fileBrowser(self):
        """
        Opens a file browser dialog box, and sets the resulting values into the
        file name text box
        """
        
        fileName = QFileDialog.getOpenFileName(self, "Open database", "~", "Database files (*.db)")
        if fileName[0] != '':
            #print fileName[0]
            self.currentFilename.setText(fileName[0])
        
        return fileName[0]
        
    def foodViewEdit(self, QModelIndex):
        row = QModelIndex.row()
        data = []
        for column in range(9):
            data.append(QModelIndex.sibling(row, column).data())
        self.editFood(data[1], data[2], data[3:9], data[0], row)
        
    def foodViewDelete(self):
        if len(self.foodView.selectedIndexes()) != 0:
            QModelIndex = self.foodView.selectedIndexes()[0]
            #row = QModelIndex.row()
            self.foodModel.deleteitem(QModelIndex)
          
    def loadState(self):
        '''Loads saved state of the application'''
        # WINDOW SIZE
        windowSize = self.settings.value('MainWindow/Size', QSize(500, 500))
        self.resize(windowSize)
    
        #FOOD: COLUMN WIDTHS
        foodColumnWidths = self.settings.value('Food/ColumnWidths',
                                    [0, 100, 100, 100, 100, 100, 100, 100, 100])
        for i in range(9):
            self.foodView.setColumnWidth(i, int(foodColumnWidths[i]))
        self.foodView.sortByColumn(1, Qt.AscendingOrder)
        for i in [0]:
            self.foodView.hideColumn(i)
        
        #FOOD LOG: COLUMN WIDTHS
        foodLogFoodwidths = self.settings.value('FoodLog/ColumnWidths1',
                                                [0, 100, 100, 0, 0, 0, 0, 0, 0])
        for i in range(9):
            self.foodLogList.setColumnWidth(i, int(foodLogFoodwidths[i]))
        self.foodLogList.sortByColumn(1, Qt.AscendingOrder)
        for i in [0, 3, 4, 5, 6, 7, 8]:
            self.foodLogList.hideColumn(i)
        
        foodLogFoodwidths2 = self.settings.value('FoodLog/ColumnWidths2',
                                                 [0, 100, 100, 100])
        for i in range(4):
            self.foodLogToday.setColumnWidth(i, int(foodLogFoodwidths2[i]))
        self.foodLogToday.sortByColumn(1, Qt.AscendingOrder)
        for i in [0]:
            self.foodLogToday.hideColumn(i)
            
        #EXERCISE
        exerciseListWidths = self.settings.value('Exercise/ListWidths',[0, 150, 0, 150])
        for i in range(4):
            self.exerciseList.setColumnWidth(i, int(exerciseListWidths[i]))
        self.exerciseList.sortByColumn(1, Qt.AscendingOrder)
        for i in [0, 2]:
            self.exerciseList.hideColumn(i)
        
        exerciseLogWidths = self.settings.value('Exercise/LogWidths',[100, 100, 30, 30, 30])
        for i in range(5):
            self.dailyExerciseLog.setColumnWidth(i, int(exerciseLogWidths[i]))
        self.dailyExerciseLog.sortByColumn(0, Qt.AscendingOrder)
    
    def closeEvent(self, event):
        '''Method to save state of the application'''
        # LAST OPEN FILE
        self.settings.setValue('AppSettings/LastOpenFile', self.filename)
        self.settings.setValue('AppSettings/OpenRecent', self.openRecent.checkState())
        
        # WINDOW SIZE
        self.settings.setValue('MainWindow/Size', self.size())
    
        #FOOD: COLUMN WIDTHS
        columnWidths = []
        for i in range(9):
            columnWidths.append(self.foodView.columnWidth(i))
        self.settings.setValue('Food/ColumnWidths',columnWidths)
        
        # FOOD LOG: COLUMN WIDTHS
        columnWidths = []
        for i in range(9):
            columnWidths.append(self.foodLogList.columnWidth(i))
        self.settings.setValue('FoodLog/ColumnWidths1',columnWidths)
        
        columnWidths = []
        for i in range(4):
            columnWidths.append(self.foodLogToday.columnWidth(i))
        self.settings.setValue('FoodLog/ColumnWidths2',columnWidths)
        
        #EXERCISE: COLUMN WIDTHS
        columnWidths = []
        for i in range(4):
            columnWidths.append(self.exerciseList.columnWidth(i))
        self.settings.setValue('Exercise/ListWidths',columnWidths)
        
        columnWidths = []
        for i in range(5):
            columnWidths.append(self.dailyExerciseLog.columnWidth(i))
        self.settings.setValue('Exercise/LogWidths',columnWidths)
        
    def editFood(self, name='', portion='', data=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
                 foodID=0, row=0):
        dialog = EditFood(name, portion, data, foodID)
        dialog.setModal(True)
        newData = dialog.exec_()
        if newData == False:
            # cancelled add/edit
            pass
        else:
            # create or edit the item
            if newData[0] == 0:
                # brand new item
                self.foodModel.additem(newData[1])
            else:
                # edit existing item
                self.foodModel.edititem(newData[0], row, newData[1])
    
    def currentDate(self):
        '''Returns a QDate object with the date/time set to now'''
        return QDate.currentDate()
        
    def setFoodLogDate(self):
        '''Sets the date on the food Log tab to the current date'''
        self.dateEdit.setDate(self.currentDate())
    
    def setWeightLogDate(self):
        '''Sets the date on the weight log tab to the current date'''
        self.dateEdit_2.setDate(self.currentDate())
        
    def setExerciseLogDate(self, date=QDate.currentDate()):
        '''Sets the date on the weight log tab to the current date'''
        self.exerciseDateEdit.setDate(date)
        
    def setFoodLogYesterday(self):
        '''Sets the date on the food Log tab to yesterday'''
        self.dateEdit.setDate(self.currentDate().addDays(-1))
    
    def setWeightLogYesterday(self):
        '''Sets the date on the weight Log tab to yesterday'''
        self.dateEdit_2.setDate(self.currentDate().addDays(-1))
        
    def setExerciseLogYesterday(self):
        '''Sets the date on the exercise Log tab to yesterday'''
        self.exerciseDateEdit.setDate(self.currentDate().addDays(-1))
     
    def setFoodLogNextDay(self):
        '''Increments current date by 1 day'''
        self.dateEdit.setDate(self.dateEdit.date().addDays(1))
    
    def setWeightLogNextDay(self):
        '''Increments current date by 1 day'''
        self.dateEdit_2.setDate(self.dateEdit_2.date().addDays(1))
    
    def setExerciseLogNextDay(self):
        '''Increments current date by 1 day'''
        self.exerciseDateEdit.setDate(self.exerciseDateEdit.date().addDays(1))
        
    def setFoodLogPreviousDay(self):
        '''Decrements current date by 1 day'''
        self.dateEdit.setDate(self.dateEdit.date().addDays(-1))
    
    def setWeightLogPreviousDay(self):
        '''Decrements current date by 1 day'''
        self.dateEdit_2.setDate(self.dateEdit_2.date().addDays(-1))
    
    def setExerciseLogPreviousDay(self):
        '''Decrements current date by 1 day'''
        self.exerciseDateEdit.setDate(self.exerciseDateEdit.date().addDays(-1))
        
    def changeDate(self, date=QDate.currentDate()):
        '''Actions to conduct when date is changed, e.g. check if date exists in
        database, load existing food log'''
           
        self.foodLogModel = FoodLogModel(self.db, date, self)
        self.foodLogToday.setModel(self.foodLogModel)
        
    def changeWeightDate(self, date=QDate.currentDate()):
        """
        Actions to conduct when the weight date is changed.
        """

        weight = self.db.getWeight(date.toString('yyyy-MM-dd'))
        if weight != None:
            self.weight.setValue(weight['weight'])
        else:
            self.weight.setValue(0.0)
    
    def weightChanged(self):
        """
        Actions to take when the weight value is changed
        """
        
        # Check that the date exists
        dateString = self.dateEdit_2.date().toString('yyyy-MM-dd')
        weight = self.weight.value()
        d = self.db.getDate(dateString)
        if len(d) == 0: # The date does not yet exist in the database
            # has the value been changed to a default zero?
            if weight != 0:
                self.db.addDate(dateString)
                self.db.setWeight(dateString, weight)
        else: # The date exists in the database
            # change existing value
            self.db.setWeight(dateString, weight)
            
        
    def clearFilter(self):
        """
        Clears the filter box string
        """
        
        self.filterText.setText('')
        
    def filterFoodProxyModel(self):
        """
        Applies filter from the text box
        """
        
        self.foodProxyModel.setFilterFixedString(self.filterText.text())
        self.foodProxyModel.setFilterKeyColumn(1)
        
    def quantityEdit(self, QModelIndex):
        """
        Adds a food to from the food list to the daily consumption list
        """
        
        row = QModelIndex.row()
        data = []
        for column in range(9):
            data.append(QModelIndex.sibling(row,column).data())
        dialog = SetQuantity(data[0], data[1], data[2])
        dialog.setModal(True)
        newData = dialog.exec_()
        if newData == False:
            # User cancelled the operation
            pass
        else:
            # newData = [id, name, portion, quantity]
            self.foodLogModel.addFood(newData[0], newData[1],
                                      newData[2], newData[3])
    
    def quantityEditButton(self):
        """
        Adds a food to from the food list to the daily consumption list - as 
        quantityEdit, but using the pushbutton
        """
        if len(self.foodLogList.selectedIndexes()) != 0:
            QModelIndex = self.foodLogList.selectedIndexes()[0]
            self.quantityEdit(QModelIndex)
        
    def existingQuantityEdit(self, QModelIndex):
        row = QModelIndex.row()
        data = []
        for column in range(4):
            data.append(QModelIndex.sibling(row,column).data())
        dialog = SetQuantity(data[0], data[1], data[2], data[3])
        dialog.setModal(True)
        newData = dialog.exec_()
        if newData == False:
            # User cancelled the operation
            pass
        else:
            # newData = [id, name, portion, quantity]
            self.foodLogModel.editFood(newData[0], newData[3], row)
    
    def deleteFoodLogItem(self):
        if len(self.foodLogToday.selectedIndexes()) != 0:
            QModelIndex = self.foodLogToday.selectedIndexes()[0]
            self.foodLogModel.deleteFood(QModelIndex)
    
    def userNameUpdate(self):
        """
        Updates the user's name in the database file
        """

        self.db.setName(self.userName.text())
        
    def calculateBMR(self):
        """
        Calculates Basal metabolic rate and updates the information tab
        http://en.wikipedia.org/wiki/Basal_animal_metabolic_rate
        Mifflin et al. (1990)
        """

        if self.sex.currentIndex() == 0:
            # male
            BMR = 10.0*self.currentWeight.value() + 625*self.currentHeight.value() -5*self.currentAge.value() + 5
        if self.sex.currentIndex() == 1:
            # female
            BMR = 10.0*self.currentWeight.value() + 625*self.currentHeight.value() -5*self.currentAge.value() - 161
        
        self.currentBMR.setText(str(BMR))
        self.calculateMCN()
        
    def calculateMCN(self):
        """
        Calculates maintenance calorific needs, and updates ther information tab
        http://en.wikipedia.org/wiki/Harris-Benedict_equation
        Harris Benedict principle
        """
        
        multiplier = [1.2, 1.375, 1.55, 1.725, 1.9]
        MCN = float(self.currentBMR.text())*multiplier[self.activity.currentIndex()]
        self.currentMCN.setText(str(MCN))
        self.calculateTCN()
        
    def calculateTCN(self):
        """
        Calculates total calorific need based on desired weight change goal
        """
        
        calorieIncrease = [1000, 500, 0, +500, +1000]
        TCN = float(self.currentMCN.text()) + calorieIncrease[self.goal.currentIndex()]
        self.currentTCN.setText(str(TCN))
                        
        self.calculateSplit()
        
    def calculateSplit(self):
        """
        Determines the macronutrient split (by mass) and displays it in the UI
        This function should always be triggered if any of the upstream data 
        changes (i.e. sex, age, weight, height, activity and goal)
        so this function also updates the database with latest values of those
        """
        
        if self.dietMacro.currentIndex() == 0:
            c, p, f = 40.0, 40.0, 20.0    # carb, protein, fat
        if self.dietMacro.currentIndex() == 1:
            c, p, f = 40.0, 30.0, 30.0    # carb, protein, fat
        if self.dietMacro.currentIndex() == 2:
            c, p, f = 50.0, 25.0, 25.0    # carb, protein, fat
        if self.dietMacro.currentIndex() == 3:
            c, p, f = 50.0, 30.0, 20.0    # carb, protein, fat
            
        cg, pg, fg = self.db.macroSplit(c, p, f, float(self.currentTCN.text()))
        
        # set the values in the GUI
        self.targetCarbg.setText('%3i g/ day' % cg)
        self.targetProteing.setText('%3i g/ day' % pg)
        self.targetFatg.setText('%3i g/ day' % fg)
        
        # save values to DB
        self.db.updateUserData(self.userName.text(), self.sex.currentIndex(), self.currentAge.value(), self.currentHeight.value(), self.currentWeight.value(), self.activity.currentIndex(), self.goal.currentIndex(), self.dietMacro.currentIndex())
        
    def loadUserData(self):
        """
        Loads the user data from the SQL file into the GUI
        """
        
        userdata = self.db.getUserData()
        self.userName.setText(userdata['name'])
        self.sex.setCurrentIndex(userdata['sex'])
        self.currentAge.setValue(userdata['age'])
        self.currentHeight.setValue(userdata['height'])
        self.currentWeight.setValue(userdata['weight'])
        self.activity.setCurrentIndex(userdata['activity'])
        self.goal.setCurrentIndex(userdata['goal'])
        self.dietMacro.setCurrentIndex(userdata['macrosplit'])
        
    def createExercise(self, name='', typeID=1, row=False, existingID=-1):
        """
        Brings up the 'create exercise' dialog
        """

        dialog = CreateExercise(self.db, name, typeID)
        dialog.setModal(True)
        exData = dialog.exec_() # [description, typeID]
        if exData != False:
            if row == False:
                # Add a new item
                self.exerciseModel.addItem(exData[0], exData[1])
            else:
                # edit existing item in row row
                self.exerciseModel.editItem(exData[0], exData[1], row, existingID)
    
    def modifyExercise(self):
        if len(self.exerciseList.selectedIndexes()) != 0:
            QModelIndex = self.exerciseList.selectedIndexes()[0]
            row = QModelIndex.row()
            data = []
            for column in range(4):
                data.append(QModelIndex.sibling(row, column).data())
            self.createExercise(data[1], data[2], row, data[0])
    
    def removeExercise(self):
        """
        Deletes exercise from the exercises list (not the log)
        """
        
        if len(self.exerciseList.selectedIndexes()) != 0:
            QModelIndex = self.exerciseList.selectedIndexes()[0]
            row = QModelIndex.row()
            exID = QModelIndex.sibling(row, 0).data()
            self.exerciseModel.deleteItem(exID, row)
    
    def logExercise(self, QModelIndex):
        """
        Logs the exercise to the currently selected day
        """
        row = QModelIndex.row()
        exID = QModelIndex.sibling(row, 0).data()
        
        dialog = LogExercise(self.db, exID)
        dialog.setModal(True)
        exData = dialog.exec_()
        dateString = self.exerciseDateEdit.date().toString('yyyy-MM-dd')
        self.db.logExercise(dateString, exData[0], exData[1], exData[2], exData[3], exData[4])
        # reload model
        self.changeExerciseDate(self.exerciseDateEdit.date())
        
    def logExerciseClick(self):
        """
        Use the button to log the currently selected exercise to the currently
        selected day
        """
        if len(self.exerciseList.selectedIndexes()) != 0:
            QModelIndex = self.exerciseList.selectedIndexes()[0]
            self.logExercise(QModelIndex)
        
    def changeExerciseDate(self, date=QDate.currentDate()):
        """
        Actions to conduct when date is changed, e.g. check if date exists in
        database, load existing exercise log
        """
        
        self.exerciseLogModel = ExerciseLogModel(self.db, date, self)
        self.dailyExerciseLog.setModel(self.exerciseLogModel)