English translation

This commit is contained in:
Rnhmjoj 2014-01-17 15:27:08 +01:00
parent 48650d1c3d
commit 17536b6986
6 changed files with 250 additions and 326 deletions

View File

@ -1,59 +1,59 @@
import tkinter, tkinter.filedialog, tkinter.messagebox, tkinter.simpledialog
import tempfile, json, datetime, re, sys
import re
import sys
import tempfile
import json
import datetime
import tkinter
import tkinter.filedialog
import tkinter.messagebox
import tkinter.simpledialog
class Text(tkinter.Text):
"""
Tkinter Text Widget
Override che permette di evidenziare il contenuto tramite
espressioni regolari.
Override that allows to highlight words with regex.
"""
def __init__(self, *args, **kwargs):
tkinter.Text.__init__(self, *args, **kwargs)
def evidenzia(self, pattern, tag, inizio="1.0", fine="end", regex=True):
def highlight(self, pattern, tag, start="1.0", stop="end", regex=True):
"""
Evidenzia il testo selezionato da "pattern" e gli assegna
il tag "tag". Specificare "inizio" e "fine" per ristringere
il campo della ricerca e regex=False se non si utilizza un
espressione regolare.
Highlight text matched by "pattern" and apply it the tag "tag"
Specify "start" and "stop" in order to restrict the search and
regex=False if pattern is not a regex.
"""
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()
start = self.index(start)
stop = self.index(stop)
self.mark_set("matchStart", start)
self.mark_set("matchEnd", start)
self.mark_set("searchLimit", stop)
occurrences = tkinter.IntVar()
while True:
indice = self.search(
index = self.search(
pattern,
"matchEnd",
"searchLimit",
count=occorrenze,
count=occurrences,
regexp=regex
)
if indice == "":
if index == "":
break
self.mark_set("matchStart", indice)
self.mark_set("matchEnd", "%s+%sc" % (indice, occorrenze.get()))
self.mark_set("matchStart", index)
self.mark_set("matchEnd", "%s+%sc" % (index, occurrences.get()))
self.tag_add(tag, "matchStart", "matchEnd")
class Application(tkinter.Frame):
"""Application class"""
def __init__(self):
tkinter.Frame.__init__(self, window)
window.iconify()
class Applicazione(tkinter.Frame):
"""
Classe dell'applicazione
Inizializzarla con un finestra creata con Tk().
"""
def __init__(self, finestra):
tkinter.Frame.__init__(self, finestra)
finestra.iconify()
#Variabili
#Vars
self.temp = tempfile.TemporaryFile(mode="w+t")
self.testo = tkinter.StringVar()
self.text = tkinter.StringVar()
self.file = ""
self.opzionifile = {
"parent": finestra,
"parent": window,
"filetypes": [("text files", ".txt")],
"defaultextension": ".txt",
"initialfile": "file.txt"
@ -64,367 +64,296 @@ class Applicazione(tkinter.Frame):
"highlightthickness": 0
}
#Gestione delle preferenze
#pref management
try:
self.preferenze = json.load(open("preferenze.json"))
self.prefs = json.load(open("prefs.json"))
except FileNotFoundError:
tkinter.messagebox.showwarning(
"Dropchat",
"File delle preferenze non trovato!",
detail="Preferenze di default ricostruite."
)
self.creapreferenze()
"Preferences file non found!",
detail="Default preferences rebuilt.")
self.build_prefs()
#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()
#Gestione della window
window.geometry(self.prefs["geometry"])
window.configure(background="#a8a8a8")
window.columnconfigure(1, weight=1)
window.rowconfigure(0, weight=1)
window.protocol('WM_DELETE_WINDOW', self.close)
window.deiconify()
self.grid()
#Inizzializzazione
self.cambiatitolo()
self.set_title()
self.widgets()
self.leggi()
self.read()
#Gestione delle ultime conversazioni
try:
self.cancellanontrovati()
self.file = self.preferenze["Chat"][-1]
self.delete_not_found()
self.file = self.prefs["chat"][-1]
except IndexError:
risposta = tkinter.messagebox.askquestion(
response = tkinter.messagebox.askquestion(
"Dropchat",
"Nessuna conversazione trovata.",
detail="Crearne una nuova ?"
)
if risposta == "yes":
self.nuovofile()
"No conversations found.",
detail="Make a new one?")
if response == "yes":
self.new_file()
#Loop principale
self.loop()
#Widget della finestra
#Widget della window
def widgets(self):
"""
Creare e disegna i widgets della finestra.
Draw window widgets.
"""
self.menubar = tkinter.Menu(finestra)
self.chat = Text(
finestra,
width=100,
height=30,
self.menubar = tkinter.Menu(window)
self.chat = Text(window,
width=100, height=30,
relief="sunken",
insertbackground="#fff",
**self.opzionichat
)
**self.opzionichat)
self.sidebar = tkinter.Listbox(
finestra,
width=20,
window, width=20,
borderwidth=0,
background="#dce0e8"
)
self.casella = tkinter.Entry(
finestra,
textvariable=self.testo,
**self.opzionichat
)
background="#dce0e8")
self.textbox = tkinter.Entry(
window, textvariable=self.text,
**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.textbox.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)
self.sidebar.bind("<Double-Button-1>", self.switch_file)
self.sidebar.bind("<Button-2>", self.show_menu)
self.textbox.bind("<Return>", self.write)
#Barra dei menu
#Menu bar
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)
#Menu 1
self.menubar.add_cascade(label="Conversation", menu=menu)
menu.add_command(label="New file", command=self.new_file)
menu.add_command(label="Open file...", command=self.open_file)
#Secondo menu
#Menu 2
menu = tkinter.Menu(self.menubar)
self.menubar.add_cascade(label="Profilo", menu=menu)
self.menubar.add_cascade(label="Profile", menu=menu)
menu.add_command(
label="Nome utente",
command=lambda: self.modificapreferenza(
"Utente",
label="User name",
command=lambda: self.edit_prefs(
"username",
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
)
)
)
"User name",
"Insert your name:",
initialvalue=self.prefs["username"],
parent=window)))
#Terzo menu
#Menu 3
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)
self.menubar.add_cascade(label="Edit", menu=menu)
menu.add_command(label="Cut",
command=lambda: window.focus_get().event_generate("<<Cut>>"))
menu.add_command(label="Copy",
command=lambda: window.focus_get().event_generate("<<Copy>>"))
menu.add_command(label="Paste",
command=lambda: window.focus_get().event_generate("<<Paste>>"))
window.config(menu=self.menubar)
#Menu contestuale 1
#Context menu 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_command(label="Open", command=self.switch_file)
self.menu1.add_command(label="Delete", command=self.delete_file)
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")
)
self.menu1.add_command(label="New file", command=self.new_file)
self.menu1.add_command(label="Reload",
command=lambda: self.sidebar.delete(0, "end"))
#Menu contestuale 2
#Contextmenu 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")
)
self.menu2.add_command(label="New file", command=self.new_file)
self.menu2.add_command(label="Reload",
command=lambda: self.sidebar.delete(0, "end"))
def leggi(self):
"""Legge il file corrente dal buffer e lo scrive nella chat"""
self.aggiorna()
def read(self):
"""
Reads the current file from the buffer
and writes it into the chat.
"""
self.update()
self.temp.seek(0)
self.chat.delete(0.0, "end")
self.chat.insert("end", self.temp.read())
self.colora()
self.highlight()
def scrivi(self, event):
"""Scrive un messaggio nel file"""
def write(self, event):
"""Write a message in the current file"""
if self.file != "":
with open(self.file, "a") as file:
if self.testo.get() != "":
riga = "[%s] %s: %s\n" % (
if self.text.get() != "":
row = "[%s] %s: %s\n" % (
datetime.datetime.now().strftime("%d-%m-%y %H:%M"),
self.preferenze["Utente"],
self.testo.get()
)
self.testo.set("")
file.write(riga)
self.prefs["username"],
self.text.get())
self.text.set("")
file.write(row)
def aggiorna(self):
"""Copia il file nel Buffer"""
def update(self):
"""Copy file into the buffer"""
self.temp.seek(0)
self.temp.truncate()
if self.file != "":
with open(self.file) as testo:
self.temp.write(testo.read())
with open(self.file) as text:
self.temp.write(text.read())
def cambiatitolo(self):
"""
Aggiorna il titolo della finestra in modo che corrisponda
al file correntemente aperto.
"""
def set_title(self):
"""Update window's title to match current conversation"""
file = re.search("([^/]*)$", self.file)
if self.file == "":
finestra.title("Dropchat")
window.title("Dropchat")
else:
finestra.title("Dropchat - " + file.group(0))
window.title("Dropchat - " + file.group(0))
def colora(self):
def highlight(self):
"""
Evidenzia parti semantiche nel testo della chat
(Data, proprio nome utente e di altri).
Highlight semantic parts in the text chat.
(Date, username and others)
"""
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")
self.chat.tag_configure("date", foreground="#005d8f")
self.chat.tag_configure("name", foreground="#648f00")
self.chat.tag_configure("other", foreground="#de7a31")
self.chat.highlight("\[\d+-\d+-\d+ \d+:\d+\]", "data")
for name in re.findall(" ([a-zA-Z]+): ", self.chat.get(0.0, "end")):
if name == self.prefs["username"]:
self.chat.highlight(name, "name")
else:
self.chat.evidenzia(nome, "altronome")
self.chat.highlight(name, "other")
def mostramenu(self, event):
"""
Gestisce l'apertura e il posizionamento dei menu contestuali
della sidebar.
"""
self.sidebar.indice = self.sidebar.nearest(event.y)
if self.sidebar.indice < 0:
def show_menu(self, event):
"""Manages the opening and positioning of context menu"""
self.sidebar.index = self.sidebar.nearest(event.y)
if self.sidebar.index < 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.sidebar.activate(self.sidebar.index)
_, offset, _, height = self.sidebar.bbox(self.sidebar.index)
if event.y > height + offset + self.sidebar.size():
self.menu2.post(event.x_root, event.y_root)
else:
self.menu1.post(event.x_root, event.y_root)
def filerecenti(self):
"""Inserisce nella sidebar i file recentemente aperti"""
for x, file in enumerate(self.preferenze["Chat"]):
def recent_files(self):
"""Inserts recently opened files into the sidebar"""
for x, file in enumerate(self.prefs["chat"]):
file = " - " + re.search("([^/]*)$", file).group(0)
if file not in self.sidebar.get(x):
self.sidebar.insert(x, file)
def cancellafile(self):
"""Rimuove dalla sidebar il file correntemente selezionato"""
if self.preferenze["Chat"][self.sidebar.indice] == self.file:
def delete_file(self):
"""Removes the currently selected file from the sidebar"""
if self.prefs["Chat"][self.sidebar.index] == self.file:
self.file = ""
del self.preferenze["Chat"][self.sidebar.indice]
json.dump(self.preferenze, open("preferenze.json", "w"))
self.leggi()
self.cambiatitolo()
del self.prefs["Chat"][self.sidebar.index]
json.dump(self.prefs, open("prefs.json", "w"))
self.read()
self.set_title()
def cambiafile(self, _=None):
"""
Apre il file correntemente selezionato
dalla sidebar nella chat.
"""
file = self.preferenze["Chat"][int(self.sidebar.curselection()[0])]
def switch_file(self, _=None):
"""Opens the currently selected file from the sidebar in the chat"""
file = self.prefs["chat"][int(self.sidebar.curselection()[0])]
if self.file != file:
self.file = file
self.leggi()
self.cambiatitolo()
self.read()
self.set_title()
def aprifile(self):
"""
Gestisce la finestra di selezione di un nuovo file
e lo apre nella chat.
"""
def open_file(self):
"""Selects a new file and opens it in the chat."""
if sys.platform == "darwin":
file = tkinter.filedialog.askopenfilename(
title="Scegli un file...",
message="Apri una conversazione esistente.",
**self.opzionifile
)
title="Choose a file...",
message="Open a conversation.",
**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"))
title="Choose a file...",
**self.opzionifile)
if file not in self.prefs["Chat"] and file != "":
self.prefs["chat"] += file,
json.dump(self.prefs, open("prefs.json", "w"))
self.file = file
self.leggi()
self.cambiatitolo()
self.read()
self.set_title()
def nuovofile(self):
"""
Gestisce la finestra per la creazione di un nuovo file
e lo apre nella chat.
"""
def new_file(self):
"""Creates a new file and opens it in the chat"""
if sys.platform == "darwin":
file = tkinter.filedialog.asksaveasfilename(
title="Crea un file...",
message="Scegli il nome della nuova conversazione.",
**self.opzionifile
)
title="Create a file...",
message="Select the name of the new conversation.",
**self.opzionifile)
else:
file = tkinter.filedialog.asksaveasfilename(
title="Crea un file...",
**self.opzionifile
)
title="Creates a new file...",
**self.opzionifile)
if file != "":
self.file = file
open(self.file, "w").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()
if self.file not in self.prefs["chat"]:
self.prefs["chat"] += self.file,
json.dump(self.prefs, open("prefs.json", "w"))
self.read()
self.set_title()
def cancellanontrovati(self):
"""
Rimuove i riferimenti dalla sidebar di tutti i file che
non sono più disponibili.
"""
for x, file in enumerate(self.preferenze["Chat"]):
def delete_not_found(self):
"""Removes files that are no longer available"""
for x, file in enumerate(self.prefs["chat"]):
try:
open(file)
self.file = file
except FileNotFoundError:
del self.preferenze["Chat"][x]
del self.prefs["Chat"][x]
continue
json.dump(self.preferenze, open("preferenze.json", "w"))
json.dump(self.prefs, open("prefs.json", "w"))
def creapreferenze(self):
"""
Ricrea le preferenze di default se non vengono trovate.
"""
def build_prefs(self):
"""Rebuild default preferences"""
default = {
"Utente": "Nomeutente",
"Chat": ["chat.txt"],
"Chiave": "chiave.key",
"Geometria": "800x500+500+250"
"username": "user",
"chat": ["chat.txt"],
"geometry": "800x500+500+250"
}
json.dump(default, open("preferenze.json", "w"))
self.preferenze = json.load(open("preferenze.json"))
json.dump(default, open("prefs.json", "w"))
self.prefs = json.load(open("prefs.json"))
def modificapreferenza(self, chiave, preferenza):
"""
Modifica una preferenza e la salva nel file esterno.
"""
if preferenza != "":
self.preferenze[chiave] = preferenza
json.dump(self.preferenze, open("preferenze.json", "w"))
def edit_prefs(self, key, pref):
"""Changing a preference and saves it into an external file."""
if pref != "":
self.prefs[key] = pref
json.dump(self.prefs, open("prefs.json", "w"))
def chiudi(self):
def close(self):
"""
Salva la geometria della finestra per il prossimo avvio,
chiude ed elimina la cache,
chiude la finestra ed esce.
Save the geometry of the window for the next boot,
closes and deletes the cache,
closes the window and exits.
"""
self.modificapreferenza("Geometria", finestra.geometry())
self.edit_prefs("geometry", window.geometry())
self.temp.close()
finestra.destroy()
window.destroy()
def loop(self):
"""
Loop principale
Viene eseguito ogni 200 ms.
Aggiorna i file recenti e il file aperto nella chat.
Main loop
Update recent files and current covnersation.
"""
self.filerecenti()
self.leggi()
self.recent_files()
self.read()
self.after(200, self.loop)
finestra = tkinter.Tk()
app = Applicazione(finestra)
window = tkinter.Tk()
app = Application()
app.mainloop()

View File

@ -1,10 +0,0 @@
* 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

View File

@ -1,27 +1,31 @@
Dropchat
========
# Dropchat
Chat tramite Dropbox in python 3.
---------------------------------
## Chat with Dropbox.
### Informazioni
Un chat client per chattare tramite le cartelle condivise di Dropbox.
Realizzato usando python 3 e l'interfaccia Tk.
### Istruzioni
Primo utilizzo:
### Info
A chat client that uses shared folders to Dropbox.
Made using python 3 and Tk interface.
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.
### Instructions
First usage:
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".
From the menu bar select:
* Profile -> "User Name" and enter your name.
* Conversation -> "New File" or "Open File .." and choose a text file
Write a message in the text box and press return to enter it in the file.
Once written, the file is synced with Dropbox so that others can respond.
### Conversione
È incluso un setup.py per convertire Dropchat.py in un binario tramite py2app o py2exe.
Utilizzo:
Recent files are listed in the sidebar and on the last used is reopened at startup.
To permanently delete a file, simply move it to the trash while to remove the reference from the right-click on the file in the sidebar and select "Delete".
python setup.py
### Building
A setup is included to convert Dropchat into a binary using py2exe or py2app.
Usage:
python setup.py build
### License
Dual licensed under the MIT and GPL licenses:
http://www.opensource.org/licenses/mit-license.php
http://www.gnu.org/licenses/gpl.html

