From 580be2096ec246f29d1065fc72dacb207dda9c37 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 12:13:37 +0200 Subject: [PATCH 01/58] Ref: reorder messages --- PapersCited/UI/messages.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/PapersCited/UI/messages.py b/PapersCited/UI/messages.py index 7699486..ac0223e 100644 --- a/PapersCited/UI/messages.py +++ b/PapersCited/UI/messages.py @@ -14,6 +14,17 @@ "\nAlternatively, you can manually copy the text from the .pdf and paste it into a" + \ "supported file format, such as .docx or .txt." +reading_txt_warning = "Warning! " + \ + "If you encounter problems reading this .txt file, backup the original file, then try saving it in UTF-8 or ANSI encoding.\ + \n(\"Save as...\" dialog, \"Encoding:\" at the bottom.)\n" + +saving_cancelled = "\n" + break_with_lines + \ + "\nSaving cancelled." + +no_citations_found = "No citations were found." + +no_citations_to_save = "Cannot save file: no citations found." + def filename_cant_be_read_message(filename, extension): message = f"The file {filename} couldn't be read. Make sure the file is a valid textual file." @@ -47,17 +58,7 @@ def report_found_citations(filename, citations, wider_citations): return(success_message) -no_citations_found = "No citations were found." -no_citations_to_save = "Cannot save file: no citations found." - def cant_write_file(filename): message = f"Cannot create citation file for {filename}." + \ "\nPossible permissions issue, can you create files at that folder?" return(message) - -reading_txt_warning = "Warning! " + \ - "If you encounter problems reading this .txt file, backup the original file, then try saving it in UTF-8 or ANSI encoding.\ - \n(\"Save as...\" dialog, \"Encoding:\" at the bottom.)\n" - -saving_cancelled = "\n" + break_with_lines + \ - "\nSaving cancelled." \ No newline at end of file From eaee228230a1c9e168e125f600dae8385108fc23 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 12:20:04 +0200 Subject: [PATCH 02/58] dot for No file selected message --- PapersCited/UI/appData.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PapersCited/UI/appData.py b/PapersCited/UI/appData.py index 32a336c..ed63074 100644 --- a/PapersCited/UI/appData.py +++ b/PapersCited/UI/appData.py @@ -17,7 +17,7 @@ def __init__(self, startup_filename, startup_results): self.__char_width_px = 6 # What to display when no file chosen: - self.__no_file_selected_txt = "(No file selected)" + self.__no_file_selected_txt = "(No file selected.)" def __calculate_chars_from_width(self, width): right_edge_buffer_px = self.__right_edge_buffer_px From 3e6c51251f3fc6accb30b1ba5407803b2b12f8b3 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 12:26:38 +0200 Subject: [PATCH 03/58] Intro message now instructs user --- PapersCited/UI/windowUI.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PapersCited/UI/windowUI.py b/PapersCited/UI/windowUI.py index e8182c8..16fc4a8 100644 --- a/PapersCited/UI/windowUI.py +++ b/PapersCited/UI/windowUI.py @@ -12,7 +12,8 @@ light_yellow = "#ffe08f" startup_filename = ".../path/to/file" -startup_results = "Welcome to PapersCited " + version + "\nResults will be shown here..." +startup_results = "Welcome to PapersCited " + version + "!" + \ + "\n\nFind citations in the text of a file by selecting 'Choose document'. Alternatively, analyse the text in your clipboard by selecting 'From clipboard'." citations_font = "Segoe UI Variable" citations_font_size = 11 From a40f166bbb78a504a8a5280a9c3c390c13ac870f Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 12:28:05 +0200 Subject: [PATCH 04/58] Move intro message to messages.py --- PapersCited/UI/messages.py | 3 +++ PapersCited/UI/windowUI.py | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/PapersCited/UI/messages.py b/PapersCited/UI/messages.py index ac0223e..c3b24fa 100644 --- a/PapersCited/UI/messages.py +++ b/PapersCited/UI/messages.py @@ -2,6 +2,9 @@ break_with_lines = "--------------------" +intro_message = "Welcome to PapersCited " + version + "!" + \ + "\n\nFind citations in the text of a file by selecting 'Choose document'. Alternatively, analyse the text in your clipboard by selecting 'From clipboard'." + cant_read_doc_msg = "NOTE: An additional library is required to read .doc files." + \ "\nThe simplest solution is to convert the file to a .docx file, then try analysing it again." + \ "\n\nAnother solution is to setup Antiword." + \ diff --git a/PapersCited/UI/windowUI.py b/PapersCited/UI/windowUI.py index 16fc4a8..eb04d6c 100644 --- a/PapersCited/UI/windowUI.py +++ b/PapersCited/UI/windowUI.py @@ -12,8 +12,7 @@ light_yellow = "#ffe08f" startup_filename = ".../path/to/file" -startup_results = "Welcome to PapersCited " + version + "!" + \ - "\n\nFind citations in the text of a file by selecting 'Choose document'. Alternatively, analyse the text in your clipboard by selecting 'From clipboard'." +startup_results = ms.intro_message citations_font = "Segoe UI Variable" citations_font_size = 11 From 9adeff926056ba07999b61a858e4084ed7fa80ae Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 12:44:23 +0200 Subject: [PATCH 05/58] Current filename in window title --- PapersCited/UI/appData.py | 28 +++++++++++++++------------- PapersCited/UI/windowUI.py | 22 ++-------------------- 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/PapersCited/UI/appData.py b/PapersCited/UI/appData.py index ed63074..6a55b8f 100644 --- a/PapersCited/UI/appData.py +++ b/PapersCited/UI/appData.py @@ -7,7 +7,7 @@ class AppData: def __init__(self, startup_filename, startup_results): - self.input_filename = startup_filename + self.input_filepath = startup_filename self.output_filename = "" self.citations = [] self.active_results = startup_results @@ -26,23 +26,25 @@ def __calculate_chars_from_width(self, width): label_width_chars = round(frame_width / char_width_px) return(label_width_chars) - def set_new_filename(self, filename, list_affected_wg, frame): - user_filename = filename - if user_filename == "": - user_filename = self.__no_file_selected_txt + def set_new_filename(self, filename, list_affected_wg): + user_filepath = filename + if user_filepath == "": + user_filepath = self.__no_file_selected_txt - self.input_filename = user_filename + self.input_filepath = user_filepath self.__set_output_filename() - frame_width = frame.winfo_width() - label_width_chars = self.__calculate_chars_from_width(frame_width) + print(os.path.splitext(user_filepath)) + + input_filename = os.path.basename(user_filepath) + # Display the document title in main window for widget in list_affected_wg: - widget["text"] = shorten_filename(self.input_filename, label_width_chars) + widget.title(input_filename) # When the window gets resized def update_filename_display(self, list_affected_wg, frame): - filename = self.get_input_filename() + filename = self.get_input_filepath() frame_width = frame.winfo_width() label_width_chars = self.__calculate_chars_from_width(frame_width) @@ -84,12 +86,12 @@ def warning_in_text_widget(self, warning_text, list_affected_wg): widget.config(state = "disabled") widget.see('1.0') - def get_input_filename(self): - return(self.input_filename) + def get_input_filepath(self): + return(self.input_filepath) def __set_output_filename(self): # append _citations, no extension - input = self.get_input_filename() + input = self.get_input_filepath() # Special case: blank filename when pasting from clipboard if input == self.__no_file_selected_txt: diff --git a/PapersCited/UI/windowUI.py b/PapersCited/UI/windowUI.py index eb04d6c..b1f8027 100644 --- a/PapersCited/UI/windowUI.py +++ b/PapersCited/UI/windowUI.py @@ -53,12 +53,6 @@ fr_current_file.grid(row = 0, column = 3, columnspan = 2, sticky = "NWES", padx = 10, pady = 5) -lbl_current_file = tk.Label(master = fr_current_file, - text = app_data.input_filename, bg = light_yellow, - pady = 3) - -lbl_current_file.grid(row = 0, column = 0, sticky = "W", padx = 5, pady = 5) - fr_results = tk.Frame(master = main_window, bg = "white", borderwidth = 2, relief = tk.GROOVE) fr_results.grid(row = 1, column = 0, sticky = "NWSE", columnspan = 5, @@ -112,8 +106,7 @@ def fn_btn_choose(event): title = "Select a document to search for citations:" ) app_data.set_new_filename(filename, - list_affected_wg=[lbl_current_file], - frame = fr_current_file) + list_affected_wg=[main_window]) try: reading_operation = fm.read_document(filename) @@ -149,8 +142,7 @@ def fn_from_clipboard(event): clipboard_text = "" app_data.set_new_filename(filename = "", - list_affected_wg=[lbl_current_file], - frame = fr_current_file) + list_affected_wg=[main_window]) try: message = None citations = fm.find_citations(clipboard_text) @@ -235,16 +227,6 @@ def fn_btn_save_txt(event): btn_save_txt.bind("", fn_btn_save_txt) btn_save_txt.bind("", lambda event, btn = btn_save_txt: fn_btn_release(event, btn)) - -# On resize, re-render the filename display -def fn_window_resize(event): - app_data.update_filename_display( - list_affected_wg=[lbl_current_file], - frame = fr_current_file - ) - -main_window.bind("", fn_window_resize) - # Right-click menu for copying citations rc_menu = tk.Menu(main_window, tearoff = 0) From 91d1f3d4de15be001c16fe48ce56cb3e2085f3d1 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 12:58:53 +0200 Subject: [PATCH 06/58] Display Paperscited at the end of filename --- PapersCited/UI/appData.py | 11 +++++++---- PapersCited/UI/windowUI.py | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/PapersCited/UI/appData.py b/PapersCited/UI/appData.py index 6a55b8f..d0c3611 100644 --- a/PapersCited/UI/appData.py +++ b/PapersCited/UI/appData.py @@ -17,7 +17,7 @@ def __init__(self, startup_filename, startup_results): self.__char_width_px = 6 # What to display when no file chosen: - self.__no_file_selected_txt = "(No file selected.)" + self.__no_file_selected_txt = "" def __calculate_chars_from_width(self, width): right_edge_buffer_px = self.__right_edge_buffer_px @@ -34,11 +34,14 @@ def set_new_filename(self, filename, list_affected_wg): self.input_filepath = user_filepath self.__set_output_filename() - print(os.path.splitext(user_filepath)) - + # Display the document title in main window input_filename = os.path.basename(user_filepath) - # Display the document title in main window + if input_filename == self.__no_file_selected_txt: + input_filename = "PapersCited" + else: + input_filename = input_filename + " - PapersCited" + for widget in list_affected_wg: widget.title(input_filename) diff --git a/PapersCited/UI/windowUI.py b/PapersCited/UI/windowUI.py index b1f8027..b6ffb4a 100644 --- a/PapersCited/UI/windowUI.py +++ b/PapersCited/UI/windowUI.py @@ -30,6 +30,8 @@ main_window.rowconfigure(1, weight = 2, minsize = 400) main_window.rowconfigure(2, weight = 0, minsize = 30) +main_window.title("PapersCited") + main_window.minsize(750, 500) btn_choose = tk.Button(master = main_window, @@ -91,7 +93,6 @@ btn_save_txt.grid(row = 2, column = 4, sticky = "SE", padx = 10, pady = 5) -main_window.title("PapersCited " + version) # Bind functions ---- From f28a950d2bd49a89d2a3cc91ffffe447967e0dc5 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 13:04:40 +0200 Subject: [PATCH 07/58] Remove window frame for filename --- PapersCited/UI/windowUI.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/PapersCited/UI/windowUI.py b/PapersCited/UI/windowUI.py index b6ffb4a..8e7f822 100644 --- a/PapersCited/UI/windowUI.py +++ b/PapersCited/UI/windowUI.py @@ -50,11 +50,6 @@ btn_from_clipboard.grid(row = 0, column = 1, sticky = "NW", padx = 5, pady = 5) - -fr_current_file = tk.Frame(master = main_window, bg = light_yellow) -fr_current_file.grid(row = 0, column = 3, columnspan = 2, sticky = "NWES", - padx = 10, pady = 5) - fr_results = tk.Frame(master = main_window, bg = "white", borderwidth = 2, relief = tk.GROOVE) fr_results.grid(row = 1, column = 0, sticky = "NWSE", columnspan = 5, From 18580a17421481b32061f20e57d85e4075493d3e Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 13:06:09 +0200 Subject: [PATCH 08/58] Distinguish output filepath and filename --- PapersCited/UI/appData.py | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/PapersCited/UI/appData.py b/PapersCited/UI/appData.py index d0c3611..6b8e261 100644 --- a/PapersCited/UI/appData.py +++ b/PapersCited/UI/appData.py @@ -8,7 +8,7 @@ class AppData: def __init__(self, startup_filename, startup_results): self.input_filepath = startup_filename - self.output_filename = "" + self.output_filepath = "" self.citations = [] self.active_results = startup_results @@ -32,7 +32,7 @@ def set_new_filename(self, filename, list_affected_wg): user_filepath = self.__no_file_selected_txt self.input_filepath = user_filepath - self.__set_output_filename() + self.__set_output_filepath() # Display the document title in main window input_filename = os.path.basename(user_filepath) @@ -44,16 +44,6 @@ def set_new_filename(self, filename, list_affected_wg): for widget in list_affected_wg: widget.title(input_filename) - - # When the window gets resized - def update_filename_display(self, list_affected_wg, frame): - filename = self.get_input_filepath() - - frame_width = frame.winfo_width() - label_width_chars = self.__calculate_chars_from_width(frame_width) - - for widget in list_affected_wg: - widget["text"] = shorten_filename(filename, label_width_chars) def set_new_results_citations(self, citations, list_affected_wg): self.citations = citations @@ -92,28 +82,28 @@ def warning_in_text_widget(self, warning_text, list_affected_wg): def get_input_filepath(self): return(self.input_filepath) - def __set_output_filename(self): + def __set_output_filepath(self): # append _citations, no extension input = self.get_input_filepath() # Special case: blank filename when pasting from clipboard if input == self.__no_file_selected_txt: - self.output_filename = "Citations_found" + self.output_filepath = "Citations_found" return(None) output_file_prefix = os.path.splitext(input) - output_filename = output_file_prefix[0] + "_citations" + output_filepath = output_file_prefix[0] + "_citations" - self.output_filename = output_filename + self.output_filepath = output_filepath - def get_output_filename(self): - return(self.output_filename) + def get_output_filepath(self): + return(self.output_filepath) def popup_ask_save_file(self, extension): - output_filename = self.get_output_filename() + output_filepath = self.get_output_filepath() given_extension = extension - directory, name = os.path.split(output_filename) + directory, name = os.path.split(output_filepath) default_filename = name + given_extension @@ -126,8 +116,8 @@ def popup_ask_save_file(self, extension): user_filename = asksaveasfilename( initialfile = default_filename, - initialdir= directory, - filetypes= (filetype, ) # Tuple of tuples required, single item requires comma + initialdir = directory, + filetypes = (filetype, ) # Tuple of tuples required, single item requires comma ) # Check if user cancelled the action: From 3c38f9bc209692b51fe01534c9f804ac5ab96ee7 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 13:08:03 +0200 Subject: [PATCH 09/58] Remove unused functions related to filename size --- PapersCited/UI/appData.py | 1 - PapersCited/UI/fileManipulation.py | 9 --------- 2 files changed, 10 deletions(-) diff --git a/PapersCited/UI/appData.py b/PapersCited/UI/appData.py index 6b8e261..be12b32 100644 --- a/PapersCited/UI/appData.py +++ b/PapersCited/UI/appData.py @@ -3,7 +3,6 @@ import UI.transformCitations as tc import UI.messages as ms import os -from UI.fileManipulation import shorten_filename class AppData: def __init__(self, startup_filename, startup_results): diff --git a/PapersCited/UI/fileManipulation.py b/PapersCited/UI/fileManipulation.py index d374ab4..ca9eac0 100644 --- a/PapersCited/UI/fileManipulation.py +++ b/PapersCited/UI/fileManipulation.py @@ -171,13 +171,4 @@ def write_txt(filename, citations, wider_citations): return(success_message) -def shorten_filename(filename, nchar = 50): - f_length = len(filename) - if f_length <= nchar: return(filename) - - cutoff_length = nchar - 2 - first_part = filename[0:(cutoff_length - 1)] - shortened_name = first_part + "..." - return(shortened_name) - \ No newline at end of file From e8522ff4af478e3294be73e8fec247517ca01ea4 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 13:10:39 +0200 Subject: [PATCH 10/58] Startup filename is blank --- PapersCited/UI/windowUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PapersCited/UI/windowUI.py b/PapersCited/UI/windowUI.py index 8e7f822..3192429 100644 --- a/PapersCited/UI/windowUI.py +++ b/PapersCited/UI/windowUI.py @@ -11,7 +11,7 @@ light_yellow = "#ffe08f" -startup_filename = ".../path/to/file" +startup_filename = "" startup_results = ms.intro_message citations_font = "Segoe UI Variable" From 2f23e8cd9f26121ed304fa6279ae70ba81a818d2 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 13:21:28 +0200 Subject: [PATCH 11/58] specify message for "No file selected" --- PapersCited/UI/fileManipulation.py | 4 ++-- PapersCited/UI/messages.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/PapersCited/UI/fileManipulation.py b/PapersCited/UI/fileManipulation.py index ca9eac0..847dadc 100644 --- a/PapersCited/UI/fileManipulation.py +++ b/PapersCited/UI/fileManipulation.py @@ -15,7 +15,7 @@ def check_file(filename): file_exists = os.path.isfile(filename) if file_exists == False: - raise Exception("No file selected") + raise Exception(ms.no_file_selected) warning = None @@ -56,7 +56,7 @@ def read_document(filename): try: message = check_file(filename) except: - raise Exception("No file selected") + raise Exception(ms.no_file_selected) file_extension = os.path.splitext(filename)[1].casefold() diff --git a/PapersCited/UI/messages.py b/PapersCited/UI/messages.py index c3b24fa..8b3a0de 100644 --- a/PapersCited/UI/messages.py +++ b/PapersCited/UI/messages.py @@ -28,6 +28,8 @@ no_citations_to_save = "Cannot save file: no citations found." +no_file_selected = "No file selected." + def filename_cant_be_read_message(filename, extension): message = f"The file {filename} couldn't be read. Make sure the file is a valid textual file." From f9acc134644494ab55b996b2001f0d92cb11ef9d Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 13:24:30 +0200 Subject: [PATCH 12/58] Remove unneeded function for counting characters --- PapersCited/UI/appData.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/PapersCited/UI/appData.py b/PapersCited/UI/appData.py index be12b32..97d49b1 100644 --- a/PapersCited/UI/appData.py +++ b/PapersCited/UI/appData.py @@ -17,13 +17,6 @@ def __init__(self, startup_filename, startup_results): # What to display when no file chosen: self.__no_file_selected_txt = "" - - def __calculate_chars_from_width(self, width): - right_edge_buffer_px = self.__right_edge_buffer_px - frame_width = width - right_edge_buffer_px - char_width_px = self.__char_width_px - label_width_chars = round(frame_width / char_width_px) - return(label_width_chars) def set_new_filename(self, filename, list_affected_wg): user_filepath = filename From 884e4d7dbaa6690fad8a3bb51e64290267e3ebf3 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 13:44:56 +0200 Subject: [PATCH 13/58] Remove test for removed fn --- PapersCited/tests/test_ui_functions.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/PapersCited/tests/test_ui_functions.py b/PapersCited/tests/test_ui_functions.py index f7b3950..e69de29 100644 --- a/PapersCited/tests/test_ui_functions.py +++ b/PapersCited/tests/test_ui_functions.py @@ -1,14 +0,0 @@ -from UI.fileManipulation import shorten_filename - -def test_shortening_names(): - short_name = "aeiou" - long_name = "0123456789" + "0123456789" + "0123456789" + "0123456789" + "0123456789" - - assert shorten_filename(short_name) == short_name - assert shorten_filename(short_name, 4) == "a..." - assert shorten_filename(short_name, 5) == short_name - - assert shorten_filename(long_name, 50) == long_name - assert shorten_filename(long_name, 5) == "01..." - assert shorten_filename(long_name, 10) == "0123456..." - \ No newline at end of file From 67858ed243c30788f6ce1d273e37af50c6752c0d Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 18:04:28 +0200 Subject: [PATCH 14/58] encoding shebang on very start of main file --- PapersCited/PapersCited.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/PapersCited/PapersCited.py b/PapersCited/PapersCited.py index d5e441e..00ed983 100644 --- a/PapersCited/PapersCited.py +++ b/PapersCited/PapersCited.py @@ -1,8 +1,7 @@ +# -*- coding: utf-8 -*- from UI.windowUI import main_window from UI.messages import version -# -*- coding: utf-8 -*- - # Welcome message, before loading anything if __name__ == "__main__": print("PapersCited", version, "startup. Please wait...") From 967552e2b455305df1f86f1d6d7b9f0f39f151ed Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 18:07:39 +0200 Subject: [PATCH 15/58] Specify UTF8 encoding writing to .txt --- PapersCited/UI/fileManipulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PapersCited/UI/fileManipulation.py b/PapersCited/UI/fileManipulation.py index 847dadc..ba7c695 100644 --- a/PapersCited/UI/fileManipulation.py +++ b/PapersCited/UI/fileManipulation.py @@ -164,7 +164,7 @@ def write_txt(filename, citations, wider_citations): citations_string = tc.citations_to_string_pretty(citations, wider_citations) # Create a file - with open(output_filename, 'w') as f: + with open(output_filename, 'w', encoding = "utf-8") as f: f.write(citations_string) success_message = ms.report_found_citations(output_filename, citations, wider_citations) From ea941fe96df33566d67ad2329a33fd76c8f47470 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 18:20:36 +0200 Subject: [PATCH 16/58] help_with_libraries correct Poppler link --- help_with_libraries.txt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/help_with_libraries.txt b/help_with_libraries.txt index 1d27a57..201368a 100644 --- a/help_with_libraries.txt +++ b/help_with_libraries.txt @@ -18,12 +18,15 @@ If you get an error reading .doc files on Windows, you need to download Antiword With this, you have added the Antiword libraries to your %PATH% variable, so programs, including PapersCited, can access it to manipulate .doc files. # .pdf files -The procedure is very similar to the one described for .doc files. +The Poppler utility is used to read text from PDF files. It can be installed on Windows +in a few steps. PapersCited is tested using Poppler 23.08.0, so the links will reflect that. -1) Download poppler-0.68.0_x86 from https://blog.alivate.com.au/poppler-windows/ -2) Extract the file and move the "poppler-0.68.0" folder to -"C:\Program Files" -3) Edit the %PATH% like in steps 4)-6) for .doc files. -7) Press "New" and paste the following: "C:\Program Files\poppler-0.68.0\bin" +1) Download Release-23.08.0-0.zip from (the following Github link)[https://github.com/oschwartz10612/poppler-windows/releases/tag/v23.08.0-0] +2) Extract the archive using a tool like 7zip. +3) Move the *"poppler-23.08.0"* folder to "C:\Program Files" +4) Now you need to add it to %PATH%. To do so, open the Windows start menu and type "Edit the system environment variables", then select it. +5) On the "Advanced" tab, select "Environment Variables..." +6) One row should be labelled "Path". Select it, and press the "Edit..." button below. +7) Press "New" and paste the following: "C:\Program Files\poppler-23.08.0\Library\bin" 8) Press "OK". -9) Restart the computer. \ No newline at end of file +9) Restart the computer for the changes to take effect. \ No newline at end of file From 92f4dc6321ec9e6b11b35001b407682e40547eb1 Mon Sep 17 00:00:00 2001 From: Mkranj <111303584+Mkranj@users.noreply.github.com> Date: Sat, 30 Sep 2023 18:24:36 +0200 Subject: [PATCH 17/58] non-markdown link --- help_with_libraries.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/help_with_libraries.txt b/help_with_libraries.txt index 201368a..94cf8cd 100644 --- a/help_with_libraries.txt +++ b/help_with_libraries.txt @@ -21,7 +21,7 @@ With this, you have added the Antiword libraries to your %PATH% variable, so pro The Poppler utility is used to read text from PDF files. It can be installed on Windows in a few steps. PapersCited is tested using Poppler 23.08.0, so the links will reflect that. -1) Download Release-23.08.0-0.zip from (the following Github link)[https://github.com/oschwartz10612/poppler-windows/releases/tag/v23.08.0-0] +1) Download Release-23.08.0-0.zip from the following Github link: https://github.com/oschwartz10612/poppler-windows/releases/tag/v23.08.0-0 2) Extract the archive using a tool like 7zip. 3) Move the *"poppler-23.08.0"* folder to "C:\Program Files" 4) Now you need to add it to %PATH%. To do so, open the Windows start menu and type "Edit the system environment variables", then select it. @@ -29,4 +29,4 @@ in a few steps. PapersCited is tested using Poppler 23.08.0, so the links will r 6) One row should be labelled "Path". Select it, and press the "Edit..." button below. 7) Press "New" and paste the following: "C:\Program Files\poppler-23.08.0\Library\bin" 8) Press "OK". -9) Restart the computer for the changes to take effect. \ No newline at end of file +9) Restart the computer for the changes to take effect. From 749538c05fb250812cfbbb0d4e120e9bf82066ba Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 20:33:50 +0200 Subject: [PATCH 18/58] Reconstruct the UI in main_window class --- PapersCited/PapersCited.py | 8 ++- PapersCited/UI/main_window.py | 108 ++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 PapersCited/UI/main_window.py diff --git a/PapersCited/PapersCited.py b/PapersCited/PapersCited.py index 00ed983..6569859 100644 --- a/PapersCited/PapersCited.py +++ b/PapersCited/PapersCited.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from UI.windowUI import main_window +from UI.main_window import main_window from UI.messages import version # Welcome message, before loading anything @@ -10,8 +10,10 @@ # MAIN ---- def main(): - main_window.focus_force() - main_window.mainloop() + UI = main_window() + + UI.focus_force() + UI.mainloop() if __name__ == "__main__": main() diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py new file mode 100644 index 0000000..a6b53cd --- /dev/null +++ b/PapersCited/UI/main_window.py @@ -0,0 +1,108 @@ +import tkinter as tk +import tkinter as tk +from tkinter import filedialog +from tkinter import messagebox + +import UI.fileManipulation as fm +import UI.messages as ms +from UI.messages import version +from UI.appData import AppData + +# Variables ---- + +light_yellow = "#ffe08f" + +startup_filename = "" +startup_results = ms.intro_message + +citations_font = "Segoe UI Variable" +citations_font_size = 11 + +app_data = AppData(startup_filename, startup_results) + +class main_window(tk.Tk): + def __init__(self): + super().__init__() + + self.title("PapersCited") + self.minsize(750, 500) + + self.columnconfigure(0, weight = 0, minsize = 50) + self.columnconfigure(1, weight = 0, minsize = 50) + self.columnconfigure(2, weight = 0, minsize = 20) + self.columnconfigure(3, weight = 1, minsize = 100) + self.rowconfigure(0, weight = 0, minsize = 30) + self.rowconfigure(1, weight = 2, minsize = 400) + self.rowconfigure(2, weight = 0, minsize = 30) + + self.create_widgets() + + def create_widgets(self): + # Sets up individual UI elements + self.__btn_choose() + self.__btn_from_clipboard() + self.__results() + self.__save_excel() + self.__save_text() + + def __btn_choose(self): + btn_choose = tk.Button(master = self, + text = "Choose document", + borderwidth = 3, relief=tk.RAISED, + padx = 8, pady = 5 + ) + + btn_choose.grid(row = 0, column = 0, sticky = "NW", padx = 10, pady = 5) + + def __btn_from_clipboard(self): + btn_from_clipboard = tk.Button(master = self, + text = "From clipboard", + borderwidth = 3, relief=tk.RAISED, + padx = 8, pady = 5 + ) + + btn_from_clipboard.grid(row = 0, column = 1, sticky = "NW", padx = 5, pady = 5) + + def __results(self): + # Frame element + fr_results = tk.Frame(master = self, bg = "white", + borderwidth = 2, relief = tk.GROOVE) + fr_results.grid(row = 1, column = 0, sticky = "NWSE", columnspan = 5, + padx = 10) + + fr_results.columnconfigure(0, weight = 1) + fr_results.columnconfigure(1, weight = 0) + fr_results.rowconfigure(0, weight = 1) + + # Scrollbar element + scr_results = tk.Scrollbar(fr_results, orient = "vertical") + scr_results.grid(row = 0, column = 1, sticky = "NS") + + # Text field element + txt_results = tk.Text(master = fr_results, bg = "white", yscrollcommand = scr_results.set, wrap = tk.WORD) + txt_results.configure(font = (citations_font, citations_font_size)) + txt_results.insert(tk.END, app_data.active_results) + + scr_results.config(command=txt_results.yview) + + txt_results.config(state = "normal") + txt_results.grid(row = 0, column = 0, sticky="NSWE") + txt_results.config(state = "disabled") + + def __save_excel(self): + btn_save_xlsx = tk.Button(master = self, + text = "Save as .xlsx", + borderwidth = 2, + padx = 5, pady = 5) + + btn_save_xlsx.grid(row = 2, column = 3, sticky = "SE", + padx = 10, pady = 5) + + def __save_text(self): + btn_save_txt = tk.Button(master = self, + text = "Save as .txt", + borderwidth = 2, + padx = 5, pady = 5) + + btn_save_txt.grid(row = 2, column = 4, sticky = "SE", + padx = 10, pady = 5) \ No newline at end of file From ee9d73977e2b726fb7c5b1e6554b95871f83fd0f Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 20:36:53 +0200 Subject: [PATCH 19/58] Specify building methods --- PapersCited/UI/main_window.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index a6b53cd..b06c4d9 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -39,13 +39,13 @@ def __init__(self): def create_widgets(self): # Sets up individual UI elements - self.__btn_choose() - self.__btn_from_clipboard() - self.__results() - self.__save_excel() - self.__save_text() + self.__build_btn_choose() + self.__build_btn_from_clipboard() + self.__build_results() + self.__build_save_excel() + self.__build_save_text() - def __btn_choose(self): + def __build_btn_choose(self): btn_choose = tk.Button(master = self, text = "Choose document", borderwidth = 3, relief=tk.RAISED, @@ -54,7 +54,7 @@ def __btn_choose(self): btn_choose.grid(row = 0, column = 0, sticky = "NW", padx = 10, pady = 5) - def __btn_from_clipboard(self): + def __build_btn_from_clipboard(self): btn_from_clipboard = tk.Button(master = self, text = "From clipboard", borderwidth = 3, relief=tk.RAISED, @@ -63,7 +63,7 @@ def __btn_from_clipboard(self): btn_from_clipboard.grid(row = 0, column = 1, sticky = "NW", padx = 5, pady = 5) - def __results(self): + def __build_results(self): # Frame element fr_results = tk.Frame(master = self, bg = "white", borderwidth = 2, relief = tk.GROOVE) @@ -89,7 +89,7 @@ def __results(self): txt_results.grid(row = 0, column = 0, sticky="NSWE") txt_results.config(state = "disabled") - def __save_excel(self): + def __build_save_excel(self): btn_save_xlsx = tk.Button(master = self, text = "Save as .xlsx", borderwidth = 2, @@ -98,11 +98,13 @@ def __save_excel(self): btn_save_xlsx.grid(row = 2, column = 3, sticky = "SE", padx = 10, pady = 5) - def __save_text(self): + def __build_save_text(self): btn_save_txt = tk.Button(master = self, text = "Save as .txt", borderwidth = 2, padx = 5, pady = 5) btn_save_txt.grid(row = 2, column = 4, sticky = "SE", - padx = 10, pady = 5) \ No newline at end of file + padx = 10, pady = 5) + + # \ No newline at end of file From f5983ba9ccddbbec225ee0d1022b61a92a55ed82 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 20:55:12 +0200 Subject: [PATCH 20/58] Start - individual classes for components So that bindings can be (at least somewhere) contained in the component part. And every class instance will be an attribute of the main window. So that main window fns can call individual objects --- PapersCited/UI/main_window.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index b06c4d9..18567b3 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -39,21 +39,12 @@ def __init__(self): def create_widgets(self): # Sets up individual UI elements - self.__build_btn_choose() + self.btn_choose = btnChoose(self).get() self.__build_btn_from_clipboard() self.__build_results() self.__build_save_excel() self.__build_save_text() - def __build_btn_choose(self): - btn_choose = tk.Button(master = self, - text = "Choose document", - borderwidth = 3, relief=tk.RAISED, - padx = 8, pady = 5 - ) - - btn_choose.grid(row = 0, column = 0, sticky = "NW", padx = 10, pady = 5) - def __build_btn_from_clipboard(self): btn_from_clipboard = tk.Button(master = self, text = "From clipboard", @@ -107,4 +98,16 @@ def __build_save_text(self): btn_save_txt.grid(row = 2, column = 4, sticky = "SE", padx = 10, pady = 5) - # \ No newline at end of file +class btnChoose(): + def __init__(self, master): + self.master = master + + def get(self): + btn_choose = tk.Button(master = self.master, + text = "Choose document", + borderwidth = 3, relief=tk.RAISED, + padx = 8, pady = 5 + ) + + btn_choose.grid(row = 0, column = 0, sticky = "NW", padx = 10, pady = 5) + return(self) \ No newline at end of file From 14a0adddf79f8e9ff89891161e500ba53a4b7478 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 30 Sep 2023 22:08:03 +0200 Subject: [PATCH 21/58] Implemen btn choose and results as classes --- PapersCited/UI/main_window.py | 115 +++++++++++++++++++++++++--------- 1 file changed, 85 insertions(+), 30 deletions(-) diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index 18567b3..fc63935 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -35,13 +35,14 @@ def __init__(self): self.rowconfigure(1, weight = 2, minsize = 400) self.rowconfigure(2, weight = 0, minsize = 30) + self.data = app_data self.create_widgets() def create_widgets(self): # Sets up individual UI elements self.btn_choose = btnChoose(self).get() self.__build_btn_from_clipboard() - self.__build_results() + self.ui_results = uiResults(self).get() self.__build_save_excel() self.__build_save_text() @@ -54,32 +55,6 @@ def __build_btn_from_clipboard(self): btn_from_clipboard.grid(row = 0, column = 1, sticky = "NW", padx = 5, pady = 5) - def __build_results(self): - # Frame element - fr_results = tk.Frame(master = self, bg = "white", - borderwidth = 2, relief = tk.GROOVE) - fr_results.grid(row = 1, column = 0, sticky = "NWSE", columnspan = 5, - padx = 10) - - fr_results.columnconfigure(0, weight = 1) - fr_results.columnconfigure(1, weight = 0) - fr_results.rowconfigure(0, weight = 1) - - # Scrollbar element - scr_results = tk.Scrollbar(fr_results, orient = "vertical") - scr_results.grid(row = 0, column = 1, sticky = "NS") - - # Text field element - txt_results = tk.Text(master = fr_results, bg = "white", yscrollcommand = scr_results.set, wrap = tk.WORD) - txt_results.configure(font = (citations_font, citations_font_size)) - txt_results.insert(tk.END, app_data.active_results) - - scr_results.config(command=txt_results.yview) - - txt_results.config(state = "normal") - txt_results.grid(row = 0, column = 0, sticky="NSWE") - txt_results.config(state = "disabled") - def __build_save_excel(self): btn_save_xlsx = tk.Button(master = self, text = "Save as .xlsx", @@ -97,12 +72,18 @@ def __build_save_text(self): btn_save_txt.grid(row = 2, column = 4, sticky = "SE", padx = 10, pady = 5) + +# Helper to return buttons to rest state after a click +def fn_btn_release(event, btn): + btn.config(relief="raised") + return("break") + +# Individual components and their bindings class btnChoose(): def __init__(self, master): self.master = master - - def get(self): + btn_choose = tk.Button(master = self.master, text = "Choose document", borderwidth = 3, relief=tk.RAISED, @@ -110,4 +91,78 @@ def get(self): ) btn_choose.grid(row = 0, column = 0, sticky = "NW", padx = 10, pady = 5) - return(self) \ No newline at end of file + + self.UI = btn_choose + + def on_click(self, event): + + self.UI.config(relief="sunken") + + filename = filedialog.askopenfilename( + title = "Select a document to search for citations:" + ) + app_data.set_new_filename(filename, + list_affected_wg=[self.master]) + try: + reading_operation = fm.read_document(filename) + + message = reading_operation["status_message"] + contents = reading_operation["document_text"] + citations = fm.find_citations(contents) + + except Exception as e: + error = str(e) + app_data.reset_on_error(error, list_affected_wg = [self.master.ui_results]) + return("break") + + app_data.set_new_results_citations(citations, + list_affected_wg = [self.master.ui_results]) + + if message: + app_data.warning_in_text_widget(message, list_affected_wg = [self.master.ui_results]) + + return("break") + + def get(self): + output_component = self.UI + output_component.bind("", self.on_click) + output_component.bind("", lambda event, + btn=output_component: fn_btn_release(event, btn)) + return(output_component) + + +class uiResults(): + def __init__(self, master): + self.master = master + + # Frame element + fr_results = tk.Frame(master=master, bg="white", + borderwidth=2, relief=tk.GROOVE) + fr_results.grid(row=1, column=0, sticky="NWSE", columnspan=5, + padx=10) + + fr_results.columnconfigure(0, weight=1) + fr_results.columnconfigure(1, weight=0) + fr_results.rowconfigure(0, weight=1) + + # Scrollbar element + scr_results = tk.Scrollbar(fr_results, orient="vertical") + scr_results.grid(row=0, column=1, sticky="NS") + + # Text field element + txt_results = tk.Text(master=fr_results, bg="white", + yscrollcommand=scr_results.set, wrap=tk.WORD) + txt_results.configure(font=(citations_font, citations_font_size)) + txt_results.insert(tk.END, app_data.active_results) + + scr_results.config(command=txt_results.yview) + + txt_results.config(state="normal") + txt_results.grid(row=0, column=0, sticky="NSWE") + txt_results.config(state="disabled") + + self.UI = txt_results + + def get(self): + output_component = self.UI + return(output_component) From 2f64c328c05c9e0838f7de84ce5fb0f6e390154f Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 11:24:59 +0200 Subject: [PATCH 22/58] Revert "Implemen btn choose and results as classes" This reverts commit 14a0adddf79f8e9ff89891161e500ba53a4b7478. --- PapersCited/UI/main_window.py | 115 +++++++++------------------------- 1 file changed, 30 insertions(+), 85 deletions(-) diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index fc63935..18567b3 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -35,14 +35,13 @@ def __init__(self): self.rowconfigure(1, weight = 2, minsize = 400) self.rowconfigure(2, weight = 0, minsize = 30) - self.data = app_data self.create_widgets() def create_widgets(self): # Sets up individual UI elements self.btn_choose = btnChoose(self).get() self.__build_btn_from_clipboard() - self.ui_results = uiResults(self).get() + self.__build_results() self.__build_save_excel() self.__build_save_text() @@ -55,6 +54,32 @@ def __build_btn_from_clipboard(self): btn_from_clipboard.grid(row = 0, column = 1, sticky = "NW", padx = 5, pady = 5) + def __build_results(self): + # Frame element + fr_results = tk.Frame(master = self, bg = "white", + borderwidth = 2, relief = tk.GROOVE) + fr_results.grid(row = 1, column = 0, sticky = "NWSE", columnspan = 5, + padx = 10) + + fr_results.columnconfigure(0, weight = 1) + fr_results.columnconfigure(1, weight = 0) + fr_results.rowconfigure(0, weight = 1) + + # Scrollbar element + scr_results = tk.Scrollbar(fr_results, orient = "vertical") + scr_results.grid(row = 0, column = 1, sticky = "NS") + + # Text field element + txt_results = tk.Text(master = fr_results, bg = "white", yscrollcommand = scr_results.set, wrap = tk.WORD) + txt_results.configure(font = (citations_font, citations_font_size)) + txt_results.insert(tk.END, app_data.active_results) + + scr_results.config(command=txt_results.yview) + + txt_results.config(state = "normal") + txt_results.grid(row = 0, column = 0, sticky="NSWE") + txt_results.config(state = "disabled") + def __build_save_excel(self): btn_save_xlsx = tk.Button(master = self, text = "Save as .xlsx", @@ -72,18 +97,12 @@ def __build_save_text(self): btn_save_txt.grid(row = 2, column = 4, sticky = "SE", padx = 10, pady = 5) - -# Helper to return buttons to rest state after a click -def fn_btn_release(event, btn): - btn.config(relief="raised") - return("break") - -# Individual components and their bindings class btnChoose(): def __init__(self, master): self.master = master - + + def get(self): btn_choose = tk.Button(master = self.master, text = "Choose document", borderwidth = 3, relief=tk.RAISED, @@ -91,78 +110,4 @@ def __init__(self, master): ) btn_choose.grid(row = 0, column = 0, sticky = "NW", padx = 10, pady = 5) - - self.UI = btn_choose - - def on_click(self, event): - - self.UI.config(relief="sunken") - - filename = filedialog.askopenfilename( - title = "Select a document to search for citations:" - ) - app_data.set_new_filename(filename, - list_affected_wg=[self.master]) - try: - reading_operation = fm.read_document(filename) - - message = reading_operation["status_message"] - contents = reading_operation["document_text"] - citations = fm.find_citations(contents) - - except Exception as e: - error = str(e) - app_data.reset_on_error(error, list_affected_wg = [self.master.ui_results]) - return("break") - - app_data.set_new_results_citations(citations, - list_affected_wg = [self.master.ui_results]) - - if message: - app_data.warning_in_text_widget(message, list_affected_wg = [self.master.ui_results]) - - return("break") - - def get(self): - output_component = self.UI - output_component.bind("", self.on_click) - output_component.bind("", lambda event, - btn=output_component: fn_btn_release(event, btn)) - return(output_component) - - -class uiResults(): - def __init__(self, master): - self.master = master - - # Frame element - fr_results = tk.Frame(master=master, bg="white", - borderwidth=2, relief=tk.GROOVE) - fr_results.grid(row=1, column=0, sticky="NWSE", columnspan=5, - padx=10) - - fr_results.columnconfigure(0, weight=1) - fr_results.columnconfigure(1, weight=0) - fr_results.rowconfigure(0, weight=1) - - # Scrollbar element - scr_results = tk.Scrollbar(fr_results, orient="vertical") - scr_results.grid(row=0, column=1, sticky="NS") - - # Text field element - txt_results = tk.Text(master=fr_results, bg="white", - yscrollcommand=scr_results.set, wrap=tk.WORD) - txt_results.configure(font=(citations_font, citations_font_size)) - txt_results.insert(tk.END, app_data.active_results) - - scr_results.config(command=txt_results.yview) - - txt_results.config(state="normal") - txt_results.grid(row=0, column=0, sticky="NSWE") - txt_results.config(state="disabled") - - self.UI = txt_results - - def get(self): - output_component = self.UI - return(output_component) + return(self) \ No newline at end of file From b336ca82b515ab5b5d826d7860328b5a0bca0224 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 11:25:38 +0200 Subject: [PATCH 23/58] Revert "Start - individual classes for components" This reverts commit f5983ba9ccddbbec225ee0d1022b61a92a55ed82. --- PapersCited/UI/main_window.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index 18567b3..b06c4d9 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -39,12 +39,21 @@ def __init__(self): def create_widgets(self): # Sets up individual UI elements - self.btn_choose = btnChoose(self).get() + self.__build_btn_choose() self.__build_btn_from_clipboard() self.__build_results() self.__build_save_excel() self.__build_save_text() + def __build_btn_choose(self): + btn_choose = tk.Button(master = self, + text = "Choose document", + borderwidth = 3, relief=tk.RAISED, + padx = 8, pady = 5 + ) + + btn_choose.grid(row = 0, column = 0, sticky = "NW", padx = 10, pady = 5) + def __build_btn_from_clipboard(self): btn_from_clipboard = tk.Button(master = self, text = "From clipboard", @@ -98,16 +107,4 @@ def __build_save_text(self): btn_save_txt.grid(row = 2, column = 4, sticky = "SE", padx = 10, pady = 5) -class btnChoose(): - def __init__(self, master): - self.master = master - - def get(self): - btn_choose = tk.Button(master = self.master, - text = "Choose document", - borderwidth = 3, relief=tk.RAISED, - padx = 8, pady = 5 - ) - - btn_choose.grid(row = 0, column = 0, sticky = "NW", padx = 10, pady = 5) - return(self) \ No newline at end of file + # \ No newline at end of file From 7acf0246ca40cf3d359447a999ba3c613e1ffd4e Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 11:29:31 +0200 Subject: [PATCH 24/58] main_window gets components as attributes --- PapersCited/UI/main_window.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index b06c4d9..cd393cc 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -42,8 +42,8 @@ def create_widgets(self): self.__build_btn_choose() self.__build_btn_from_clipboard() self.__build_results() - self.__build_save_excel() - self.__build_save_text() + self.__build_save_xlsx() + self.__build_save_txt() def __build_btn_choose(self): btn_choose = tk.Button(master = self, @@ -53,6 +53,7 @@ def __build_btn_choose(self): ) btn_choose.grid(row = 0, column = 0, sticky = "NW", padx = 10, pady = 5) + self.btn_choose = btn_choose def __build_btn_from_clipboard(self): btn_from_clipboard = tk.Button(master = self, @@ -62,6 +63,7 @@ def __build_btn_from_clipboard(self): ) btn_from_clipboard.grid(row = 0, column = 1, sticky = "NW", padx = 5, pady = 5) + self.btn_from_clipboard = btn_from_clipboard def __build_results(self): # Frame element @@ -88,8 +90,9 @@ def __build_results(self): txt_results.config(state = "normal") txt_results.grid(row = 0, column = 0, sticky="NSWE") txt_results.config(state = "disabled") + self.txt_results = txt_results - def __build_save_excel(self): + def __build_save_xlsx(self): btn_save_xlsx = tk.Button(master = self, text = "Save as .xlsx", borderwidth = 2, @@ -97,8 +100,9 @@ def __build_save_excel(self): btn_save_xlsx.grid(row = 2, column = 3, sticky = "SE", padx = 10, pady = 5) + self.btn_save_xlsx = btn_save_xlsx - def __build_save_text(self): + def __build_save_txt(self): btn_save_txt = tk.Button(master = self, text = "Save as .txt", borderwidth = 2, @@ -106,5 +110,5 @@ def __build_save_text(self): btn_save_txt.grid(row = 2, column = 4, sticky = "SE", padx = 10, pady = 5) - - # \ No newline at end of file + self.btn_save_txt = btn_save_txt + \ No newline at end of file From a02cb818a7d46983a2f78b655b01604dbd1fcd9c Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 11:37:43 +0200 Subject: [PATCH 25/58] Module with button functions Implemented fn for btn_choose --- PapersCited/UI/btn_functions.py | 35 +++++++++++++++++++++++++++++++++ PapersCited/UI/main_window.py | 9 +++++++++ 2 files changed, 44 insertions(+) create mode 100644 PapersCited/UI/btn_functions.py diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btn_functions.py new file mode 100644 index 0000000..f7b22b6 --- /dev/null +++ b/PapersCited/UI/btn_functions.py @@ -0,0 +1,35 @@ +import UI.fileManipulation as fm +from tkinter import filedialog + +# Helper function for raising a pressed button +def fn_btn_release(event, btn): + btn.config(relief = "raised") + return("break") + + +def fn_btn_choose(event, btn_choose, master, data, text_component): + btn_choose.config(relief="sunken") + filename = filedialog.askopenfilename( + title="Select a document to search for citations:" + ) + data.set_new_filename(filename, + list_affected_wg=[master]) + try: + reading_operation = fm.read_document(filename) + + message = reading_operation["status_message"] + contents = reading_operation["document_text"] + citations = fm.find_citations(contents) + + except Exception as e: + error = str(e) + data.reset_on_error(error, list_affected_wg=[text_component]) + return("break") + + data.set_new_results_citations(citations, + list_affected_wg=[text_component]) + + if message: + data.warning_in_text_widget(message, list_affected_wg=[text_component]) + + return("break") diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index cd393cc..d1dc69e 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -7,6 +7,7 @@ import UI.messages as ms from UI.messages import version from UI.appData import AppData +import UI.btn_functions as bfn # Variables ---- @@ -35,7 +36,9 @@ def __init__(self): self.rowconfigure(1, weight = 2, minsize = 400) self.rowconfigure(2, weight = 0, minsize = 30) + self.data = app_data self.create_widgets() + self.create_event_bindings() def create_widgets(self): # Sets up individual UI elements @@ -111,4 +114,10 @@ def __build_save_txt(self): btn_save_txt.grid(row = 2, column = 4, sticky = "SE", padx = 10, pady = 5) self.btn_save_txt = btn_save_txt + + def create_event_bindings(self): + # Bind functionality to UI parts. Functions itself defined in btn_functions + self.btn_choose.bind("", lambda event, btn = self.btn_choose: + bfn.fn_btn_choose(event, self.btn_choose, master = self, data = self.data, text_component = self.txt_results)) + self.btn_choose.bind("", lambda event, btn = self.btn_choose: bfn.fn_btn_release(event, btn)) \ No newline at end of file From 3cb702ae4902518ef0db34d20e7ac55d77dbd891 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 12:07:14 +0200 Subject: [PATCH 26/58] Decouple app_data from updating text widget --- PapersCited/UI/appData.py | 35 ++------------- PapersCited/UI/btn_functions.py | 77 +++++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/PapersCited/UI/appData.py b/PapersCited/UI/appData.py index 97d49b1..bb57aae 100644 --- a/PapersCited/UI/appData.py +++ b/PapersCited/UI/appData.py @@ -18,7 +18,7 @@ def __init__(self, startup_filename, startup_results): # What to display when no file chosen: self.__no_file_selected_txt = "" - def set_new_filename(self, filename, list_affected_wg): + def set_new_filename(self, filename): user_filepath = filename if user_filepath == "": user_filepath = self.__no_file_selected_txt @@ -26,18 +26,8 @@ def set_new_filename(self, filename, list_affected_wg): self.input_filepath = user_filepath self.__set_output_filepath() - # Display the document title in main window - input_filename = os.path.basename(user_filepath) - - if input_filename == self.__no_file_selected_txt: - input_filename = "PapersCited" - else: - input_filename = input_filename + " - PapersCited" - - for widget in list_affected_wg: - widget.title(input_filename) - def set_new_results_citations(self, citations, list_affected_wg): + def set_new_results_citations(self, citations): self.citations = citations citations_as_string = tc.citations_to_string_pretty( citations[0], citations[1] @@ -47,11 +37,6 @@ def set_new_results_citations(self, citations, list_affected_wg): citations_as_string = ms.no_citations_found self.active_results = citations_as_string - for widget in list_affected_wg: - widget.config(state = "normal") - widget.delete("1.0", tk.END) - widget.insert("1.0", self.active_results) - widget.config(state = "disabled") def update_text_widget(self, update_text, list_affected_wg): # Add new text to window, like success messages. @@ -62,15 +47,6 @@ def update_text_widget(self, update_text, list_affected_wg): widget.config(state = "disabled") widget.see(tk.END) - def warning_in_text_widget(self, warning_text, list_affected_wg): - # Add new text to window, like success messages. - - for widget in list_affected_wg: - widget.config(state = "normal") - widget.insert('1.0', warning_text + "\n") - widget.config(state = "disabled") - widget.see('1.0') - def get_input_filepath(self): return(self.input_filepath) @@ -137,14 +113,9 @@ def any_citations_recorded(self): def get_active_results(self): return(self.active_results) - def reset_on_error(self, error, list_affected_wg): + def reset_on_error(self, error): # Failing to read a file should clear the textbox and # the stored citations self.citations = [] self.active_results = error - for widget in list_affected_wg: - widget.config(state = "normal") - widget.delete("1.0", tk.END) - widget.insert("1.0", self.active_results) - widget.config(state = "disabled") \ No newline at end of file diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btn_functions.py index f7b22b6..d157b6a 100644 --- a/PapersCited/UI/btn_functions.py +++ b/PapersCited/UI/btn_functions.py @@ -1,35 +1,64 @@ import UI.fileManipulation as fm +import tkinter as tk from tkinter import filedialog +import os # Helper function for raising a pressed button def fn_btn_release(event, btn): - btn.config(relief = "raised") - return("break") + btn.config(relief = "raised") + return("break") def fn_btn_choose(event, btn_choose, master, data, text_component): - btn_choose.config(relief="sunken") - filename = filedialog.askopenfilename( - title="Select a document to search for citations:" - ) - data.set_new_filename(filename, - list_affected_wg=[master]) - try: - reading_operation = fm.read_document(filename) - - message = reading_operation["status_message"] - contents = reading_operation["document_text"] - citations = fm.find_citations(contents) - - except Exception as e: - error = str(e) - data.reset_on_error(error, list_affected_wg=[text_component]) - return("break") + btn_choose.config(relief="sunken") + + filepath = filedialog.askopenfilename( + title="Select a document to search for citations:" + ) + + data.set_new_filename(filepath) + + # Display the document title in main window + input_filename = os.path.basename(filepath) + + if input_filename == "": + input_filename = "PapersCited" + else: + input_filename = input_filename + " - PapersCited" + + master.title(input_filename) + + # Read document text and find citations + try: + reading_operation = fm.read_document(filepath) - data.set_new_results_citations(citations, - list_affected_wg=[text_component]) + message = reading_operation["status_message"] + contents = reading_operation["document_text"] + citations = fm.find_citations(contents) - if message: - data.warning_in_text_widget(message, list_affected_wg=[text_component]) + except Exception as e: + # Failure to read file + error = str(e) + + data.reset_on_error(error) + + text_component.config(state = "normal") + text_component.delete("1.0", tk.END) + text_component.insert("1.0", data.active_results) + text_component.config(state = "disabled") + return("break") - return("break") + data.set_new_results_citations(citations) + + text_component.config(state = "normal") + text_component.delete("1.0", tk.END) + text_component.insert("1.0", data.active_results) + text_component.config(state = "disabled") + + if message: + text_component.config(state="normal") + text_component.insert('1.0', message + "\n") + text_component.config(state="disabled") + text_component.see('1.0') + + return("break") From 5b64799b2ffc376716721327e1e33d09cbe2ced9 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 12:25:28 +0200 Subject: [PATCH 27/58] Create a method for updating text widget --- PapersCited/UI/btn_functions.py | 10 ++-------- PapersCited/UI/main_window.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btn_functions.py index d157b6a..f622bd1 100644 --- a/PapersCited/UI/btn_functions.py +++ b/PapersCited/UI/btn_functions.py @@ -50,15 +50,9 @@ def fn_btn_choose(event, btn_choose, master, data, text_component): data.set_new_results_citations(citations) - text_component.config(state = "normal") - text_component.delete("1.0", tk.END) - text_component.insert("1.0", data.active_results) - text_component.config(state = "disabled") + master.update_text_widget(data.active_results, replace = True) if message: - text_component.config(state="normal") - text_component.insert('1.0', message + "\n") - text_component.config(state="disabled") - text_component.see('1.0') + master.update_text_widget(message + "\n", position = "start") return("break") diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index d1dc69e..9c65cc6 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -120,4 +120,23 @@ def create_event_bindings(self): self.btn_choose.bind("", lambda event, btn = self.btn_choose: bfn.fn_btn_choose(event, self.btn_choose, master = self, data = self.data, text_component = self.txt_results)) self.btn_choose.bind("", lambda event, btn = self.btn_choose: bfn.fn_btn_release(event, btn)) + + def update_text_widget(self, new_text, replace = False, position = "end", scroll_to_update = False): + text_wg = self.txt_results + + if position == "start": + place_to_write = "1.0" + elif position == "end": + place_to_write = tk.END + else: + Exception("Incorrect position argument!") + + text_wg.config(state = "normal") + if replace: + text_wg.delete("1.0", tk.END) + text_wg.insert(place_to_write, new_text) + text_wg.config(state = "disabled") + + if scroll_to_update: + text_wg.see(position) \ No newline at end of file From 6ada99bd230f814ab7c368159116c12483bc9a58 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 12:27:10 +0200 Subject: [PATCH 28/58] Errors also written via new method --- PapersCited/UI/btn_functions.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btn_functions.py index f622bd1..cc91408 100644 --- a/PapersCited/UI/btn_functions.py +++ b/PapersCited/UI/btn_functions.py @@ -42,10 +42,7 @@ def fn_btn_choose(event, btn_choose, master, data, text_component): data.reset_on_error(error) - text_component.config(state = "normal") - text_component.delete("1.0", tk.END) - text_component.insert("1.0", data.active_results) - text_component.config(state = "disabled") + master.update_text_widget(data.active_results, replace = True) return("break") data.set_new_results_citations(citations) From 609227c6a1032c661cb7bfc55fee303699c66df5 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 12:32:31 +0200 Subject: [PATCH 29/58] Remove unnecessary arguments --- PapersCited/UI/btn_functions.py | 2 +- PapersCited/UI/main_window.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btn_functions.py index cc91408..be77b96 100644 --- a/PapersCited/UI/btn_functions.py +++ b/PapersCited/UI/btn_functions.py @@ -9,7 +9,7 @@ def fn_btn_release(event, btn): return("break") -def fn_btn_choose(event, btn_choose, master, data, text_component): +def fn_btn_choose(event, btn_choose, master, data): btn_choose.config(relief="sunken") filepath = filedialog.askopenfilename( diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index 9c65cc6..729c04d 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -117,9 +117,10 @@ def __build_save_txt(self): def create_event_bindings(self): # Bind functionality to UI parts. Functions itself defined in btn_functions - self.btn_choose.bind("", lambda event, btn = self.btn_choose: - bfn.fn_btn_choose(event, self.btn_choose, master = self, data = self.data, text_component = self.txt_results)) - self.btn_choose.bind("", lambda event, btn = self.btn_choose: bfn.fn_btn_release(event, btn)) + self.btn_choose.bind("", lambda event: + bfn.fn_btn_choose(event, self.btn_choose, master = self, data = self.data)) + self.btn_choose.bind( + "", lambda event: bfn.fn_btn_release(event, self.btn_choose)) def update_text_widget(self, new_text, replace = False, position = "end", scroll_to_update = False): text_wg = self.txt_results From 51a83ab09745ddde9bcd0c374f817e00f3b389e9 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 12:44:42 +0200 Subject: [PATCH 30/58] Doc: button functions and update_text method --- PapersCited/UI/btn_functions.py | 19 ++++++++++++++++++- PapersCited/UI/main_window.py | 9 +++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btn_functions.py index be77b96..e8cb52d 100644 --- a/PapersCited/UI/btn_functions.py +++ b/PapersCited/UI/btn_functions.py @@ -1,15 +1,32 @@ +# Individual functions that are meant to be bound to UI elements when clicked. import UI.fileManipulation as fm import tkinter as tk from tkinter import filedialog import os -# Helper function for raising a pressed button def fn_btn_release(event, btn): + """Helper function for raising a pressed button + + Args: + event (event): UI event + btn (tk.Button): Button for which to apply de-pressing. Should be the same one the bind method is called on. + """ btn.config(relief = "raised") return("break") def fn_btn_choose(event, btn_choose, master, data): + """Clicking on Choose document button + + A popup for choosing a file appears. The chosen filepath is stored in application data. The filename is reflected + in the program title bar, and the file contents are scanned for citations. + + Args: + event (event): UI event + btn_choose (tk.Button): The button this function should be bound to. + master (main_window): The master window. + data (AppData): Application data belonging to master. + """ btn_choose.config(relief="sunken") filepath = filedialog.askopenfilename( diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index 729c04d..ef5a528 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -123,6 +123,15 @@ def create_event_bindings(self): "", lambda event: bfn.fn_btn_release(event, self.btn_choose)) def update_text_widget(self, new_text, replace = False, position = "end", scroll_to_update = False): + """Change displayed text. + + Args: + new_text (string): What should be displayed in the text widget. + replace (bool, optional): Should this text replace existing content instead of being appended? Defaults to False. + position (str, optional): Where should this text be appended? Possible values are "start" and "end". + If replace is true, doesn't affect the result. Defaults to "end". + scroll_to_update (bool, optional): Should the text widget scroll to the newly added text? Defaults to False. + """ text_wg = self.txt_results if position == "start": From 8b8f5a3040b8dcd3589c2c171e051db2d306fa83 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 12:49:58 +0200 Subject: [PATCH 31/58] Update appdata test to not take widget args --- PapersCited/tests/test_appdata.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PapersCited/tests/test_appdata.py b/PapersCited/tests/test_appdata.py index 9c40c82..7b91562 100644 --- a/PapersCited/tests/test_appdata.py +++ b/PapersCited/tests/test_appdata.py @@ -9,15 +9,15 @@ def test_checking_for_empty_citation_list(): appdata = AppData("", "") - appdata.set_new_results_citations([narrow_empty, wide_empty], list_affected_wg=[]) + appdata.set_new_results_citations([narrow_empty, wide_empty]) assert appdata.any_citations_recorded() == False - appdata.set_new_results_citations([narrow_full, wide_empty], list_affected_wg=[]) + appdata.set_new_results_citations([narrow_full, wide_empty]) assert appdata.any_citations_recorded() == True - appdata.set_new_results_citations([narrow_empty, wide_full], list_affected_wg=[]) + appdata.set_new_results_citations([narrow_empty, wide_full]) assert appdata.any_citations_recorded() == True - appdata.set_new_results_citations([narrow_full, wide_full], list_affected_wg=[]) + appdata.set_new_results_citations([narrow_full, wide_full]) assert appdata.any_citations_recorded() == True \ No newline at end of file From 69cd46585bd3bccb741006abb432778e9832ab6e Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 13:52:32 +0200 Subject: [PATCH 32/58] Implement functionality From clipboard --- PapersCited/UI/btn_functions.py | 39 +++++++++++++++++++++++++++++++++ PapersCited/UI/main_window.py | 5 +++++ 2 files changed, 44 insertions(+) diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btn_functions.py index e8cb52d..86a5a2e 100644 --- a/PapersCited/UI/btn_functions.py +++ b/PapersCited/UI/btn_functions.py @@ -70,3 +70,42 @@ def fn_btn_choose(event, btn_choose, master, data): master.update_text_widget(message + "\n", position = "start") return("break") + + +def fn_btn_from_clipboard(event, btn_from_clipboard, master, data): + """Clicking on From clipboard button + + The filepath is set to empty, and the clipboard contents are scanned for citations. + + Args: + event (event): UI event + btn_from_clipboard (tk.Button): The button this function should be bound to. + master (main_window): The master window. + data (AppData): Application data belonging to master. + """ + btn_from_clipboard.config(relief="sunken") + + # clipboard_get() errors when clipboard is empty + try: + clipboard_text = master.clipboard_get() + + except Exception as e: + clipboard_text = "" + + data.set_new_filename(filename="") + master.title("PapersCited") + + try: + citations = fm.find_citations(clipboard_text) + + except Exception as e: + error = str(e) + data.reset_on_error(error) + master.update_text_widget(data.active_results, replace=True) + return("break") + + data.set_new_results_citations(citations) + + master.update_text_widget(data.active_results, replace = True) + + return("break") diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index ef5a528..8a53c0e 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -121,6 +121,11 @@ def create_event_bindings(self): bfn.fn_btn_choose(event, self.btn_choose, master = self, data = self.data)) self.btn_choose.bind( "", lambda event: bfn.fn_btn_release(event, self.btn_choose)) + + self.btn_from_clipboard.bind("", lambda event: + bfn.fn_btn_from_clipboard(event, self.btn_from_clipboard, master=self, data=self.data)) + self.btn_from_clipboard.bind( + "", lambda event: bfn.fn_btn_release(event, self.btn_from_clipboard)) def update_text_widget(self, new_text, replace = False, position = "end", scroll_to_update = False): """Change displayed text. From 169d0ed77ebfc9330a43e97d45abf86e5bc5e9da Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 14:03:45 +0200 Subject: [PATCH 33/58] Add save excel functionality Now an unsuccessful save doesn't wipe current citations and display --- PapersCited/UI/btn_functions.py | 29 +++++++++++++++++++++++++++++ PapersCited/UI/main_window.py | 5 +++++ PapersCited/UI/messages.py | 3 ++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btn_functions.py index 86a5a2e..8fb72cc 100644 --- a/PapersCited/UI/btn_functions.py +++ b/PapersCited/UI/btn_functions.py @@ -1,5 +1,6 @@ # Individual functions that are meant to be bound to UI elements when clicked. import UI.fileManipulation as fm +import UI.messages as ms import tkinter as tk from tkinter import filedialog import os @@ -109,3 +110,31 @@ def fn_btn_from_clipboard(event, btn_from_clipboard, master, data): master.update_text_widget(data.active_results, replace = True) return("break") + + +def fn_btn_save_xlsx(event, btn_save_xlsx, master, data): + btn_save_xlsx.config(relief="sunken") + citations = data.get_citations() + + if not data.any_citations_recorded(): + master.update_text_widget(ms.no_citations_to_save, position = "end", scroll_to_update = True) + return("break") + + # Ask user where to save, notify if cancelled + try: + doc_filename = data.popup_ask_save_file(".xlsx") + except Exception as e: + master.update_text_widget(ms.saving_cancelled, position = "end", scroll_to_update = True) + return("break") + + try: + message = fm.write_excel(doc_filename, + citations[0], citations[1]) + except Exception as e: + error = str(e) + master.update_text_widget(ms.cant_write_file(doc_filename) + f"\n\n{error}", + position="end", scroll_to_update=True) + return("break") + + master.update_text_widget(message, position = "end", scroll_to_update = True) + return("break") diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index 8a53c0e..5ad1d9a 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -127,6 +127,11 @@ def create_event_bindings(self): self.btn_from_clipboard.bind( "", lambda event: bfn.fn_btn_release(event, self.btn_from_clipboard)) + self.btn_save_xlsx.bind("", lambda event: + bfn.fn_btn_save_xlsx(event, self.btn_save_xlsx, master=self, data=self.data)) + self.btn_save_xlsx.bind( + "", lambda event: bfn.fn_btn_release(event, self.btn_save_xlsx)) + def update_text_widget(self, new_text, replace = False, position = "end", scroll_to_update = False): """Change displayed text. diff --git a/PapersCited/UI/messages.py b/PapersCited/UI/messages.py index 8b3a0de..2367ee7 100644 --- a/PapersCited/UI/messages.py +++ b/PapersCited/UI/messages.py @@ -26,7 +26,8 @@ no_citations_found = "No citations were found." -no_citations_to_save = "Cannot save file: no citations found." +no_citations_to_save = "\n" + break_with_lines + \ + "\nCannot save file: no citations found." no_file_selected = "No file selected." From 645d620ce763134654a4c1790d3def740ec0ab8e Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 14:11:00 +0200 Subject: [PATCH 34/58] Remove unneeded from appData Clarify startup_text instead of startup_results Use get_active_results() method instead of accessing attribute --- PapersCited/UI/appData.py | 13 ++----------- PapersCited/UI/btn_functions.py | 8 ++++---- PapersCited/UI/main_window.py | 10 ++++------ 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/PapersCited/UI/appData.py b/PapersCited/UI/appData.py index bb57aae..b7eb9b7 100644 --- a/PapersCited/UI/appData.py +++ b/PapersCited/UI/appData.py @@ -5,11 +5,11 @@ import os class AppData: - def __init__(self, startup_filename, startup_results): + def __init__(self, startup_filename, startup_text): self.input_filepath = startup_filename self.output_filepath = "" self.citations = [] - self.active_results = startup_results + self.active_results = startup_text # Options for dynamic trimming of displayed filename self.__right_edge_buffer_px = 0 @@ -37,15 +37,6 @@ def set_new_results_citations(self, citations): citations_as_string = ms.no_citations_found self.active_results = citations_as_string - - def update_text_widget(self, update_text, list_affected_wg): - # Add new text to window, like success messages. - - for widget in list_affected_wg: - widget.config(state = "normal") - widget.insert(tk.END, update_text) - widget.config(state = "disabled") - widget.see(tk.END) def get_input_filepath(self): return(self.input_filepath) diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btn_functions.py index 8fb72cc..0a199c9 100644 --- a/PapersCited/UI/btn_functions.py +++ b/PapersCited/UI/btn_functions.py @@ -60,12 +60,12 @@ def fn_btn_choose(event, btn_choose, master, data): data.reset_on_error(error) - master.update_text_widget(data.active_results, replace = True) + master.update_text_widget(data.get_active_results(), replace=True) return("break") data.set_new_results_citations(citations) - master.update_text_widget(data.active_results, replace = True) + master.update_text_widget(data.get_active_results(), replace = True) if message: master.update_text_widget(message + "\n", position = "start") @@ -102,12 +102,12 @@ def fn_btn_from_clipboard(event, btn_from_clipboard, master, data): except Exception as e: error = str(e) data.reset_on_error(error) - master.update_text_widget(data.active_results, replace=True) + master.update_text_widget(data.get_active_results(), replace=True) return("break") data.set_new_results_citations(citations) - master.update_text_widget(data.active_results, replace = True) + master.update_text_widget(data.get_active_results(), replace=True) return("break") diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index 5ad1d9a..5f2e06d 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -9,18 +9,16 @@ from UI.appData import AppData import UI.btn_functions as bfn -# Variables ---- +# Constants ---- light_yellow = "#ffe08f" startup_filename = "" -startup_results = ms.intro_message +startup_text = ms.intro_message citations_font = "Segoe UI Variable" citations_font_size = 11 -app_data = AppData(startup_filename, startup_results) - class main_window(tk.Tk): def __init__(self): super().__init__() @@ -36,7 +34,7 @@ def __init__(self): self.rowconfigure(1, weight = 2, minsize = 400) self.rowconfigure(2, weight = 0, minsize = 30) - self.data = app_data + self.data = AppData(startup_filename, startup_text) self.create_widgets() self.create_event_bindings() @@ -86,7 +84,7 @@ def __build_results(self): # Text field element txt_results = tk.Text(master = fr_results, bg = "white", yscrollcommand = scr_results.set, wrap = tk.WORD) txt_results.configure(font = (citations_font, citations_font_size)) - txt_results.insert(tk.END, app_data.active_results) + txt_results.insert(tk.END, self.data.get_active_results()) scr_results.config(command=txt_results.yview) From 7eaf1af27d05000d8c8be82f746a317b71436426 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 14:15:16 +0200 Subject: [PATCH 35/58] Implement save as txt --- PapersCited/UI/btn_functions.py | 29 +++++++++++++++++++++++++++++ PapersCited/UI/main_window.py | 5 +++++ 2 files changed, 34 insertions(+) diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btn_functions.py index 0a199c9..dd3dfd8 100644 --- a/PapersCited/UI/btn_functions.py +++ b/PapersCited/UI/btn_functions.py @@ -138,3 +138,32 @@ def fn_btn_save_xlsx(event, btn_save_xlsx, master, data): master.update_text_widget(message, position = "end", scroll_to_update = True) return("break") + + +def fn_btn_save_txt(event, btn_save_txt, master, data): + btn_save_txt.config(relief="sunken") + citations = data.get_citations() + + if not data.any_citations_recorded(): + master.update_text_widget( + ms.no_citations_to_save, position="end", scroll_to_update=True) + return("break") + + # Ask user where to save, notify if cancelled + try: + doc_filename = data.popup_ask_save_file(".txt") + except Exception as e: + master.update_text_widget(ms.saving_cancelled, position = "end", scroll_to_update = True) + return("break") + + try: + message = fm.write_txt(doc_filename, + citations[0], citations[1]) + except Exception as e: + error = str(e) + master.update_text_widget(ms.cant_write_file(doc_filename) + f"\n\n{error}", + position="end", scroll_to_update=True) + return("break") + + master.update_text_widget(message, position="end", scroll_to_update=True) + return("break") diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index 5f2e06d..1af5f1b 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -130,6 +130,11 @@ def create_event_bindings(self): self.btn_save_xlsx.bind( "", lambda event: bfn.fn_btn_release(event, self.btn_save_xlsx)) + self.btn_save_txt.bind("", lambda event: + bfn.fn_btn_save_txt(event, self.btn_save_txt, master=self, data=self.data)) + self.btn_save_txt.bind( + "", lambda event: bfn.fn_btn_release(event, self.btn_save_txt)) + def update_text_widget(self, new_text, replace = False, position = "end", scroll_to_update = False): """Change displayed text. From 21cde4e66a1da88146221ff3b4f1d77eb59a51bb Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 14:28:00 +0200 Subject: [PATCH 36/58] Add rightclick Copy fn --- PapersCited/UI/btn_functions.py | 29 +++++++++++++++++++++++++++++ PapersCited/UI/main_window.py | 9 +++++++++ 2 files changed, 38 insertions(+) diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btn_functions.py index dd3dfd8..9a92733 100644 --- a/PapersCited/UI/btn_functions.py +++ b/PapersCited/UI/btn_functions.py @@ -167,3 +167,32 @@ def fn_btn_save_txt(event, btn_save_txt, master, data): master.update_text_widget(message, position="end", scroll_to_update=True) return("break") + +def popup_menu(event, rc_menu): + """The binded object allows right-clicking to access menu. Should be bound to the textbox only. + + Args: + event (event): UI event + rc_menu (tk.Menu): UI right_click_menu element + """ + try: + rc_menu.tk_popup(event.x_root, event.y_root) + finally: + rc_menu.grab_release() + +# Note - a menu command must NOT have event argument +def copy_to_clipboard(master): + """Command to copy selected text from a text widget to clipboard. + + Args: + master (main_window): The master window. + """ + master.clipboard_clear() + + try: + selected_text = master.txt_results.get(tk.SEL_FIRST, tk.SEL_LAST) + except: + # In case the main window/selection is empty, there's no SEL_FIRST + selected_text = "" + + master.clipboard_append(selected_text) diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index 1af5f1b..76911b1 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -45,6 +45,7 @@ def create_widgets(self): self.__build_results() self.__build_save_xlsx() self.__build_save_txt() + self.__build_right_click_menu() def __build_btn_choose(self): btn_choose = tk.Button(master = self, @@ -112,6 +113,10 @@ def __build_save_txt(self): btn_save_txt.grid(row = 2, column = 4, sticky = "SE", padx = 10, pady = 5) self.btn_save_txt = btn_save_txt + + def __build_right_click_menu(self): + rc_menu = tk.Menu(master = self, tearoff=0) + self.rc_menu = rc_menu def create_event_bindings(self): # Bind functionality to UI parts. Functions itself defined in btn_functions @@ -135,6 +140,10 @@ def create_event_bindings(self): self.btn_save_txt.bind( "", lambda event: bfn.fn_btn_release(event, self.btn_save_txt)) + # The text widget can be copied from + self.rc_menu.add_command(label="Copy", command = lambda: bfn.copy_to_clipboard(master = self)) + self.txt_results.bind("", lambda event: bfn.popup_menu(event, self.rc_menu)) + def update_text_widget(self, new_text, replace = False, position = "end", scroll_to_update = False): """Change displayed text. From 0623e16707a4ff04d5e2feb12313c1da324299ed Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 14:29:34 +0200 Subject: [PATCH 37/58] Include icon in startup --- PapersCited/UI/main_window.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/main_window.py index 76911b1..1fb4fc4 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/main_window.py @@ -35,6 +35,11 @@ def __init__(self): self.rowconfigure(2, weight = 0, minsize = 30) self.data = AppData(startup_filename, startup_text) + + # Create an icon for the main window + PC_icon = tk.PhotoImage(file = "UI/miniicon.png") + self.iconphoto(True, PC_icon) + self.create_widgets() self.create_event_bindings() From 1210c99074e5e23dbd266da99ea22247e3f3d13e Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 14:32:09 +0200 Subject: [PATCH 38/58] Remove old windowUI, rename class files --- PapersCited/PapersCited.py | 2 +- .../UI/{btn_functions.py => btnFunctions.py} | 0 .../UI/{main_window.py => mainWindow.py} | 2 +- PapersCited/UI/windowUI.py | 254 ------------------ 4 files changed, 2 insertions(+), 256 deletions(-) rename PapersCited/UI/{btn_functions.py => btnFunctions.py} (100%) rename PapersCited/UI/{main_window.py => mainWindow.py} (99%) delete mode 100644 PapersCited/UI/windowUI.py diff --git a/PapersCited/PapersCited.py b/PapersCited/PapersCited.py index 6569859..8c5909c 100644 --- a/PapersCited/PapersCited.py +++ b/PapersCited/PapersCited.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from UI.main_window import main_window +from UI.mainWindow import main_window from UI.messages import version # Welcome message, before loading anything diff --git a/PapersCited/UI/btn_functions.py b/PapersCited/UI/btnFunctions.py similarity index 100% rename from PapersCited/UI/btn_functions.py rename to PapersCited/UI/btnFunctions.py diff --git a/PapersCited/UI/main_window.py b/PapersCited/UI/mainWindow.py similarity index 99% rename from PapersCited/UI/main_window.py rename to PapersCited/UI/mainWindow.py index 1fb4fc4..13dde46 100644 --- a/PapersCited/UI/main_window.py +++ b/PapersCited/UI/mainWindow.py @@ -7,7 +7,7 @@ import UI.messages as ms from UI.messages import version from UI.appData import AppData -import UI.btn_functions as bfn +import UI.btnFunctions as bfn # Constants ---- diff --git a/PapersCited/UI/windowUI.py b/PapersCited/UI/windowUI.py deleted file mode 100644 index 3192429..0000000 --- a/PapersCited/UI/windowUI.py +++ /dev/null @@ -1,254 +0,0 @@ -import tkinter as tk -from tkinter import filedialog -from tkinter import messagebox - -import UI.fileManipulation as fm -import UI.messages as ms -from UI.messages import version -from UI.appData import AppData - -# Variables ---- - -light_yellow = "#ffe08f" - -startup_filename = "" -startup_results = ms.intro_message - -citations_font = "Segoe UI Variable" -citations_font_size = 11 - -app_data = AppData(startup_filename, startup_results) - -# Build UI parts ---- - -main_window = tk.Tk() -main_window.columnconfigure(0, weight = 0, minsize = 50) -main_window.columnconfigure(1, weight = 0, minsize = 50) -main_window.columnconfigure(2, weight = 0, minsize = 20) -main_window.columnconfigure(3, weight = 1, minsize = 100) -main_window.rowconfigure(0, weight = 0, minsize = 30) -main_window.rowconfigure(1, weight = 2, minsize = 400) -main_window.rowconfigure(2, weight = 0, minsize = 30) - -main_window.title("PapersCited") - -main_window.minsize(750, 500) - -btn_choose = tk.Button(master = main_window, - text = "Choose document", - borderwidth = 3, relief=tk.RAISED, - padx = 8, pady = 5 - ) - -btn_choose.grid(row = 0, column = 0, sticky = "NW", padx = 10, pady = 5) - -btn_from_clipboard = tk.Button(master = main_window, - text = "From clipboard", - borderwidth = 3, relief=tk.RAISED, - padx = 8, pady = 5 - ) - -btn_from_clipboard.grid(row = 0, column = 1, sticky = "NW", padx = 5, pady = 5) - -fr_results = tk.Frame(master = main_window, bg = "white", - borderwidth = 2, relief = tk.GROOVE) -fr_results.grid(row = 1, column = 0, sticky = "NWSE", columnspan = 5, - padx = 10) - -fr_results.columnconfigure(0, weight = 1) -fr_results.columnconfigure(1, weight = 0) -fr_results.rowconfigure(0, weight = 1) - -scr_results = tk.Scrollbar(fr_results, orient = "vertical") -scr_results.grid(row = 0, column = 1, sticky = "NS") - -txt_results = tk.Text(master = fr_results, bg = "white", yscrollcommand = scr_results.set, wrap = tk.WORD) -txt_results.configure(font = (citations_font, citations_font_size)) -txt_results.insert(tk.END, app_data.active_results) - -scr_results.config(command=txt_results.yview) - -txt_results.config(state = "normal") -txt_results.grid(row = 0, column = 0, sticky="NSWE") -txt_results.config(state = "disabled") - -btn_save_xlsx = tk.Button(master = main_window, - text = "Save as .xlsx", - borderwidth = 2, - padx = 5, pady = 5) - -btn_save_xlsx.grid(row = 2, column = 3, sticky = "SE", - padx = 10, pady = 5) - -btn_save_txt = tk.Button(master = main_window, - text = "Save as .txt", - borderwidth = 2, - padx = 5, pady = 5) - -btn_save_txt.grid(row = 2, column = 4, sticky = "SE", - padx = 10, pady = 5) - - -# Bind functions ---- - -# Helper to return buttons to rest state after a click -def fn_btn_release(event, btn): - btn.config(relief = "raised") - return("break") - -def fn_btn_choose(event): - btn_choose.config(relief = "sunken") - filename = filedialog.askopenfilename( - title = "Select a document to search for citations:" - ) - app_data.set_new_filename(filename, - list_affected_wg=[main_window]) - try: - reading_operation = fm.read_document(filename) - - message = reading_operation["status_message"] - contents = reading_operation["document_text"] - citations = fm.find_citations(contents) - - except Exception as e: - error = str(e) - app_data.reset_on_error(error, list_affected_wg = [txt_results]) - return("break") - - app_data.set_new_results_citations(citations, - list_affected_wg = [txt_results]) - - if message: - app_data.warning_in_text_widget(message, list_affected_wg = [txt_results]) - - return("break") - -btn_choose.bind("", fn_btn_choose) -btn_choose.bind("", lambda event, btn = btn_choose: fn_btn_release(event, btn)) - -# Reading from clipboard -def fn_from_clipboard(event): - btn_from_clipboard.config(relief = "sunken") - - # clipboard_get() errors when clipboard is empty - try: - clipboard_text = main_window.clipboard_get() - - except Exception as e: - clipboard_text = "" - - app_data.set_new_filename(filename = "", - list_affected_wg=[main_window]) - try: - message = None - citations = fm.find_citations(clipboard_text) - - except Exception as e: - error = str(e) - app_data.reset_on_error(error, list_affected_wg = [txt_results]) - return("break") - - app_data.set_new_results_citations(citations, - list_affected_wg = [txt_results]) - - if message: - app_data.warning_in_text_widget(message, list_affected_wg = [txt_results]) - - return("break") - -btn_from_clipboard.bind("", fn_from_clipboard) -btn_from_clipboard.bind("", lambda event, btn = btn_from_clipboard: fn_btn_release(event, btn)) - -def fn_btn_save_excel(event): - btn_save_xlsx.config(relief = "sunken") - citations = app_data.get_citations() - - if not app_data.any_citations_recorded(): - app_data.reset_on_error(ms.no_citations_to_save, list_affected_wg = [txt_results]) - return("break") - - # Ask user where to save, notify if cancelled - try: - doc_filename = app_data.popup_ask_save_file(".xlsx") - except Exception as e: - app_data.update_text_widget(ms.saving_cancelled, - list_affected_wg = [txt_results]) - return("break") - - try: - message = fm.write_excel(doc_filename, - citations[0], citations[1]) - except Exception as e: - error = str(e) - app_data.reset_on_error(ms.cant_write_file(doc_filename) + f"\n\n{error}", - list_affected_wg = [txt_results]) - return("break") - - app_data.update_text_widget(message, - list_affected_wg = [txt_results]) - return("break") - -btn_save_xlsx.bind("", fn_btn_save_excel) -btn_save_xlsx.bind("", lambda event, btn = btn_save_xlsx: fn_btn_release(event, btn)) - -def fn_btn_save_txt(event): - btn_save_txt.config(relief = "sunken") - citations = app_data.get_citations() - - if not app_data.any_citations_recorded(): - app_data.reset_on_error(ms.no_citations_to_save, list_affected_wg = [txt_results]) - return("break") - - # Ask user where to save, notify if cancelled - try: - doc_filename = app_data.popup_ask_save_file(".txt") - except Exception as e: - app_data.update_text_widget(ms.saving_cancelled, - list_affected_wg = [txt_results]) - return("break") - - try: - message = fm.write_txt(doc_filename, - citations[0], citations[1]) - except Exception as e: - error = str(e) - app_data.reset_on_error(ms.cant_write_file(doc_filename) + f"\n\n{error}", - list_affected_wg = [txt_results]) - return("break") - - app_data.update_text_widget(message, - list_affected_wg = [txt_results]) - return("break") - -btn_save_txt.bind("", fn_btn_save_txt) -btn_save_txt.bind("", lambda event, btn = btn_save_txt: fn_btn_release(event, btn)) - -# Right-click menu for copying citations -rc_menu = tk.Menu(main_window, tearoff = 0) - -def popup_menu(event): - try: - rc_menu.tk_popup(event.x_root, event.y_root) - finally: - rc_menu.grab_release() - -# Note - a menu command must NOT have event argument -def copy_to_clipboard(): - main_window.clipboard_clear() - - try: - selected_text = txt_results.get(tk.SEL_FIRST, tk.SEL_LAST) - except: - # In case the main window/selection is empty, there's no SEL_FIRST - selected_text = "" - - main_window.clipboard_append(selected_text) - -rc_menu.add_command(label = "Copy", command = copy_to_clipboard) - -# Bind only to results pane, copying not important for other parts -txt_results.bind("", popup_menu) - -# Create an icon for the main window -PC_icon = tk.PhotoImage(file = "UI/miniicon.png") -main_window.iconphoto(True, PC_icon) \ No newline at end of file From f1b1feb81698d7ff18af13789a55008e2232bcad Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 14:44:34 +0200 Subject: [PATCH 39/58] Remove argument data main_window has it as an attribute, so it doesn't need to be specified --- PapersCited/UI/btnFunctions.py | 40 +++++++++++++++++----------------- PapersCited/UI/mainWindow.py | 8 +++---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/PapersCited/UI/btnFunctions.py b/PapersCited/UI/btnFunctions.py index 9a92733..9452974 100644 --- a/PapersCited/UI/btnFunctions.py +++ b/PapersCited/UI/btnFunctions.py @@ -16,7 +16,7 @@ def fn_btn_release(event, btn): return("break") -def fn_btn_choose(event, btn_choose, master, data): +def fn_btn_choose(event, btn_choose, master): """Clicking on Choose document button A popup for choosing a file appears. The chosen filepath is stored in application data. The filename is reflected @@ -34,7 +34,7 @@ def fn_btn_choose(event, btn_choose, master, data): title="Select a document to search for citations:" ) - data.set_new_filename(filepath) + master.data.set_new_filename(filepath) # Display the document title in main window input_filename = os.path.basename(filepath) @@ -58,14 +58,14 @@ def fn_btn_choose(event, btn_choose, master, data): # Failure to read file error = str(e) - data.reset_on_error(error) + master.data.reset_on_error(error) - master.update_text_widget(data.get_active_results(), replace=True) + master.update_text_widget(master.data.get_active_results(), replace=True) return("break") - data.set_new_results_citations(citations) + master.data.set_new_results_citations(citations) - master.update_text_widget(data.get_active_results(), replace = True) + master.update_text_widget(master.data.get_active_results(), replace = True) if message: master.update_text_widget(message + "\n", position = "start") @@ -73,7 +73,7 @@ def fn_btn_choose(event, btn_choose, master, data): return("break") -def fn_btn_from_clipboard(event, btn_from_clipboard, master, data): +def fn_btn_from_clipboard(event, btn_from_clipboard, master): """Clicking on From clipboard button The filepath is set to empty, and the clipboard contents are scanned for citations. @@ -93,7 +93,7 @@ def fn_btn_from_clipboard(event, btn_from_clipboard, master, data): except Exception as e: clipboard_text = "" - data.set_new_filename(filename="") + master.data.set_new_filename(filename="") master.title("PapersCited") try: @@ -101,28 +101,28 @@ def fn_btn_from_clipboard(event, btn_from_clipboard, master, data): except Exception as e: error = str(e) - data.reset_on_error(error) - master.update_text_widget(data.get_active_results(), replace=True) + master.data.reset_on_error(error) + master.update_text_widget(master.data.get_active_results(), replace=True) return("break") - data.set_new_results_citations(citations) + master.data.set_new_results_citations(citations) - master.update_text_widget(data.get_active_results(), replace=True) + master.update_text_widget(master.data.get_active_results(), replace=True) return("break") -def fn_btn_save_xlsx(event, btn_save_xlsx, master, data): +def fn_btn_save_xlsx(event, btn_save_xlsx, master): btn_save_xlsx.config(relief="sunken") - citations = data.get_citations() + citations = master.data.get_citations() - if not data.any_citations_recorded(): + if not master.data.any_citations_recorded(): master.update_text_widget(ms.no_citations_to_save, position = "end", scroll_to_update = True) return("break") # Ask user where to save, notify if cancelled try: - doc_filename = data.popup_ask_save_file(".xlsx") + doc_filename = master.data.popup_ask_save_file(".xlsx") except Exception as e: master.update_text_widget(ms.saving_cancelled, position = "end", scroll_to_update = True) return("break") @@ -140,18 +140,18 @@ def fn_btn_save_xlsx(event, btn_save_xlsx, master, data): return("break") -def fn_btn_save_txt(event, btn_save_txt, master, data): +def fn_btn_save_txt(event, btn_save_txt, master): btn_save_txt.config(relief="sunken") - citations = data.get_citations() + citations = master.data.get_citations() - if not data.any_citations_recorded(): + if not master.data.any_citations_recorded(): master.update_text_widget( ms.no_citations_to_save, position="end", scroll_to_update=True) return("break") # Ask user where to save, notify if cancelled try: - doc_filename = data.popup_ask_save_file(".txt") + doc_filename = master.data.popup_ask_save_file(".txt") except Exception as e: master.update_text_widget(ms.saving_cancelled, position = "end", scroll_to_update = True) return("break") diff --git a/PapersCited/UI/mainWindow.py b/PapersCited/UI/mainWindow.py index 13dde46..f37263a 100644 --- a/PapersCited/UI/mainWindow.py +++ b/PapersCited/UI/mainWindow.py @@ -126,22 +126,22 @@ def __build_right_click_menu(self): def create_event_bindings(self): # Bind functionality to UI parts. Functions itself defined in btn_functions self.btn_choose.bind("", lambda event: - bfn.fn_btn_choose(event, self.btn_choose, master = self, data = self.data)) + bfn.fn_btn_choose(event, self.btn_choose, master = self)) self.btn_choose.bind( "", lambda event: bfn.fn_btn_release(event, self.btn_choose)) self.btn_from_clipboard.bind("", lambda event: - bfn.fn_btn_from_clipboard(event, self.btn_from_clipboard, master=self, data=self.data)) + bfn.fn_btn_from_clipboard(event, self.btn_from_clipboard, master=self)) self.btn_from_clipboard.bind( "", lambda event: bfn.fn_btn_release(event, self.btn_from_clipboard)) self.btn_save_xlsx.bind("", lambda event: - bfn.fn_btn_save_xlsx(event, self.btn_save_xlsx, master=self, data=self.data)) + bfn.fn_btn_save_xlsx(event, self.btn_save_xlsx, master=self)) self.btn_save_xlsx.bind( "", lambda event: bfn.fn_btn_release(event, self.btn_save_xlsx)) self.btn_save_txt.bind("", lambda event: - bfn.fn_btn_save_txt(event, self.btn_save_txt, master=self, data=self.data)) + bfn.fn_btn_save_txt(event, self.btn_save_txt, master=self)) self.btn_save_txt.bind( "", lambda event: bfn.fn_btn_release(event, self.btn_save_txt)) From 8224ed8cea91b21dbd7463f298512791a93ad952 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 22:11:09 +0200 Subject: [PATCH 40/58] Rename main class to mainWindow --- PapersCited/PapersCited.py | 4 ++-- PapersCited/UI/mainWindow.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PapersCited/PapersCited.py b/PapersCited/PapersCited.py index 8c5909c..94bc37e 100644 --- a/PapersCited/PapersCited.py +++ b/PapersCited/PapersCited.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from UI.mainWindow import main_window +from UI.mainWindow import mainWindow from UI.messages import version # Welcome message, before loading anything @@ -10,7 +10,7 @@ # MAIN ---- def main(): - UI = main_window() + UI = mainWindow() UI.focus_force() UI.mainloop() diff --git a/PapersCited/UI/mainWindow.py b/PapersCited/UI/mainWindow.py index f37263a..28f1ad4 100644 --- a/PapersCited/UI/mainWindow.py +++ b/PapersCited/UI/mainWindow.py @@ -19,7 +19,7 @@ citations_font = "Segoe UI Variable" citations_font_size = 11 -class main_window(tk.Tk): +class mainWindow(tk.Tk): def __init__(self): super().__init__() From f9d1b355f27a67ce43307051db81104883fe1870 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 22:13:21 +0200 Subject: [PATCH 41/58] Remove unused imports --- PapersCited/UI/appData.py | 1 - PapersCited/UI/fileManipulation.py | 3 --- PapersCited/UI/mainWindow.py | 5 ----- 3 files changed, 9 deletions(-) diff --git a/PapersCited/UI/appData.py b/PapersCited/UI/appData.py index b7eb9b7..c601105 100644 --- a/PapersCited/UI/appData.py +++ b/PapersCited/UI/appData.py @@ -1,4 +1,3 @@ -import tkinter as tk from tkinter.filedialog import asksaveasfilename import UI.transformCitations as tc import UI.messages as ms diff --git a/PapersCited/UI/fileManipulation.py b/PapersCited/UI/fileManipulation.py index ba7c695..6a1c0c9 100644 --- a/PapersCited/UI/fileManipulation.py +++ b/PapersCited/UI/fileManipulation.py @@ -3,11 +3,8 @@ import UI.transformCitations as tc import os -import sys import textract import xlsxwriter -import tkinter -from tkinter import filedialog from docx2python import docx2python def check_file(filename): diff --git a/PapersCited/UI/mainWindow.py b/PapersCited/UI/mainWindow.py index 28f1ad4..c226bb3 100644 --- a/PapersCited/UI/mainWindow.py +++ b/PapersCited/UI/mainWindow.py @@ -1,11 +1,6 @@ import tkinter as tk import tkinter as tk -from tkinter import filedialog -from tkinter import messagebox - -import UI.fileManipulation as fm import UI.messages as ms -from UI.messages import version from UI.appData import AppData import UI.btnFunctions as bfn From 0dc94ae5f3b3d451e285f5b5972ce84921a5e5d5 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 22:17:26 +0200 Subject: [PATCH 42/58] Remove unecessary try except clauses reading file --- PapersCited/UI/btnFunctions.py | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/PapersCited/UI/btnFunctions.py b/PapersCited/UI/btnFunctions.py index 9452974..6cbb521 100644 --- a/PapersCited/UI/btnFunctions.py +++ b/PapersCited/UI/btnFunctions.py @@ -49,22 +49,18 @@ def fn_btn_choose(event, btn_choose, master): # Read document text and find citations try: reading_operation = fm.read_document(filepath) - - message = reading_operation["status_message"] - contents = reading_operation["document_text"] - citations = fm.find_citations(contents) - except Exception as e: # Failure to read file error = str(e) - master.data.reset_on_error(error) - master.update_text_widget(master.data.get_active_results(), replace=True) return("break") - master.data.set_new_results_citations(citations) + message = reading_operation["status_message"] + contents = reading_operation["document_text"] + citations = fm.find_citations(contents) + master.data.set_new_results_citations(citations) master.update_text_widget(master.data.get_active_results(), replace = True) if message: @@ -96,17 +92,8 @@ def fn_btn_from_clipboard(event, btn_from_clipboard, master): master.data.set_new_filename(filename="") master.title("PapersCited") - try: - citations = fm.find_citations(clipboard_text) - - except Exception as e: - error = str(e) - master.data.reset_on_error(error) - master.update_text_widget(master.data.get_active_results(), replace=True) - return("break") - + citations = fm.find_citations(clipboard_text) master.data.set_new_results_citations(citations) - master.update_text_widget(master.data.get_active_results(), replace=True) return("break") From 11abb7046910c45f9ab7b9386bbada3b393e19d1 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 22:24:18 +0200 Subject: [PATCH 43/58] Specify TclError when empty clipboard --- PapersCited/UI/btnFunctions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PapersCited/UI/btnFunctions.py b/PapersCited/UI/btnFunctions.py index 6cbb521..5974bd2 100644 --- a/PapersCited/UI/btnFunctions.py +++ b/PapersCited/UI/btnFunctions.py @@ -86,7 +86,7 @@ def fn_btn_from_clipboard(event, btn_from_clipboard, master): try: clipboard_text = master.clipboard_get() - except Exception as e: + except tk.TclError as e: clipboard_text = "" master.data.set_new_filename(filename="") From c0d37e0894841c7f0acd2c18e2defb2df4cbfd2a Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sun, 1 Oct 2023 22:28:46 +0200 Subject: [PATCH 44/58] Remove nonexistent docstring argument --- PapersCited/UI/btnFunctions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/PapersCited/UI/btnFunctions.py b/PapersCited/UI/btnFunctions.py index 5974bd2..75a547c 100644 --- a/PapersCited/UI/btnFunctions.py +++ b/PapersCited/UI/btnFunctions.py @@ -26,7 +26,6 @@ def fn_btn_choose(event, btn_choose, master): event (event): UI event btn_choose (tk.Button): The button this function should be bound to. master (main_window): The master window. - data (AppData): Application data belonging to master. """ btn_choose.config(relief="sunken") @@ -78,7 +77,6 @@ def fn_btn_from_clipboard(event, btn_from_clipboard, master): event (event): UI event btn_from_clipboard (tk.Button): The button this function should be bound to. master (main_window): The master window. - data (AppData): Application data belonging to master. """ btn_from_clipboard.config(relief="sunken") From caed5159bae6e8ee36e56077fe4226210a3739e8 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Wed, 4 Oct 2023 20:34:09 +0200 Subject: [PATCH 45/58] New program icon --- PapersCited/UI/P_icon.png | Bin 0 -> 6373 bytes PapersCited/UI/mainWindow.py | 4 ++-- PapersCited/UI/miniicon.png | Bin 262 -> 0 bytes 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 PapersCited/UI/P_icon.png delete mode 100644 PapersCited/UI/miniicon.png diff --git a/PapersCited/UI/P_icon.png b/PapersCited/UI/P_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a91b68a61c757c1d949057acb8a486721f81dd7e GIT binary patch literal 6373 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 C)LI7s From d40101cb7809885b5f47f053f603c21c751fa0ce Mon Sep 17 00:00:00 2001 From: Mkranj Date: Wed, 4 Oct 2023 20:36:07 +0200 Subject: [PATCH 46/58] Check for DPI setting Should make it less blurry on larger displays --- PapersCited/PapersCited.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PapersCited/PapersCited.py b/PapersCited/PapersCited.py index 94bc37e..e2b8dad 100644 --- a/PapersCited/PapersCited.py +++ b/PapersCited/PapersCited.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from UI.mainWindow import mainWindow from UI.messages import version +from ctypes import windll # Welcome message, before loading anything if __name__ == "__main__": @@ -10,6 +11,8 @@ # MAIN ---- def main(): + # Resolution awareness - prevents from being blurry on high DPI + windll.shcore.SetProcessDpiAwareness(1) UI = mainWindow() UI.focus_force() From 9f97ed532af570c4545e6b824a59b10180e09462 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Thu, 5 Oct 2023 17:44:59 +0200 Subject: [PATCH 47/58] Reorganize so root holds main folders --- PapersCited/PapersCited.py => PapersCited.py | 0 {PapersCited/UI => UI}/P_icon.png | Bin {PapersCited/UI => UI}/__init__.py | 0 {PapersCited/UI => UI}/appData.py | 0 {PapersCited/UI => UI}/btnFunctions.py | 0 {PapersCited/UI => UI}/fileManipulation.py | 0 {PapersCited/UI => UI}/mainWindow.py | 0 {PapersCited/UI => UI}/messages.py | 0 {PapersCited/UI => UI}/transformCitations.py | 0 .../__init__.py | 0 .../citationAnalysis.py | 0 {PapersCited/tests => tests}/__init__.py | 0 {PapersCited/tests => tests}/conftest.py | 0 .../tests => tests}/document_footnotes.docx | Bin .../tests => tests}/document_no_footnotes.docx | Bin {PapersCited/tests => tests}/sample_text.txt | 0 .../sample_text_full_correct_list_citations.txt | 0 {PapersCited/tests => tests}/sample_text_utf8.txt | 0 {PapersCited/tests => tests}/test_appdata.py | 0 {PapersCited/tests => tests}/test_classes.py | 0 .../tests => tests}/test_detecting_authors.py | 0 {PapersCited/tests => tests}/test_integration.py | 0 {PapersCited/tests => tests}/test_ui_functions.py | 0 23 files changed, 0 insertions(+), 0 deletions(-) rename PapersCited/PapersCited.py => PapersCited.py (100%) rename {PapersCited/UI => UI}/P_icon.png (100%) rename {PapersCited/UI => UI}/__init__.py (100%) rename {PapersCited/UI => UI}/appData.py (100%) rename {PapersCited/UI => UI}/btnFunctions.py (100%) rename {PapersCited/UI => UI}/fileManipulation.py (100%) rename {PapersCited/UI => UI}/mainWindow.py (100%) rename {PapersCited/UI => UI}/messages.py (100%) rename {PapersCited/UI => UI}/transformCitations.py (100%) rename {PapersCited/citationAnalysis => citationAnalysis}/__init__.py (100%) rename {PapersCited/citationAnalysis => citationAnalysis}/citationAnalysis.py (100%) rename {PapersCited/tests => tests}/__init__.py (100%) rename {PapersCited/tests => tests}/conftest.py (100%) rename {PapersCited/tests => tests}/document_footnotes.docx (100%) rename {PapersCited/tests => tests}/document_no_footnotes.docx (100%) rename {PapersCited/tests => tests}/sample_text.txt (100%) rename {PapersCited/tests => tests}/sample_text_full_correct_list_citations.txt (100%) rename {PapersCited/tests => tests}/sample_text_utf8.txt (100%) rename {PapersCited/tests => tests}/test_appdata.py (100%) rename {PapersCited/tests => tests}/test_classes.py (100%) rename {PapersCited/tests => tests}/test_detecting_authors.py (100%) rename {PapersCited/tests => tests}/test_integration.py (100%) rename {PapersCited/tests => tests}/test_ui_functions.py (100%) diff --git a/PapersCited/PapersCited.py b/PapersCited.py similarity index 100% rename from PapersCited/PapersCited.py rename to PapersCited.py diff --git a/PapersCited/UI/P_icon.png b/UI/P_icon.png similarity index 100% rename from PapersCited/UI/P_icon.png rename to UI/P_icon.png diff --git a/PapersCited/UI/__init__.py b/UI/__init__.py similarity index 100% rename from PapersCited/UI/__init__.py rename to UI/__init__.py diff --git a/PapersCited/UI/appData.py b/UI/appData.py similarity index 100% rename from PapersCited/UI/appData.py rename to UI/appData.py diff --git a/PapersCited/UI/btnFunctions.py b/UI/btnFunctions.py similarity index 100% rename from PapersCited/UI/btnFunctions.py rename to UI/btnFunctions.py diff --git a/PapersCited/UI/fileManipulation.py b/UI/fileManipulation.py similarity index 100% rename from PapersCited/UI/fileManipulation.py rename to UI/fileManipulation.py diff --git a/PapersCited/UI/mainWindow.py b/UI/mainWindow.py similarity index 100% rename from PapersCited/UI/mainWindow.py rename to UI/mainWindow.py diff --git a/PapersCited/UI/messages.py b/UI/messages.py similarity index 100% rename from PapersCited/UI/messages.py rename to UI/messages.py diff --git a/PapersCited/UI/transformCitations.py b/UI/transformCitations.py similarity index 100% rename from PapersCited/UI/transformCitations.py rename to UI/transformCitations.py diff --git a/PapersCited/citationAnalysis/__init__.py b/citationAnalysis/__init__.py similarity index 100% rename from PapersCited/citationAnalysis/__init__.py rename to citationAnalysis/__init__.py diff --git a/PapersCited/citationAnalysis/citationAnalysis.py b/citationAnalysis/citationAnalysis.py similarity index 100% rename from PapersCited/citationAnalysis/citationAnalysis.py rename to citationAnalysis/citationAnalysis.py diff --git a/PapersCited/tests/__init__.py b/tests/__init__.py similarity index 100% rename from PapersCited/tests/__init__.py rename to tests/__init__.py diff --git a/PapersCited/tests/conftest.py b/tests/conftest.py similarity index 100% rename from PapersCited/tests/conftest.py rename to tests/conftest.py diff --git a/PapersCited/tests/document_footnotes.docx b/tests/document_footnotes.docx similarity index 100% rename from PapersCited/tests/document_footnotes.docx rename to tests/document_footnotes.docx diff --git a/PapersCited/tests/document_no_footnotes.docx b/tests/document_no_footnotes.docx similarity index 100% rename from PapersCited/tests/document_no_footnotes.docx rename to tests/document_no_footnotes.docx diff --git a/PapersCited/tests/sample_text.txt b/tests/sample_text.txt similarity index 100% rename from PapersCited/tests/sample_text.txt rename to tests/sample_text.txt diff --git a/PapersCited/tests/sample_text_full_correct_list_citations.txt b/tests/sample_text_full_correct_list_citations.txt similarity index 100% rename from PapersCited/tests/sample_text_full_correct_list_citations.txt rename to tests/sample_text_full_correct_list_citations.txt diff --git a/PapersCited/tests/sample_text_utf8.txt b/tests/sample_text_utf8.txt similarity index 100% rename from PapersCited/tests/sample_text_utf8.txt rename to tests/sample_text_utf8.txt diff --git a/PapersCited/tests/test_appdata.py b/tests/test_appdata.py similarity index 100% rename from PapersCited/tests/test_appdata.py rename to tests/test_appdata.py diff --git a/PapersCited/tests/test_classes.py b/tests/test_classes.py similarity index 100% rename from PapersCited/tests/test_classes.py rename to tests/test_classes.py diff --git a/PapersCited/tests/test_detecting_authors.py b/tests/test_detecting_authors.py similarity index 100% rename from PapersCited/tests/test_detecting_authors.py rename to tests/test_detecting_authors.py diff --git a/PapersCited/tests/test_integration.py b/tests/test_integration.py similarity index 100% rename from PapersCited/tests/test_integration.py rename to tests/test_integration.py diff --git a/PapersCited/tests/test_ui_functions.py b/tests/test_ui_functions.py similarity index 100% rename from PapersCited/tests/test_ui_functions.py rename to tests/test_ui_functions.py From 5cac0995c6ff684c57564a969f0fdc7a674fde67 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Thu, 5 Oct 2023 18:07:11 +0200 Subject: [PATCH 48/58] Specify filepath with os.path --- UI/mainWindow.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/UI/mainWindow.py b/UI/mainWindow.py index 8bc6500..433fb25 100644 --- a/UI/mainWindow.py +++ b/UI/mainWindow.py @@ -3,6 +3,7 @@ import UI.messages as ms from UI.appData import AppData import UI.btnFunctions as bfn +import os.path # Constants ---- @@ -32,7 +33,9 @@ def __init__(self): self.data = AppData(startup_filename, startup_text) # Create an icon for the main window - PC_icon = tk.PhotoImage(file = "UI/P_icon.png") + UI_dir = os.path.dirname(os.path.abspath(__file__)) + PC_icon_file = os.path.join(UI_dir, "P_icon.png") + PC_icon = tk.PhotoImage(file = PC_icon_file) self.wm_iconphoto(True, PC_icon) self.create_widgets() From f804e9502f6a5e96cf9c7927f0103521b461102e Mon Sep 17 00:00:00 2001 From: Mkranj Date: Thu, 5 Oct 2023 19:32:50 +0200 Subject: [PATCH 49/58] Rename test for citationAnalysis classes --- tests/{test_classes.py => test_citationanalysis_class.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{test_classes.py => test_citationanalysis_class.py} (100%) diff --git a/tests/test_classes.py b/tests/test_citationanalysis_class.py similarity index 100% rename from tests/test_classes.py rename to tests/test_citationanalysis_class.py From afa4a614847b24fa3ed9ab61b707e0be82103f51 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Thu, 5 Oct 2023 19:56:31 +0200 Subject: [PATCH 50/58] Add test for wrapper fn Consolidates the process of finding, cleaning and removing duplicate citations --- tests/test_detecting_authors.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/test_detecting_authors.py b/tests/test_detecting_authors.py index bb16560..eab2235 100644 --- a/tests/test_detecting_authors.py +++ b/tests/test_detecting_authors.py @@ -1,4 +1,5 @@ import citationAnalysis.citationAnalysis as ca +from UI.fileManipulation import find_citations # The \ indicates code continues in the next line # When testing individual detection functions, they SHOULD catch extra characters @@ -171,4 +172,14 @@ def test_surnames_apostrophe_s_recognised(): matches = ca.get_matches_solo_author(text) matches.cleanup() assert matches.citations == ["O'Samuel 1999", "O'Sullivan 2000"] - \ No newline at end of file + +def test_find_citations_wrapper(): + text = "One and two (1212) often collaborate. This is well documented (Aesop and Berry, 1999). Aasimov (1999) had a revelation (Bassimov, 2000). Long Surname (2020) found his match." + + # Specifying sought-after matches. Berry, 1999 is a side-effect not considered harmful. + expected_narrow = ["Aasimov 1999", "Bassimov 2000", "Aesop & Berry 1999", "One & two 1212"] + expected_wider = ["Long Surname 2020"] + + found_citations = find_citations(text) + assert all([citation in found_citations[0].citations for citation in expected_narrow]) + assert all([citation in found_citations[1].citations for citation in expected_wider]) \ No newline at end of file From 715f13ba11a88da9523f5a89e118e77f89bf1052 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Fri, 6 Oct 2023 21:38:05 +0200 Subject: [PATCH 51/58] Reorganize and document test file groupings --- tests/test_citation_finding_wrapper.py | 15 +++++++++++++++ ...class.py => test_citationanalysis_cleaners.py} | 4 ++-- ...authors.py => test_individual_citation_fns.py} | 13 +------------ 3 files changed, 18 insertions(+), 14 deletions(-) create mode 100644 tests/test_citation_finding_wrapper.py rename tests/{test_citationanalysis_class.py => test_citationanalysis_cleaners.py} (97%) rename tests/{test_detecting_authors.py => test_individual_citation_fns.py} (92%) diff --git a/tests/test_citation_finding_wrapper.py b/tests/test_citation_finding_wrapper.py new file mode 100644 index 0000000..19c28b7 --- /dev/null +++ b/tests/test_citation_finding_wrapper.py @@ -0,0 +1,15 @@ +# Tests the wrapper which handles all existing fns related to finding citations in text, organising the output +# so there are no duplicates, removing extraneous characters etc. This is what happens when you click the "Analyse document" button. +# Lower level fns tested in test_individual_citation_fns. +from UI.fileManipulation import find_citations + +def test_find_citations_wrapper(): + text = "One and two (1212) often collaborate. This is well documented (Aesop and Berry, 1999). Aasimov (1999) had a revelation (Bassimov, 2000). Long Surname (2020) found his match." + + # Specifying sought-after matches. Berry, 1999 is a side-effect not considered harmful. + expected_narrow = ["Aasimov 1999", "Bassimov 2000", "Aesop & Berry 1999", "One & two 1212"] + expected_wider = ["Long Surname 2020"] + + found_citations = find_citations(text) + assert all([citation in found_citations[0].citations for citation in expected_narrow]) + assert all([citation in found_citations[1].citations for citation in expected_wider]) \ No newline at end of file diff --git a/tests/test_citationanalysis_class.py b/tests/test_citationanalysis_cleaners.py similarity index 97% rename from tests/test_citationanalysis_class.py rename to tests/test_citationanalysis_cleaners.py index 76a595d..276377c 100644 --- a/tests/test_citationanalysis_class.py +++ b/tests/test_citationanalysis_cleaners.py @@ -1,7 +1,7 @@ -import pytest +# Test fns in citationAnalysis that don't find matches itself, but perform +# cleanup, characters removal, duplicates removal etc. import citationAnalysis.citationAnalysis as ca -# Test class behavour def test_PhrasesToChange_has_all_attributes(): phrases = ca.PhrasesToChange() assert isinstance(phrases.characters_to_exclude, list) diff --git a/tests/test_detecting_authors.py b/tests/test_individual_citation_fns.py similarity index 92% rename from tests/test_detecting_authors.py rename to tests/test_individual_citation_fns.py index eab2235..bb16560 100644 --- a/tests/test_detecting_authors.py +++ b/tests/test_individual_citation_fns.py @@ -1,5 +1,4 @@ import citationAnalysis.citationAnalysis as ca -from UI.fileManipulation import find_citations # The \ indicates code continues in the next line # When testing individual detection functions, they SHOULD catch extra characters @@ -172,14 +171,4 @@ def test_surnames_apostrophe_s_recognised(): matches = ca.get_matches_solo_author(text) matches.cleanup() assert matches.citations == ["O'Samuel 1999", "O'Sullivan 2000"] - -def test_find_citations_wrapper(): - text = "One and two (1212) often collaborate. This is well documented (Aesop and Berry, 1999). Aasimov (1999) had a revelation (Bassimov, 2000). Long Surname (2020) found his match." - - # Specifying sought-after matches. Berry, 1999 is a side-effect not considered harmful. - expected_narrow = ["Aasimov 1999", "Bassimov 2000", "Aesop & Berry 1999", "One & two 1212"] - expected_wider = ["Long Surname 2020"] - - found_citations = find_citations(text) - assert all([citation in found_citations[0].citations for citation in expected_narrow]) - assert all([citation in found_citations[1].citations for citation in expected_wider]) \ No newline at end of file + \ No newline at end of file From 27ed72566622ee3551cf45f11394a112e738d545 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Fri, 6 Oct 2023 21:54:53 +0200 Subject: [PATCH 52/58] Add appdata tests filename, startup txt --- tests/test_appdata.py | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/test_appdata.py b/tests/test_appdata.py index 7b91562..57be1e1 100644 --- a/tests/test_appdata.py +++ b/tests/test_appdata.py @@ -1,5 +1,6 @@ from UI.appData import AppData from citationAnalysis.citationAnalysis import CitationType +import os def test_checking_for_empty_citation_list(): narrow_empty = CitationType([]) @@ -20,4 +21,41 @@ def test_checking_for_empty_citation_list(): appdata.set_new_results_citations([narrow_full, wide_full]) assert appdata.any_citations_recorded() == True - \ No newline at end of file + +def test_input_filepath_stored(): + appdata = AppData("", "") + + filename = os.path.abspath("C:/User/Documents/my_text.txt") + + appdata.set_new_filename(filename) + assert appdata.get_input_filepath() == filename + +def test_input_filepath_with_relevant_output_filename(): + appdata = AppData("", "") + + filename = os.path.abspath("C:/User/Documents/my_text.txt") + + # The output shouldn't have an extension - that is decided when users + # chooses what kind of file to save as + desired_default_output_filepath = os.path.abspath("C:/User/Documents/my_text_citations") + + appdata.set_new_filename(filename) + assert appdata.get_output_filepath() == desired_default_output_filepath + +def test_input_no_filepath_is_blank(): + appdata = AppData("", "") + + appdata.set_new_filename("") + assert appdata.get_input_filepath() == "" + +def test_input_no_filepath_output_file_called_citations_found(): + appdata = AppData("", "") + + appdata.set_new_filename("") + assert appdata.get_output_filepath() == "Citations_found" + +def test_startup_text_reflected_in_results(): + startup_text = "Howdy" + appdata = AppData("", startup_text) + + assert appdata.get_active_results() == startup_text \ No newline at end of file From 0a881bd97627f2e5aacea21335bddfda4bf4ec22 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Fri, 6 Oct 2023 21:57:22 +0200 Subject: [PATCH 53/58] Test reset_on_error clear citations displays text --- tests/test_appdata.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/test_appdata.py b/tests/test_appdata.py index 57be1e1..cae42c9 100644 --- a/tests/test_appdata.py +++ b/tests/test_appdata.py @@ -58,4 +58,14 @@ def test_startup_text_reflected_in_results(): startup_text = "Howdy" appdata = AppData("", startup_text) - assert appdata.get_active_results() == startup_text \ No newline at end of file + assert appdata.get_active_results() == startup_text + +def test_result_on_error_no_citations_records_error(): + startup_text = "Howdy" + appdata = AppData("", startup_text) + + error_text = "My error" + appdata.reset_on_error(error_text) + + assert appdata.get_active_results() == error_text + assert appdata.get_citations() == [] \ No newline at end of file From e9b0bcd4d6125bbefaf3c982903e4f3a718dad82 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Fri, 6 Oct 2023 22:02:50 +0200 Subject: [PATCH 54/58] Test reset_on_error when filled with citations --- tests/test_appdata.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_appdata.py b/tests/test_appdata.py index cae42c9..1653841 100644 --- a/tests/test_appdata.py +++ b/tests/test_appdata.py @@ -67,5 +67,18 @@ def test_result_on_error_no_citations_records_error(): error_text = "My error" appdata.reset_on_error(error_text) + assert appdata.get_active_results() == error_text + assert appdata.get_citations() == [] + + # Store some citations, then cleanup on error should empty them + narrow_citations = CitationType(["First 2010", "Second 2020"]) + wide_citations_none = CitationType([]) + appdata.set_new_results_citations([narrow_citations, wide_citations_none]) + + assert appdata.get_citations != [] + assert appdata.get_active_results != error_text + + appdata.reset_on_error(error_text) + assert appdata.get_active_results() == error_text assert appdata.get_citations() == [] \ No newline at end of file From 4d378b2b22237548af2a4c5ff121bce168344fea Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 7 Oct 2023 10:19:10 +0200 Subject: [PATCH 55/58] Update icon pic to be centered horizontally --- UI/P_icon.png | Bin 6373 -> 6610 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/UI/P_icon.png b/UI/P_icon.png index a91b68a61c757c1d949057acb8a486721f81dd7e..3acf7cac3c67947f4687b0e799fe5ccc93008582 100644 GIT binary patch literal 6610 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 Date: Sat, 7 Oct 2023 10:43:08 +0200 Subject: [PATCH 56/58] Test citations to string keeps all members --- tests/test_transformCitations.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/test_transformCitations.py diff --git a/tests/test_transformCitations.py b/tests/test_transformCitations.py new file mode 100644 index 0000000..f1b8d2a --- /dev/null +++ b/tests/test_transformCitations.py @@ -0,0 +1,17 @@ +import citationAnalysis.citationAnalysis as ca +import UI.transformCitations as tc +import regex + +def test_citations_to_string_pretty_includes_all(): + narrow_citations = ca.CitationType(["Aaron 2010", "Baron 2020"]) + wide_citations = ca.CitationType(["Carron 2030"]) + + stringified = tc.citations_to_string_pretty(narrow_citations, wide_citations) + + # The result is a string + assert isinstance(stringified, str) + + matches = [regex.search(citation, stringified) is not None for citation in narrow_citations.citations + wide_citations.citations] + assert all(matches) + + \ No newline at end of file From a74d19e21d029e70f098429bf67f5b753485bbbb Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 7 Oct 2023 10:52:19 +0200 Subject: [PATCH 57/58] Remove last newline --- UI/transformCitations.py | 3 +++ tests/test_transformCitations.py | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/UI/transformCitations.py b/UI/transformCitations.py index 707eda2..f7f3841 100644 --- a/UI/transformCitations.py +++ b/UI/transformCitations.py @@ -17,4 +17,7 @@ def citations_to_string_pretty(narrower_citations, wider_citations): "\nLonger citations detected:\n\n") [citation_string.append(citation + "\n") for citation in wider_citations.citations] results = "".join(citation_string) + + # Remove newline at end, it counts as one character + results = results[:-1] return(results) \ No newline at end of file diff --git a/tests/test_transformCitations.py b/tests/test_transformCitations.py index f1b8d2a..6f629cd 100644 --- a/tests/test_transformCitations.py +++ b/tests/test_transformCitations.py @@ -14,4 +14,11 @@ def test_citations_to_string_pretty_includes_all(): matches = [regex.search(citation, stringified) is not None for citation in narrow_citations.citations + wide_citations.citations] assert all(matches) - \ No newline at end of file +def test_citations_to_string_no_newline_at_end(): + narrow_citations = ca.CitationType(["Aaron 2010", "Baron 2020"]) + wide_citations = ca.CitationType(["Carron 2030"]) + + stringified = tc.citations_to_string_pretty(narrow_citations, wide_citations) + + match = regex.search("\n$", stringified) + assert match is None \ No newline at end of file From 29c92185c76e1499627db5a3e3718359ed4a4d02 Mon Sep 17 00:00:00 2001 From: Mkranj Date: Sat, 7 Oct 2023 10:53:23 +0200 Subject: [PATCH 58/58] Remove unused fn for citations to string wo format --- UI/transformCitations.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/UI/transformCitations.py b/UI/transformCitations.py index f7f3841..fc03e1e 100644 --- a/UI/transformCitations.py +++ b/UI/transformCitations.py @@ -1,13 +1,5 @@ import UI.messages as ms -def citations_to_string(narrower_citations, wider_citations): - citation_string = [] - [citation_string.append(citation + "\n") for citation in narrower_citations.citations] - if len(wider_citations.citations) > 0: - [citation_string.append(citation + "\n") for citation in wider_citations.citations] - results = "".join(citation_string) - return(results) - # For display and saving to .txt, visually separate wider citations def citations_to_string_pretty(narrower_citations, wider_citations): citation_string = []