import tkinter, tkinter.filedialog, tkinter.messagebox, tkinter.simpledialog import tempfile, json, datetime, re, sys class Text(tkinter.Text): def __init__(self, *args, **kwargs): tkinter.Text.__init__(self, *args, **kwargs) def evidenzia(self, pattern, tag, inizio="1.0", fine="end", regex=True): inizio = self.index(inizio) fine = self.index(fine) self.mark_set("matchStart", inizio) self.mark_set("matchEnd", inizio) self.mark_set("searchLimit", fine) occorrenze = tkinter.IntVar() while True: indice = self.search(pattern, "matchEnd", "searchLimit", count = occorrenze, regexp = regex) if indice == "": break self.mark_set("matchStart", indice) self.mark_set("matchEnd", "%s+%sc" % (indice, occorrenze.get())) self.tag_add(tag, "matchStart", "matchEnd") class applicazione(tkinter.Frame): def __init__(self, finestra): tkinter.Frame.__init__(self, finestra) finestra.iconify() #Variabili self.temp = tempfile.NamedTemporaryFile(mode = "w+t") self.testo = tkinter.StringVar() self.file = "" self.opzionifile = { "parent": finestra, "filetypes": [("text files", ".txt")], "defaultextension": ".txt", "initialfile": "file.txt" } self.opzionichat = { "font": ("Monaco", 13), "borderwidth": 2, "highlightthickness": 0 } #Gestione delle preferenze ed eventuali errori try: self.preferenze = json.load(open("preferenze.json")) except FileNotFoundError: tkinter.messagebox.showwarning("Dropchat", "File delle preferenze non trovato!", detail = "Preferenze di default ricostruite.") self.creapreferenze() try: self.cancellanontrovati() self.file = self.preferenze["Chat"][-1] except IndexError: if tkinter.messagebox.askquestion("Dropchat","Nessuna conversazione trovata.", detail = "Crearne una nuova ?") == "yes": self.nuovofile() #Gestione della finestra finestra.geometry(self.preferenze["Geometria"]) finestra.configure(background = "#a8a8a8") finestra.columnconfigure(1, weight=1) finestra.rowconfigure(0, weight=1) finestra.protocol('WM_DELETE_WINDOW', self.chiudi) finestra.deiconify() self.grid() #Inizzializzazione e loop self.cambiatitolo() self.widgets() self.leggi() self.loop() #Widget della finestra def widgets(self): self.menubar = tkinter.Menu(finestra) self.chat = Text(finestra, width = 100, height = 30, relief = "sunken", insertbackground = "#fff", **self.opzionichat) self.sidebar = tkinter.Listbox(finestra, width = 20, borderwidth = 0, background ="#dce0e8") self.casella = tkinter.Entry(finestra, textvariable = self.testo, **self.opzionichat) self.chat.grid(column = 1, row = 0, sticky = "nswe", pady = (6, 3), padx = 6) self.casella.grid(column = 1, row = 1, sticky = "nswe", pady = (3, 6), padx = 6) self.sidebar.grid(column = 0, row = 0, sticky = "nswe", rowspan = 2) #Bindings self.chat.bind("", "break") self.sidebar.bind("", self.cambiafile) self.sidebar.bind("", self.mostramenu) self.casella.bind("", self.scrivi) #Barra dei menu self.menubar = tkinter.Menu(self) menu = tkinter.Menu(self.menubar) #Primo menu self.menubar.add_cascade(label = "Conversazione", menu = menu) menu.add_command(label = "Nuovo file", command = self.nuovofile) menu.add_command(label = "Apri file...", command = self.aprifile) #Secondo menu menu = tkinter.Menu(self.menubar) self.menubar.add_cascade(label="Profilo", menu = menu) menu.add_command(label = "Nome utente", command = lambda: self.modificapreferenza("Utente", tkinter.simpledialog.askstring("Nome Utente", "Scrivi il nome:", initialvalue = self.preferenze["Utente"], parent = finestra))) menu.add_command(label = "Chiave", command = lambda: self.modificapreferenza("Chiave", tkinter.filedialog.askopenfilename(title = "Scegli un file...", message = "Apri una chiave di decodifica.", **self.opzionifile))) #Terzo menu menu = tkinter.Menu(self.menubar) self.menubar.add_cascade(label="Modifica", menu = menu) menu.add_command(label = "Taglia", command = lambda: finestra.focus_get().event_generate("<>")) menu.add_command(label = "Copia", command = lambda: finestra.focus_get().event_generate("<>")) menu.add_command(label = "Incolla", command = lambda: finestra.focus_get().event_generate("<>")) finestra.config(menu=self.menubar) #Menu contestuale 1 self.menu1 = tkinter.Menu(self) self.menu1.add_command(label = "Apri", command = self.cambiafile) self.menu1.add_command(label = "Cancella", command = self.cancellafile) self.menu1.add_separator() self.menu1.add_command(label = "Nuovo file", command = self.nuovofile) self.menu1.add_command(label = "Ricarica", command = lambda: self.sidebar.delete(0,"end")) #Menu contestuale 2 self.menu2 = tkinter.Menu(self) self.menu2.add_command(label = "Nuovo file", command = self.nuovofile) self.menu2.add_command(label = "Ricarica", command = lambda: self.sidebar.delete(0,"end")) #Legge il file dal buffer e lo scrive nella chat def leggi(self): self.aggiorna() self.temp.seek(0) self.chat.delete(0.0,"end") self.chat.insert("end", self.temp.read()) self.colora() #Scrive un messaggio nel file def scrivi(self, event): if self.file != "": with open(self.file, "a") as file: if self.testo.get() != "": riga = "[" + datetime.datetime.now().strftime("%d-%m-%y %H:%M") + "] " + self.preferenze["Utente"] + ": " + self.testo.get() + "\n" self.testo.set("") file.write(riga) #copia il file nel buffer def aggiorna(self): open(self.temp.name,"w").close() if self.file != "": self.temp.seek(0) with open(self.file) as testo: self.temp.write(testo.read()) def cambiatitolo(self): file = re.search("([^/]*)$", self.file) if self.file == "": finestra.title("Dropchat") else: finestra.title("Dropchat - " + file.group(0)) #Colora il testo della chat def colora(self): self.chat.tag_configure("data", foreground = "#005d8f") self.chat.tag_configure("nome", foreground = "#648f00") self.chat.tag_configure("altronome", foreground = "#de7a31") self.chat.evidenzia("\[\d+-\d+-\d+ \d+:\d+\]", "data") for nome in re.findall(" ([a-zA-Z]+): ", self.chat.get(0.0, "end")): if nome == self.preferenze["Utente"]: self.chat.evidenzia(nome, "nome") else: self.chat.evidenzia(nome, "altronome") #Gestisce i menu contestuali def mostramenu(self, event): self.sidebar.indice = self.sidebar.nearest(event.y) if self.sidebar.indice < 0: self.menu2.post(event.x_root, event.y_root) return self.sidebar.activate(self.sidebar.indice) _, offset, _, altezza = self.sidebar.bbox(self.sidebar.indice) if event.y > altezza + offset + self.sidebar.size(): self.menu2.post(event.x_root, event.y_root) else: self.menu1.post(event.x_root, event.y_root) #Scrive i file aperti nella sidebar def filerecenti(self): for x, file in enumerate(self.preferenze["Chat"]): file = " - " + re.search("([^/]*)$", file).group(0) if file not in self.sidebar.get(x): self.sidebar.insert(x, file) #Cancella il file selezionato nella sidebar def cancellafile(self): if self.preferenze["Chat"][self.sidebar.indice] == self.file: self.file = "" del self.preferenze["Chat"][self.sidebar.indice] json.dump(self.preferenze, open("preferenze.json", "w")) self.leggi() self.cambiatitolo() #Apre il file selezionato nella sidebar def cambiafile(self, _ = None): file = self.preferenze["Chat"][int(self.sidebar.curselection()[0])] if self.file != file: self.file = file self.leggi() self.cambiatitolo() #Apre un file def aprifile(self): if sys.platform == "darwin": file = tkinter.filedialog.askopenfilename(title = "Scegli un file...", message = "Apri una conversazione esistente.", **self.opzionifile) else: file = tkinter.filedialog.askopenfilename(title = "Scegli un file...", **self.opzionifile) if file not in self.preferenze["Chat"] and file != "": self.preferenze["Chat"] += file, json.dump(self.preferenze, open("preferenze.json", "w")) self.file = file self.leggi() self.cambiatitolo() #Crea un nuovo file e lo apre def nuovofile(self): if sys.platform == "darwin": file = tkinter.filedialog.asksaveasfilename(title = "Crea un file...", message = "Scegli il nome della nuova conversazione.", **self.opzionifile) else: file = tkinter.filedialog.asksaveasfilename(title = "Crea un file...", **self.opzionifile) if file != "": self.file = file file = open(self.file,"w") file.close() if self.file not in self.preferenze["Chat"]: self.preferenze["Chat"] += self.file, json.dump(self.preferenze, open("preferenze.json", "w")) self.leggi() self.cambiatitolo() #Cancella i file non trovati dalle preferenze def cancellanontrovati(self): for x, file in enumerate(self.preferenze["Chat"]): try: open(file) self.file = file except FileNotFoundError: del self.preferenze["Chat"][x] continue json.dump(self.preferenze, open("preferenze.json", "w")) #Ricrea le preferenze se vengono cancellate def creapreferenze(self): default = { "Utente": "Nomeutente", "Chat": ["chat.txt"], "Chiave": "chiave.key", "Geometria": "800x500+500+250" } json.dump(default,open("preferenze.json", "w")) self.preferenze = json.load(open("preferenze.json")) #Cambia una preferenze e la salva def modificapreferenza(self, chiave, preferenza): if preferenza != "": self.preferenze[chiave] = preferenza json.dump(self.preferenze, open("preferenze.json", "w")) #Salva la geometria della finestra e la chiude def chiudi(self): self.modificapreferenza("Geometria", finestra.geometry()) self.temp.close() finestra.destroy() #Loop principale def loop(self): self.filerecenti() self.leggi() self.after(200, self.loop) finestra = tkinter.Tk() app = applicazione(finestra) app.mainloop()