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")
Ejemplo n.º 2
0
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)