Advertisement
Guest User

Untitled

a guest
Mar 29th, 2019
187
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 73.80 KB | None | 0 0
  1. import tkinter
  2. # python gui toolkit
  3. # used to create windows and GUIs
  4.  
  5. import ctypes
  6. # used to interact C and dll files with python
  7. # used in my program to access windows SystemMetrics to retrieve screen size
  8.  
  9. import socket
  10. # python network connections module
  11. # allows network connections in python so the client and server can communicate
  12.  
  13. import json
  14. # this is the python JSON module
  15. # it allows python to convert string and data structures to and from JSON
  16.  
  17. import re
  18. # the python regular expressions module
  19. # allows the program to check whether
  20. # certain characters are used in entry boxes
  21.  
  22. import time
  23. # python module used to track and use time
  24. # used in program to add delays to some functions
  25.  
  26. import math
  27. # python mathematics module
  28. # used in program to round numbers up to next integer
  29.  
  30. import datetime
  31. # python module to retrieve date and time
  32. # used in program to retrieve current date to create new uniform event
  33.  
  34. from tkinter import messagebox
  35. from tkinter import ttk
  36. # these are subclasses of the GUI toolkit that need to be imported separately
  37. # tkinter.messagebox is allows the code to create pop-up messageboxes
  38. # that provide the user with information
  39. # tkinter.ttk allows the code to create native-style widgets in the GUI
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47. user32 = ctypes.windll.user32
  48. screensize = user32.GetSystemMetrics(0),user32.GetSystemMetrics(1)
  49. # detecting screen size to place window correctly
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59. #setting ttk styles
  60. def quicksort(data):
  61.    
  62.     less = []
  63.     # creates array for the values less than the pivot
  64.     equal = []
  65.     # creates array for values equal to the pivot
  66.     greater = []
  67.     # creates array for values greater than the pivot
  68.     if len(data) > 1:
  69.         pivot = data[0]
  70.         # selects first value of the array as a pivot
  71.         for i in data:
  72.             if i < pivot:
  73.                 less.append(i)
  74.                 # append any items less than the pivot to a less array
  75.             elif i == pivot:
  76.                 equal.append(i)
  77.                 # append any items greater than the pivot to an equal array
  78.             elif i > pivot:
  79.                 greater.append(i)
  80.                 # append any items greater than the pivot
  81.         return quicksort(less)+equal+quicksort(greater)
  82.         # runs recursively as allows for greater efficiency
  83.     else:  
  84.         return data
  85.  
  86.  
  87.  
  88.  
  89.  
  90.  
  91.  
  92.    
  93. class SquadBot(tkinter.Tk):
  94.     palette = {"bgblue":"#5d8aa8","white":"#ffffff","darkblue":"#366192",
  95.                "afb":"#4b7da0"}
  96.     def __init__(self):
  97.         tkinter.Tk.__init__(self)
  98.         self.withdraw()
  99.         self.pkey = "18657"
  100.         self.userlvl = tkinter.IntVar()
  101.         self.userlvl.set(1)
  102.         self.userid = tkinter.IntVar()
  103.         self.userid.set(0)
  104.         self.fullname = None
  105.         self.welcomemessage = tkinter.StringVar()
  106.         # <nf>
  107.        
  108.         self.container = tkinter.Frame(self)
  109.         self.container.pack(side="top",fill="both",expand=True)
  110.         self.container.grid_rowconfigure(0,weight=1)
  111.         self.container.grid_columnconfigure(0,weight=1)
  112.         # creating container for the window
  113.        
  114.        
  115.         # setting dictionaries to keep design constant
  116.        
  117.         self.geometry("700x500+%d+%d"%(screensize[0]/2-400,screensize[1]/2-300))
  118.         self.resizable(0,0)
  119.         # setting location on screen
  120.        
  121.         self.pages = {} # dictionary of pages
  122.         page = LoginPage(self.container,self)
  123.         # instantiating class of page
  124.        
  125.         self.pages[LoginPage] = page
  126.         # adding instance to dictionary
  127.        
  128.         page.grid(row=0,column=0,sticky="nsew")
  129.         # placing instance in window
  130.        
  131.        
  132.         self.title("SquadBot")  # setting title of window
  133.         self.tk.call('wm', 'iconbitmap', self._w, "resources/crest.ico")
  134.         #changing icon of all windows to crest
  135.         self.protocol("WM_DELETE_WINDOW",self.checkClosing)
  136.         # setting protocol of closing window to run custom function
  137.         self.configure(bg = self.palette["bgblue"])
  138.         # setting background of page to 'bgblue'
  139.         ttk.Style().configure("TButton", relief="flat",background="#72a0c1")
  140.         # setting style of a ttk button
  141.         self.serverConnect(socket.gethostname())    # connect to server
  142.        
  143.         page = LoginPage(self.container,self)         # repeated same as above
  144.         self.pages[LoginPage] = page
  145.         page.grid(row=0,column=0,sticky="nsew")
  146.        
  147.         # instantiating pages for window
  148.        
  149.        
  150.         self.deiconify()
  151.     def showPage(self,slide,old):
  152.         page = slide(self.container,self)
  153.         self.pages = {}
  154.         self.pages[slide] = page
  155.         page.grid(row=0,column=0,sticky="nsew")
  156.         page = self.pages[slide]
  157.         page.tkraise()
  158.         old.grid_forget(self)
  159.     # function shows page given in argument
  160.        
  161.     def checkClosing(self):
  162.         closing = messagebox.askquestion("Quit","Are you sure you want to quit?")
  163.         # message pop-up
  164.         if closing == "yes":
  165.             self.conn.close()
  166.             self.destroy()
  167.             #quit(0)
  168.     # function checks whether the user actually wants to leave program
  169.  
  170.    
  171.     def createImages(self): # this is a separate function, as creating images
  172.                             # requires the tkinter runtime to be running, which
  173.                             # allows the subclasses to inherit the function and
  174.                             # store their own image dictionaries
  175.         self.images = {"bigcrest":tkinter.PhotoImage(file="resources/crest_wo_background_large.png"),
  176.                        "smallcrest":tkinter.PhotoImage(file="resources/crest_wo_background_small.png"),
  177.                        "quit":tkinter.PhotoImage(file="resources/exiticon2.png"),
  178.                        "hide":tkinter.PhotoImage(file="resources/hideicon.png"),
  179.                        "mute":tkinter.PhotoImage(file="resources/muteicon.png"),
  180.                        "support":tkinter.PhotoImage(file="resources/supporticon.png")}
  181.  
  182.        
  183.     def serverConnect(self,ip):
  184.         try:
  185.             self.conn = socket.socket(socket.AF_INET,socket.SOCK_STREAM)    # creating socket
  186.             self.conn.connect((ip,8881))    # connecting to correct port
  187.             data = self.conn.recv(1024)     # receving data from server
  188.             if data == "Handshake started, authenticate".encode():  # ensuring it is correct program to connect to
  189.                 self.conn.sendall("Handshake accepted".encode())    # accepting connection
  190.                 spkey = self.conn.recv(1024)    # code to send encryption key
  191.                
  192.                 print(spkey.decode())   # <nf>
  193.                
  194.                 self.conn.sendall(self.pkey.encode())
  195.             else:
  196.                 tkinter.messagebox.showerror("Error", "Handshake failed")   # error message if connection acquired but not server
  197.         except:
  198.             tkinter.messagebox.showerror("Error", "Could not connect to server")    # error message if no connection
  199.             self.destroy()
  200.             #quit(0)
  201.     # function tries to connect to server and will close program if it cannot
  202.    
  203.     def logout(self):
  204.         self.userlvl.set(0)
  205.         self.showPage(LoginPage,MainPage)
  206.     # sets userlvl to 0 and shows login page
  207.    
  208.     def getuserlvl(self):
  209.         return self.userlvl.get()
  210.     # getter method for userlvl
  211.            
  212.     def change_text(self,**kwargs):
  213.         # this function sanitises text as the user is typing, preventing attacks
  214.         done = False
  215.         while not done:
  216.             print(kwargs["var"].get())
  217.             if ";" in kwargs["var"].get():
  218.                 kwargs["var"].set(kwargs["var"].get().replace(";",","))
  219.                 done = False
  220.                 self.change_text(**kwargs)
  221.             elif "&&" in kwargs["var"].get():
  222.                 kwargs["var"].set(kwargs["var"].get().replace("&&","&"))
  223.                 done = False
  224.                 self.change_text(**kwargs)
  225.             elif "'" in kwargs["var"].get():
  226.                 kwargs["var"].set(kwargs["var"].get().replace("'",""))
  227.                 done = False
  228.                 self.change_text(**kwargs)
  229.             elif "|" in kwargs["var"].get():
  230.                 kwargs["var"].set(kwargs["var"].get().replace("|",""))
  231.                 done = False
  232.                 self.change_text(**kwargs)
  233.             elif "<" in kwargs["var"].get():
  234.                 kwargs["var"].set(kwargs["var"].get().replace("<",""))
  235.                 done = False
  236.                 self.change_text(**kwargs)
  237.             elif ">" in kwargs["var"].get():
  238.                 kwargs["var"].set(kwargs["var"].get().replace(">",""))
  239.                 done = False
  240.                 self.change_text(**kwargs)
  241.             elif "=" in kwargs["var"].get():
  242.                 kwargs["var"].set(kwargs["var"].get().replace("=",""))
  243.                 done = False
  244.                 self.change_text(**kwargs)
  245.             else:
  246.                 done = True
  247.                 print("finished")
  248.             try:
  249.                 print(1)
  250.                 if kwargs["limit"]=="alpha":
  251.                     print(2)
  252.                     pattern = re.compile(r"[^A-Za-z ]")
  253.                     print(pattern)
  254.                     print(3)
  255.                     print("RE: ",pattern.sub("",kwargs["var"].get()))
  256.                     kwargs["var"].set(re.sub(pattern,"",kwargs["var"].get()))
  257.                     print(4)
  258.             except:
  259.                 pass
  260. class LoginPage(tkinter.Frame,SquadBot):
  261.     def __init__(self,master,controller):
  262.         tkinter.Frame.__init__(self,master)
  263.         # initialising inherited parent class
  264.         self.createImages()
  265.         # creating an array of images for the class to use
  266.        
  267.         crestlabel = tkinter.Label(self,image=self.images["bigcrest"],background=self.palette["bgblue"])
  268.         crestlabel.place(x=350,y=0,anchor="n")
  269.         # creating crest image in centre of page
  270.        
  271.         self.unamelabel = tkinter.Label(self,text="Username:",background=self.palette["bgblue"],font="TkDefaultFont 9 bold")
  272.         self.unamelabel.place(x=250,y=375,anchor="nw")
  273.         # creating a label to show where to enter the username to login
  274.         self.usernamevar = tkinter.StringVar()
  275.         self.usernamevar.trace_add("write", lambda x,y,z: self.change_text(var=self.usernamevar))
  276.         self.unameentry = ttk.Entry(self,text = self.usernamevar)
  277.         self.unameentry.place(x=350,y=395,anchor="n",width=200)
  278.         # creating the text box for the user to enter their username
  279.        
  280.         pwordlabel = ttk.Label(self,text="Password:",background=self.palette["bgblue"],font="TkDefaultFont 9 bold")
  281.         pwordlabel.place(x=250,y=420,anchor="nw")
  282.         # creating a label to show the user where to enter their password
  283.         self.passwordvar = tkinter.StringVar()
  284.         self.passwordvar.trace_add("write", lambda x,y,z: self.change_text(var=self.passwordvar))
  285.         self.pwordentry = ttk.Entry(self,show="•",text=self.passwordvar)  
  286.         self.pwordentry.place(x=350,y=440,anchor="n",width=200)
  287.         # creating a text box for the user to enter their password
  288.         # shows • instead of characters when the user types their password in to prevent people seeing their password
  289.        
  290.         loginbutton = ttk.Button(self,text="Login",command = lambda: self.login(controller))
  291.         loginbutton.place(x=350,y=468,anchor="n")
  292.         # creates a button that executes LoginPage.Login() with SquadBot as an argument
  293.        
  294.         self.configure(bg=self.palette["bgblue"])
  295.         # setting background of frame to palette["bgblue"], which is the main background colour of the program
  296.        
  297.         #notbutton = tkinter.Button(self,text="test",command = lambda: self.shownot(controller))
  298.         #notbutton.place(x=700,y=500,anchor="se")
  299.         # <nf> TESTING NOTIFICATIONS
  300.        
  301.     def shownot(self,parent):
  302.         window = Notification(self,parent)
  303.         # <nf>  MORE NOTIFICATION TESTING
  304.        
  305.     def login(self,parent):
  306.         username = self.unameentry.get()
  307.         password = self.pwordentry.get()
  308.         # retrieves username and password from the boxes,
  309.         # and replaces any semicolons with a comma
  310.        
  311.         self.unameentry.delete(0,"end")
  312.         self.pwordentry.delete(0,"end")
  313.         # removes text from entry boxes, so that they are clear for when the user logs out
  314.        
  315.         data = (username,password)
  316.         # creating tuple from entered data
  317.        
  318.         jsondata = json.dumps(data)
  319.         # creating a JSON string from tuple
  320.        
  321.         sendingdata = "l" + jsondata
  322.         # adding an "l" to the front - indicates it is a login request when the server parses it
  323.        
  324.         parent.conn.sendall(sendingdata.encode())
  325.         # sends the string to the server
  326.        
  327.         print(sendingdata.encode()) # <nf>
  328.        
  329.         response = parent.conn.recv(1024).decode()
  330.         # receives the response from the server
  331.        
  332.         if response[0] == "a":  # indicates accepted login
  333.             fullresp = response[1:]
  334.             # removes the 'a' from the front of the data so the rest of it can be decoded
  335.            
  336.             data = fullresp.split(",")
  337.             # creates an array of strings from the data, splitting it at commas
  338.            
  339.             parent.userlvl.set(int(data[0]))
  340.             # setting userlevel to set certain functions depending on different users
  341.            
  342.             parent.fullname = data[2]
  343.             # setting the name of the user to allow better human-computer interaction
  344.            
  345.             print(parent.fullname)
  346.             print("login successful")
  347.             print(parent.getuserlvl())  # <nf>
  348.             # receives the user data from the server
  349.    
  350.            
  351.             parent.userid.set(int(data[1]))
  352.             # sets the user id of the user
  353.             requestdata = parent.conn.recv(1024)
  354.             print(requestdata)
  355.             requests = json.loads(requestdata)
  356.             msg = "There have been responses to your requests:\n\n"
  357.             if len(requests) >0:
  358.                 for i in requests:
  359.                     msg += i[0]+":"+i[1]+"\n"
  360.                 notif = Notification(parent,msg)
  361.            
  362.             parent.welcomemessage.set("Welcome, {name}!".format(name=parent.fullname))
  363.             # creates a welcome message that is displayed upon loggin in
  364.             parent.showPage(MainPage,LoginPage)   # displaying main page, from which other pages can be reached
  365.            
  366.         elif response[0] == "p":    # password incorrect
  367.             tkinter.messagebox.showerror("Error logging in","Password incorrect")
  368.         elif response[0] == "u":    # user not found
  369.             tkinter.messagebox.showerror("Error logging in","Username or password incorrect")
  370.  
  371.        
  372. class MainPage(tkinter.Frame,SquadBot): # main page class
  373.     def __init__(self,master,controller):   # initialisation function
  374.         tkinter.Frame.__init__(self,master) # initialising inherited class to produce visible object
  375.         self.toptip = tkinter.StringVar()
  376.         self.toptip.set("None")
  377.         self.createImages()
  378.         controller.conn.send("rc".encode()) # retrieves uniform scores to present to the user
  379.         response = controller.conn.recv(1024)
  380.         datadict = json.loads(response)
  381.         data = {}
  382.         print("Datadict:",datadict)
  383.         for i in datadict:
  384.             data[i[1]] = i[0]
  385.         sorteduniform = quicksort(list(data.keys()))
  386.         top5cadets = []
  387.         a=0
  388.  
  389.         # below code presents the list of top 5 cadets for uniform to the user
  390.         for i in sorteduniform[::-1]:
  391.             if a >= 5:
  392.                 break
  393.             controller.conn.send("rn{cid}".format(cid=data[i]).encode())
  394.             jsonname = controller.conn.recv(1024).decode()
  395.             splitname = json.loads(jsonname)
  396.             name = splitname[0]+" "+splitname[1]+" "+splitname[2]
  397.             print("name:",name)
  398.             top5cadets.append(name)
  399.             a+=1
  400.  
  401.            
  402.         print("top5:",top5cadets)
  403.  
  404.  
  405.         # below code creates a window that allows the user to change password
  406.         def changepword():
  407.             def sendpword():
  408.                 if pwordentry.get() == pwordconfirm.get():
  409.                     if len(pwordentry.get())>=8:
  410.                         controller.conn.send("pc{uid}+{pword}".format(uid=controller.userid.get(),pword=re.sub(";",",",pwordentry.get())).encode())
  411.                         self.pwordchange.destroy()
  412.                         tkinter.messagebox.showinfo("Success","Password successfully changed")
  413.                     else:
  414.                         pwordentry.delete(0,"end")
  415.                         pwordconfirm.delete(0,"end")
  416.                         tkinter.messagebox.showerror("Error","Password must be longer than 8 characters")
  417.                 else:
  418.                     pwordentry.delete(0,"end")
  419.                     pwordconfirm.delete(0,"end")
  420.                     tkinter.messagebox.showerror("Error","Passwords do not match")
  421.             self.pwordchange = tkinter.Toplevel(controller)
  422.             self.pwordchange.grab_set()
  423.             self.pwordchange.geometry("200x150")
  424.             userlbl = tkinter.Label(self.pwordchange,text="New Password:")
  425.             userlbl.place(x=100,y=0,anchor="n")
  426.             pwordvar = tkinter.StringVar()
  427.             pwordvar.trace_add("write", lambda x,y,z: self.change_text(var=pwordvar))
  428.             pwordentry = tkinter.Entry(self.pwordchange,text=pwordvar)
  429.             pwordentry.place(x=100,y=30,anchor="n")
  430.             pwordconfirmvar = tkinter.StringVar()
  431.             pwordconfirmvar.trace_add("write", lambda x,y,z: self.change_text(var=pwordconfirmvar))
  432.             pwordconfirmlbl = tkinter.Label(self.pwordchange,text="Confirm Password:")
  433.             pwordconfirmlbl.place(x=100,y=60,anchor="n")
  434.             pwordconfirm = tkinter.Entry(self.pwordchange,text=pwordconfirmvar)
  435.             pwordconfirm.place(x=100,y=90,anchor="n")
  436.             submitbtn = tkinter.Button(self.pwordchange,text="Submit Password",command = lambda: sendpword())
  437.             submitbtn.place(x=100,y=120,anchor="n")
  438.  
  439.            
  440.         self.configure(bg=self.palette["bgblue"]) # setting background
  441.         colourbar = tkinter.Frame(self,background=self.palette["darkblue"])
  442.         colourbar.place(x=0,y=0,width=700,height=90,anchor="nw")    # accent bar at top of window
  443.         logoutbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Log Out",
  444.                                       fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.logout())
  445.         logoutbutton.place(height=50,width=100,x=680,y=45,anchor="e")   # log out button in bar
  446.         changepwordbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Change \nPassword",
  447.                                            fg="white",font=("TkDefaultFont","10","bold"),command=lambda: changepword())
  448.         changepwordbutton.place(height=50,width=100,x=560,y=45,anchor="e")
  449.         crestlbl = tkinter.Label(self,image=self.images["smallcrest"],background=self.palette["darkblue"])
  450.         crestlbl.place(x=0,y=0,anchor="nw",width=99,height=135) # squadron crest image in accent bar
  451.         ufsbframe = tkinter.Frame(self,background=self.palette["afb"],borderwidth=2,highlightbackground="white",relief = "groove") # creating area for notifications/announcements
  452.         # uniform scoreboard frame
  453.         if controller.getuserlvl() == 1:
  454.             ufsbframe.place(x=700,y=320,anchor="se",height=200,width=250)
  455.         else:
  456.             ufsbframe.place(x=700,y=90,anchor="ne",height=230,width=250)
  457.         ufsbtitle = tkinter.Label(ufsbframe,text="Top 5 for Uniform:",font=("Arial Black","16","underline"),bg=self.palette["afb"],fg='white')
  458.         ufsbtitle.place(x=5,y=5,anchor="nw")    # title for area
  459.         b=0
  460.         for i in top5cadets:
  461.             tkinter.Label(ufsbframe,text=str(b+1)+":  "+i,font=("Arial Black","12","bold"),bg=self.palette["afb"],fg="white").place(x=5,y=40+32*b,anchor="nw")
  462.             b+=1
  463.         personalframe = tkinter.Frame(self,background=self.palette["afb"],borderwidth=2,highlightbackground="white",relief="groove")
  464.  
  465.        
  466.         if controller.userlvl.get() == 1:# tests if the user is a high enough level to access user management
  467.             personalframe.place(x=700,y=500,anchor="se",width=250,height=180)
  468.             personallbl = tkinter.Label(personalframe,text="Average Uniform Score:",background=self.palette["afb"],foreground="white",font=("Arial Black","12","underline"))
  469.             personallbl.place(x=125,y=22.5,height=45,anchor="center")
  470.             improvementlbl = tkinter.Label(personalframe,text="To improve:",background=self.palette["afb"],foreground="white",font=("Arial Black","12","underline"))
  471.             improvementlbl.place(x=125,y=112.5,height=45,anchor="center")
  472.             improvement = tkinter.Label(personalframe,
  473.                                         textvariable=self.toptip,
  474.                                         background=self.palette["afb"],
  475.                                         foreground="white",
  476.                                         font=("Arial Black","12","bold"))
  477.             improvement.place(x=125,y=135,anchor="n")
  478.             sqnavgframe = tkinter.Frame(self,background = self.palette["afb"],borderwidth=2,highlightbackground="white",relief="groove")
  479.             sqnavgframe.place(x=700,y=120,anchor="se",width=250,height=30)
  480.             sqnavglbl = tkinter.Label(sqnavgframe,text="Squadron Average:",background=self.palette["afb"],foreground="white",font=("Arial Black","11","underline"))
  481.             sqnavglbl.place(x=0,y=0,anchor="nw",height=25)
  482.             controller.conn.send("rs".encode())
  483.             response = controller.conn.recv(1024).decode()
  484.             data = json.loads(response)
  485.             total = 0
  486.             print(data)
  487.             if data:
  488.                 for i in data:
  489.                     total+=i[1]
  490.                 avg = total/len(data)
  491.                 avglbl = tkinter.Label(sqnavgframe,text=round(avg,2),background=self.palette["afb"],foreground="white",font=("Arial Black","11","underline"))
  492.                 avglbl.place(x=175,y=0,anchor="nw",height=25)
  493.         else:
  494.             personalframe.place(x=700,y=500,anchor="se",width=250,height=180)
  495.             sqnlbl = tkinter.Label(personalframe,text="Squadron Average \nUniform Score:",background=self.palette["afb"],foreground="white",font=("Arial Black","10","underline"))
  496.             sqnlbl.place(x=125,y=22.5,height=45,anchor="center")
  497.             controller.conn.send("rs".encode())
  498.             response = controller.conn.recv(1024).decode()
  499.             data = json.loads(response)
  500.             total = 0
  501.             print(data)
  502.             if data:
  503.                 for i in data:
  504.                     total+=i[1]
  505.             avg = total/len(data)
  506.             avglbl = tkinter.Label(personalframe,text=round(avg,2),background=self.palette["afb"],foreground="white",font=("Arial Black","18"))
  507.             avglbl.place(x=125,y=67.5,anchor="center",height=25)
  508.             improvementlbl = tkinter.Label(personalframe,text="Most common improvement:",background=self.palette["afb"],foreground="white",font=("Arial Black","9","underline"))
  509.             improvementlbl.place(x=125,y=112.5,height=45,anchor="center")
  510.             improvement = tkinter.Label(personalframe,
  511.                                         textvariable=self.toptip,
  512.                                         background=self.palette["afb"],
  513.                                         foreground="white",
  514.                                         font=("Arial Black","12","bold"))
  515.             improvement.place(x=125,y=135,anchor="n")
  516.  
  517.            
  518.         def callback(self1,self2,self3):    # sorts the data to produce the modal value
  519.             print(self1)
  520.             print(self2)
  521.             print(self3)
  522.             cid = controller.userid.get()
  523.             if controller.userlvl.get() == 1:
  524.                 controller.conn.send("rx{cid}".format(cid=cid).encode())
  525.             else:
  526.                 controller.conn.send("rx0".encode())
  527.             result = controller.conn.recv(1024).decode()
  528.             print("result:",result)
  529.             arrayraised = json.loads(result)
  530.             print("ARRRR:",arrayraised)
  531.             tipsarray = []
  532.             for i in arrayraised:
  533.                 print(i)
  534.                 tipsarray.append(i[0])
  535.            
  536.             data = []
  537.            
  538.             for i in tipsarray:
  539.                 data.append(i)
  540.             print("DaTa:",data)
  541.             sortedtips = quicksort(data)
  542.             nametonum = {}
  543.             print("Sorted:",sortedtips)
  544.             for i in range(len(sortedtips)):
  545.                  if sortedtips[i] == sortedtips[i-1]:
  546.                     nametonum[sortedtips[i]] += 1
  547.                  else:
  548.                     nametonum[sortedtips[i]] = 1
  549.             numtoname = {}
  550.             for i in list(nametonum.keys()):
  551.                 numtoname[nametonum[i]] = i
  552.             self.toptip.set(numtoname[quicksort(list(numtoname.keys()))[-1]])
  553.             print("freq:",self.toptip.get())
  554.                
  555.         controller.userid.trace_add("write",callback)
  556.        
  557.        
  558.        
  559.         suppbutt = tkinter.Button(self,text="Request\nSupport",bg=self.palette["white"],command = lambda: controller.showPage(SupportPage,MainPage),justify="center",font=("Arial Black",14))
  560.         suppbutt.place(x=137.5,y=230,anchor="center",width=125,height=125)    # button to access support request window
  561.         unibutt = tkinter.Button(self,text="View\nUniform",bg=self.palette["white"],command=lambda:controller.showPage(UniformPage,MainPage),justify="center",font=("Arial Black",14))
  562.         unibutt.place(x=312.5,y=230,height=125,width=125,anchor="center")  # button to access uniform scores area
  563.         if controller.getuserlvl() != 1:
  564.             userorgbutt = tkinter.Button(self,text="User Management",bg=self.palette["white"],command = lambda: controller.showPage(UserOrgPage,MainPage),font=("Arial Black",14))
  565.             userorgbutt.place(x=75,y=342.5,anchor="nw",height=125,width=300)  # button to access user management page
  566.         welcomelbl = tkinter.Label(colourbar,textvariable=controller.welcomemessage,font=("Arial Black","20","bold"),foreground="white",background=self.palette["darkblue"])
  567.         welcomelbl.place(y=45,x=100,anchor="w")
  568.         # controller.userlvl.trace_add()
  569.        
  570.     def updatepage(self):
  571.         pass        
  572.  
  573.  
  574.  
  575.  
  576.  
  577.        
  578.        
  579. class SupportPage(tkinter.Frame,SquadBot):  # page for support requests
  580.     def __init__(self,master,controller):   # initialising
  581.         tkinter.Frame.__init__(self,master) # initialising inherited class
  582.         self.createImages()
  583.         self.configure(bg=self.palette["bgblue"])
  584.         colourbar = tkinter.Frame(self,background=self.palette["darkblue"])
  585.         colourbar.place(x=0,y=0,width=700,height=90,anchor="nw")
  586.         logoutbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Log Out",
  587.                                       fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.logout())
  588.         logoutbutton.place(height=50,width=100,x=680,y=45,anchor="e")
  589.         mainscreenbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Back",
  590.                                           fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.showPage(MainPage,SupportPage))
  591.         mainscreenbutton.place(height=50,width=100,x=560,y=45,anchor="e")
  592.         crestlbl = tkinter.Label(self,image=self.images["smallcrest"],background=self.palette["darkblue"])
  593.         crestlbl.place(x=0,y=0,anchor="nw",width=99,height=135)
  594.         pagelbl = tkinter.Label(colourbar,text="Support",font=("Arial Black","20","bold"),foreground="white",background=self.palette["darkblue"])
  595.         pagelbl.place(y=45,x=100,anchor="w")
  596.         # code above creates accent bar and associated objects
  597.         entrylabel = tkinter.Label(self,text="Please enter your question in the box below",font=("TkDefaultFont","10","bold"),bg=self.palette["bgblue"])
  598.         entrylabel.place(x=150,y=145,anchor="sw")   # Label to show where to enter issue
  599.         requestvar = tkinter.StringVar()
  600.         self.entrybox = tkinter.ttk.Entry(self,text=requestvar)
  601.         self.entrybox.place(x=350,y=250,height=200,width=400,anchor="center")   # text box to enter issue
  602.         requestvar.trace_add("write", lambda x,y,z: self.change_text(var=requestvar))
  603.         urgencyframe = tkinter.Frame(self)
  604.         urgencyframe.configure(background=self.palette["bgblue"])
  605.         urgencyframe.place(height=30,width=200,x=150,y=360,anchor="nw") # creating frame to contain urgency selector
  606.         sendresponse = tkinter.Button(self,text="Send question",command = lambda: self.sendrequest(controller),font=("Arial Black",10))
  607.         sendresponse.place(height=30,x=375,y=360,anchor="nw",width=150)   # button to send response
  608.         urgencylabel = tkinter.Label(urgencyframe,text="Urgency:",background = self.palette["bgblue"],font=("TkDefaultFont","8","bold"))  # label to show where to select
  609.         self.urgencyvar = tkinter.IntVar()  # creating tkinter variable to use with urgency buttons - must be used with to retrieve value
  610.         self.urgencyvar.set(2)
  611.         highurgency = tkinter.Radiobutton(urgencyframe,text="High",value=1,background=self.palette["bgblue"],activebackground="#ffffff",variable=self.urgencyvar)
  612.         lowurgency = tkinter.Radiobutton(urgencyframe,text="Low",value=2,background=self.palette["bgblue"],activebackground="#ffffff",variable=self.urgencyvar)
  613.         lowurgency.place(x=105,y=15,anchor="w")
  614.         highurgency.place(x=55,y=15,anchor="w")
  615.         urgencylabel.place(x=4,y=15,anchor="w") # placing items in frame
  616.         responsebutton = tkinter.Button(self,text = "Respond to requests",command = lambda: self.respond(controller),font=("Arial Black",10))  # button for higher user levels to respond to requests
  617.         if controller.getuserlvl() >= 2:
  618.             responsebutton.place(x=0,y=500,anchor="sw",height=50,width=200) # testing to see whether user is able to access area or not
  619.        
  620.  
  621.     def sendrequest(self,parent):   # function to send support request
  622.         request = self.entrybox.get()
  623.         urgency = self.urgencyvar.get()
  624.         if request != "":
  625.             data = (urgency,request)
  626.             jsondata = json.dumps(data)
  627.             sendingdata = "sr" + jsondata
  628.             parent.conn.sendall(sendingdata.encode())
  629.             self.entrybox.delete(0,"end")
  630.         else:
  631.             tkinter.messagebox.showerror("Error","Request cannot be blank")
  632.     def respond(self,parent):
  633.         self.selectorwindow = tkinter.Toplevel()
  634.         self.selectorwindow.geometry("400x300")
  635.         self.selectorwindow.grab_set()
  636.         def scrollfunc(event):
  637.             can.configure(scrollregion=can.bbox("all"),width=400,height=300)
  638.         canvasframe = tkinter.Frame(self.selectorwindow,relief="groove",width=383,height=300)
  639.         canvasframe.place(x=0,y=0)
  640.         def senddata(reply,rid):
  641.             data = (reply,rid)
  642.             jsondata = json.dumps(data)
  643.             sendingdata = "ss" + jsondata
  644.             parent.conn.send(sendingdata.encode())
  645.             self.selectorwindow.destroy
  646.         can = tkinter.Canvas(canvasframe)
  647.         frame = tkinter.Frame(can)
  648.         scrollbar = tkinter.Scrollbar(canvasframe,orient="vertical",command=can.yview)
  649.         can.configure(yscrollcommand=scrollbar.set)
  650.         scrollbar.pack(side="right",fill="y")
  651.         can.pack(side="left")
  652.         can.create_window((0,0),window=frame,anchor="nw")
  653.         frame.bind("<Configure>",scrollfunc)
  654.         parent.conn.send("rh".encode())
  655.         response = parent.conn.recv(1024)
  656.         data = json.loads(response.decode())
  657.         a=0
  658.         print(data)
  659.        
  660.         controller = parent
  661.         self.responses = []
  662.         if controller.userlvl.get() == 3:
  663.             tkinter.Label(frame,text="Rank").grid(row=a,column=0)
  664.             tkinter.Label(frame,text="Name").grid(row=a,column=1)
  665.         tkinter.Label(frame,text="Request").grid(row=a,column=3)
  666.         tkinter.Label(frame,text="Response").grid(row=a,column=4)
  667.         entryboxes = []
  668.         for i in data:
  669.             a+=1
  670.             self.responses.append(tkinter.StringVar())
  671.             self.responses[-1].set("")
  672.             if controller.userlvl.get() == 3:
  673.                 tkinter.Label(frame,text=i[3]).grid(row=a,column=0)
  674.                 tkinter.Label(frame,text=i[1]).grid(row=a,column=1)
  675.                 tkinter.Label(frame,text=i[2]).grid(row=a,column=2)
  676.             tkinter.Label(frame,text=i[14]).grid(row=a,column=3)
  677.             entryboxes.append(tkinter.Entry(frame,text=self.responses[-1]))
  678.             entryboxes[-1].grid(row=a,column=4)
  679.             tkinter.Button(frame,command = lambda x=i[11],y=entryboxes[-1]: senddata(y.get(),x),text="Reply").grid(row=a,column=5)
  680.            
  681.            
  682.            
  683.        
  684. class UniformPage(tkinter.Frame,SquadBot):
  685.     def __init__(self,parent,controller):
  686.         tkinter.Frame.__init__(self,parent)
  687.         self.createImages()
  688.         self.graphs = []
  689.         self.configure(bg=self.palette["bgblue"])
  690.         colourbar = tkinter.Frame(self,background=self.palette["darkblue"])
  691.         colourbar.place(x=0,y=0,width=700,height=90,anchor="nw")
  692.         logoutbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Log Out",
  693.                                       fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.logout())
  694.         logoutbutton.place(height=50,width=100,x=680,y=45,anchor="e")
  695.         mainscreenbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Back",
  696.                                           fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.showPage(MainPage,UniformPage))
  697.         mainscreenbutton.place(height=50,width=100,x=560,y=45,anchor="e")
  698.         crestlbl = tkinter.Label(self,image=self.images["smallcrest"],background=self.palette["darkblue"])
  699.         crestlbl.place(x=0,y=0,anchor="nw",width=99,height=135)
  700.         pagelbl = tkinter.Label(colourbar,text="Uniform",font=("Arial Black","20","bold"),foreground="white",background=self.palette["darkblue"])
  701.         pagelbl.place(y=45,x=100,anchor="w")
  702.         if controller.getuserlvl() == 1:
  703.             uniform = tkinter.Button(self,text = "View my own uniform scores",command = lambda: self.returnowndata(controller),justify="center")
  704.             uniform.place(x=50,y=150,anchor="nw",width = 200,height = 125)
  705.             sqnudata = tkinter.Button(self,text="View average uniform \nscores for the squadron",command = lambda: self.returnsqndata(controller),justify="center")
  706.             sqnudata.place(x=50,y=450,anchor="sw",width=200,height=125)
  707.         else:
  708.             uniform = tkinter.Button(self,text="Create new \nuniform record",command = lambda: self.newnight(controller),justify="center")
  709.             uniform.place(x=50,y=150,anchor="nw",height=80,width=200)
  710.             cdtdata = tkinter.Button(self,text="Choose data for specific cadet",command = lambda: self.returncadetdata(controller))
  711.             cdtdata.place(x=50,y=300,anchor="w",height=80,width=200)
  712.             sqnudata = tkinter.Button(self,text="View average uniform \nscores for the squadron",command = lambda: self.returnsqndata(controller),justify="center")
  713.             sqnudata.place(x=50,y=450,anchor="sw",height=80,width=200)
  714.         self.returnsqndata(controller,delay=0)
  715.     def choosecadet(self,num,name,controller):
  716.         for i in self.graphs:
  717.             i.place_forget()
  718.         print(num)
  719.         controller.conn.send(("rz{c}".format(c=num)).encode())
  720.         self.selectorwindow.destroy()
  721.         jsonscores = controller.conn.recv(1024)
  722.         datanest = json.loads(jsonscores)
  723.         print(datanest)
  724.         data = self.cleansedatenest(datanest)
  725.         cdtgraph = Graph(self,400,300,data,700,100,"ne",maxi=6,title="Uniform Scores for {nam}".format(nam=name),goal=3)
  726.         self.graphs.append(cdtgraph)
  727.         controller.conn.send("rx{cid}".format(cid=num).encode())
  728.         result = controller.conn.recv(1024).decode()
  729.         arrayraised = json.loads(result)
  730.         tipsarray = []
  731.         for i in arrayraised:
  732.             print(i)
  733.             tipsarray.append(i[0])
  734.            
  735.         data = tipsarray
  736.         print("DaTa:",data)
  737.         sortedtips = quicksort(data)
  738.         nametonum = {}
  739.         print("Sorted:",sortedtips)
  740.         for i in range(len(sortedtips)):
  741.             if sortedtips[i] == sortedtips[i-1]:
  742.                 nametonum[sortedtips[i]] += 1
  743.             else:
  744.                 nametonum[sortedtips[i]] = 1
  745.         numtoname = {}
  746.         for i in list(nametonum.keys()):
  747.             numtoname[nametonum[i]] = i
  748.         tip = numtoname[quicksort(list(numtoname.keys()))[-1]]
  749.         self.graphs.append(tkinter.Label(self,text="To Improve: {improv}".format(improv=tip),font=("Arial Black",12),foreground="white",background=self.palette["bgblue"]))
  750.         self.graphs[-1].place(anchor="s",x=500,y=470)
  751.     def cleansedatenest(self,datanest):
  752.         b=0
  753.         for i in datanest:
  754.             print(datanest[b][0])
  755.             datanest[b][0] = (datanest[b][0])[8:]+"-"+(datanest[b][0])[5:7]
  756.             b+=1
  757.         data = {}
  758.         for i in datanest:
  759.             data[i[0]] = i[1]
  760.         return data
  761.     def returncadetdata(self,parent):
  762.         self.selectorwindow = tkinter.Toplevel()
  763.         self.selectorwindow.geometry("200x200")
  764.         def scrollfunc(event):
  765.             can.configure(scrollregion=can.bbox("all"),width=200,height=200)
  766.         canvasframe = tkinter.Frame(self.selectorwindow,relief="groove",width=183,height=200)
  767.         canvasframe.place(x=0,y=0)
  768.        
  769.         can = tkinter.Canvas(canvasframe)
  770.         frame = tkinter.Frame(can)
  771.         scrollbar = tkinter.Scrollbar(canvasframe,orient="vertical",command=can.yview)
  772.         can.configure(yscrollcommand=scrollbar.set)
  773.         scrollbar.pack(side="right",fill="y")
  774.         can.pack(side="left")
  775.         can.create_window((0,0),window=frame,anchor="nw")
  776.         frame.bind("<Configure>",scrollfunc)
  777.         parent.conn.send("ru".encode())
  778.         response = parent.conn.recv(1024)
  779.         data = json.loads(response.decode())
  780.         a=0
  781.         print(data)
  782.         controller = parent
  783.         for i in data:
  784.             tkinter.Label(frame,text=i[0]).grid(row=a,column=0)
  785.             tkinter.Label(frame,text=i[1]).grid(row=a,column=1)
  786.             tkinter.Label(frame,text=i[2]).grid(row=a,column=2)
  787.             name = i[0]+" "+i[1]+" "+i[2]
  788.             tkinter.Button(frame,text="Select",command=lambda b=i[3], nom=name: self.choosecadet(b,nom,controller)).grid(row=a,column=3)
  789.             print("button",i,":",i[3])
  790.             a+=1
  791.     def returnsqndata(self,parent,**kwargs):
  792.         for i in self.graphs:
  793.             i.place_forget()
  794.         parent.conn.send("rs".encode())
  795.         jsonscores = parent.conn.recv(1024)
  796.         datanest = json.loads(jsonscores)
  797.         data = self.cleansedatenest(datanest)
  798.         if "delay" in kwargs:
  799.             sqngraph = Graph(self,400,300,data,700,100,"ne",maxi=6,title="Average uniform for 1000(Blyth) Squadron",delay=kwargs["delay"],goal=4)
  800.             print("nodelay")
  801.         else:
  802.             sqngraph = Graph(self,400,300,data,700,100,"ne",maxi=6,title="Average uniform for 1000(Blyth) Squadron",goal=4)
  803.         self.graphs.append(sqngraph)
  804.         parent.conn.send("rx0".encode())
  805.         result = parent.conn.recv(1024).decode()
  806.         arrayraised = json.loads(result)
  807.         tipsarray = []
  808.         for i in arrayraised:
  809.             print(i)
  810.             tipsarray.append(i[0])
  811.            
  812.         data = tipsarray
  813.         print("DaTa:",data)
  814.         sortedtips = quicksort(data)
  815.         nametonum = {}
  816.         print("Sorted:",sortedtips)
  817.         for i in range(len(sortedtips)):
  818.             if sortedtips[i] == sortedtips[i-1]:
  819.                 nametonum[sortedtips[i]] += 1
  820.             else:
  821.                 nametonum[sortedtips[i]] = 1
  822.         numtoname = {}
  823.         for i in list(nametonum.keys()):
  824.             numtoname[nametonum[i]] = i
  825.         tip = numtoname[quicksort(list(numtoname.keys()))[-1]]
  826.         self.graphs.append(tkinter.Label(self,text="Main improvement required: {improv}".format(improv=tip),font=("Arial Black",12),foreground="white",background=self.palette["bgblue"]))
  827.         self.graphs[-1].place(anchor="s",x=500,y=470)
  828.        
  829.    
  830.        
  831.        
  832.     def returnowndata(self,parent):
  833.         for i in self.graphs:
  834.             i.place_forget()
  835.         controller.conn.send(("rz{c}".format(c=parent.userid.get())).encode())
  836.         self.selectorwindow.destroy()
  837.         jsonscores = controller.conn.recv(1024)
  838.         datanest = json.loads(jsonscores)
  839.         print(datanest)
  840.         data = self.cleansedatenest(datanest)
  841.         cdtgraph = Graph(self,400,300,data,700,100,"ne",maxi=6,title="Uniform Scores for {nam}".format(nam=parent.fullname),goal=3)
  842.         self.graphs.append(cdtgraph)
  843.         controller.conn.send("rx{cid}".format(cid=parent.userid.get()).encode())
  844.         result = controller.conn.recv(1024).decode()
  845.         arrayraised = json.loads(result)
  846.         tipsarray = []
  847.         for i in arrayraised:
  848.             print(i)
  849.             tipsarray.append(i[0])
  850.            
  851.         data = tipsarray
  852.         print("DaTa:",data)
  853.         sortedtips = quicksort(data)
  854.         nametonum = {}
  855.         print("Sorted:",sortedtips)
  856.         for i in range(len(sortedtips)):
  857.             if sortedtips[i] == sortedtips[i-1]:
  858.                 nametonum[sortedtips[i]] += 1
  859.             else:
  860.                 nametonum[sortedtips[i]] = 1
  861.         numtoname = {}
  862.         for i in list(nametonum.keys()):
  863.             numtoname[nametonum[i]] = i
  864.         tip = numtoname[quicksort(list(numtoname.keys()))[-1]]
  865.         self.graphs.append(tkinter.Label(self,text="To Improve: {improv}".format(improv=tip),font=("Arial Black",12),foreground="white",background=self.palette["bgblue"]))
  866.         self.graphs[-1].place(anchor="s",x=500,y=470)
  867.  
  868.     def newnight(self,parent):
  869.         def senddata(parent):
  870.             date = datetime.datetime.today().strftime('%Y-%m-%d')
  871.             userdata = []
  872.             for i in range(len(data)):
  873.                 if self.absent[i].get() == True:
  874.                     absent = "X"
  875.                     self.tips[i].set("NULL")
  876.                     score = "NULL"
  877.                 else:
  878.                     absent = "/"
  879.                     score = self.score[i].get()
  880.                 user = (data[i][3],date,absent,score,self.tips[i].get())
  881.                 userdata.append(user)
  882.             sendingdata = json.dumps(userdata)
  883.             encodingdata = "<"+sendingdata+">"
  884.             parent.conn.send(encodingdata.encode())
  885.             returned = parent.conn.recv(1024)
  886.             if returned.decode() == "DAR":
  887.                 tkinter.messagebox.showerror("Error","Data already recorded for today")
  888.             elif returned.decode() == "DSU":
  889.                 tkinter.messagebox.showinfo("Success","Uniform data successfully uploaded")
  890.             self.selectorwindow.destroy()
  891.         parent.conn.send("sa".encode())
  892.         endofdata = False
  893.         data=""
  894.         while not endofdata:
  895.             received = parent.conn.recv(1024)
  896.             decoded = received.decode()
  897.             print("received:",decoded)
  898.             data = data.join(decoded)
  899.             if data[-1] == ">":
  900.                 endofdata = True
  901.         jsondata = data[1:-1]
  902.         data = json.loads(jsondata)
  903.         for i in data:
  904.             print(i)
  905.         def closingwindow():
  906.             tkinter.messagebox.showerror("Error","Uniform scores must be submitted in order to close this window")
  907.         self.selectorwindow = tkinter.Toplevel()
  908.         self.selectorwindow.geometry("400x240+200+200")
  909.         self.selectorwindow.tk.call('wm', 'iconbitmap', self.selectorwindow._w, "resources/crest.ico")
  910.         self.selectorwindow.configure(bg=self.palette["bgblue"])
  911.         self.selectorwindow.protocol("WM_DELETE_WINDOW",closingwindow)
  912.         self.selectorwindow.grab_set()
  913.         def scrollfunc(event):
  914.             can.configure(scrollregion=can.bbox("all"),width=400,height=200)
  915.         canvasframe = tkinter.Frame(self.selectorwindow,relief="groove",width=383,height=200)
  916.         canvasframe.place(x=0,y=0)
  917.        
  918.         can = tkinter.Canvas(canvasframe)
  919.         frame = tkinter.Frame(can)
  920.         scrollbar = tkinter.Scrollbar(canvasframe,orient="vertical",command=can.yview)
  921.         can.configure(yscrollcommand=scrollbar.set)
  922.         scrollbar.pack(side="right",fill="y")
  923.         can.pack(side="left")
  924.         can.create_window((0,0),window=frame,anchor="nw")
  925.         frame.bind("<Configure>",scrollfunc)
  926.         submitbutton = tkinter.ttk.Button(self.selectorwindow,text="Submit",command = lambda: senddata(parent))
  927.         submitbutton.place(x=200,y=237.5,anchor="s",height=30)
  928.         a=0
  929.         print(data)
  930.         controller = parent
  931.         self.absent = []
  932.         self.score = []
  933.         self.tips = []
  934.         tkinter.Label(frame,text="Rank").grid(row=a,column=0)
  935.         tkinter.Label(frame,text="Name").grid(row=a,column=1)
  936.         tkinter.Label(frame,text="Absent/Civvies?").grid(row=a,column=3)
  937.         # civvies = colloquial name for cilivian clothing
  938.         # on other official programs, it is also used in this form
  939.         tkinter.Label(frame,text="Score").grid(row=a,column=4)
  940.         tkinter.Label(frame,text="To improve").grid(row=a,column=5)
  941.        
  942.         for i in data:
  943.             a+=1
  944.             tkinter.Label(frame,text=i[0]).grid(row=a,column=0)
  945.             tkinter.Label(frame,text=i[1]).grid(row=a,column=1)
  946.             tkinter.Label(frame,text=i[2]).grid(row=a,column=2)
  947.             name = i[0]+" "+i[1]+" "+i[2]
  948.             self.absent.append(tkinter.BooleanVar())
  949.             self.absent[-1].set(False)
  950.             tkinter.Checkbutton(frame,variable=self.absent[-1]).grid(row=a,column=3)
  951.             self.score.append(tkinter.Spinbox(frame,from_=0,to=6))
  952.             self.score[-1].grid(row=a,column=4)
  953.             self.tips.append(tkinter.StringVar())
  954.             self.tips[-1].set("Beret")
  955.             tkinter.OptionMenu(frame,self.tips[-1],"Beret","Shirt","Brassard","Trousers","Shoes","Turnout").grid(row=a,column=5)
  956.             print("button",i,":",i[3])
  957.        
  958.        
  959.            
  960.            
  961.            
  962.            
  963.            
  964. class UserOrgPage(tkinter.Frame,SquadBot):
  965.     def __init__(self,parent,controller):
  966.         tkinter.Frame.__init__(self,parent)
  967.         self.createImages() # creates array of images
  968.         self.configure(bg=self.palette["bgblue"])
  969.         colourbar = tkinter.Frame(self,background=self.palette["darkblue"])
  970.         colourbar.place(x=0,y=0,width=700,height=90,anchor="nw")
  971.         logoutbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Log Out",
  972.                                       fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.logout())
  973.         logoutbutton.place(height=50,width=100,x=680,y=45,anchor="e")
  974.  
  975.         mainscreenbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Back",
  976.                                           fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.showPage(MainPage,UserOrgPage))
  977.         mainscreenbutton.place(height=50,width=100,x=560,y=45,anchor="e")
  978.  
  979.         crestlbl = tkinter.Label(self,image=self.images["smallcrest"],background=self.palette["darkblue"])
  980.         crestlbl.place(x=0,y=0,anchor="nw",width=99,height=135)
  981.         pagelbl = tkinter.Label(colourbar,text="User Management",font=("Arial Black","20","bold"),foreground="white",background=self.palette["darkblue"])
  982.         pagelbl.place(y=45,x=100,anchor="w")
  983.         # above code is the same setup as other pages
  984.  
  985.        
  986.         useraddframe = tkinter.Frame(self,background = self.palette["afb"])
  987.         useraddframe.place(x=10,y=145,anchor="nw",width=375,height=300)
  988.         # creates frame to add new user
  989.  
  990.         newubutton = tkinter.Button(useraddframe,text="Add new user",command=lambda: self.addnewuser(controller))
  991.         newubutton.place(x=187.5,y=260,height=25,width=80,anchor="n")
  992.  
  993.         forenamelbl = tkinter.Label(useraddframe,text="Forename:",bg=self.palette["afb"])
  994.         forenamelbl.place(x=25,y=15,anchor="nw")
  995.         self.forenamevar = tkinter.StringVar()
  996.         self.forenamevar.trace_add("write", lambda x,y,z: self.change_text(var=self.forenamevar))
  997.         self.forenameentry = tkinter.Entry(useraddframe,text=self.forenamevar)
  998.         self.forenameentry.place(x=100,y=40,anchor="n",width=150)
  999.         self.usernamevar = tkinter.StringVar()
  1000.         self.usernamevar.trace_add("write", lambda x,y,z: self.change_text(var=self.usernamevar))
  1001.         usernamelbl = tkinter.Label(useraddframe,text="Username:",bg=self.palette["afb"])
  1002.         usernamelbl.place(x=200,y=15,anchor="nw")
  1003.         self.usernameentry = tkinter.Entry(useraddframe,text = self.usernamevar)
  1004.         self.usernameentry.place(x=275,y=40,anchor="n",width=150)
  1005.        
  1006.         surnamelbl = tkinter.Label(useraddframe,text="Surname:",bg=self.palette["afb"])
  1007.         surnamelbl.place(x=25,y=65,anchor="nw")
  1008.         self.surnamevar = tkinter.StringVar()
  1009.         self.surnamevar.trace_add("write", lambda x,y,z: self.change_text(var=self.surnamevar))
  1010.         self.surnameentry = tkinter.Entry(useraddframe,text=self.surnamevar)
  1011.         self.surnameentry.place(x=100,y=90,width=150,anchor="n")
  1012.         passwordlbl = tkinter.Label(useraddframe,text="Password:",bg=self.palette["afb"])
  1013.         passwordlbl.place(x=200,y=65,anchor="nw")
  1014.         self.passwordvar = tkinter.StringVar()
  1015.         self.passwordvar.trace_add("write", lambda x,y,z: self.change_text(var=self.passwordvar))
  1016.         self.passwordentry = tkinter.Entry(useraddframe,text=self.passwordvar)
  1017.         self.passwordentry.place(x=275,y=90,anchor="n",width=150)
  1018.         self.pwordcheckvar = tkinter.StringVar()
  1019.         self.pwordcheckvar.trace_add("write", lambda x,y,z: self.change_text(var=self.pwordcheckvar))
  1020.         passwordchecklbl = tkinter.Label(useraddframe,text="Confirm Password:",bg=self.palette["afb"])
  1021.         passwordchecklbl.place(x=200,y=115,anchor="nw")
  1022.         self.passwordcheck = tkinter.Entry(useraddframe,text=self.pwordcheckvar)
  1023.         self.passwordcheck.place(x=275,y=140,anchor="n",width=150)
  1024.        
  1025.         self.gender = tkinter.StringVar()
  1026.         genderlabel = tkinter.Label(useraddframe,text="Gender:",bg=self.palette["afb"])
  1027.         genderlabel.place(x=25,y=120,anchor="nw")
  1028.         genderentry = tkinter.OptionMenu(useraddframe,self.gender,"Male","Female")
  1029.         genderentry.configure(highlightbackground=self.palette["afb"])
  1030.         genderentry.place(x=100,y=115,anchor="nw",width=75)
  1031.  
  1032.         self.flight = tkinter.StringVar()
  1033.         flightlabel = tkinter.Label(useraddframe,text="Flight:",bg=self.palette["afb"])
  1034.         flightlabel.place(x=25,y=155,anchor="nw")
  1035.         flightentry = tkinter.OptionMenu(useraddframe,self.flight,"A","B","T")
  1036.         flightentry.configure(highlightbackground=self.palette["afb"])
  1037.         flightentry.place(x=100,y=150,anchor="nw",width=75)
  1038.  
  1039.         self.rank = tkinter.StringVar()
  1040.         ranklabel = tkinter.Label(useraddframe,text="Rank:",bg=self.palette["afb"])
  1041.         ranklabel.place(x=25,y=190,anchor="nw")
  1042.         rankentry = tkinter.OptionMenu(useraddframe,self.rank,"Cdt","Cpl","Sgt","FS","CWO")
  1043.         rankentry.configure(highlightbackground=self.palette["afb"])
  1044.         rankentry.place(x=100,y=185,anchor="nw",width=75)
  1045.        
  1046.         def changerankoptions():    # changes the rank options if the user is a staff member, as staff have different ranks to cadets
  1047.             print("rankchanging")
  1048.             cadet = staff.get()
  1049.             print(cadet)
  1050.             staff_ranks = ("CI","SI","Sgt (ATC)","FS (ATC)","WO (ATC)","Plt Off","Fg Off","Flt Lt","Sqn Ldr","Wg Cdr","Gp Capt")
  1051.             cadet_ranks = ("Cdt","Cpl","Sgt","FS","CWO")
  1052.             rankentry["menu"].delete(0,"end")
  1053.             flightentry["menu"].delete(0,"end")
  1054.             if cadet:
  1055.                 for i in staff_ranks:
  1056.                     rankentry["menu"].add_command(label=i,command=tkinter._setit(self.rank, i))
  1057.                 flightentry["menu"].add_command(label="S",command=tkinter._setit(self.flight,"S"))
  1058.                 self.flight.set("S")
  1059.                 self.rank.set("CI")
  1060.             else:
  1061.                 for i in cadet_ranks:
  1062.                     rankentry["menu"].add_command(label=i,command=tkinter._setit(self.rank, i))
  1063.                 for i in ("A","B","T"):
  1064.                     flightentry["menu"].add_command(label=i,command=tkinter._setit(self.flight, i))
  1065.                 self.flight.set("A")
  1066.                 self.rank.set("Cdt")
  1067.                
  1068.         stafflbl = tkinter.Label(useraddframe,text="Staff? :",bg=self.palette["afb"])
  1069.         stafflbl.place(x=200,y=190)
  1070.         staff = tkinter.BooleanVar()
  1071.         staff.set(False)
  1072.         staffbtn = tkinter.Checkbutton(useraddframe,variable=staff,command=lambda:changerankoptions())
  1073.         staffbtn.place(x=275,y=190)
  1074.        
  1075.         doblabel = tkinter.Label(useraddframe,text="D.O.B:",bg=self.palette["afb"])
  1076.         doblabel.place(x=25,y=225,anchor="nw")
  1077.         self.month = tkinter.StringVar()
  1078.         self.month.set("Jan")
  1079.         self.dayentry = tkinter.Spinbox(useraddframe,from_=1,to=31)
  1080.         self.dayentry.place(x=103,y=220,width=50,height=25)
  1081.         self.monthdict = {"Jan":1,"Feb":2,"Mar":3,"Apr":4,"May":5,"Jun":6,"Jul":7,"Aug":8,"Sep":9,"Oct":10,"Nov":11,"Dec":12}
  1082.         monthentry = tkinter.OptionMenu(useraddframe,self.month,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec")
  1083.         monthentry.configure(highlightbackground=self.palette["afb"],indicatoron=False)
  1084.         monthentry.place(x=188,y=218,width=60,height=30,anchor="n")
  1085.         self.year = tkinter.StringVar()
  1086.         self.year.set("2000")
  1087.         self.yearentry = tkinter.Spinbox(useraddframe,from_=1930,to=int(datetime.datetime.today().strftime("%Y"))-11,textvariable=self.year)
  1088.         self.yearentry.place(x=223,y=220,width=50,height=25)
  1089.         # above code creates buttons and boxes to allows entry of a new user
  1090.  
  1091.         manageuserbtn = tkinter.Button(self,text="Manage Users",command=lambda:self.manageusers(controller),font=("Arial Black",14))
  1092.         manageuserbtn.place(x=420,y=185,width=250,height=50,anchor="w")
  1093.         controller.conn.send("rr".encode())
  1094.         response = controller.conn.recv(1024).decode()
  1095.         data = json.loads(response)
  1096.         officernumber = staffnumber = nconumber = cadetnumber = 0
  1097.         for i in data:
  1098.             rank = i[0]
  1099.             if rank in ("Plt Off","Fg Off","Flt Lt","Sqn Ldr","Wg Cdr","Gp Capt"):
  1100.                 officernumber+=1
  1101.             elif rank in ("CI","SI","Sgt (ATC)","FS (ATC)","WO (ATC)"):
  1102.                 staffnumber+=1
  1103.             elif rank in ("Cpl","Sgt","FS","CWO"):
  1104.                 nconumber+=1
  1105.             elif rank == "Cdt":
  1106.                 cadetnumber+=1
  1107.                 # counts total number of users to display how many of each type there are
  1108.         usernoframe = tkinter.Frame(self,background = self.palette["afb"])
  1109.         usernoframe.place(x=420,y=245,anchor="nw",width=250,height=200)
  1110.         usernotitle = tkinter.Label(usernoframe,text="Users",background=self.palette["afb"],foreground="white",font=("Arial Black","15","underline"))
  1111.         noofusers = tkinter.Label(usernoframe,text="""
  1112. Officers:       {offno}
  1113. Other Staff:    {staffno}
  1114. NCOs:           {ncono}
  1115. Cadets:         {cadetno}""".format(offno=officernumber,staffno=staffnumber,ncono=nconumber,cadetno=cadetnumber)
  1116.                                   ,background = self.palette["afb"],foreground="white",font=("Arial Black","12"),justify="left")
  1117.         usernotitle.place(x=125,y=10,anchor="n")
  1118.         noofusers.place(x=125,y=50,anchor="n")
  1119.         # displays number of users
  1120.  
  1121.  
  1122.        
  1123.     def manageusers(self,parent):
  1124.         parent.conn.send("d".encode())
  1125.         # client wishes to change details of a user
  1126.         endofdata = False
  1127.         data=""
  1128.         while not endofdata:
  1129.             received = parent.conn.recv(1024)
  1130.             decoded = received.decode()
  1131.             print("received:",decoded)
  1132.             data = data.join(decoded)
  1133.             if data[-1] == ">":
  1134.                 endofdata = True
  1135.         jsondata = data[1:-1]
  1136.         data = json.loads(jsondata)
  1137.         # above code receives data and decodes it to usable format
  1138.         for i in data:
  1139.             print(i)
  1140.         self.managementwindow = tkinter.Toplevel()
  1141.         self.managementwindow.geometry("400x200+200+200")
  1142.         self.managementwindow.tk.call('wm', 'iconbitmap', self.managementwindow._w, "resources/crest.ico")
  1143.         self.managementwindow.configure(bg=self.palette["bgblue"])
  1144.         self.managementwindow.grab_set()
  1145.         # creates extra window to select users to edit
  1146.         def scrollfunc(event):
  1147.             can.configure(scrollregion=can.bbox("all"),width=383,height=200)
  1148.         canvasframe = tkinter.Frame(self.managementwindow,relief="groove",width=383,height=200)
  1149.         canvasframe.place(x=0,y=0)
  1150.        
  1151.         can = tkinter.Canvas(canvasframe)
  1152.         frame = tkinter.Frame(can)
  1153.         scrollbar = tkinter.Scrollbar(canvasframe,orient="vertical",command=can.yview)
  1154.         can.configure(yscrollcommand=scrollbar.set)
  1155.         scrollbar.pack(side="right",fill="y")
  1156.         can.pack(side="left")
  1157.         can.create_window((0,0),window=frame,anchor="nw")
  1158.         frame.bind("<Configure>",scrollfunc)
  1159.         a=0
  1160.         print(data)
  1161.         controller = parent
  1162.         def selectuser(uid,parent,num):
  1163.             option = self.selection[num-1].get()
  1164.             print(option,uid)
  1165.             if option == "Delete User": # this code allows a user to be deleted
  1166.                 checking = tkinter.messagebox.askquestion("Delete User","Are you sure you want to delete this user? It cannot be undone")
  1167.                 if checking == "yes":
  1168.                     parent.conn.send("px{userid}".format(userid=uid).encode())
  1169.                     response = parent.conn.recv(1024).decode()
  1170.                     if response == "UFD":
  1171.                         tkinter.messagebox.showinfo("Success","User Successfully Deleted")
  1172.                         self.managementwindow.destroy()
  1173.                     else:
  1174.                         tkinter.messagebox.showerror("Error","An error occured. Try again")
  1175.                        
  1176.             elif option == "Reset Password":    # this code resets a user's password and receoves a randomly-generated one
  1177.                 checking = tkinter.messagebox.askquestion("Reset Password","Are you sure you want to reset this user's password?")
  1178.                 if checking == "yes":
  1179.                     parent.conn.send("pp{userid}".format(userid=uid).encode())
  1180.                     npw = parent.conn.recv(1024).decode()
  1181.                     print(npw)
  1182.                     print(npw[:3])
  1183.                     if npw[:3] == "npw":
  1184.                         tkinter.messagebox.showinfo("New Password","The new password for this user is: {pw}\nIt is strongly advised they write this down.".format(pw=npw[3:]))
  1185.             elif option == "Edit User":
  1186.                 usereditwindow = tkinter.Toplevel(parent)
  1187.                 # creates a separate window to the main program
  1188.                 usereditwindow.grab_set()
  1189.                 # makes it so that the main window cannot be interacted with unil this window has been closed
  1190.                 usereditwindow.geometry("200x140")
  1191.                 # setting size of window
  1192.                 usereditwindow.resizable(0,0)
  1193.                 # preventing the window from being resized
  1194.                 userlbl = tkinter.Label(usereditwindow,text="Which attribute would \nyou like to change?")
  1195.                 userlbl.place(x=100,y=0,anchor="n")
  1196.                 attribute = tkinter.StringVar()
  1197.                 newval = tkinter.StringVar()
  1198.                 newval.trace_add("write", lambda x,y,z: self.change_text(var=newval,limit="alpha"))
  1199.                 attribute.set("Forename")
  1200.                 attributebox = tkinter.OptionMenu(usereditwindow,attribute,"Forename","Surname","Gender","Rank","Flight","Username")
  1201.                 attributebox.place(x=100,y=40,anchor="n")
  1202.                 self.entrywidg = []
  1203.                 entrybox = tkinter.Entry(usereditwindow,text=newval)
  1204.                 entrybox.place(x=100,y=70,anchor="n")
  1205.                 submit = tkinter.Button(usereditwindow,text="Submit Changes",command = lambda: submitdata())
  1206.                 submit.place(x=100,y=100,anchor="n")
  1207.                 def submitdata():
  1208.                     print("helllllllo")
  1209.                     ranks = ("Cdt","Cpl","Sgt","FS","CWO","CI","SI","Sgt (ATC)","FS (ATC)","WO (ATC)","Plt Off","Fg Off","Flt Lt","Sqn Ldr","Wg Cdr","Gp Capt")
  1210.                     varchanging = attribute.get()
  1211.                     newdata = entrybox.get()
  1212.                     if varchanging == "Gender" and len(newdata)!=1:
  1213.                         tkinter.messagebox.showerror("Error","Gender must be 1 character")
  1214.                         return 0
  1215.                     elif varchanging == "Rank" and newdata not in ranks:
  1216.                         tkinter.messagebox.showerror("Error","Not a valid rank. Valid ranks are:\n Cdt, Cpl, Sgt, FS, CWO,\n CI, SI, Sgt (ATC), WO (ATC), Plt Off,\n Fg Off, Flt Lt, Sqn Ldr, Wg Cdr, Gp Capt")
  1217.                         return 0
  1218.                     elif newdata == "":
  1219.                         tkinter.messagebox.showerror("Error","Data field cannot be empty")
  1220.                         return 0
  1221.                     parent.conn.send("pd{cid}+{typ}+{dat}".format(typ=varchanging,dat=newdata,cid=uid).encode())
  1222.                     response = parent.conn.recv(1024).decode()
  1223.                     if response == "DCS":
  1224.                         tkinter.messagebox.showinfo("Success","Details successfully changed")
  1225.                         usereditwindow.destroy()
  1226.                     elif response == "UAE":
  1227.                         tkinter.messagebox.showerror("Error","That username already exists")
  1228.         self.selection = []
  1229.         tkinter.Label(frame,text="Rank").grid(row=a,column=0)
  1230.         tkinter.Label(frame,text="Name").grid(row=a,column=1)
  1231.         tkinter.Label(frame,text="Option").grid(row=a,column=3)
  1232.         self.buttons = []
  1233.         for i in data:
  1234.             a+=1
  1235.             tkinter.Label(frame,text=i[0]).grid(row=a,column=0)
  1236.             tkinter.Label(frame,text=i[1]).grid(row=a,column=1)
  1237.             tkinter.Label(frame,text=i[2]).grid(row=a,column=2)
  1238.             name = i[0]+" "+i[1]+" "+i[2]
  1239.             self.selection.append(tkinter.StringVar())
  1240.             self.selection[-1].set("Edit User")
  1241.             tkinter.OptionMenu(frame,self.selection[-1],"Edit User","Reset Password","Delete User").grid(row=a,column=3)
  1242.             print("button",i,":",i[3])
  1243.             self.buttons.append(tkinter.Button(frame,command = lambda x=i[3],y=a: selectuser(x,parent,y),text="Select"))
  1244.             self.buttons[-1].grid(row=a,column=4)
  1245.     def addnewuser(self,parent):
  1246.         forename = self.forenameentry.get()
  1247.         surname = self.surnameentry.get()
  1248.         username = self.usernameentry.get()
  1249.         password = self.passwordentry.get()
  1250.         password2 = self.passwordcheck.get()
  1251.         flight = self.flight.get()
  1252.         rank = self.rank.get()
  1253.         gender = self.gender.get()
  1254.         if gender == "Male":
  1255.             gender = "M"
  1256.         else:
  1257.             gender = "F"
  1258.         dob = self.getdob()
  1259.         if password == password2:
  1260.             if len(password)>=8:
  1261.                 userdata = (forename,surname,rank,flight,gender,dob,username,password)
  1262.                 jsondata = json.dumps(userdata)
  1263.                 sendingdata = "su" + jsondata
  1264.                 parent.conn.send(sendingdata.encode())
  1265.                 response = parent.conn.recv(1024).decode()
  1266.                 if response == "UAS":
  1267.                     self.forenameentry.delete(0,"end")
  1268.                     self.surnameentry.delete(0,"end")
  1269.                     self.usernameentry.delete(0,"end")
  1270.                     self.passwordentry.delete(0,"end")
  1271.                     self.passwordcheck.delete(0,"end")
  1272.                    
  1273.                     tkinter.messagebox.showinfo("Success","User successfully added")
  1274.                 elif response == "UAE":
  1275.                     tkinter.messagebox.showerror("Error","That username is taken")
  1276.             else:
  1277.                 tkinter.messagebox.showerror("Error","Password must be 8 characters or longer")
  1278.         else:
  1279.             tkinter.messagebox.showerror("Error","Passwords do not match")
  1280.     def checkcontent(string):
  1281.         pattern = ""
  1282.     def getdob(self):
  1283.         day = self.dayentry.get()
  1284.         month = self.month.get()
  1285.         monthnum = self.monthdict[month]
  1286.         try:
  1287.             print(str(monthnum)[1])
  1288.             monthnum = str(monthnum)
  1289.         except:
  1290.             monthnum = "0"+str(monthnum)
  1291.         year = self.yearentry.get()
  1292.         datestr = str(year)+"-"+str(monthnum)+"-"+str(day)
  1293.         print(datestr)
  1294.         return datestr
  1295.        
  1296. class Notification(tkinter.Toplevel,SquadBot):
  1297.     def __init__(self,parent,notif):
  1298.         tkinter.Toplevel.__init__(self,parent)
  1299.         self.geometry("400x210+%d+%d"%(screensize[0]-265,screensize[1]-215))
  1300.         self.overrideredirect(1)
  1301.         self.attributes("-topmost",1)
  1302.         notification = notif
  1303.         self.configure(borderwidth=5,relief="ridge")
  1304.         tkinter.Label(self,text=notification,anchor="nw",justify="left",font=("TkDefaultFont 10")).place(x=5,y=5,anchor="nw",height=110,width=240)
  1305.         self.after(60000,self.destroy)
  1306.         self.deiconify()
  1307.         self.title("GOODBYE")
  1308.  
  1309. class Graph(tkinter.Canvas):
  1310.     def __init__(self,parent,width,height,dataunclean,xcoord,ycoord,anch,**kwargs):
  1311.         tkinter.Canvas.__init__(self,parent)
  1312.         # initialises the tkinter canvas class to provide a drawing surface
  1313.                                                                
  1314.         self.configure(width=width,height=height)
  1315.         # setting width and height of canvas to arguments provided
  1316.                                                                
  1317.         self.create_line(50,(height-50),(width-50),(height-50),width=2)
  1318.         self.create_line(50,50,50,height-50,width=2)
  1319.         # drawing the axes of the graph
  1320.        
  1321.         graph_width = width-100
  1322.         graph_height = height-100
  1323.         # setting width of the graph within the canvas
  1324.        
  1325.         self.place(x=xcoord,y=ycoord,anchor=anch)
  1326.         # placing the canvas at the coordinates provided in the arguments
  1327.        
  1328.         if isinstance(dataunclean,dict):
  1329.         # tests if dataunclean is a dictionary
  1330.         # dataunclean is the raw data coming, unclean as it may contain None or string values
  1331.             a = 0
  1332.             uncleanvalues = list(dataunclean.values())
  1333.             # creates list from dataunclean's values
  1334.             data = []
  1335.             for i in uncleanvalues:
  1336.                 if isinstance(i,int):
  1337.                     data.append(uncleanvalues[a])
  1338.                     # appends if value is an integer
  1339.                 elif isinstance(i,float):
  1340.                     data.append(uncleanvalues[a])
  1341.                     # appends if value is a float
  1342.                 else:
  1343.                     try:
  1344.                         data.append((uncleanvalues[a-1]+uncleanvalues[a+1])/2)
  1345.                         # if not integer, take average values of weeks before and after
  1346.                     except IndexError:
  1347.                         data.append(uncleanvalues[a-1])
  1348.                         # if week after does not exist (latest week value), take value of week before
  1349.                     except TypeError:
  1350.                         data.append(uncleanvalues[0])
  1351.                         # if week before and after do not exist, set value as first recorded value
  1352.                         # there will always be a first recorded value, as users will only be added when they are present, and therefore will have a score
  1353.                        
  1354.                 a+=1
  1355.             print("DAT:",data)
  1356.             # data is now 'cleaned' - all the non-numerical values have been removed
  1357.             xinc = graph_width/(len(data)-1)
  1358.             # sets the increment on the x axis as the increment required to fit all data within the width of the graph
  1359.             if "maxi" in kwargs:
  1360.                 # custom maximum value can be set if data range may not reach the highest score required for the data
  1361.                 yinc = graph_height/kwargs["maxi"]
  1362.                 # setting the y axis increment to fit all the data in the height set
  1363.             else:
  1364.                 yinc = graph_height/max(data)
  1365.                 # take the maximum value of the data as the highest value the graph should show
  1366.             values = list(data)
  1367.             # taking the values from the cleaned data
  1368.             keys = list(dataunclean.keys())
  1369.             for i in range(math.ceil((graph_height/yinc)+0.5)):
  1370.                 self.create_line(45,(height-50)-yinc*i,50,(height-50)-yinc*i,width=2)   # y axis incremented lines
  1371.                 self.create_text(43,(height-50)-yinc*i,text=i,anchor="e")               # y axis legend
  1372.             for i in range(len(keys)):
  1373.                 self.create_line(50+i*xinc,height-50,50+i*xinc,height-40,width=2)       # x axis incremented lines
  1374.                 self.create_text(50+i*xinc,height-40,anchor="e",text=keys[i],angle=45,font=("TkDefaultFont","7"))  # x axis legend
  1375.             a=0
  1376.             total = 0
  1377.             if "delay" in kwargs:
  1378.                 interval = kwargs["delay"]/len(data)
  1379.                 # sets the delay of graph being drawn to provided delay
  1380.             else:
  1381.                 interval = 1/len(data)
  1382.                 # this draws the graph in 1 second, as it is more eye-catching, and makes the user notice it has been updated
  1383.             for i in values[:-1]:
  1384.                 self.create_line(50+a*xinc,(height-50)-(i*yinc),50+(a+1)*xinc,(height-50)-(values[a+1]*yinc),width=2)
  1385.                 # draws a line between points of data
  1386.                 a+=1
  1387.                 time.sleep(interval)
  1388.                 # pauses before drawing the next line
  1389.                 if interval != 0:
  1390.                     parent.update()
  1391.                     # if graph is not updated, line is not shown until end
  1392.                     # if interval is 0, there is no need to update and display lines
  1393.                 total += i
  1394.            
  1395.         elif isinstance(dataunclean,list):
  1396.             # code below is similar to code above, but works with a list that does not provide any keys to place on y axis
  1397.             print("22222")
  1398.             print(dataunclean)
  1399.             a = 0
  1400.             data = []
  1401.             for i in dataunclean:
  1402.                 if isinstance(i,int):
  1403.                     data.append(dataunclean[a])
  1404.                 else:
  1405.                     try:
  1406.                         data.append((dataunclean[a-1]+dataunclean[a+1])/2)
  1407.                     except IndexError:
  1408.                         data.append(dataunclean[a-1])
  1409.                     except TypeError:
  1410.                         data.append(dataunclean[0])
  1411.                 a+=1
  1412.             print(data)
  1413.             xinc = graph_width/(len(data)-1)
  1414.             if "maxi" in kwargs:
  1415.                 yinc = graph_height/kwargs["maxi"]
  1416.             else:
  1417.                 yinc = graph_height/max(data)
  1418.             values = list(data)
  1419.             for i in range(math.ceil((graph_height/yinc)+0.5)):
  1420.                 self.create_line(45,(height-50)-yinc*i,50,(height-50)-yinc*i,width=2)   # y axis lines
  1421.                 self.create_text(43,(height-50)-yinc*i,text=i,anchor="e")
  1422.             for i in range(len(data)):
  1423.                 self.create_line(50+i*xinc,height-50,50+i*xinc,height-40,width=2)       # x axis lines
  1424.                 self.create_text(42+i*xinc,height-30,anchor="n",text=i,angle=90)
  1425.             a=0
  1426.             total = 0
  1427.             if "delay" in kwargs:
  1428.                 interval = kwargs["delay"]/len(data)
  1429.             else:
  1430.                 interval = 1/len(data)
  1431.             for i in values[:-1]:
  1432.                 self.create_line(50+a*xinc,(height-50)-(i*yinc),50+(a+1)*xinc,(height-50)-(values[a+1]*yinc),width=2)
  1433.                 a+=1
  1434.                
  1435.                 time.sleep(interval)
  1436.                 if interval != 0:
  1437.                     parent.update()
  1438.                 total += i
  1439.                
  1440.         avg = round(total/len(values),2)
  1441.         # average value is calculated
  1442.         try:
  1443.             if avg <= kwargs["goal"]:
  1444.                 self.create_text(width/2,25,text="Average Score: {av}".format(av=avg),fill="red",font=("TkDefaultFont","10","bold"))
  1445.                 self.create_line(50,(height-50)-(avg*yinc),50+graph_width,(height-50)-(avg*yinc),dash=(6,4),fill="red",width=5)
  1446.                 # creates a label for the average score
  1447.                 # if the average score is less than 3, label is turned red to draw attention to it
  1448.             elif kwargs["goal"]+(max(data)*0.1) >= avg:
  1449.                 self.create_text(width/2,25,text="Average Score: {av}".format(av=avg),fill="orange",font=("TkDefaultFont","10","bold"))
  1450.                 self.create_line(50,(height-50)-(avg*yinc),50+graph_width,(height-50)-(avg*yinc),dash=(6,4),fill="orange",width=5)
  1451.             else:
  1452.                 self.create_text(width/2,25,text="Average Score: {av}".format(av=avg),fill="green",font=("TkDefaultFont","10","bold"))
  1453.                 self.create_line(50,(height-50)-(avg*yinc),50+graph_width,(height-50)-(avg*yinc),dash=(6,4),fill="green",width=5)
  1454.                 # if not more than 3, label is normal text
  1455.         except:
  1456.             self.create_text(width/2,25,text="Average Score: {av}".format(av=avg))
  1457.             self.create_line(50,(height-50)-(avg*yinc),50+graph_width,(height-50)-(avg*yinc),dash=(6,4),width=5)
  1458.  
  1459.         if "title" in kwargs:
  1460.             self.create_text(width/2,10,text=kwargs["title"])
  1461.             # creates title if there is a title provided
  1462.         parent.update()
  1463.        
  1464.        
  1465.  
  1466.  
  1467.  
  1468. window = SquadBot()
  1469. window.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement