class ModifyCalendarController: def __init__(self, parent_window, caller_window, modify_type, clicked_time): self.database_interface = DatabaseInterface() # Get the window of the caller self.caller_window = caller_window # Initial values of times if modify_type == "update_or_delete": self.init_begin_time = self.database_interface.get_begin_row_from_time( clicked_time) self.init_end_time = self.database_interface.get_end_row_from_time( clicked_time) current_project_name = self.init_begin_time["project_name"] elif modify_type == "add": current_project_name = None # Create the window begin_printed_time, end_printed_time = self.get_printed_times( clicked_time, modify_type) project_names = self.database_interface.get_project_names() self.modify_calendar_window = ModifyCalendarWindow( parent_window, modify_type, begin_printed_time, end_printed_time, project_names, current_project_name) # Modify buttons if modify_type == "update_or_delete": self.modify_calendar_window.set_update_button_command( self.update_time_row) self.modify_calendar_window.set_delete_button_command( self.delete_time_row) elif modify_type == "add": self.modify_calendar_window.set_add_button_command( self.add_time_row) # Get printed times def get_printed_times(self, clicked_time, modify_type): if modify_type == "update_or_delete": begin_printed_time = self.init_begin_time["time"] end_printed_time = self.init_end_time["time"] elif modify_type == "add": begin_printed_time = clicked_time.strftime( format="%Y-%m-%d %H:%M:%S") end_printed_time = (clicked_time + timedelta(hours=1)).strftime( format="%Y-%m-%d %H:%M:%S") return begin_printed_time, end_printed_time # Modify buttons def get_entry_time(self, entry_time, time_type): # Test if the time entered is ok if not entry_time.isdigit(): return None entry_time = int(entry_time) if time_type == "hour" and (entry_time < 0 or entry_time > 23): return None if time_type in ["minute", "second"] and (entry_time < 0 or entry_time > 59): return None # Convert the time to a good string format entry_time = str(entry_time) if len(entry_time) == 1: entry_time = "0%s" % (entry_time) return entry_time def modify_time_row(self, modify_type): # Get the new values project_name = self.modify_calendar_window.get_project_name() row_date = self.modify_calendar_window.get_date() begin_hour = self.get_entry_time( self.modify_calendar_window.get_begin_hour(), "hour") begin_minute = self.get_entry_time( self.modify_calendar_window.get_begin_minute(), "minute") begin_second = self.get_entry_time( self.modify_calendar_window.get_begin_second(), "second") end_hour = self.get_entry_time( self.modify_calendar_window.get_end_hour(), "hour") end_minute = self.get_entry_time( self.modify_calendar_window.get_end_minute(), "minute") end_second = self.get_entry_time( self.modify_calendar_window.get_end_second(), "second") if None in [ begin_hour, begin_minute, begin_second, end_hour, end_minute, end_second ]: messagebox.showerror("Error", "A time is not well formated") return begin_time = "%s %s:%s:%s" % (row_date, begin_hour, begin_minute, begin_second) end_time = "%s %s:%s:%s" % (row_date, end_hour, end_minute, end_second) # Check if the new time does not overlap another one df = self.database_interface.get_dataframe_all_times() df["time"] = pd.to_datetime(df["time"]) df["last_time"] = df["time"].shift() df = df[df["action_type"] == "END"] begin_datetime = pd.to_datetime(begin_time) end_datetime = pd.to_datetime(end_time) print(df[((df["last_time"] > begin_datetime) & (df["last_time"] < end_datetime)) | ((df["time"] > begin_datetime) & (df["time"] < end_datetime))]) print(df[((begin_datetime > df["last_time"]) & (begin_datetime < df["time"])) | ((end_datetime > df["last_time"]) & (end_datetime < df["time"]))]) problematic_blocks = df[((df["last_time"] > begin_datetime) & (df["last_time"] < end_datetime)) | ((df["time"] > begin_datetime) & (df["time"] < end_datetime))] if not problematic_blocks.empty: if modify_type in ["update", "delete"]: if not problematic_blocks["last_time"].min() == pd.to_datetime( self.init_begin_time["time"] ) or not problematic_blocks["time"].max() == pd.to_datetime( self.init_end_time["time"]): messagebox.showerror("Error", "The new time overlap another block") return else: messagebox.showerror("Error", "The new time overlap another block") return problematic_blocks = df[((begin_datetime > df["last_time"]) & (begin_datetime < df["time"])) | ((end_datetime > df["last_time"]) & (end_datetime < df["time"]))] if not problematic_blocks.empty: if modify_type in ["update", "delete"]: if not problematic_blocks["last_time"].min() == pd.to_datetime( self.init_begin_time["time"] ) or not problematic_blocks["time"].max() == pd.to_datetime( self.init_end_time["time"]): messagebox.showerror("Error", "The new time overlap another block") return else: messagebox.showerror("Error", "The new time overlap another block") return # Get all the project names project_names = self.database_interface.get_project_names() if not project_name in project_names: messagebox.showerror("Error", "%s is not in the database" % (project_name)) return # Modify the database if modify_type == "update": self.database_interface.update_row( project_name, begin_time, self.init_begin_time["project_name"], self.init_begin_time["time"], self.database_interface.begin_action) self.database_interface.update_row( project_name, end_time, self.init_end_time["project_name"], self.init_end_time["time"], self.database_interface.end_action) elif modify_type == "delete": self.database_interface.delete_row( self.init_begin_time["project_name"], self.init_begin_time["time"], self.database_interface.begin_action) self.database_interface.delete_row( self.init_end_time["project_name"], self.init_end_time["time"], self.database_interface.end_action) elif modify_type == "add": self.database_interface.create_row( project_name, begin_time, self.database_interface.begin_action) self.database_interface.create_row( project_name, end_time, self.database_interface.end_action) # Update the canvas project_names = self.database_interface.get_project_names() times_df = self.database_interface.get_dataframe_times() self.caller_window.update_calendar_project_block( project_names, times_df) # Remove the window self.modify_calendar_window.destroy_window() def add_time_row(self): self.modify_time_row("add") def delete_time_row(self): self.modify_time_row("delete") def update_time_row(self): self.modify_time_row("update")
class MainController: def __init__(self, root): # Variables self.database_interface = DatabaseInterface() self.root = root # Time format self.time_format = '%Y-%m-%d %H:%M:%S' # Get variables to create the main window last_action = self.database_interface.get_last_action() if last_action is None: last_action = { "time": "N/A N/A", "project_name": "N/A", "action_type": "N/A" } project_names = self.database_interface.get_project_names() # Create the main window self.main_window = MainWindow(self.root, project_names, last_action) # Start and stop buttons self.main_window.set_start_button_command(self.add_work_time) self.main_window.set_stop_button_command(self.end_work_time) # Add and delete project buttons self.main_window.set_add_project_button_command( self.create_add_project_window) self.main_window.set_modify_project_button_command( self.create_modify_project_window) # self.main_window.set_delete_project_button_command(self.create_delete_project_window) # Summary button self.main_window.set_summary_button_command(self.create_summary_window) # Calendar button self.main_window.set_calendar_button_command( self.create_calendar_window) # Start and stop buttons def write_work_time(self, project_name, now, action_type): self.database_interface.create_row(project_name, now, action_type) if action_type == self.database_interface.begin_action: action_type = "Start" else: action_type = "Stop" self.main_window.update_last_action_labels(now, project_name, action_type) def is_project_names(self): project_names = self.database_interface.get_project_names() if not project_names: messagebox.error("Error", "The project list is empty") return False return True def add_work_time(self): if self.is_project_names(): self.end_work_time() active_project_name = self.main_window.get_active_project_name() now = datetime.now().strftime(self.time_format) self.write_work_time(active_project_name, now, self.database_interface.begin_action) def fill_missing_days(self, now, last_action): last_date = datetime.strptime(last_action["time"], self.time_format) while (last_date.day < now.day): # Write the time to the end of the day last_date_end_day = last_date.replace(hour=23, minute=59, second=59, microsecond=0).strftime( self.time_format) self.write_work_time(last_action["project_name"], last_date_end_day, self.database_interface.end_action) # Write the time begining the next day last_date = last_date + timedelta(days=1) last_date_begin_day = last_date.replace(hour=0, minute=0, second=0, microsecond=0).strftime( self.time_format) self.write_work_time(last_action["project_name"], last_date_begin_day, self.database_interface.begin_action) def end_work_time(self): if self.is_project_names(): last_action = self.database_interface.get_last_action() if last_action and last_action[ "action_type"] == self.database_interface.begin_action: now = datetime.now() self.fill_missing_days(now, last_action) now_str = now.strftime(self.time_format) self.write_work_time(last_action["project_name"], now_str, self.database_interface.end_action) # Add and delete project buttons def create_add_project_window(self): modify_project_names_controller = ModifyProjectNamesController( self.root, self.main_window, "add") def create_modify_project_window(self): modify_project_names_controller = ModifyProjectNamesController( self.root, self.main_window, "modify") # def create_delete_project_window(self): # modify_project_names_controller = ModifyProjectNamesController(self.root, self.main_window, "delete") # Summary button def create_summary_window(self): summary_controller = SummaryController(self.root) # Calendar button def create_calendar_window(self): calendar_controller = CalendarController(self.root)