else
More updates to Editor
This commit is contained in:
parent
214b657ead
commit
6f6c8fb5b1
3 changed files with 76 additions and 33 deletions
|
@ -1,6 +1,4 @@
|
||||||
Editor
|
Editor
|
||||||
==========
|
==========
|
||||||
|
|
||||||
A neat idea that I would one day like to make into a website or something. Users read and write text files simply by choosing the file name. If it exists, the text is returned to them for editing. If it does not, it will be created when they press Save. No logins and no file security. Since it's using a database instead of actual txt files, there are no filename character restrictions, only a maximum title length for sanity's sake.
|
A neat idea that would make for a fun website. Users read and write text files by choosing the file name. If it exists, the text is returned to them for editing. If it does not, it will be created when they press Save. No logins and no file security. Since it's using a database instead of actual txt files, there are no filename character restrictions, only a maximum title length and a couple self-imposed rules for sanity's sake.
|
||||||
|
|
||||||
For now, it's just a tkinter toy.
|
|
103
Editor/editor.py
103
Editor/editor.py
|
@ -5,7 +5,8 @@ import random
|
||||||
|
|
||||||
class Editor:
|
class Editor:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.WINDOWS_BADCHARS = '\\/?:*"><|'
|
#self.WINDOWS_BADCHARS = '\\/?:*"><|'
|
||||||
|
self.windowtitle = 'Editor'
|
||||||
|
|
||||||
self.sql = sqlite3.connect('textfiles.db')
|
self.sql = sqlite3.connect('textfiles.db')
|
||||||
self.cur = self.sql.cursor()
|
self.cur = self.sql.cursor()
|
||||||
|
@ -23,6 +24,7 @@ class Editor:
|
||||||
self.maximum_title = 64
|
self.maximum_title = 64
|
||||||
|
|
||||||
self.t = tkinter.Tk()
|
self.t = tkinter.Tk()
|
||||||
|
self.t.title(self.windowtitle)
|
||||||
self.w = 450
|
self.w = 450
|
||||||
self.h = 350
|
self.h = 350
|
||||||
self.screenwidth = self.t.winfo_screenwidth()
|
self.screenwidth = self.t.winfo_screenwidth()
|
||||||
|
@ -34,98 +36,115 @@ class Editor:
|
||||||
self.geometrystring = '%dx%d+%d+%d' % (self.windowwidth, self.windowheight, self.windowx, self.windowy)
|
self.geometrystring = '%dx%d+%d+%d' % (self.windowwidth, self.windowheight, self.windowx, self.windowy)
|
||||||
self.t.geometry(self.geometrystring)
|
self.t.geometry(self.geometrystring)
|
||||||
|
|
||||||
|
self.reserved_filenames = ['random', 'list']
|
||||||
|
self.has_filenames_changed = True
|
||||||
self.entities = []
|
self.entities = []
|
||||||
self.filename = None
|
self.filename = None
|
||||||
self.gui_build_fileloader()
|
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.gui_build_fileloader()
|
||||||
self.t.mainloop()
|
self.t.mainloop()
|
||||||
|
|
||||||
def annihilate(self):
|
def annihilate(self):
|
||||||
for x in self.entities:
|
while len(self.entities) > 0:
|
||||||
try:
|
self.entities[0].destroy()
|
||||||
x.grid_forget()
|
del self.entities[0]
|
||||||
x.pack_forget()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
x.destroy()
|
|
||||||
|
|
||||||
def gui_build_fileloader(self, *b):
|
def gui_build_fileloader(self, *b):
|
||||||
self.annihilate()
|
self.annihilate()
|
||||||
|
self.t.title(self.windowtitle)
|
||||||
|
###
|
||||||
self.frame_fileloader = tkinter.Frame(self.t)
|
self.frame_fileloader = tkinter.Frame(self.t)
|
||||||
self.entities.append(self.frame_fileloader)
|
self.entities.append(self.frame_fileloader)
|
||||||
|
#
|
||||||
self.entry_filename = tkinter.Entry(self.frame_fileloader, font=self.font_large, justify='right')
|
self.entry_filename = tkinter.Entry(self.frame_fileloader, font=self.font_large, justify='right')
|
||||||
self.entry_filename.grid(row=0, column=0, columnspan=3)
|
self.entry_filename.grid(row=0, column=0, columnspan=3)
|
||||||
self.entry_filename.focus_set()
|
self.entry_filename.focus_set()
|
||||||
self.entry_filename.bind("<Return>", self.loadfile_smart)
|
self.entry_filename.bind("<Return>", self.loadfile_smart)
|
||||||
self.entities.append(self.entry_filename)
|
self.entities.append(self.entry_filename)
|
||||||
|
#
|
||||||
self.label_filename = tkinter.Label(self.frame_fileloader, font=self.font_large, text='.txt')
|
self.label_filename = tkinter.Label(self.frame_fileloader, font=self.font_large, text='.txt')
|
||||||
self.label_filename.grid(row=0, column=3)
|
self.label_filename.grid(row=0, column=3)
|
||||||
self.entities.append(self.label_filename)
|
self.entities.append(self.label_filename)
|
||||||
|
#
|
||||||
self.button_fileloader = tkinter.Button(self.frame_fileloader, font=self.font_large, text='Load', command=self.loadfile_smart)
|
self.button_fileloader = tkinter.Button(self.frame_fileloader, font=self.font_large, text='Load', command=self.loadfile_smart)
|
||||||
self.button_fileloader.grid(row=1, column=1, pady=10)
|
self.button_fileloader.grid(row=1, column=1, pady=10)
|
||||||
self.entities.append(self.button_fileloader)
|
self.entities.append(self.button_fileloader)
|
||||||
width = self.t.winfo_width()
|
#
|
||||||
height = self.t.winfo_height()
|
|
||||||
if min([width, height]) < 20:
|
|
||||||
width = self.w
|
|
||||||
height = self.h
|
|
||||||
self.frame_fileloader.pack(expand=True, anchor='center')
|
self.frame_fileloader.pack(expand=True, anchor='center')
|
||||||
#self.frame_fileloader.place(x=width/2, y=(height/2)-10, anchor='center')
|
#self.frame_fileloader.place(x=width/2, y=(height/2)-10, anchor='center')
|
||||||
|
|
||||||
def gui_build_editor(self, filetext, *b):
|
def gui_build_editor(self, filetext, *b):
|
||||||
self.annihilate()
|
self.annihilate()
|
||||||
|
###
|
||||||
self.frame_toolbar = tkinter.Frame(self.t)
|
self.frame_toolbar = tkinter.Frame(self.t)
|
||||||
self.frame_toolbar.pack()
|
self.frame_toolbar.pack()
|
||||||
self.entities.append(self.frame_toolbar)
|
self.entities.append(self.frame_toolbar)
|
||||||
|
#
|
||||||
self.button_back = tkinter.Button(self.frame_toolbar, text='back', command=self.gui_build_fileloader, font=self.font_small)
|
self.button_back = tkinter.Button(self.frame_toolbar, text='back', command=self.gui_build_fileloader, font=self.font_small)
|
||||||
self.button_back.grid(row=0, column=0)
|
self.button_back.grid(row=0, column=0)
|
||||||
self.entities.append(self.button_back)
|
self.entities.append(self.button_back)
|
||||||
|
#
|
||||||
self.label_filename = tkinter.Label(self.frame_toolbar, text=self.filename, font=self.font_small)
|
self.label_filename = tkinter.Label(self.frame_toolbar, text=self.filename, font=self.font_small)
|
||||||
self.label_filename.grid(row=0, column=1, padx=20)
|
self.label_filename.grid(row=0, column=1, padx=70)
|
||||||
self.entities.append(self.label_filename)
|
self.entities.append(self.label_filename)
|
||||||
|
#
|
||||||
self.button_save = tkinter.Button(self.frame_toolbar, text='save', command=self.savefile_smart, font=self.font_small)
|
self.button_save = tkinter.Button(self.frame_toolbar, text='save', command=self.savefile_smart, font=self.font_small)
|
||||||
self.button_save.grid(row=0, column=2)
|
self.button_save.grid(row=0, column=2)
|
||||||
self.entities.append(self.button_save)
|
self.entities.append(self.button_save)
|
||||||
|
#
|
||||||
self.label_filesize = tkinter.Label(self.frame_toolbar, text='', font=self.font_small)
|
self.label_filesize = tkinter.Label(self.frame_toolbar, text='', font=self.font_small)
|
||||||
self.label_filesize.grid(row=1, column=0, columnspan=10)
|
self.label_filesize.grid(row=1, column=0, columnspan=3)
|
||||||
self.entities.append(self.label_filesize)
|
self.entities.append(self.label_filesize)
|
||||||
self.text_editor = tkinter.Text(self.t, wrap='word', font=self.font_med)
|
#
|
||||||
|
self.scrollbar_editor = tkinter.Scrollbar(self.t)
|
||||||
|
self.scrollbar_editor.pack(side='right', fill='y')
|
||||||
|
self.text_editor = tkinter.Text(self.t, wrap='word', font=self.font_med, yscrollcommand=self.scrollbar_editor.set)
|
||||||
|
self.scrollbar_editor.configure(command=self.text_editor.yview)
|
||||||
self.text_editor.insert('end', filetext)
|
self.text_editor.insert('end', filetext)
|
||||||
self.text_editor.pack(expand=True, fill='both')
|
self.text_editor.pack(expand=True, fill='both')
|
||||||
self.text_editor.focus_set()
|
self.text_editor.focus_set()
|
||||||
self.text_editor.bind('<Control-s>', self.savefile_smart)
|
self.text_editor.bind('<Control-s>', self.savefile_smart)
|
||||||
self.text_editor.bind('<Control-w>', self.gui_build_fileloader)
|
self.text_editor.bind('<Control-w>', self.gui_build_fileloader)
|
||||||
self.entities.append(self.text_editor)
|
self.entities.append(self.text_editor)
|
||||||
|
self.entities.append(self.scrollbar_editor)
|
||||||
|
###
|
||||||
|
|
||||||
def savefile_smart(self, *b):
|
def savefile_smart(self, *b):
|
||||||
try:
|
try:
|
||||||
filetext = self.text_editor.get('0.0', 'end')
|
filetext = self.text_editor.get('0.0', 'end')
|
||||||
self.savefile(self.filename, filetext)
|
|
||||||
filesize = len(filetext) - 1
|
filesize = len(filetext) - 1
|
||||||
self.label_filesize.configure(text=self.filesizestring(filesize))
|
try:
|
||||||
|
self.savefile(self.filename, filetext)
|
||||||
|
self.label_filesize.configure(text=self.filesizestring(filesize))
|
||||||
|
except EditorException as ee:
|
||||||
|
self.label_filesize.configure(text=ee.args[0])
|
||||||
except NameError:
|
except NameError:
|
||||||
# text editor does not exist for some reason
|
# text editor does not exist for some reason
|
||||||
return
|
return
|
||||||
|
|
||||||
def savefile(self, filename, filetext):
|
def savefile(self, filename, filetext, permissions=False):
|
||||||
|
if filename is None:
|
||||||
|
raise EditorException('Please enter a filename')
|
||||||
|
if permissions is False and filename in self.reserved_filenames:
|
||||||
|
print('This file is restricted. You are not permitted to modify it.')
|
||||||
|
raise EditorException("Restricted file")
|
||||||
|
filename = filename.replace(' ', '_')
|
||||||
filetext = filetext[:-1]
|
filetext = filetext[:-1]
|
||||||
# Text widget seems to add \n to the end at all times
|
# Text widget seems to add \n to the end at all times
|
||||||
# So remove it.
|
# So remove it.
|
||||||
if self.filename is None:
|
|
||||||
return False
|
|
||||||
filesize = len(filetext)
|
filesize = len(filetext)
|
||||||
namesize = len(filename)
|
namesize = len(filename)
|
||||||
if filesize > self.maximum_characters:
|
if filesize > self.maximum_characters:
|
||||||
diff = filesize-self.maximum_characters
|
diff = filesize-self.maximum_characters
|
||||||
print('File exceeds maximum character limit. %d / %d (-%d)' % (filesize, self.maximum_characters, diff))
|
sizeerror = 'too big: %d / %d (-%d)' % (filesize, self.maximum_characters, diff)
|
||||||
return False
|
print('File exceeds maximum character limit. %s' % sizeerror)
|
||||||
|
raise EditorException(sizeerror)
|
||||||
elif namesize > self.maximum_title:
|
elif namesize > self.maximum_title:
|
||||||
diff = namesize - self.maximum_title
|
diff = namesize - self.maximum_title
|
||||||
print('Filename exceeds maximum character limit: %d / %d (-%d)' % (namesize, self.maximum_title, diff))
|
sizeerror = '%d / %d (-%d)' % (namesize, self.maximum_title, diff)
|
||||||
return False
|
print('Filename exceeds maximum character limit: %s' % sizeerror)
|
||||||
|
raise EditorException('Filename too big: %s' % sizeerror)
|
||||||
|
|
||||||
sha = self.sha(filename)
|
sha = self.sha(filename)
|
||||||
self.cur.execute('SELECT * FROM textfiles WHERE id=?', [sha])
|
self.cur.execute('SELECT * FROM textfiles WHERE id=?', [sha])
|
||||||
|
@ -133,12 +152,19 @@ class Editor:
|
||||||
if filesize == 0:
|
if filesize == 0:
|
||||||
print('Deleting %s' % filename)
|
print('Deleting %s' % filename)
|
||||||
self.cur.execute('DELETE FROM textfiles WHERE id=?', [sha])
|
self.cur.execute('DELETE FROM textfiles WHERE id=?', [sha])
|
||||||
|
if fetch:
|
||||||
|
# If fetch: It previously existed and is now deleted
|
||||||
|
# If not fetch: User just created this workspace, and
|
||||||
|
# is now closing it without adding anything
|
||||||
|
# so nothing has changed on disk.
|
||||||
|
self.has_filenames_changed = True
|
||||||
else:
|
else:
|
||||||
if fetch:
|
if fetch:
|
||||||
self.cur.execute('UPDATE textfiles SET filename=?, filetext=? WHERE id=?', [filename, filetext, sha])
|
self.cur.execute('UPDATE textfiles SET filename=?, filetext=? WHERE id=?', [filename, filetext, sha])
|
||||||
else:
|
else:
|
||||||
self.cur.execute('INSERT INTO textfiles VALUES(?, ?, ?)', [sha, filename, filetext])
|
self.cur.execute('INSERT INTO textfiles VALUES(?, ?, ?)', [sha, filename, filetext])
|
||||||
print('Wrote %s: %s' % (filename, self.filesizestring(filesize)))
|
print('Wrote %s: %s' % (filename, self.filesizestring(filesize)))
|
||||||
|
self.has_filenames_changed = True
|
||||||
self.sql.commit()
|
self.sql.commit()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -157,11 +183,15 @@ class Editor:
|
||||||
filetext = self.loadfile(filename)
|
filetext = self.loadfile(filename)
|
||||||
if filetext is not None:
|
if filetext is not None:
|
||||||
self.gui_build_editor(filetext)
|
self.gui_build_editor(filetext)
|
||||||
|
self.t.title(filename)
|
||||||
return
|
return
|
||||||
|
|
||||||
def loadfile(self, filename):
|
def loadfile(self, filename):
|
||||||
if filename == 'random':
|
if filename == 'random':
|
||||||
filename = self.loadrandom()
|
filename = self.loadrandom()
|
||||||
|
if filename == 'list':
|
||||||
|
self.generate_listfile()
|
||||||
|
filename = filename.replace(' ', '_')
|
||||||
if len(filename) < 1:
|
if len(filename) < 1:
|
||||||
return None
|
return None
|
||||||
if len(filename) > self.maximum_title:
|
if len(filename) > self.maximum_title:
|
||||||
|
@ -185,6 +215,17 @@ class Editor:
|
||||||
return ""
|
return ""
|
||||||
return random.choice(fetch)[1]
|
return random.choice(fetch)[1]
|
||||||
|
|
||||||
|
def generate_listfile(self):
|
||||||
|
if self.has_filenames_changed:
|
||||||
|
print('Refreshing list file')
|
||||||
|
self.cur.execute('SELECT * FROM textfiles')
|
||||||
|
fetch = self.cur.fetchall()
|
||||||
|
fetch = [x[1] for x in fetch]
|
||||||
|
fetch.sort(key=lambda x:x.lower())
|
||||||
|
fetch = '\n'.join(fetch)
|
||||||
|
self.savefile('list', fetch, permissions=True)
|
||||||
|
self.has_filenames_changed = False
|
||||||
|
|
||||||
def strip_to_filename(self, s):
|
def strip_to_filename(self, s):
|
||||||
for bad in self.WINDOWS_BADCHARS:
|
for bad in self.WINDOWS_BADCHARS:
|
||||||
s = s.replace(bad, '')
|
s = s.replace(bad, '')
|
||||||
|
@ -197,4 +238,8 @@ class Editor:
|
||||||
sha = sha.hexdigest()
|
sha = sha.hexdigest()
|
||||||
return sha
|
return sha
|
||||||
|
|
||||||
|
class EditorException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
editor = Editor()
|
editor = Editor()
|
||||||
|
editor.start()
|
Binary file not shown.
Loading…
Reference in a new issue