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)
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)