Notes
Jan 26, 2021 4:55:42 GMT -8
Post by Uncle Buddy on Jan 26, 2021 4:55:42 GMT -8
# notes.py (import as notes)
import tkinter as tk
import sqlite3
import widgets as wdg
import messages as msg
import styles as st
import names
import right_click_menu as rcm
import message_strings as ms
import utes
import custom_listbox_widget as clw
import files
ST = st.ThemeStyles()
class InputDialog(wdg.Toplevel):
def __init__(
self,
master,
prompt='',
finding_id=0,
new_subtopic='',
new_index=0,
above_below=0,
**options):
wdg.Toplevel.__init__(self, master, **options)
self.master = master
self.prompt = prompt
self.finding_id = finding_id
self.new_subtopic = new_subtopic
self.new_index = new_index
self.above_below = above_below
self.grab_set()
self.protocol('WM_DELETE_WINDOW', self.close_dialog)
self.bind('<Escape>', self.close_dialog)
self.current_file = files.get_current_file()[0]
self.make_widgets()
def close_dialog(self, evt=None):
self.destroy()
self.master.subtopic_input.replace_default_text()
def make_widgets(self):
new_note_title = wdg.LabelH3(self, text=self.prompt)
self.new_note_input = wdg.ScrolledText(self)
self.new_note_input.text.focus_set()
new_note_ok = wdg.Button(
self, text='Submit', command=self.submit_new_note)
new_note_title.grid(column=0, row=0, pady=(24,0))
self.new_note_input.grid(column=0, row=1, padx=24, pady=24)
new_note_ok.grid(column=0, row=2, sticky='se', padx=24, pady=24)
def submit_new_note(self, evt=None):
new_note_text = self.new_note_input.text.get(1.0, 'end-1c')
conn = sqlite3.connect(self.current_file)
conn.execute('PRAGMA foreign_keys = 1')
cur = conn.cursor()
cur.execute(
'''
INSERT INTO note
VALUES (null, ?, 0, ?)
''',
(new_note_text, self.new_subtopic))
conn.commit()
# get last note_id created
cur.execute("SELECT seq FROM SQLITE_SEQUENCE WHERE name = 'note'")
new_note_id = cur.fetchone()[0]
cur.execute(
'''
INSERT INTO findings_notes
VALUES (null, ?, ?, ?)
''',
(self.finding_id, new_note_id, self.new_index))
conn.commit()
cur.close()
conn.close()
self.save_new_note_order(self.above_below, new_note_id, self.new_index)
self.master.current_note_text = new_note_text
self.grab_release()
self.close_dialog()
self.master.subtopic_input.delete(0, 'end')
self.master.refresh_notes_per_finding()
self.master.toc.insert(self.new_index, self.new_subtopic)
items = self.master.toc.listbox_content.winfo_children()
for child in items:
child.bind('<<ListboxSelected>>', self.master.switch_note)
self.master.toc.resize_scrollbar()
self.master.toc.selection_set(self.new_index)
self.master.switch_note()
self.master.subtopic_input.replace_default_text()
def save_new_note_order(self, above_below, new_note_id, new_index):
def update_db(note_id, order_index):
cur.execute(
'''
UPDATE findings_notes
SET order_subtopic = ?
WHERE note_id = ?
''',
(order_index, note_id))
conn.commit()
conn = sqlite3.connect(self.current_file)
conn.execute('PRAGMA foreign_keys = 1')
cur = conn.cursor()
cur.execute(
'''
SELECT note_id, order_subtopic
FROM findings_notes
WHERE finding_id = ?
AND order_subtopic >= ?
AND note_id != ?
''',
(self.finding_id, new_index, new_note_id))
reorder_these = cur.fetchall()
for tup in reorder_these:
note_id = tup[0]
order_index = tup[1] + 1
update_db(note_id, order_index)
cur.close()
conn.close()
class NotesDialog(wdg.Toplevel):
def __init__(
self,
master,
subject,
note_string,
dlg_header,
finding_id=None,
root=None,
*args,
**kwargs):
wdg.Toplevel.__init__(self, *args, **kwargs)
self.master = master
self.subject = subject
self.dlg_header = dlg_header
self.finding_id = finding_id
self.root = root
new_index = None
self.current_note_text = ''
self.current_subtopic = ''
self.current_note_id = None
self.current_file = files.get_current_file()[0]
self.bind('<Escape>', self.close_dialog)
self.subtopics = []
self.privacy = tk.IntVar()
self.refresh_notes_per_finding()
self.rc_menu = rcm.RightClickMenu(self.root)
self.make_widgets()
self.protocol('WM_DELETE_WINDOW', self.close_dialog)
def refresh_notes_per_finding(self):
conn = sqlite3.connect(self.current_file)
conn.execute('PRAGMA foreign_keys = 1')
cur = conn.cursor()
cur.execute(
'''
SELECT
findings_notes.note_id,
subtopic, notes, order_subtopic
FROM note
JOIN findings_notes
ON note.note_id = findings_notes.note_id
WHERE finding_id = ?
''',
(self.finding_id,))
notes = cur.fetchall()
all_subtopics = []
if len(notes) != 0:
for tup in notes:
all_subtopics.append([tup[1], tup[3]])
all_subtopics.sort(key=lambda i: i[1])
self.sorted_subtopics = []
for lst in all_subtopics:
self.sorted_subtopics.append(lst[0])
self.subtopics = self.sorted_subtopics
self.notesdict = {}
for tup in notes:
self.notesdict[tup[0]] = [tup[1], tup[2]]
cur.close()
conn.close()
def close_dialog(self, evt=None):
self.destroy()
self.master.focus_set()
if self.notesdict != self.opening_state:
self.master.master.save()
def save_new_subtopic(self):
def create_first_note():
'''
If user has deleted all notes, this runs.
'''
self.note_input.config(state='normal')
new_note_dlg = InputDialog(
self,
prompt='New Note Input',
finding_id=self.finding_id,
new_subtopic=new_subtopic,
new_index=0,
above_below=0)
self.refresh()
new_subtopic = self.subtopic_input.get()
selected = self.toc.curselection()
if selected is None and self.toc.size() == 0:
create_first_note()
return
elif selected is None:
no_select = msg.ErrorMessage(
self,
message='No subtopic was selected.',
title='Input Lacking')
return
if (len(new_subtopic) == 0 or
new_subtopic == self.default_text or
new_subtopic in self.sorted_subtopics):
no_select = msg.ErrorMessage(
self,
message='Provide a unique subtopic name.',
title='Input Lacking')
self.subtopic_input.focus_set()
return
if self.above_or_below.get() == 0:
new_index = selected
elif self.above_or_below.get() == 1:
new_index = selected + 1
above_below = self.above_or_below.get()
new_note_dlg = InputDialog(
self,
prompt='New Note Input',
finding_id=self.finding_id,
new_subtopic=new_subtopic,
new_index=new_index,
above_below=above_below)
def make_widgets(self):
def detect_subtopic_lack(evt):
if self.note_input.text['state'] == 'disabled':
self.save_new_subtopic()
self.title('{}{} ({})'.format(
'Notes for Conclusion #',
self.finding_id,
self.subject))
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(1, weight=1)
header = wdg.Frame(self)
header.grid_columnconfigure(1, weight=1)
header.grid_rowconfigure(0, weight=1)
subtopic_choices = wdg.LabelFrame(
header, text='Insert new subtopic...')
self.notes_dialog_header = wdg.Frame(header)
content = wdg.Frame(self)
self.above_or_below = tk.IntVar()
above = wdg.Radiobutton(
subtopic_choices,
variable=self.above_or_below,
value=0,
text='...above selected.')
below = wdg.Radiobutton(
subtopic_choices,
variable=self.above_or_below,
value=1,
text='...below selected.')
self.default_text = 'New subtopic name'
self.subtopic_input = wdg.EntryDefaultText(
subtopic_choices, self.default_text)
left_panel = wdg.Frame(content)
top = wdg.Label(left_panel, text='Note Subtopics')
self.toc = clw.Listbox(
left_panel,
self.sorted_subtopics,
view_height=424,
view_width=180,
scrollbar=False)
new = wdg.Button(
left_panel,
text='Create a New Note',
command=self.save_new_subtopic)
rename = wdg.Button(
left_panel,
text='Rename Selected Note',
command=self.rename_note)
delete = wdg.Button(
left_panel,
text='Delete Selected Note',
command=self.delete_note)
self.note_input = wdg.ScrolledTextSaver(content, self.use_input)
self.note_input.bind('<Button-1>', detect_subtopic_lack)
order = wdg.Button(
content,
text='Change Order of Subtopics',
command=self.reorder_notes)
radframe = wdg.LabelFrame(content, text='Make selected note...')
self.public = wdg.Radiobutton(
radframe,
text='...public',
anchor='w',
variable=self.privacy,
value=0,
command=self.save_privacy_setting)
self.private = wdg.Radiobutton(
radframe,
text='...private',
anchor='w',
variable=self.privacy,
value=1,
command=self.save_privacy_setting)
close = wdg.Button(content, text='DONE', command=self.close_dialog)
notes_statusbar = wdg.StatusbarTooltips(self)
visited = (
(above,
'this is a notes_statusbar message',
'this is a tooltip'),
(below,
'this is also a notes_statusbar message',
'this is another tooltip'))
wdg.run_statusbar_tooltips(
visited,
notes_statusbar.status_label,
notes_statusbar.tooltip_label)
# grid in self
header.grid(column=0, row=0, columnspan=2, pady=12, sticky='we')
content.grid(column=0, row=1, sticky='news', padx=(0,6))
notes_statusbar.grid(column=0, row=2, sticky='ew')
# grid in header
subtopic_choices.grid(
column=0, row=0, pady=24, padx=24, sticky='sw', rowspan=3)
subtopic_choices.grid_columnconfigure(0, weight=1)
self.notes_dialog_header.grid(column=1, row=0, sticky='ew')
self.notes_dialog_header.grid_columnconfigure(0, weight=1)
# grid in subtopic_choices
above.grid(column=0, row=1)
below.grid(column=0, row=2)
self.subtopic_input.grid(column=0, row=3, pady=(6,12), padx=6)
# grid in content
left_panel.grid(
column=0, row=0, sticky='news',
rowspan=2, pady=24)
self.note_input.grid(
column=1, row=0, columnspan=3, sticky='nsew', padx=(0,24), pady=12)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
content.grid_rowconfigure(1, weight=1)
order.grid(column=1, row=1)
radframe.grid(column=2, row=1, sticky='n', pady=24)
close.grid(column=3, row=1, sticky='se', padx=24, pady=(0,24))
# pack in left_panel
top.pack(side='top')
self.toc.pack(side='top', pady=(18,24))
for child in self.toc.listbox_content.winfo_children():
child.bind('<<ListboxSelected>>', self.switch_note)
new.pack(side='top', pady=6)
rename.pack(side='top', pady=6, padx=24)
delete.pack(side='top', pady=6)
# grid in radframe
self.public.grid(column=0, row=0, sticky='news', padx=24)
self.private.grid(column=0, row=1, sticky='news', padx=24)
if self.toc.size() == 0:
self.note_input.config(state='disabled')
self.opening_state = self.notesdict
rcm_widgets = (self.subtopic_input.ent, self.note_input.text)
rcm.make_rc_menus(
rcm_widgets,
self.rc_menu,
ms.note_dlg_msg,
header_parent=self.notes_dialog_header,
dlg_header=self.dlg_header,
which_dlg='notes')
above.focus_set()
ST.config_generic(self)
utes.center_window(self)
def save_privacy_setting(self):
privacy_setting = self.privacy.get()
conn = sqlite3.connect(self.current_file)
conn.execute('PRAGMA foreign_keys = 1')
cur = conn.cursor()
cur.execute('''
UPDATE note
SET private = ?
WHERE note_id = ? ''',
(privacy_setting, self.current_note_id))
conn.commit()
cur.close()
conn.close()
def get_user_input_notes(self, input, widg):
''' '''
if self.current_note_id is None:
pass
conn = sqlite3.connect(self.current_file)
conn.execute('PRAGMA foreign_keys = 1')
cur = conn.cursor()
cur.execute(
'''
UPDATE note
SET notes = ?
WHERE note_id = ?
''',
(input, self.current_note_id))
conn.commit()
cur.close()
conn.close()
self.refresh()
def use_input(self, input, widg):
self.get_user_input_notes(input, widg)
def get_selected_subtopic(self):
# "is not None" has to be explicit here
if self.toc.curselection() is not None:
subtopic_index = self.toc.curselection()
else:
return
self.current_subtopic = self.toc.get(subtopic_index)
for k,v in self.notesdict.items():
if v[0] == self.current_subtopic:
break
self.current_note_id = k
self.current_note_text = v[1]
def switch_note(self, evt=None):
self.get_selected_subtopic()
if len(self.current_subtopic) == 0:
return
self.note_input.text.delete(1.0, 'end')
self.note_input.text.insert(1.0, self.current_note_text)
conn = sqlite3.connect(self.current_file)
cur = conn.cursor()
cur.execute('''
SELECT private
FROM note
JOIN findings_notes
ON note.note_id = findings_notes.note_id
WHERE note.subtopic = ?
AND finding_id = ? ''',
(self.current_subtopic, self.finding_id))
privacy_setting = cur.fetchone()[0]
cur.close()
conn.close()
if privacy_setting == 0:
self.public.select()
elif privacy_setting == 1:
self.private.select()
def rename_note(self):
new_name = self.subtopic_input.get()
if new_name in (self.default_text, ''):
no_select = msg.ErrorMessage(
self,
message='Provide a new subtopic name.',
title='Input Lacking')
self.subtopic_input.focus_set()
return
selected = self.toc.curselection()
if not selected:
no_select = msg.ErrorMessage(
self,
message='No subtopic was selected.',
title='Input Lacking')
return
self.toc.delete(selected)
self.toc.insert(selected, new_name)
self.subtopic_input.delete(0, 'end')
conn = sqlite3.connect(self.current_file)
conn.execute('PRAGMA foreign_keys = 1')
cur = conn.cursor()
cur.execute(
'''
UPDATE note
SET subtopic = ?
WHERE note_id = ?
''',
(new_name, self.current_note_id))
conn.commit()
cur.close()
conn.close()
self.refresh()
self.subtopic_input.replace_default_text()
self.toc.selection_set(selected)
def delete_note(self):
selected = self.toc.curselection()
subtopic = self.toc.get(selected)
self.toc.delete(selected)
self.note_input.text.delete(1.0, 'end')
conn = sqlite3.connect(self.current_file)
conn.execute('PRAGMA foreign_keys = 1')
cur = conn.cursor()
cur.execute(
'''
SELECT note_id
FROM note
WHERE subtopic = ?
''',
(subtopic,))
deletable = cur.fetchone()[0]
cur.execute(
'''
DELETE FROM findings_notes
WHERE note_id = ?
AND finding_id = ?
''',
(deletable, self.finding_id))
conn.commit()
cur.execute(
'''
DELETE FROM note
WHERE note_id = ?
''',
(deletable,))
conn.commit()
cur.close()
conn.close()
self.refresh()
self.subtopic_input.replace_default_text()
def refresh(self):
self.refresh_notes_per_finding()
self.toc.make_listbox_content()
for child in self.toc.listbox_content.winfo_children():
child.bind('<<ListboxSelected>>', self.switch_note)
def reorder_notes(self):
'''
'''
if self.toc.size() < 2:
return
self.order_dlg = wdg.Toplevel(self)
self.order_dlg.grab_set()
self.order_dlg.protocol('WM_DELETE_WINDOW', self.ignore_changes)
self.order_dlg.bind('<Return>', self.save_close_reorder_dlg)
self.order_dlg.bind('<Escape>', self.ignore_changes)
self.order_dlg.grid_columnconfigure(0, weight=1)
self.order_dlg.title('Reorder Subtopics')
instrux = (
'Tab or Ctrl+Tab selects movable subtopic.\n'
'Arrow keys change subtopic order up or down.')
top = wdg.LabelH3(self.order_dlg, text=instrux, anchor='center')
self.labels = wdg.Frame(self.order_dlg)
e = 0
for subtopic in self.subtopics:
lab = wdg.LabelMovable(self.labels, text=subtopic, anchor='w')
if e == 0:
first = lab
e += 1
lab.grid(column=0, row=e, padx=3, sticky='ew')
first.focus_set()
close2 = wdg.Button(
self.order_dlg,
text='OK',
command=self.save_close_reorder_dlg)
top.grid(column=0, row=0, pady=(24,0), padx=24, columnspan=2)
self.labels.grid(column=0, row=1, columnspan=2, padx=24, pady=24)
self.labels.grid_columnconfigure(0, weight=1)
close2.grid(column=1, row=2, sticky='se', padx=12, pady=(0,12))
utes.center_window(self.order_dlg)
def ignore_changes(self, evt=None):
self.order_dlg.grab_release()
self.order_dlg.destroy()
self.focus_set()
def save_close_reorder_dlg(self, evt=None):
'''
Replace the values list.
'''
q = 0
new_order = []
save_order = []
for child in self.labels.winfo_children():
text = child.cget('text')
new_order.append(text)
save_order.append([text, q])
q += 1
conn = sqlite3.connect(self.current_file)
conn.execute('PRAGMA foreign_keys = 1')
cur = conn.cursor()
for lst in save_order:
cur.execute(
'''
SELECT note_id
FROM note
WHERE subtopic = ?
''',
(lst[0],))
note_id = cur.fetchone()[0]
cur.execute(
'''
UPDATE findings_notes
SET order_subtopic = ?
WHERE finding_id = ?
AND note_id = ?
''',
(lst[1], self.finding_id, note_id))
conn.commit()
cur.close()
conn.close()
self.subtopics = self.toc.items = new_order
self.refresh()
self.order_dlg.grab_release()
self.order_dlg.destroy()
self.focus_set()
if __name__ == '__main__':
dlg_header = 'occupation: from ? to 1912/00/00, Egbert, Salvation Army Band'
def open_note_dialog():
dlg = NotesDialog(root,
'Jeremiah Laurence Grimaldo', None, dlg_header, 3)
dlg.focus_set()
root = tk.Tk()
root.geometry('+0+900')
open = wdg.Button(root, text='OPEN NOTE', command=open_note_dialog)
open.grid()
open.focus_set()
root.mainloop()