import tkinter
import tkinter.ttk
import getpass
import uuid
import os
import time
import traceback
# XXX The file will be obsolete by tomorrow.
HOLD = 'Logos Storage'
################################################################################
class Logos(tkinter.ttk.Frame):
@classmethod
def main(cls):
# Create and configure the root.
tkinter.NoDefaultRoot()
root = tkinter.Tk()
root.title('Logos')
root.minsize(200, 200)
# Create Logos and setup for resizing.
view = cls(root)
view.grid(row=0, column=0, sticky=tkinter.NSEW)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
# Enter the main GUI event loop.
root.mainloop()
########################################################################
# These are all instance methods.
def __init__(self, master):
super().__init__(master)
# Get the username and save list of found files.
self.__user = getpass.getuser()
self.__dirlist = set()
# Create widgets.
self.__log = tkinter.Text(self)
self.__bar = tkinter.ttk.Scrollbar(self, orient=tkinter.VERTICAL,
command=self.__log.yview)
self.__ent = tkinter.ttk.Entry(self, cursor='xterm')
# Configure widgets.
self.__log.configure(state=tkinter.DISABLED, wrap=tkinter.WORD,
yscrollcommand=self.__bar.set)
# Create binding.
self.__ent.bind('<Return>', self.create_message)
# Position widgets.
self.__log.grid(row=0, column=0, sticky=tkinter.NSEW)
self.__bar.grid(row=0, column=1, sticky=tkinter.NS)
self.__ent.grid(row=1, column=0, columnspan=2, sticky=tkinter.EW)
# Configure resizing.
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
# Focus entry.
self.__ent.focus_set()
# Schedule message discovery.
self.after_idle(self.get_messages)
def get_messages(self):
# Schedule method for one second from now.
self.after(1000, self.get_messages)
# Get a list of new files.
files = set(os.listdir(HOLD))
diff = files - self.__dirlist
self.__dirlist = files
# Load each new message.
messages = []
for name in diff:
path = os.path.join(HOLD, name)
try:
with open(path) as file:
user, clock, message = self.load_message(file)
messages.append((user, float(clock), message))
except:
# Print any error for debugging purposes.
traceback.print_exc()
os.remove(path)
# Sort the messages according to time and display them.
messages.sort(key=lambda m: m[1])
for m in messages:
self.display_message(m[0], m[2])
def display_message(self, user, text):
# Put a new message on the screen.
self.__log['state'] = tkinter.NORMAL
message = '{} - {}\n'.format(user, text)
self.__log.insert('1.0', message)
self.__log['state'] = tkinter.DISABLED
def create_message(self, event):
# Get the text, clear it, show on screen, and create file.
text = event.widget.get()
event.widget.delete(0, tkinter.END)
self.display_message(self.__user, text)
self.save_file(text)
def save_file(self, message):
# Save message in HOLD using a UUID for the name.
name = uuid.uuid1().hex
path = os.path.join(HOLD, name)
self.__dirlist.add(name)
with open(path, 'w') as file:
self.save_message(file, message)
########################################################################
# If one the format is changed, both methods must be altered.
def load_message(self, file):
# Read the file, splitting on newline, and get first three lines.
user, clock, message = file.read().split('\n')[:3]
return user, clock, message
def save_message(self, file, message):
# Save username, timestamp, and message on separate lines.
print(self.__user, file=file)
print(time.time(), file=file)
print(message, file=file, end='')
################################################################################
if __name__ == '__main__':
Logos.main()