Team Ai
Apppublic

abhi-bit-2/Genetic_Algorithm

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
modern_timetable_gui.py1790 linesDownload Raw Back to root
1import tkinter as tk2from tkinter import ttk, messagebox, scrolledtext, filedialog3import sys4import io5import threading6import sqlite37import os8import datetime9import pandas as pd10from openpyxl import Workbook11from openpyxl.styles import Font, Alignment, PatternFill, Border, Side12from openpyxl.utils import get_column_letter13from db_operations import initialize_database, fetch_data_from_db, get_course_classes, set_course_classes14from db_operations import add_professor, add_course, add_branch, add_branch_teacher_course_mapping15from db_operations import delete_course, delete_course_teacher_mapping16from db_operations import get_all_professors, get_professor_courses, get_available_courses_for_professor17from db_operations import add_course_to_professor, remove_course_from_professor18from simplified_genetic_algorithm import genetic_algorithm, print_timetable, print_professor_schedules19from main import debug_database, verify_database_integrity20 21# Color scheme22COLORS = {23    "primary": "#3498db",      # Blue24    "secondary": "#2ecc71",    # Green25    "accent": "#e74c3c",       # Red26    "background": "#f5f5f5",   # Light gray27    "text": "#2c3e50",         # Dark blue/gray28    "light_text": "#7f8c8d",   # Light gray text29    "success": "#27ae60",      # Dark green30    "warning": "#f39c12",      # Orange31    "error": "#c0392b"         # Dark red32}33 34# Redirect stdout to capture print statements35class StdoutRedirector:36    def __init__(self, text_widget):37        self.text_widget = text_widget38        self.buffer = io.StringIO()39 40    def write(self, string):41        self.buffer.write(string)42        self.text_widget.insert(tk.END, string)43        self.text_widget.see(tk.END)  # Auto-scroll to the end44        45    def flush(self):46        pass47 48class ModernTimetableApp:49    def __init__(self, root):50        self.root = root51        self.root.title("Fast Timetable Generator")52        self.root.geometry("1200x800")53        self.root.minsize(1000, 700)54        55        # Configure the style56        self.configure_style()57        58        # Store the last generated timetable and professor schedules59        self.last_timetable = None60        self.last_professor_schedules = None61        62        # Create main frame63        self.main_frame = ttk.Frame(root)64        self.main_frame.pack(fill=tk.BOTH, expand=True)65        66        # Create sidebar and content area67        self.create_sidebar()68        self.create_content_area()69        70        # Initialize the database71        self.initialize_db()72        73        # Show the home screen by default74        self.show_home()75    76    def configure_style(self):77        """Configure the ttk styles for a modern look"""78        style = ttk.Style()79        style.theme_use('clam')  # Use the 'clam' theme as a base80        81        # Configure colors82        style.configure('TFrame', background=COLORS["background"])83        style.configure('TLabel', background=COLORS["background"], foreground=COLORS["text"])84        style.configure('TButton', background=COLORS["primary"], foreground="white", font=('Arial', 10))85        style.map('TButton', background=[('active', COLORS["secondary"])])86        87        # Sidebar button style88        style.configure('Sidebar.TButton', font=('Arial', 11), padding=10)89        90        # Heading style91        style.configure('Heading.TLabel', font=('Arial', 16, 'bold'), foreground=COLORS["primary"])92        style.configure('SubHeading.TLabel', font=('Arial', 12, 'italic'), foreground=COLORS["light_text"])93        94        # Card style95        style.configure('Card.TFrame', background="white", relief="raised", borderwidth=1)96        97        # Success and error styles98        style.configure('Success.TLabel', foreground=COLORS["success"])99        style.configure('Error.TLabel', foreground=COLORS["error"])100    101    def create_sidebar(self):102        """Create the sidebar with navigation buttons"""103        self.sidebar = ttk.Frame(self.main_frame, width=200, style='TFrame')104        self.sidebar.pack(side=tk.LEFT, fill=tk.Y, padx=0, pady=0)105        106        # Make the sidebar fixed width107        self.sidebar.pack_propagate(False)108        109        # App title110        title_frame = ttk.Frame(self.sidebar, style='TFrame')111        title_frame.pack(fill=tk.X, padx=10, pady=20)112        113        ttk.Label(title_frame, text="Timetable", font=('Arial', 18, 'bold'), 114                 foreground=COLORS["primary"], style='TLabel').pack(anchor=tk.W)115        ttk.Label(title_frame, text="Generator", font=('Arial', 14), 116                 foreground=COLORS["secondary"], style='TLabel').pack(anchor=tk.W)117        118        # Navigation buttons119        self.nav_buttons = []120        121        nav_items = [122            ("Home", self.show_home),123            ("Database", self.show_database),124            ("Courses", self.show_courses),125            ("Classes", self.show_classes),126            ("Professor Courses", self.show_professor_courses),127            ("Generate", self.show_generate),128            ("View Timetable", self.show_timetable),129            ("Professor Schedules", self.show_professors)130        ]131        132        for text, command in nav_items:133            btn = ttk.Button(self.sidebar, text=text, command=command, style='Sidebar.TButton')134            btn.pack(fill=tk.X, padx=10, pady=5)135            self.nav_buttons.append(btn)136        137        # Status section at bottom of sidebar138        status_frame = ttk.Frame(self.sidebar, style='TFrame')139        status_frame.pack(side=tk.BOTTOM, fill=tk.X, padx=10, pady=20)140        141        ttk.Label(status_frame, text="Status:", style='TLabel').pack(anchor=tk.W)142        self.status_var = tk.StringVar(value="Ready")143        ttk.Label(status_frame, textvariable=self.status_var, style='TLabel').pack(anchor=tk.W, pady=5)144    145    def create_content_area(self):146        """Create the main content area"""147        self.content = ttk.Frame(self.main_frame, style='TFrame')148        self.content.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=20, pady=20)149        150        # Create frames for each section (only one will be visible at a time)151        self.home_frame = ttk.Frame(self.content, style='TFrame')152        self.database_frame = ttk.Frame(self.content, style='TFrame')153        self.courses_frame = ttk.Frame(self.content, style='TFrame')154        self.classes_frame = ttk.Frame(self.content, style='TFrame')  # New frame for classes management155        self.professor_courses_frame = ttk.Frame(self.content, style='TFrame')  # New frame for professor courses156        self.generate_frame = ttk.Frame(self.content, style='TFrame')157        self.timetable_frame = ttk.Frame(self.content, style='TFrame')158        self.professors_frame = ttk.Frame(self.content, style='TFrame')159 160        # Set up each frame161        self.setup_home_frame()162        self.setup_database_frame()163        self.setup_courses_frame()164        self.setup_classes_frame()  # Setup the new classes frame165        self.setup_professor_courses_frame()  # Setup the professor courses frame166        self.setup_generate_frame()167        self.setup_timetable_frame()168        self.setup_professors_frame()169    170    def hide_all_frames(self):171        """Hide all content frames"""172        for frame in [self.home_frame, self.database_frame, self.courses_frame, self.classes_frame,173                     self.professor_courses_frame, self.generate_frame, self.timetable_frame, self.professors_frame]:174            frame.pack_forget()175    176    def show_home(self):177        self.hide_all_frames()178        self.home_frame.pack(fill=tk.BOTH, expand=True)179    180    def show_database(self):181        self.hide_all_frames()182        self.database_frame.pack(fill=tk.BOTH, expand=True)183    184    def show_courses(self):185        self.hide_all_frames()186        self.courses_frame.pack(fill=tk.BOTH, expand=True)187        self.refresh_courses()188        self.refresh_branches()189        self.refresh_mapping_lists()190 191    def show_classes(self):192        self.hide_all_frames()193        self.classes_frame.pack(fill=tk.BOTH, expand=True)194        self.refresh_courses_for_classes()195 196    def show_professor_courses(self):197        self.hide_all_frames()198        self.professor_courses_frame.pack(fill=tk.BOTH, expand=True)199        self.refresh_professors_list()200 201    def show_generate(self):202        self.hide_all_frames()203        self.generate_frame.pack(fill=tk.BOTH, expand=True)204    205    def show_timetable(self):206        self.hide_all_frames()207        self.timetable_frame.pack(fill=tk.BOTH, expand=True)208    209    def show_professors(self):210        self.hide_all_frames()211        self.professors_frame.pack(fill=tk.BOTH, expand=True)212        self.refresh_professors()213    214    def setup_home_frame(self):215        """Set up the home screen with a modern, clean design"""216        # Title with improved styling217        title_frame = ttk.Frame(self.home_frame, style='TFrame')218        title_frame.pack(fill=tk.X, pady=(0, 20))219 220        ttk.Label(title_frame, text="Timetable Generator",221                 font=('Arial', 24, 'bold'), foreground=COLORS["primary"],222                 style='TLabel').pack(pady=(0, 5))223        ttk.Label(title_frame, text="Create optimal timetables using genetic algorithms",224                 style='SubHeading.TLabel').pack(pady=(0, 10))225 226        # Main content in a two-column layout227        content_frame = ttk.Frame(self.home_frame, style='TFrame')228        content_frame.pack(fill=tk.BOTH, expand=True, pady=10)229        content_frame.columnconfigure(0, weight=1)230        content_frame.columnconfigure(1, weight=1)231 232        # Left column: Stats and actions233        left_col = ttk.Frame(content_frame, style='TFrame')234        left_col.grid(row=0, column=0, padx=10, pady=10, sticky=tk.N+tk.S+tk.W+tk.E)235 236        # Stats cards237        stats_frame = ttk.LabelFrame(left_col, text="Database Statistics", style='TFrame')238        stats_frame.pack(fill=tk.X, pady=10)239 240        stats_grid = ttk.Frame(stats_frame, style='TFrame')241        stats_grid.pack(fill=tk.X, padx=10, pady=10)242        stats_grid.columnconfigure(0, weight=1)243        stats_grid.columnconfigure(1, weight=1)244        stats_grid.columnconfigure(2, weight=1)245 246        # Create stat cards in a grid247        self.create_stat_card(stats_grid, "Branches", "branch_count", 0, 0)248        self.create_stat_card(stats_grid, "Courses", "course_count", 0, 1)249        self.create_stat_card(stats_grid, "Teachers", "teacher_count", 0, 2)250 251        # Quick actions252        actions_frame = ttk.LabelFrame(left_col, text="Quick Actions", style='TFrame')253        actions_frame.pack(fill=tk.X, pady=10)254 255        # Create a grid for buttons with 2 columns256        button_grid = ttk.Frame(actions_frame, style='TFrame')257        button_grid.pack(fill=tk.X, padx=10, pady=10)258        button_grid.columnconfigure(0, weight=1)259        button_grid.columnconfigure(1, weight=1)260 261        # Add buttons with icons (using text for now)262        ttk.Button(button_grid, text="Initialize Database",263                  command=self.initialize_db).grid(row=0, column=0, padx=5, pady=5, sticky=tk.W+tk.E)264        ttk.Button(button_grid, text="Generate Timetable",265                  command=self.generate_timetable).grid(row=0, column=1, padx=5, pady=5, sticky=tk.W+tk.E)266        ttk.Button(button_grid, text="View Timetable",267                  command=self.show_timetable).grid(row=1, column=0, padx=5, pady=5, sticky=tk.W+tk.E)268        ttk.Button(button_grid, text="View Professor Schedules",269                  command=self.show_professors).grid(row=1, column=1, padx=5, pady=5, sticky=tk.W+tk.E)270 271        # Right column: Console output272        right_col = ttk.Frame(content_frame, style='TFrame')273        right_col.grid(row=0, column=1, padx=10, pady=10, sticky=tk.N+tk.S+tk.W+tk.E)274 275        console_frame = ttk.LabelFrame(right_col, text="Console Output", style='TFrame')276        console_frame.pack(fill=tk.BOTH, expand=True)277 278        self.console = scrolledtext.ScrolledText(console_frame, wrap=tk.WORD, height=15,279                                               font=('Consolas', 9))280        self.console.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)281 282        # Add a welcome message to the console283        welcome_msg = (284            "Welcome to Timetable Generator!\n\n"285            "This application helps you create optimal timetables using genetic algorithms.\n\n"286            "To get started:\n"287            "1. Initialize the database\n"288            "2. Add branches, professors, and courses\n"289            "3. Generate a timetable\n\n"290            "System ready and waiting for commands...\n"291        )292        self.console.insert(tk.END, welcome_msg)293 294        # Redirect stdout to the console295        sys.stdout = StdoutRedirector(self.console)296    297    def create_stat_card(self, parent, title, var_name, row, col):298        """Create a statistics card"""299        card = ttk.Frame(parent, style='Card.TFrame')300        card.grid(row=row, column=col, padx=10, pady=10, sticky=tk.W+tk.E)301        302        ttk.Label(card, text=title, font=('Arial', 12), background="white").pack(pady=(10, 5))303        304        # Create a variable to hold the count305        setattr(self, var_name, tk.StringVar(value="0"))306        ttk.Label(card, textvariable=getattr(self, var_name), 307                 font=('Arial', 24, 'bold'), foreground=COLORS["primary"], 308                 background="white").pack(pady=(0, 10))309    310    def setup_database_frame(self):311        """Set up the database management frame"""312        # Title313        ttk.Label(self.database_frame, text="Database Management", 314                 style='Heading.TLabel').pack(pady=(0, 20))315        316        # Create a notebook for tabs317        notebook = ttk.Notebook(self.database_frame)318        notebook.pack(fill=tk.BOTH, expand=True)319        320        # Create tabs321        actions_tab = ttk.Frame(notebook, style='TFrame')322        branch_tab = ttk.Frame(notebook, style='TFrame')323        professor_tab = ttk.Frame(notebook, style='TFrame')324        325        notebook.add(actions_tab, text="Database Actions")326        notebook.add(branch_tab, text="Add Branch")327        notebook.add(professor_tab, text="Add Professor")328        329        # Database actions tab330        actions_frame = ttk.Frame(actions_tab, style='TFrame')331        actions_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)332        333        ttk.Button(actions_frame, text="Initialize Database", 334                  command=self.initialize_db).pack(fill=tk.X, pady=10)335        ttk.Button(actions_frame, text="Debug Database", 336                  command=self.debug_database).pack(fill=tk.X, pady=10)337        ttk.Button(actions_frame, text="Verify Database Integrity", 338                  command=self.verify_database).pack(fill=tk.X, pady=10)339        340        # Console output for actions341        console_frame = ttk.LabelFrame(actions_frame, text="Console Output", style='TFrame')342        console_frame.pack(fill=tk.BOTH, expand=True, pady=20)343        344        self.db_console = scrolledtext.ScrolledText(console_frame, wrap=tk.WORD, height=10)345        self.db_console.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)346        347        # Branch tab348        branch_frame = ttk.Frame(branch_tab, style='TFrame')349        branch_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)350        351        ttk.Label(branch_frame, text="Branch Name:").pack(anchor=tk.W, pady=(0, 5))352        self.branch_name_var = tk.StringVar()353        ttk.Entry(branch_frame, textvariable=self.branch_name_var, width=40).pack(fill=tk.X, pady=(0, 10))354        355        ttk.Button(branch_frame, text="Add Branch", 356                  command=self.add_branch).pack(anchor=tk.W, pady=10)357        358        # Professor tab359        prof_frame = ttk.Frame(professor_tab, style='TFrame')360        prof_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)361        362        ttk.Label(prof_frame, text="Professor Name:").pack(anchor=tk.W, pady=(0, 5))363        self.prof_name_var = tk.StringVar()364        ttk.Entry(prof_frame, textvariable=self.prof_name_var, width=40).pack(fill=tk.X, pady=(0, 10))365        366        ttk.Label(prof_frame, text="Branch:").pack(anchor=tk.W, pady=(10, 5))367        self.prof_branch_var = tk.StringVar()368        self.prof_branch_combo = ttk.Combobox(prof_frame, textvariable=self.prof_branch_var, width=40)369        self.prof_branch_combo.pack(fill=tk.X, pady=(0, 10))370        371        button_frame = ttk.Frame(prof_frame, style='TFrame')372        button_frame.pack(fill=tk.X, pady=10)373        374        ttk.Button(button_frame, text="Add Professor", 375                  command=self.add_professor).pack(side=tk.LEFT, padx=(0, 10))376        ttk.Button(button_frame, text="Refresh Branches", 377                  command=self.refresh_branches).pack(side=tk.LEFT)378    379    def setup_courses_frame(self):380        """Set up the course management frame"""381        # Title382        ttk.Label(self.courses_frame, text="Course Management", 383                 style='Heading.TLabel').pack(pady=(0, 20))384        385        # Create a notebook for tabs386        notebook = ttk.Notebook(self.courses_frame)387        notebook.pack(fill=tk.BOTH, expand=True)388        389        # Create tabs390        add_course_tab = ttk.Frame(notebook, style='TFrame')391        mapping_tab = ttk.Frame(notebook, style='TFrame')392        delete_tab = ttk.Frame(notebook, style='TFrame')393        394        notebook.add(add_course_tab, text="Add Course")395        notebook.add(mapping_tab, text="Add Mapping")396        notebook.add(delete_tab, text="Delete Course")397        398        # Add course tab399        course_frame = ttk.Frame(add_course_tab, style='TFrame')400        course_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)401        402        ttk.Label(course_frame, text="Course Code:").pack(anchor=tk.W, pady=(0, 5))403        self.course_code_var = tk.StringVar()404        ttk.Entry(course_frame, textvariable=self.course_code_var, width=40).pack(fill=tk.X, pady=(0, 10))405        406        ttk.Label(course_frame, text="Course Name:").pack(anchor=tk.W, pady=(10, 5))407        self.course_name_var = tk.StringVar()408        ttk.Entry(course_frame, textvariable=self.course_name_var, width=40).pack(fill=tk.X, pady=(0, 10))409        410        ttk.Label(course_frame, text="Branch:").pack(anchor=tk.W, pady=(10, 5))411        self.course_branch_var = tk.StringVar()412        self.course_branch_combo = ttk.Combobox(course_frame, textvariable=self.course_branch_var, width=40)413        self.course_branch_combo.pack(fill=tk.X, pady=(0, 10))414        415        button_frame = ttk.Frame(course_frame, style='TFrame')416        button_frame.pack(fill=tk.X, pady=10)417        418        ttk.Button(button_frame, text="Add Course", 419                  command=self.add_course).pack(side=tk.LEFT, padx=(0, 10))420        ttk.Button(button_frame, text="Refresh Branches", 421                  command=self.refresh_branches).pack(side=tk.LEFT)422        423        # Mapping tab424        mapping_frame = ttk.Frame(mapping_tab, style='TFrame')425        mapping_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)426        427        ttk.Label(mapping_frame, text="Branch:").pack(anchor=tk.W, pady=(0, 5))428        self.mapping_branch_var = tk.StringVar()429        self.mapping_branch_combo = ttk.Combobox(mapping_frame, textvariable=self.mapping_branch_var, width=40)430        self.mapping_branch_combo.pack(fill=tk.X, pady=(0, 10))431        432        ttk.Label(mapping_frame, text="Teacher:").pack(anchor=tk.W, pady=(10, 5))433        self.mapping_teacher_var = tk.StringVar()434        self.mapping_teacher_combo = ttk.Combobox(mapping_frame, textvariable=self.mapping_teacher_var, width=40)435        self.mapping_teacher_combo.pack(fill=tk.X, pady=(0, 10))436        437        ttk.Label(mapping_frame, text="Course:").pack(anchor=tk.W, pady=(10, 5))438        self.mapping_course_var = tk.StringVar()439        self.mapping_course_combo = ttk.Combobox(mapping_frame, textvariable=self.mapping_course_var, width=40)440        self.mapping_course_combo.pack(fill=tk.X, pady=(0, 10))441        442        button_frame = ttk.Frame(mapping_frame, style='TFrame')443        button_frame.pack(fill=tk.X, pady=10)444        445        ttk.Button(button_frame, text="Add Mapping", 446                  command=self.add_mapping).pack(side=tk.LEFT, padx=(0, 10))447        ttk.Button(button_frame, text="Refresh Lists", 448                  command=self.refresh_mapping_lists).pack(side=tk.LEFT)449        450        # Delete course tab451        delete_frame = ttk.Frame(delete_tab, style='TFrame')452        delete_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)453        454        ttk.Label(delete_frame, text="Course:").pack(anchor=tk.W, pady=(0, 5))455        self.delete_course_var = tk.StringVar()456        self.delete_course_combo = ttk.Combobox(delete_frame, textvariable=self.delete_course_var, width=40)457        self.delete_course_combo.pack(fill=tk.X, pady=(0, 10))458        459        button_frame = ttk.Frame(delete_frame, style='TFrame')460        button_frame.pack(fill=tk.X, pady=10)461        462        ttk.Button(button_frame, text="Delete Course", 463                  command=self.delete_course).pack(side=tk.LEFT, padx=(0, 10))464        ttk.Button(button_frame, text="Refresh Courses", 465                  command=self.refresh_courses).pack(side=tk.LEFT)466        467        # Console output for all tabs468        console_frame = ttk.LabelFrame(self.courses_frame, text="Console Output", style='TFrame')469        console_frame.pack(fill=tk.BOTH, expand=True, pady=20)470        471        self.course_console = scrolledtext.ScrolledText(console_frame, wrap=tk.WORD, height=10)472        self.course_console.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)473    474    def setup_generate_frame(self):475        """Set up the timetable generation frame"""476        # Title477        ttk.Label(self.generate_frame, text="Generate Timetable",478                 style='Heading.TLabel').pack(pady=(0, 20))479        ttk.Label(self.generate_frame, text="Using genetic algorithm for optimal timetable generation",480                 style='SubHeading.TLabel').pack(pady=(0, 10))481 482        # Generation options483        options_frame = ttk.LabelFrame(self.generate_frame, text="Generation Options", style='TFrame')484        options_frame.pack(fill=tk.X, pady=10)485 486        # Create a grid layout with 2 columns487        options_frame.columnconfigure(0, weight=0)488        options_frame.columnconfigure(1, weight=1)489 490        # Generations option491        ttk.Label(options_frame, text="Generations:").grid(row=0, column=0, padx=10, pady=10, sticky=tk.W)492        self.generations_var = tk.StringVar(value="100")493        ttk.Spinbox(options_frame, from_=30, to=300, increment=10,494                   textvariable=self.generations_var, width=10).grid(row=0, column=1, padx=10, pady=10, sticky=tk.W)495 496        # Generate button497        generate_btn = ttk.Button(options_frame, text="Generate Timetable",498                                 command=self.generate_timetable)499        generate_btn.grid(row=1, column=0, columnspan=2, padx=10, pady=10, sticky=tk.W+tk.E)500 501        # Status indicator502        status_frame = ttk.Frame(self.generate_frame, style='TFrame')503        status_frame.pack(fill=tk.X, pady=10)504 505        self.progress_var = tk.StringVar(value="Not started")506        ttk.Label(status_frame, text="Status:").pack(side=tk.LEFT, padx=(0, 10))507        ttk.Label(status_frame, textvariable=self.progress_var,508                 font=('Arial', 10, 'bold')).pack(side=tk.LEFT)509 510        # Information panel511        info_frame = ttk.LabelFrame(self.generate_frame, text="Information", style='TFrame')512        info_frame.pack(fill=tk.BOTH, expand=True, pady=10)513 514        info_text = (515            "The timetable generation process will run in the background.\n\n"516            "Once complete, you will be automatically redirected to the timetable view.\n\n"517            "For large datasets, this process may take several minutes.\n"518            "Please be patient while the genetic algorithm optimizes your timetable."519        )520 521        ttk.Label(info_frame, text=info_text, wraplength=500, justify="center").pack(522            fill=tk.BOTH, expand=True, padx=20, pady=20523        )524    525    def setup_timetable_frame(self):526        """Set up the timetable display frame"""527        # Title528        ttk.Label(self.timetable_frame, text="Timetable View",529                 style='Heading.TLabel').pack(pady=(0, 20))530 531        # Actions toolbar532        actions_frame = ttk.Frame(self.timetable_frame, style='TFrame')533        actions_frame.pack(fill=tk.X, pady=10)534 535        # Create a more organized button layout536        button_frame = ttk.Frame(actions_frame, style='TFrame')537        button_frame.pack(fill=tk.X)538 539        # Configure columns for even spacing540        button_frame.columnconfigure(0, weight=1)541        button_frame.columnconfigure(1, weight=1)542        button_frame.columnconfigure(2, weight=1)543 544        # Add buttons in a grid layout545        ttk.Button(button_frame, text="Generate New Timetable",546                  command=self.show_generate).grid(row=0, column=0, padx=5, pady=5, sticky=tk.W+tk.E)547        ttk.Button(button_frame, text="View Professor Schedules",548                  command=self.show_professors).grid(row=0, column=1, padx=5, pady=5, sticky=tk.W+tk.E)549        ttk.Button(button_frame, text="Export to Excel",550                  command=self.export_timetable_to_excel).grid(row=0, column=2, padx=5, pady=5, sticky=tk.W+tk.E)551 552        # Timetable display with improved styling553        timetable_frame = ttk.LabelFrame(self.timetable_frame, text="Current Timetable", style='TFrame')554        timetable_frame.pack(fill=tk.BOTH, expand=True, pady=10)555 556        # Use a monospaced font for better timetable display557        self.timetable_text = scrolledtext.ScrolledText(558            timetable_frame,559            wrap=tk.WORD,560            font=('Courier New', 10)561        )562        self.timetable_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)563 564        # Initial message with better formatting565        self.timetable_text.insert(tk.END,566            "No timetable has been generated yet.\n\n"567            "Please go to the Generate tab to create a new timetable."568        )569    570    def setup_classes_frame(self):571        """Set up the course classes management frame"""572        # Title573        ttk.Label(self.classes_frame, text="Course Classes Management",574                 style='Heading.TLabel').pack(pady=(0, 20))575        ttk.Label(self.classes_frame, text="Set the number of classes per week for each course",576                 style='SubHeading.TLabel').pack(pady=(0, 20))577 578        # Create a notebook for tabs579        notebook = ttk.Notebook(self.classes_frame)580        notebook.pack(fill=tk.BOTH, expand=True)581 582        # Create tabs583        view_tab = ttk.Frame(notebook, style='TFrame')584        update_tab = ttk.Frame(notebook, style='TFrame')585        update_all_tab = ttk.Frame(notebook, style='TFrame')586 587        notebook.add(view_tab, text="View Classes")588        notebook.add(update_tab, text="Update Course")589        notebook.add(update_all_tab, text="Update All Courses")590 591        # View classes tab592        view_frame = ttk.Frame(view_tab, style='TFrame')593        view_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)594 595        ttk.Button(view_frame, text="View Course Classes Configuration",596                  command=self.view_course_classes).pack(fill=tk.X, pady=10)597 598        # Update single course tab599        update_frame = ttk.Frame(update_tab, style='TFrame')600        update_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)601 602        ttk.Label(update_frame, text="Course:").pack(anchor=tk.W, pady=(0, 5))603        self.update_course_var = tk.StringVar()604        self.update_course_combo = ttk.Combobox(update_frame, textvariable=self.update_course_var, width=40)605        self.update_course_combo.pack(fill=tk.X, pady=(0, 10))606 607        ttk.Label(update_frame, text="Classes per Week:").pack(anchor=tk.W, pady=(10, 5))608        self.update_classes_var = tk.StringVar(value="2")609        ttk.Spinbox(update_frame, from_=1, to=5, textvariable=self.update_classes_var, width=10).pack(anchor=tk.W, pady=(0, 10))610 611        button_frame = ttk.Frame(update_frame, style='TFrame')612        button_frame.pack(fill=tk.X, pady=10)613 614        ttk.Button(button_frame, text="Update Course",615                  command=self.update_course_classes).pack(side=tk.LEFT, padx=(0, 10))616        ttk.Button(button_frame, text="Refresh Courses",617                  command=self.refresh_courses_for_classes).pack(side=tk.LEFT)618 619        # Update all courses tab620        update_all_frame = ttk.Frame(update_all_tab, style='TFrame')621        update_all_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)622 623        ttk.Label(update_all_frame, text="Classes per Week for ALL courses:").pack(anchor=tk.W, pady=(0, 5))624        self.update_all_classes_var = tk.StringVar(value="2")625        ttk.Spinbox(update_all_frame, from_=1, to=5, textvariable=self.update_all_classes_var, width=10).pack(anchor=tk.W, pady=(0, 10))626 627        ttk.Button(update_all_frame, text="Update All Courses",628                  command=self.update_all_course_classes).pack(anchor=tk.W, pady=10)629 630        # Console output for all tabs631        console_frame = ttk.LabelFrame(self.classes_frame, text="Console Output", style='TFrame')632        console_frame.pack(fill=tk.BOTH, expand=True, pady=20)633 634        self.classes_console = scrolledtext.ScrolledText(console_frame, wrap=tk.WORD, height=10)635        self.classes_console.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)636 637    def setup_professor_courses_frame(self):638        """Set up the professor courses management frame"""639        # Title640        ttk.Label(self.professor_courses_frame, text="Professor Course Management",641                 style='Heading.TLabel').pack(pady=(0, 20))642 643        # Create a split view with professors on the left and courses on the right644        main_pane = ttk.PanedWindow(self.professor_courses_frame, orient=tk.HORIZONTAL)645        main_pane.pack(fill=tk.BOTH, expand=True, pady=10)646 647        # Left frame for professor selection648        left_frame = ttk.Frame(main_pane, style='TFrame')649        main_pane.add(left_frame, weight=1)650 651        # Professor selection652        ttk.Label(left_frame, text="Select Professor:", style='SubHeading.TLabel').pack(anchor=tk.W, pady=(0, 10))653 654        # Create a frame for the professor list655        prof_list_frame = ttk.Frame(left_frame, style='TFrame')656        prof_list_frame.pack(fill=tk.BOTH, expand=True, pady=5)657 658        # Create a treeview for the professors659        self.professors_tree = ttk.Treeview(prof_list_frame, columns=("id", "name", "branch"), show="headings")660        self.professors_tree.heading("id", text="ID")661        self.professors_tree.heading("name", text="Professor Name")662        self.professors_tree.heading("branch", text="Branch")663 664        self.professors_tree.column("id", width=50)665        self.professors_tree.column("name", width=200)666        self.professors_tree.column("branch", width=150)667 668        self.professors_tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)669 670        # Add a scrollbar671        scrollbar = ttk.Scrollbar(prof_list_frame, orient=tk.VERTICAL, command=self.professors_tree.yview)672        self.professors_tree.configure(yscroll=scrollbar.set)673        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)674 675        # Bind selection event676        self.professors_tree.bind("<<TreeviewSelect>>", self.on_professor_selected)677 678        # Refresh button679        ttk.Button(left_frame, text="Refresh Professors",680                  command=self.refresh_professors_list).pack(fill=tk.X, pady=10)681 682        # Right frame for courses683        right_frame = ttk.Frame(main_pane, style='TFrame')684        main_pane.add(right_frame, weight=2)685 686        # Create a notebook for tabs687        self.prof_courses_notebook = ttk.Notebook(right_frame)688        self.prof_courses_notebook.pack(fill=tk.BOTH, expand=True)689 690        # Current courses tab691        current_courses_tab = ttk.Frame(self.prof_courses_notebook, style='TFrame')692        self.prof_courses_notebook.add(current_courses_tab, text="Current Courses")693 694        # Create a treeview for current courses695        self.current_courses_tree = ttk.Treeview(current_courses_tab, columns=("code", "name", "branch"), show="headings")696        self.current_courses_tree.heading("code", text="Course Code")697        self.current_courses_tree.heading("name", text="Course Name")698        self.current_courses_tree.heading("branch", text="Branch")699 700        self.current_courses_tree.column("code", width=100)701        self.current_courses_tree.column("name", width=250)702        self.current_courses_tree.column("branch", width=150)703 704        self.current_courses_tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)705 706        # Add a scrollbar707        scrollbar = ttk.Scrollbar(current_courses_tab, orient=tk.VERTICAL, command=self.current_courses_tree.yview)708        self.current_courses_tree.configure(yscroll=scrollbar.set)709        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)710 711        # Remove course button712        ttk.Button(current_courses_tab, text="Remove Selected Course",713                  command=self.remove_course_from_selected_professor).pack(fill=tk.X, pady=10)714 715        # Available courses tab716        available_courses_tab = ttk.Frame(self.prof_courses_notebook, style='TFrame')717        self.prof_courses_notebook.add(available_courses_tab, text="Available Courses")718 719        # Create a treeview for available courses720        self.available_courses_tree = ttk.Treeview(available_courses_tab, columns=("code", "name"), show="headings")721        self.available_courses_tree.heading("code", text="Course Code")722        self.available_courses_tree.heading("name", text="Course Name")723 724        self.available_courses_tree.column("code", width=100)725        self.available_courses_tree.column("name", width=300)726 727        self.available_courses_tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)728 729        # Add a scrollbar730        scrollbar = ttk.Scrollbar(available_courses_tab, orient=tk.VERTICAL, command=self.available_courses_tree.yview)731        self.available_courses_tree.configure(yscroll=scrollbar.set)732        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)733 734        # Add course button735        ttk.Button(available_courses_tab, text="Add Selected Course",736                  command=self.add_course_to_selected_professor).pack(fill=tk.X, pady=10)737 738    def setup_professors_frame(self):739        """Set up the professor schedules frame"""740        # Title741        ttk.Label(self.professors_frame, text="Professor Schedules",742                 style='Heading.TLabel').pack(pady=(0, 20))743 744        # Professor selection with improved layout745        select_frame = ttk.Frame(self.professors_frame, style='TFrame')746        select_frame.pack(fill=tk.X, pady=10)747 748        # Create a grid layout for better organization749        select_frame.columnconfigure(0, weight=0)  # Label750        select_frame.columnconfigure(1, weight=1)  # Combobox751        select_frame.columnconfigure(2, weight=0)  # Buttons752 753        # Row 1: Professor selection754        ttk.Label(select_frame, text="Select Professor:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)755        self.professor_var = tk.StringVar()756        self.professor_combo = ttk.Combobox(select_frame, textvariable=self.professor_var, width=30)757        self.professor_combo.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W+tk.E)758 759        # Button frame for row 1760        button_frame = ttk.Frame(select_frame, style='TFrame')761        button_frame.grid(row=0, column=2, padx=5, pady=5, sticky=tk.E)762 763        ttk.Button(button_frame, text="View Schedule",764                  command=self.view_professor_schedule).pack(side=tk.LEFT, padx=2)765        ttk.Button(button_frame, text="Refresh",766                  command=self.refresh_professors).pack(side=tk.LEFT, padx=2)767 768        # Row 2: Export button769        export_frame = ttk.Frame(self.professors_frame, style='TFrame')770        export_frame.pack(fill=tk.X, pady=(0, 10))771 772        ttk.Button(export_frame, text="Export All Schedules to Excel",773                  command=self.export_professor_schedule_to_excel).pack(anchor=tk.E, padx=5)774 775        # Schedule display with improved styling776        schedule_frame = ttk.LabelFrame(self.professors_frame, text="Professor Schedule", style='TFrame')777        schedule_frame.pack(fill=tk.BOTH, expand=True, pady=10)778 779        # Use a monospaced font for better schedule display780        self.professor_text = scrolledtext.ScrolledText(781            schedule_frame,782            wrap=tk.WORD,783            font=('Courier New', 10)784        )785        self.professor_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)786 787        # Initial message with better formatting788        self.professor_text.insert(tk.END,789            "No professor schedules available. Please generate a timetable first using the Generate tab.\n\n"790            "Once a timetable is generated, you can view the schedule for a selected professor."791        )792    793    # Database functions794    def initialize_db(self):795        """Initialize the database with sample data"""796        try:797            initialize_database()798            self.console.insert(tk.END, "Database initialized successfully!\n")799            self.status_var.set("Database initialized")800            self.refresh_branches()801            self.refresh_courses()802            self.refresh_mapping_lists()803            self.refresh_courses_for_classes()804            self.update_stats()805        except Exception as e:806            messagebox.showerror("Error", f"Failed to initialize database: {str(e)}")807            self.console.insert(tk.END, f"Error initializing database: {str(e)}\n")808            self.status_var.set("Database initialization failed")809    810    def update_stats(self):811        """Update the statistics on the home screen"""812        try:813            with sqlite3.connect("timetable.db") as conn:814                cursor = conn.cursor()815                816                # Count branches817                cursor.execute("SELECT COUNT(*) FROM branches")818                branch_count = cursor.fetchone()[0]819                self.branch_count.set(str(branch_count))820                821                # Count courses822                cursor.execute("SELECT COUNT(*) FROM courses")823                course_count = cursor.fetchone()[0]824                self.course_count.set(str(course_count))825                826                # Count teachers827                cursor.execute("SELECT COUNT(*) FROM teachers")828                teacher_count = cursor.fetchone()[0]829                self.teacher_count.set(str(teacher_count))830        except Exception as e:831            print(f"Error updating stats: {str(e)}")832    833    def debug_database(self):834        """Debug the database contents"""835        # Redirect stdout to the database console836        old_stdout = sys.stdout837        sys.stdout = StdoutRedirector(self.db_console)838        839        try:840            # Clear the console first841            self.db_console.delete(1.0, tk.END)842            843            debug_database()844            self.status_var.set("Database debug completed")845        except Exception as e:846            messagebox.showerror("Error", f"Failed to debug database: {str(e)}")847            self.db_console.insert(tk.END, f"Error debugging database: {str(e)}\n")848            self.status_var.set("Database debug failed")849        finally:850            # Restore stdout851            sys.stdout = old_stdout852    853    def verify_database(self):854        """Verify the database integrity"""855        # Redirect stdout to the database console856        old_stdout = sys.stdout857        sys.stdout = StdoutRedirector(self.db_console)858        859        try:860            # Clear the console first861            self.db_console.delete(1.0, tk.END)862            863            result = verify_database_integrity()864            if result:865                self.status_var.set("Database verification passed")866            else:867                self.status_var.set("Database verification failed")868        except Exception as e:869            messagebox.showerror("Error", f"Failed to verify database: {str(e)}")870            self.db_console.insert(tk.END, f"Error verifying database: {str(e)}\n")871            self.status_var.set("Database verification failed")872        finally:873            # Restore stdout874            sys.stdout = old_stdout875    876    def refresh_branches(self):877        """Refresh the branch comboboxes"""878        try:879            with sqlite3.connect("timetable.db") as conn:880                cursor = conn.cursor()881                cursor.execute("SELECT branch_name FROM branches ORDER BY branch_name")882                branches = [branch[0] for branch in cursor.fetchall()]883                884                # Update all branch comboboxes885                self.prof_branch_combo['values'] = branches886                self.course_branch_combo['values'] = branches887                self.mapping_branch_combo['values'] = branches888                889                if branches:890                    self.prof_branch_combo.current(0)891                    self.course_branch_combo.current(0)892                    self.mapping_branch_combo.current(0)893        except Exception as e:894            messagebox.showerror("Error", f"Failed to refresh branches: {str(e)}")895    896    def add_branch(self):897        """Add a new branch to the database"""898        branch_name = self.branch_name_var.get().strip()899        if not branch_name:900            messagebox.showerror("Error", "Branch name cannot be empty")901            return902        903        try:904            # Redirect stdout to the database console905            old_stdout = sys.stdout906            sys.stdout = StdoutRedirector(self.db_console)907            908            add_branch(branch_name)909            self.branch_name_var.set("")  # Clear the entry910            self.refresh_branches()911            self.update_stats()912            self.status_var.set(f"Branch '{branch_name}' added")913        except Exception as e:914            messagebox.showerror("Error", f"Failed to add branch: {str(e)}")915            self.db_console.insert(tk.END, f"Error adding branch: {str(e)}\n")916        finally:917            # Restore stdout918            sys.stdout = old_stdout919    920    def add_professor(self):921        """Add a new professor to the database"""922        prof_name = self.prof_name_var.get().strip()923        branch_name = self.prof_branch_var.get()924        925        if not prof_name:926            messagebox.showerror("Error", "Professor name cannot be empty")927            return928        929        if not branch_name:930            messagebox.showerror("Error", "Please select a branch")931            return932        933        try:934            # Redirect stdout to the database console935            old_stdout = sys.stdout936            sys.stdout = StdoutRedirector(self.db_console)937            938            add_professor(prof_name, branch_name)939            self.prof_name_var.set("")  # Clear the entry940            self.update_stats()941            self.status_var.set(f"Professor '{prof_name}' added")942            self.refresh_mapping_lists()943        except Exception as e:944            messagebox.showerror("Error", f"Failed to add professor: {str(e)}")945            self.db_console.insert(tk.END, f"Error adding professor: {str(e)}\n")946        finally:947            # Restore stdout948            sys.stdout = old_stdout949    950    # Course management functions951    def add_course(self):952        """Add a new course to the database"""953        course_code = self.course_code_var.get().strip().upper()954        course_name = self.course_name_var.get().strip()955        branch_name = self.course_branch_var.get()956        957        if not course_code or not course_name:958            messagebox.showerror("Error", "Course code and name cannot be empty")959            return960        961        if not branch_name:962            messagebox.showerror("Error", "Please select a branch")963            return964        965        try:966            # Redirect stdout to the course console967            old_stdout = sys.stdout968            sys.stdout = StdoutRedirector(self.course_console)969            970            # Add course with branch971            with sqlite3.connect("timetable.db") as conn:972                cursor = conn.cursor()973                cursor.execute(974                    "INSERT INTO courses (course_code, course_name, branch_name) VALUES (?, ?, ?)",975                    (course_code, course_name, branch_name)976                )977                978                # Initialize course_classes with default value (2 classes per week)979                cursor.execute(980                    "INSERT INTO course_classes (course_code, num_classes) VALUES (?, ?)",981                    (course_code, 2)982                )983                984                conn.commit()985                self.course_console.insert(tk.END, f"โœ… Course '{course_code}' added successfully!\n")986            987            self.course_code_var.set("")  # Clear the entries988            self.course_name_var.set("")989            self.update_stats()990            self.status_var.set(f"Course '{course_code}' added")991            self.refresh_courses()992            self.refresh_mapping_lists()993        except Exception as e:994            messagebox.showerror("Error", f"Failed to add course: {str(e)}")995            self.course_console.insert(tk.END, f"Error adding course: {str(e)}\n")996        finally:997            # Restore stdout998            sys.stdout = old_stdout999    1000    def refresh_courses(self):1001        """Refresh the course comboboxes"""1002        try:1003            with sqlite3.connect("timetable.db") as conn:1004                cursor = conn.cursor()1005                cursor.execute("SELECT course_code, course_name FROM courses ORDER BY course_code")1006                courses = cursor.fetchall()1007                1008                # Format courses for display1009                course_display = [f"{code}: {name}" for code, name in courses]1010                1011                # Update course comboboxes1012                self.delete_course_combo['values'] = course_display1013                self.mapping_course_combo['values'] = course_display1014                1015                if course_display:1016                    self.delete_course_combo.current(0)1017                    self.mapping_course_combo.current(0)1018        except Exception as e:1019            messagebox.showerror("Error", f"Failed to refresh courses: {str(e)}")1020    1021    def refresh_mapping_lists(self):1022        """Refresh all lists for the mapping tab"""1023        try:1024            # Refresh branches1025            self.refresh_branches()1026            1027            # Refresh courses1028            self.refresh_courses()1029            1030            # Refresh teachers1031            with sqlite3.connect("timetable.db") as conn:1032                cursor = conn.cursor()1033                cursor.execute("SELECT teacher_name FROM teachers ORDER BY teacher_name")1034                teachers = [teacher[0] for teacher in cursor.fetchall()]1035                1036                self.mapping_teacher_combo['values'] = teachers1037                1038                if teachers:1039                    self.mapping_teacher_combo.current(0)1040        except Exception as e:1041            messagebox.showerror("Error", f"Failed to refresh mapping lists: {str(e)}")1042    1043    def add_mapping(self):1044        """Add a branch-teacher-course mapping"""1045        branch_name = self.mapping_branch_var.get()1046        teacher_name = self.mapping_teacher_var.get()1047        course_full = self.mapping_course_var.get()1048        1049        if not branch_name or not teacher_name or not course_full:1050            messagebox.showerror("Error", "Please select branch, teacher, and course")1051            return1052        1053        # Extract course code from the display string (e.g., "CS101: Introduction to Programming")1054        course_code = course_full.split(":")[0].strip()1055        1056        try:1057            # Redirect stdout to the course console1058            old_stdout = sys.stdout1059            sys.stdout = StdoutRedirector(self.course_console)1060            1061            add_branch_teacher_course_mapping(branch_name, teacher_name, course_code)1062            self.status_var.set(f"Mapping added for {course_code}")1063        except Exception as e:1064            messagebox.showerror("Error", f"Failed to add mapping: {str(e)}")1065            self.course_console.insert(tk.END, f"Error adding mapping: {str(e)}\n")1066        finally:1067            # Restore stdout1068            sys.stdout = old_stdout1069    1070    def delete_course(self):1071        """Delete a course from the database"""1072        course_full = self.delete_course_var.get()1073        1074        if not course_full:1075            messagebox.showerror("Error", "Please select a course to delete")1076            return1077        1078        # Extract course code from the display string1079        course_code = course_full.split(":")[0].strip()1080        1081        # Confirm deletion1082        confirm = messagebox.askyesno("Confirm Deletion", 1083                                     f"Are you sure you want to delete course '{course_code}'?\n"1084                                     "This will also delete all mappings for this course.")1085        if not confirm:1086            return1087        1088        try:1089            # Redirect stdout to the course console1090            old_stdout = sys.stdout1091            sys.stdout = StdoutRedirector(self.course_console)1092            1093            delete_course(course_code)1094            self.update_stats()1095            self.status_var.set(f"Course '{course_code}' deleted")1096            self.refresh_courses()1097        except Exception as e:1098            messagebox.showerror("Error", f"Failed to delete course: {str(e)}")1099            self.course_console.insert(tk.END, f"Error deleting course: {str(e)}\n")1100        finally:1101            # Restore stdout1102            sys.stdout = old_stdout1103    1104    # Timetable generation functions1105    def generate_timetable(self):1106        """Generate a timetable using the genetic algorithm"""1107        # Verify database integrity first1108        try:1109            if not verify_database_integrity():1110                messagebox.showerror("Error", "Database integrity check failed. Please fix the issues before generating a timetable.")1111                return1112        except Exception as e:1113            messagebox.showerror("Error", f"Failed to verify database: {str(e)}")1114            return1115 1116        # Get branches1117        try:1118            with sqlite3.connect("timetable.db") as conn:1119                cursor = conn.cursor()1120                cursor.execute("SELECT branch_name FROM branches")1121                branches = [branch[0] for branch in cursor.fetchall()]1122 1123                if not branches:1124                    messagebox.showerror("Error", "No branches found. Please add branches first.")1125                    return1126        except Exception as e:1127            messagebox.showerror("Error", f"Failed to get branches: {str(e)}")1128            return1129 1130        # Get generations1131        try:1132            generations = int(self.generations_var.get())1133            if generations < 30:1134                messagebox.showerror("Error", "Generations must be at least 30")1135                return1136            # Limit to 200 for better performance1137            if generations > 200:1138                if not messagebox.askyesno("Warning", "Using more than 200 generations may cause the application to become unresponsive. Continue anyway?"):1139                    generations = 2001140                    self.generations_var.set("200")1141        except ValueError:1142            messagebox.showerror("Error", "Please enter a valid number for generations")1143            return1144 1145        # Show progress dialog1146        progress_window = tk.Toplevel(self.root)1147        progress_window.title("Generating Timetable")1148        progress_window.geometry("400x150")1149        progress_window.transient(self.root)1150        progress_window.grab_set()1151 1152        ttk.Label(progress_window, text="Generating timetable...", font=("Arial", 12)).pack(pady=10)1153        progress = ttk.Progressbar(progress_window, mode="indeterminate")1154        progress.pack(fill=tk.X, padx=20, pady=10)1155        progress.start()1156 1157        status_var = tk.StringVar(value="Starting genetic algorithm...")1158        ttk.Label(progress_window, textvariable=status_var).pack(pady=10)1159 1160        # Update the progress variable1161        self.progress_var.set("Generating...")1162 1163        # Function to run in a separate thread1164        def generate():1165            try:1166                # Update status in the progress window1167                def update_status(msg):1168                    self.root.after(0, lambda: status_var.set(msg))1169                    self.root.after(0, lambda: self.progress_var.set(msg))1170 1171                # Update status to show progress1172                update_status("Initializing genetic algorithm...")1173 1174                # Generate timetable using the genetic algorithm1175                # Suppress verbose output by setting verbose=False1176                result = genetic_algorithm(branches=branches, generations=generations, verbose=False)1177 1178                # Update status to show completion1179                update_status("Timetable generation complete!")1180 1181                if result:1182                    schedule, professor_schedules = result1183                    # Store for later access1184                    self.last_timetable = schedule1185                    self.last_professor_schedules = professor_schedules1186 1187                    # Display timetable1188                    timetable_output = io.StringIO()1189                    print_timetable(schedule, file=timetable_output)1190                    timetable_text = timetable_output.getvalue()1191 1192                    # Update UI in the main thread1193                    self.root.after(0, lambda: self.update_timetable_display(timetable_text))1194                    self.root.after(0, lambda: self.refresh_professors())1195                    self.root.after(0, lambda: self.status_var.set("Timetable generated successfully"))1196                    self.root.after(0, lambda: self.progress_var.set("Completed"))1197                    self.root.after(0, lambda: progress_window.destroy())1198                else:1199                    self.root.after(0, lambda: messagebox.showerror("Error", "Failed to generate a valid timetable."))1200                    self.root.after(0, lambda: self.progress_var.set("Failed"))

Showing the first 1,200 of 1790 lines. Download the file for the rest.