class MainController: def __init__(self, root): # View config self.main_view = MainView(root) self.main_view.upload_button.config(command=self.upload) self.main_view.upload_button_template.config(command=self.upload_template) self.main_view.download_button.config(command=self.download) # Paths self.input_path = '' self.input_path_template = '' self.output_path = '' # Target groups self.target_groups_dict = {} # Export content self.export_content = ExportContent() self.input_handler = None def download(self): """ Downloads word document Triggered on download_button click :return: """ self.__clear_messages() if self.input_path: self.output_path = tkFileDialog.asksaveasfilename(defaultextension=".docx") if self.output_path: self.__download_generated_word_document(self.output_path) self.__set_success_message(Messages.SUCCESS_DOWNLOAD) try: pass except ValueError as e: print e self.__set_error_message(Messages.ERROR_INVALID_JSON) except Exception as e: print e self.__set_error_message(Messages.ERROR_INVALID_INPUT_CONTENT) else: self.__set_error_message(Messages.ERROR_NO_INPUT_PATH_SELECTED) def upload(self): """ Uploads JSON input file Triggered on upload_button click :return: """ self.__clear_messages() self.main_view.disable_download_button(True) path = tkFileDialog.askopenfilename(parent=self.main_view, initialdir="/", title='Last opp JSON-fil') self.main_view.set_input_path('') if not path: pass elif self.__get_file_extension(path).lower() != 'json': self.__set_error_message(Messages.ERROR_INVALID_FILE_FORMAT) else: # Valid path try: self.input_path = path self.input_handler = InputHandler(self.input_path) self.__set_target_groups_drop_down_option() self.main_view.set_input_path(self.input_path) self.__check_downloadable() except ValueError as e: print e self.__set_error_message(Messages.ERROR_INVALID_JSON) except Exception as e: print e self.__set_error_message(Messages.ERROR_INVALID_INPUT_CONTENT) def upload_template(self): """ Uploads Word template Triggered on upload_button_template click :return: """ self.__clear_messages() self.main_view.disable_download_button(True) path = tkFileDialog.askopenfilename(parent=self.main_view, initialdir="/", title='Last opp Word-mal') self.main_view.set_input_path_template('') if not path: pass elif self.__get_file_extension(path).lower() != 'docx': self.__set_error_message(Messages.ERROR_INVALID_FILE_FORMAT) else: # Valid path try: self.input_path_template = path self.main_view.set_input_path_template(self.input_path_template) self.__check_downloadable() except ValueError as e: print e self.__set_error_message(Messages.ERROR_INVALID_JSON) except Exception as e: print e self.__set_error_message(Messages.ERROR_INVALID_INPUT_CONTENT) def __set_target_groups_drop_down_option(self): """ Updates target_groups_drop_down values from JSON file. The default value is not touched. :return: """ options = self.main_view.target_groups_drop_down.children['menu'] options.delete(1, 'end') # Clear drop down target_groups = self.input_handler.get_target_groups() for target_group in target_groups: target_group_name = target_group['name'] self.target_groups_dict[target_group_name] = target_group['id'] options.add_command(label=target_group_name, command=lambda v=self.main_view.selected_target_group, l=target_group_name: v.set(l)) def __check_downloadable(self): """ Checks that both a JSON file and a Word template is uploaded. :return: """ if self.input_path and self.input_path_template: self.main_view.disable_download_button(False) def __clear_messages(self): self.main_view.set_error_message('') self.main_view.set_success_message('') def __set_error_message(self, error_message): self.main_view.set_success_message('') self.main_view.set_error_message(error_message) def __set_success_message(self, success_message): self.main_view.set_error_message('') self.main_view.set_success_message(success_message) def __generate_word_document(self): """ Generates word document. :param input_path: :return: """ topics = self.input_handler.get_topics() for topic in topics: documents = self.input_handler.get_documents_by_topic_id(topic['id']) self.export_content.add_topic(topic, documents, self.input_handler, 0) def __generate_word_document_based_on_target_groups(self, target_group_id): """ Generates Word document with the documents in which the specified target group appears. :param target_group_id: :return: """ topics = self.input_handler.get_topics() for topic in topics: documents = self.input_handler.get_documents_by_topic_id(topic['id']) self.export_content.add_topic(topic, documents, self.input_handler, target_group_id) def __download_generated_word_document(self, output_path): # TODO: look at documentation """ Downloads docx file with the inserted values from json file. There is no support for for links in python-docx-template (docxtpl), therefore the file is first saved, and then read using python-docx (docx) to replace the links with working hyperlinks, before the file is written back to disk. :param output_path: :return: """ # Python-docx-template template = DocxTemplate(self.input_path_template) self.export_content.reset_list() # Reset list to make sure the content is not repeated on multiple downloads if self.main_view.selected_target_group.get() == GuiContent.DROP_DOWN_VALUE_NO_SELECTED_TARGET_GROUP: # If no target group is selected self.__generate_word_document() # Word document is generated with all documents else: target_group = self.input_handler.get_target_group_by_id(self.target_groups_dict[self.main_view.selected_target_group.get()]) self.__generate_word_document_based_on_target_groups(target_group['id']) # Word document is generated with all documents that contains specified target group content = self.export_content.get_content() template.render(content) # Insert values to jinja2 template try: template.save(self.output_path) # Temporary saved on disk # Python-docx - replace links and insert page breaks, before Word document is saved word_handler = WordHandler(output_path) word_handler.insert_hyper_links() word_handler.insert_new_page() word_handler.save_word_document(output_path) except IOError as e: self.__set_error_message(Messages.ERROR_CANT_WRITE_TO_FILE) except Exception as e: self.__set_error_message(Messages.ERROR_DEFAULT) print e def __get_file_path(self, full_path): """ Returns folder path. input: 'c:/folder/file.json', returns 'c:/folder' :param full_path: :return: """ end_of_path_index = full_path.rfind('/') # Last occurrence of '/' return full_path[:end_of_path_index] def __get_file_name(self, full_path): """ Returns filename. input: 'c:/folder/file.json', returns 'file.json' :param full_path: :return: """ file_name_with_extension = full_path[len(self.__get_file_path(full_path)) + 1:] file_extension_index = file_name_with_extension.rfind('.docx') return file_name_with_extension[:file_extension_index] def __get_file_extension(self, full_path): """ Returns file extension. input: 'c:/folder/file.json', returns 'json' :param full_path: :return: """ file_name_with_extension = full_path[len(self.__get_file_path(full_path)) + 1:] file_extension_index = file_name_with_extension.rfind('.') return file_name_with_extension[file_extension_index+1:]