View File

@ -1 +0,0 @@
{"Utente": "Nomeutente", "Geometria": "800x500+538+299", "Chiave": "chiave.key", "Chat": []}

1
prefs.json Normal file
View File

@ -0,0 +1 @@
{"username": null, "geometry": "871x526+487+291", "chat": ["/Users/Michele/Desktop/file.txt"]}

View File

@ -1,14 +1,15 @@
import sys, setuptools
import sys
import setuptools
opzioni = {
options = {
"name": "Dropchat",
"version": "1.0",
"description": "Chat tramite dropbox.",
"description": "Chat with dropbox.",
"author": "Rnhmjoj",
"author_email": "micheleguerinirocco@me.com",
"license": "MIT-GPL",
"app": ["Dropchat.py"],
"data_files": ["preferenze.json"],
"app": ["dropchat.py"],
"data_files": ["prefs.json"],
"options": {},
"setup_requires": [],
}
@ -17,21 +18,21 @@ if sys.platform == "darwin":
try:
import py2app
sys.argv += "py2app",
opzioni["options"] = {"py2app": {"argv_emulation": False}}
opzioni["setup_requires"] += "py2app",
options["options"] = {"py2app": {"argv_emulation": False}}
options["setup_requires"] += "py2app",
except ImportError:
exit("py2app non installato.")
sys.exit("py2app not installed")
elif sys.platform == "win32":
try:
import py2exe
sys.argv += "py2exe",
opzioni["options"] = {"py2exe": {"bundle_files": 1, "compressed": True}}
opzioni["setup_requires"] += "py2exe",
options["options"] = {"py2exe": {"bundle_files": 1, "compressed": True}}
options["setup_requires"] += "py2exe",
except ImportError:
exit("py2exe non installato.")
sys.exit("py2exe not installed")
else:
exit("Sistema non supportato")
sys.exit("OS not supported")
setuptools.setup(**opzioni)
setuptools.setup(**options)