Commit iniziale
This commit is contained in:
commit
81efbcacf2
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.DS_Store
|
||||||
|
__pycache__/
|
271
Dropchat.py
Normal file
271
Dropchat.py
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
import tkinter, tkinter.filedialog, tkinter.messagebox, tkinter.simpledialog
|
||||||
|
import tempfile, json, datetime, re
|
||||||
|
|
||||||
|
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.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()
|
||||||
|
else:
|
||||||
|
self.file = ""
|
||||||
|
|
||||||
|
#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("<KeyPress>", "break")
|
||||||
|
self.sidebar.bind("<Double-Button-1>", self.cambiafile)
|
||||||
|
self.sidebar.bind("<Button-2>", self.mostramenu)
|
||||||
|
self.casella.bind("<Return>", 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("<<Cut>>"))
|
||||||
|
menu.add_command(label = "Copia", command = lambda: finestra.focus_get().event_generate("<<Copy>>"))
|
||||||
|
menu.add_command(label = "Incolla", command = lambda: finestra.focus_get().event_generate("<<Paste>>"))
|
||||||
|
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):
|
||||||
|
file = tkinter.filedialog.askopenfilename(title = "Scegli un file...", message = "Apri una conversazione esistente.", **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):
|
||||||
|
file = tkinter.filedialog.asksaveasfilename(title = "Crea un file...", message = "Scegli il nome della nuova conversazione.", **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()
|
10
License.txt
Normal file
10
License.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
* Dropchat
|
||||||
|
*
|
||||||
|
* Chat tramite Dropbox in python 3.
|
||||||
|
*
|
||||||
|
* Dual licensed under the MIT and GPL licenses:
|
||||||
|
* http://www.opensource.org/licenses/mit-license.php
|
||||||
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
|
*
|
||||||
|
* @author Michele Guerini Rocco aka Rnhmjoj
|
||||||
|
* @since 2013
|
31
README.md
Normal file
31
README.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Dropchat
|
||||||
|
========
|
||||||
|
|
||||||
|
Chat tramite Dropbox in python 3.
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
### Informazioni
|
||||||
|
Un chat client per chattare tramite le cartelle condivise di Dropbox.
|
||||||
|
Realizzato usando python 3 e l'interfaccia Tk.
|
||||||
|
|
||||||
|
### Istruzioni
|
||||||
|
Primo utilizzo:
|
||||||
|
|
||||||
|
Dalla barra dei menu selezionare:
|
||||||
|
* Profilo -> "Nome Utente" ed immettere il proprio nome.
|
||||||
|
* Conversazione -> "Nuovo file" o "Apri file.." e scegliere un file di testo
|
||||||
|
Scrivere un messaggio nella casella di testo e dare invio per immetterlo nel file.
|
||||||
|
Una volta scritto il file viene sincronizzato con Dropbox in modo che altri possano rispondere.
|
||||||
|
|
||||||
|
I file recenti vengono elencati nella barra laterale e l'ultimo utilizzato viene riaperto all'avvio.
|
||||||
|
Per cancellare definitivamente un file basta spostarlo nel cestino mentre per rimuovere il riferimento dall'applicazione fare click destro sul file nella barra laterale e selezionare "Cancella".
|
||||||
|
|
||||||
|
### Conversione
|
||||||
|
È incluso un setup.py per convertire Dropchat.py in un binario tramite py2app o py2exe.
|
||||||
|
Utilizzo:
|
||||||
|
|
||||||
|
python setup.py py2app
|
||||||
|
|
||||||
|
o
|
||||||
|
|
||||||
|
python setup.py py2exe
|
1
preferenze.json
Normal file
1
preferenze.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Chat": [], "Utente": "Nomeutente", "Chiave": "chiave.key", "Geometria": "800x500+500+250"}
|
Loading…
Reference in New Issue
Block a user