Advertisement
TorroesPrime

handout updater 2

Apr 13th, 2023
849
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 17.63 KB | None | 0 0
  1. """interface for updating handout data file for Germanna ACE.
  2. Author: Michael G. Cividanes
  3. Date: 2023-04-10
  4. """
  5. from functools import partial
  6. import tkinter
  7. from tkinter import messagebox
  8. from tkinter import ttk
  9. from tkinter import filedialog as fd
  10. import os
  11. import json
  12. import requests
  13. import ace_exceptions as ace
  14. from settings import HEIGHT_,WIDTH_,CUR_DIR,ICON,DEBUG,DEF_CLASS_LIST,BACKGROUND_COLOR,\
  15. FOREGROUND_COLOR,TITLE_FONT,ENTRY_FONT,FULL_WIDTH,H_PAD,V_PAD,HIGHLIGHT_COLOR,BORDER_SIZE,\
  16. H_PAD_SMALL,V_PAD_SMALL,WHITE_,DB_FORGROUND_COLOR,DB_BACKGROUND_COLOR,DB_HIGHLIGHT_COLOR,\
  17. DB_BUTTON_BG_COLOR,SRC_FILE, SMALL_FONT
  18. from handouts import handout
  19.  
  20. if DEBUG:
  21.     HEIGHT_ += 100
  22. class handoutData:
  23.     """data object for handout updater program."""
  24.     def __init__(self,filename):
  25.         self.handout_title = ""
  26.         self.handout_url = ""
  27.         self.selected_classes = []
  28.         self.description = ""
  29.         self.issues = []
  30.         self.cur_data = []
  31.         self.read_data(filename)
  32.         self.cur_classes = self.get_classes()
  33.     def read_data(self,filename):
  34.         """read data from file"""
  35.         with open(filename,"r") as file:
  36.             cur_data = json.load(file)
  37.             for entry in cur_data:
  38.                 self.cur_data.append(handout(entry["name"],entry["url"],\
  39. entry["classes"],entry["description"],entry["issues"]))
  40.     def write_data(self):
  41.         """write data to file"""
  42.         with open(SRC_FILE,"w") as file:
  43.             json.dump(self.cur_data,file,indent=4)
  44.     def set_info(self,gen_info,selected_classes,description,issues):
  45.         """set handout information"""
  46.         self.handout_title = gen_info[0]
  47.         self.handout_url = gen_info[1]
  48.         self.selected_classes = selected_classes
  49.         self.description = description
  50.         self.issues = issues
  51.     def add_handout(self):
  52.         """add handout to data"""
  53.         self.cur_data.append(handout(self.handout_title,self.handout_url,self.selected_classes,\
  54. self.description,self.issues))
  55.         self.handout_title = ""
  56.         self.handout_url = ""
  57.         self.description =  ""
  58.         self.issues=[]
  59.     def get_classes(self):
  60.         """get list of classes"""
  61.         class_list = []
  62.         for entry in self.cur_data:
  63.             for cls in entry.classes:
  64.                 if cls not in class_list:
  65.                     class_list.append(cls)
  66.         return class_list
  67.     def get_info(self):
  68.         """get handout information"""
  69.         return self.handout_title,self.handout_url,self.selected_classes,self.description,self.issues
  70. class general_frame_gui():
  71.     def __init__(self,parent):
  72.         """GUI for general information"""
  73.         frame = tkinter.Frame(parent)
  74.         tkinter.Label(frame,text="Handout Title:",font=TITLE_FONT).grid(row=0,column=0,sticky="w",columnspan=2)
  75.         self.in_handout_name = tkinter.Entry(frame,font=ENTRY_FONT,width=90)
  76.         self.in_handout_name.grid(row=0,column=2,columnspan=10,sticky="we")
  77.         tkinter.Label(frame,text="Handout URL:",font=TITLE_FONT).grid(row=1,column=0,sticky="w",columnspan=2)
  78.         self.in_handout_url = tkinter.Entry(frame,font=ENTRY_FONT)
  79.         self.in_handout_url.grid(row=1,column=2,columnspan=10,sticky="we")
  80.         frame.grid(row=0,column=0,sticky="we",columnspan=12,padx=H_PAD,pady=V_PAD)
  81.     def check_handout_name(self):
  82.         """checks that the handout name is long enough"""
  83.         handout_title = self.in_handout_name.get()
  84.         if len(handout_title) > 10:
  85.             print("Handout name is long enough")
  86.             return True
  87.         else:
  88.             tkinter.messagebox.showinfo("Handout title too short", "Handout title is too short to be a valid title. Did you type it correctly and in the correct place?")
  89.             return False
  90.     def check_handout_url(self):
  91.         """checks that the url is long enough to be valid"""
  92.         url_value = self.in_handout_url.get()
  93.         if len(url_value) > 15:
  94.             try:
  95.                 if requests.get(url_value).status_code == 200:
  96.                     return True
  97.                 else:
  98.                     messagebox.showerror("Error","There is no response from the URL. This can be caused by a mistyped URL.")
  99.             except:
  100.                 messagebox.showerror("Error","There is no response from the URL. This can be caused by a mistyped URL.")
  101.                 return False
  102.         else:
  103.             messagebox.showerror("Error","Handout url is too short. Did you mis-type it?")
  104.             return False
  105.     def get_info(self):
  106.         """get handout information"""
  107.         if self.check_handout_name():
  108.             if self.check_handout_url():
  109.                 return self.in_handout_name.get(),self.in_handout_url.get()
  110.             else:
  111.                 return False
  112.         else:
  113.             return False
  114.     def clear_input(self):
  115.         """clear input fields"""
  116.         self.in_handout_name.delete(0,"end")
  117.         self.in_handout_url.delete(0,"end")
  118. class class_selector_gui():
  119.     def __init__(self,parent,cur_data):
  120.         """GUI for class selection frame"""
  121.         frame = tkinter.Frame(parent,bg=BACKGROUND_COLOR,highlightbackground=HIGHLIGHT_COLOR,\
  122. highlightthickness=BORDER_SIZE)
  123.         frame.grid(row=1,column=0,sticky="we",columnspan=12,padx=H_PAD,pady=V_PAD)
  124.         self.selected_classes = []
  125.         self.class_chx_boxes = []
  126.         tkinter.Label(frame,text="Select Classes:",font=TITLE_FONT,bg=BACKGROUND_COLOR).grid(row=0,column=0,sticky="we",\
  127. columnspan=12,padx=H_PAD,pady=V_PAD)
  128.         list_of_classes = ""
  129.         if len(cur_data.cur_classes) > len(DEF_CLASS_LIST):
  130.             list_of_classes = cur_data.cur_classes
  131.         else:
  132.             list_of_classes = DEF_CLASS_LIST
  133.         for cls in list_of_classes:
  134.             temp_check_box = tkinter.Checkbutton(frame,text=cls,bg=BACKGROUND_COLOR,\
  135. fg=FOREGROUND_COLOR,font=SMALL_FONT,command = partial(self.add_class,cls))
  136.             self.class_chx_boxes.append(temp_check_box)
  137.         row = 1
  138.         col = 0
  139.         for i in range(len(self.class_chx_boxes)):
  140.             if row > 10:
  141.                 row = 1
  142.                 col += 1
  143.             self.class_chx_boxes[i].grid(row=row,column=col,sticky="w",padx=H_PAD_SMALL,pady=V_PAD_SMALL)
  144.             row += 1
  145.     def add_class(self,cls):
  146.         """add class to selected classes"""
  147.         if cls not in self.selected_classes:
  148.             self.selected_classes.append(cls)
  149.         else:
  150.             self.selected_classes.remove(cls)
  151.     def get_info(self):
  152.         """get selected classes"""
  153.         if len(self.selected_classes) == 0:
  154.             tkinter.messagebox.showinfo("No classes selected", "No classes were selected. Please select at least one class.")
  155.             return False
  156.         else:
  157.             return self.selected_classes
  158.     def clear_input(self):
  159.         """clear input"""
  160.         for box in self.class_chx_boxes:
  161.             box.deselect()
  162.         self.selected_classes = []
  163. class description_frame_gui():
  164.     def __init__(self,parent):
  165.         """GUI for description frame"""
  166.         frame = tkinter.Frame(parent,bg=BACKGROUND_COLOR,highlightbackground=HIGHLIGHT_COLOR,\
  167. highlightthickness=BORDER_SIZE)
  168.         frame.grid(row=2,column=0,sticky="we",columnspan=6,padx=H_PAD,pady=V_PAD,ipady=V_PAD)
  169.         tkinter.Label(frame,text="Description:",font=TITLE_FONT,bg=BACKGROUND_COLOR).grid(row=0,column=0,sticky="we",columnspan=6,padx=H_PAD,pady=V_PAD)
  170.         self.in_description = tkinter.Text(frame,font=ENTRY_FONT,height=14,width=50)
  171.         self.in_description.grid(row=1,column=0,sticky="w",columnspan=6,padx=H_PAD_SMALL,pady=V_PAD_SMALL)
  172.     def get_info(self):
  173.         """get description"""
  174.         description = self.in_description.get("1.0","end-1c")
  175.         if len(description) > 125:
  176.             if len(description.split())>19 and len(description.split())<49:
  177.                 return description
  178.             else:
  179.                 if len(description.split())>=49:
  180.                     answer = tkinter.messagebox.askyesno("Description Length", "That description is quite long. Generally we want the handout descriptions to be between 20 and 50 words. Are you sure you want to enter this description?")
  181.                     print("answer:",answer)
  182.                     if answer:
  183.                         print("description:",description)
  184.                         return description              
  185.                     else:
  186.                         return False
  187.                 else:
  188.                     pass
  189.                 if len(description.split())<=19:
  190.                     tkinter.messagebox.showinfo("Description too short", "Description is too short. It should be between 20 and 50 words.")
  191.                     return False
  192.                    
  193.     def clear_input(self):
  194.         """clear description"""
  195.         self.in_description.delete("1.0","end")
  196. class issues_frame_gui():
  197.     def __init__(self,parent):
  198.         """GUI for issues frame"""
  199.         frame = tkinter.Frame(parent,bg=BACKGROUND_COLOR,highlightbackground=HIGHLIGHT_COLOR,\
  200. highlightthickness=BORDER_SIZE)
  201.         frame.grid(row=2,column=6,sticky="e",columnspan=6,padx=H_PAD,pady=V_PAD)
  202.         tkinter.Label(frame,text="Issues this handout is meant to address:",font=TITLE_FONT,bg=BACKGROUND_COLOR).grid(row=0,column=0,sticky="w",columnspan=6,padx=H_PAD,pady=V_PAD)
  203.         tkinter.Label(frame,text="Current issues:",font=SMALL_FONT,bg=BACKGROUND_COLOR).grid(row=1,column=0,sticky="w",columnspan=6,padx=H_PAD_SMALL,pady=V_PAD_SMALL)
  204.         self.in_issues = tkinter.Text(frame,font=ENTRY_FONT,height=10,width=50,state="disabled")
  205.         self.in_issues.grid(row=2,column=0,sticky="w",columnspan=6,padx=H_PAD,pady=V_PAD)
  206.         self.issues_entry = tkinter.Entry(frame,font=ENTRY_FONT)
  207.         self.issues_entry.grid(row=3,column=0,sticky="w",columnspan=4,padx=H_PAD,pady=V_PAD)
  208.         self.issues_entry.bind("<Return>",lambda event: self.add_issue())
  209.         tkinter.Button(frame,text="Add Issue",font=ENTRY_FONT,command=self.add_issue).grid(row=3,column=4,sticky="w",columnspan=2,padx=H_PAD,pady=V_PAD)
  210.     def add_issue(self):
  211.         """add issue to issues"""
  212.         self.in_issues.config(state="normal")
  213.         self.in_issues.insert(tkinter.END,"✏  "+self.issues_entry.get())
  214.         self.issues_entry.delete(0,"end")
  215.         self.in_issues.config(state="disabled")
  216.     def get_info(self):
  217.         """get issues"""
  218.         issues = self.in_issues.get("1.0","end-1c").split("✏  ")
  219.         for item in issues:
  220.             if item == "":
  221.                 issues.remove(item)
  222.         if len(issues) == 0:
  223.             tkinter.messagebox.showinfo("No issues", "No issues were added. Please add at least one issue.")
  224.             return False
  225.         else:
  226.             return issues
  227.     def clear_input(self):
  228.         """clear input"""
  229.         self.issues_entry.delete(0,"end")
  230.         self.in_issues.config(state="normal")
  231.         self.in_issues.delete("1.0","end")
  232.         self.in_issues.config(state="disabled")
  233.     def clear_data(self):
  234.         self.in_issues.delete(0,"end")
  235.         self.issues_entry.delete(0,"end")
  236.  
  237. class debug_gui():
  238.     def __init__(self,parent,cd,gi,sl,hd,hi):
  239.         """GUI for debug frame"""
  240.         self.cur_data= cd
  241.         self.gen_info = gi
  242.         self.select_classes = sl
  243.         self.description = hd
  244.         self.issues = hi
  245.         frame = tkinter.Frame(parent,bg=DB_BACKGROUND_COLOR,highlightbackground=HIGHLIGHT_COLOR,\
  246. highlightthickness=BORDER_SIZE)
  247.         frame.grid(row=4,column=0,sticky="we",columnspan=12,padx=H_PAD,pady=V_PAD)
  248.         tkinter.Label(frame,text="Debug menu:",font=TITLE_FONT,bg=BACKGROUND_COLOR).grid(row=0,column=0,sticky="we",columnspan=12,padx=H_PAD,pady=V_PAD)
  249.         tkinter.Button(frame,text="Print data",font=ENTRY_FONT,command=self.print_data).grid(row=1,column=0,sticky="w",columnspan=2,padx=H_PAD,pady=V_PAD)
  250.         tkinter.Button(frame,text="Check data",font=ENTRY_FONT,command=self.check_data).grid(row=1,column=2,sticky="w",columnspan=2,padx=H_PAD,pady=V_PAD)
  251.         tkinter.Button(frame,text="Clear data",font=ENTRY_FONT,command=self.clear_data).grid(row=1,column=4,sticky="w",columnspan=2,padx=H_PAD,pady=V_PAD)
  252.         tkinter.Button(frame,text="Check Handouts",font=ENTRY_FONT,command=self.check_handouts).grid(row=1,column=6,sticky="w",columnspan=2,padx=H_PAD,pady=V_PAD)
  253.         tkinter.Button(frame,text="Check Classes",font=ENTRY_FONT,command=self.check_classes).grid(row=1,column=8,sticky="w",columnspan=2,padx=H_PAD,pady=V_PAD)
  254.         tkinter.Button(frame,text="Check Issues",font=ENTRY_FONT,command=self.check_issues).grid(row=1,column=10,sticky="w",columnspan=2,padx=H_PAD,pady=V_PAD)
  255.         tkinter.Button(frame,text="Check URL",font=ENTRY_FONT,command=self.check_url).grid(row=1,column=12,sticky="w",columnspan=2,padx=H_PAD,pady=V_PAD)
  256.     def check_url(self):
  257.         """check url"""
  258.         print("Checking url...")
  259.         if self.gen_info.in_handout_url.get() == "":
  260.             print("url is empty!")
  261.         else:
  262.             print("url is good!")
  263.     def check_issues(self):
  264.         """check issues"""
  265.         print("Checking issues...")
  266.         if self.issues.get_info() == []:
  267.             print("No issues!")
  268.         else:
  269.             print("Issues are good!")
  270.     def check_classes(self):
  271.         """check classes"""
  272.         print("Checking classes...")
  273.         if self.select_classes.get_classes() == []:
  274.             print("No classes!")
  275.         else:
  276.             print("Classes are good!")
  277.     def check_handouts(self):
  278.         """check handouts"""
  279.         print("Checking handouts...")
  280.         for handout in self.cur_data.cur_data:
  281.             print("Checking handout:",handout.name)
  282.             if handout.name == "":
  283.                 print("Handout has no name!")
  284.             if handout.url == "":
  285.                 print("Handout has no url!")
  286.             if handout.classes == []:
  287.                 print("Handout has no classes!")
  288.             if handout.description == "":
  289.                 print("Handout has no description!")
  290.             if handout.issues == []:
  291.                 print("Handout has no issues!")
  292.             print(f"the handout \"{handout.name}\" is good!")
  293.    
  294.     def clear_data(self):
  295.         """clear data"""
  296.         self.gen_info.clear_input()
  297.         self.select_classes.clear_input()
  298.         self.description.clear_input()
  299.         self.issues.clear_input()
  300.     def check_data(self):
  301.         """check data for errors"""
  302.         print("There are currently "+str(len(self.cur_data.cur_data))+" handouts in the data file.")
  303.     def print_data(self):
  304.         """print data to console"""
  305.         print("Curent data:",self.cur_data.get_info())
  306.         print("general info:",self.gen_info.get_info())
  307.         print("Selected Classes:",self.select_classes.get_info())
  308.         print("Description:",self.description.get_info())
  309.         print("Issues:",self.issues.get_info())
  310. class HandoutUpdater:
  311.     """main GUI class"""
  312.     def __init__(self):
  313.         self.cur_data = handoutData(os.path.join(CUR_DIR,SRC_FILE))
  314.         self.main_window = tkinter.Tk()
  315.         self.main_window.geometry(f"{WIDTH_}x{HEIGHT_}")
  316.         self.main_window.resizable(False,True)
  317.         self.main_window.bind("<Configure>",lambda event:self.print_size(event))
  318.         self.main_window.title("Germanna ACE Handout Updater")
  319.         self.main_window.iconbitmap(os.path.join(CUR_DIR,ICON))
  320.         self.general_info_frame = general_frame_gui(self.main_window)
  321.         self.class_selector_frame = class_selector_gui(self.main_window,self.cur_data)
  322.         self.description_frame = description_frame_gui(self.main_window)
  323.         self.issues_frame = issues_frame_gui(self.main_window)
  324.         tkinter.Button(self.main_window,text="Update Source",command=self.update_source).grid(row=3,column=0,sticky="w",columnspan=3,padx=H_PAD,pady=V_PAD)
  325.         tkinter.Button(self.main_window,text="Add Handout",command=self.add_handout).grid(row=3,column=10,sticky="e",columnspan=3,padx=H_PAD,pady=V_PAD)
  326.         self.debug = None
  327.         if DEBUG:
  328.             self.debug = debug_gui(self.main_window,self.cur_data,self.general_info_frame,self.class_selector_frame,\
  329.                                    self.description_frame,self.issues_frame)
  330.         self.main_window.mainloop()
  331.     def update_source(self):
  332.         """update source file"""
  333.         filename = fd.askopenfilename(initialdir=CUR_DIR,title="Select file",filetypes=(("Germanna ACE DATA","*.gad"),("all files","*.*")))
  334.         self.cur_data.read_data(filename)
  335.     def check_content(self):
  336.         """checks that the content is acceptable"""
  337.         content_check = []
  338.         content_check.append(self.general_info_frame.get_info())
  339.         content_check.append(self.class_selector_frame.get_info())
  340.         content_check.append(self.description_frame.get_info()[1])
  341.         content_check.append(self.issues_frame.get_info())
  342.         if False in content_check:
  343.             return False
  344.         else:
  345.             return True, content_check
  346.        
  347.     def add_handout(self):
  348.         """add handout to source file"""
  349.         content = self.check_content()
  350.         print("content:",content)
  351.         if content[0]:
  352.             self.cur_data.set_info(content[1][0],content[1][1],content[1][2],content[1][3])
  353.             self.cur_data.add_handout()
  354.             #self.general_info_frame.clear_input()
  355.             #self.class_selector_frame.clear_input()
  356.             #self.description_frame.clear_input()
  357.             #self.issues_frame.clear_input()
  358.             #self.cur_data.write_data()
  359.  
  360.        
  361.     def print_size(self,event):
  362.         """print size of window"""
  363.         print(self.main_window.winfo_width(),"x",self.main_window.winfo_height())
  364. if __name__ == "__main__":
  365.     HandoutUpdater()
  366.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement