diff --git a/pygadmin/csv_exporter.py b/pygadmin/csv_exporter.py new file mode 100644 index 0000000..57a8712 --- /dev/null +++ b/pygadmin/csv_exporter.py @@ -0,0 +1,145 @@ +import logging + +from PyQt5.QtWidgets import QFileDialog, QMessageBox + +from pygadmin.database_query_executor import DatabaseQueryExecutor +from pygadmin.connectionfactory import global_connection_factory + + +class CSVExporter: + """ + Create a class for exporting the current results to a CSV file. TODO: Docu + """ + + def __init__(self, parent, data_list, database_connection_parameters=None, table_name=None): + """ + Get the parent for assigning the file dialog to a widget and the data list for the data, which will be saved. + """ + + # If the data list is None and the database connection parameters are None, there is no way to get the required + # data for the csv file. + if data_list is None and database_connection_parameters is None: + # Show the error to the user and end the initialization. + QMessageBox.critical(parent, "Data Error", "A data source for exporting to CSV is not given.") + return + + # Define the parent, the data list and the file name as attributes. + self.parent = parent + self.data_list = data_list + self.file_name = None + + # If the data list is None, the required data needs to be collected. + if self.data_list is None: + # Prepare the data list with building the query and preparing the database query executor. + self.prepare_data_list(database_connection_parameters, table_name) + # Set the success attribute to False, because the csv export is still in process and not successful at this + # point in the program. + self.success = False + + def prepare_data_list(self, database_connection_parameters, table_name): + """ + Prepare the relevant parts for getting the data list with the database connection, the database query executor + and the database query. + """ + + database_connection = self.get_database_connection(database_connection_parameters) + + if database_connection is None: + return + + query = "SELECT * FROM {};".format(table_name) + + self.database_query_executor = DatabaseQueryExecutor() + self.database_query_executor.result_data.connect(self.get_result_data_list) + self.database_query_executor.database_connection = database_connection + self.database_query_executor.database_query = query + + def get_database_connection(self, database_connection_parameters): + database_connection = global_connection_factory.get_database_connection(database_connection_parameters["host"], + database_connection_parameters["user"], + database_connection_parameters[ + "database"], + database_connection_parameters["port"]) + + if database_connection is None or database_connection is False: + QMessageBox.critical(self.parent, "Database Connection Fail", "The connection to the database failed, " + "please check the log for further " + "information.") + + return None + + return database_connection + + def get_result_data_list(self, data_list): + if data_list: + self.data_list = data_list + self.success = True + self.export_and_save_csv_data() + + def get_file_name_by_file_dialog(self): + """ + Create a file dialog for activating the csv export. + """ + + # Get a csv file with the default name result.csv and the file type csv. + file_dialog_with_name_and_type = QFileDialog.getSaveFileName(self.parent, "Save File", "result.csv", + "CSV (*.csv)") + + # Get the file name. + file_name = file_dialog_with_name_and_type[0] + + # If the file name is not an empty string, return the file name, because in this case, the user has entered one. + if file_name != "": + return file_name + + # Inform the user in the log about the abort. + else: + logging.info("The current file saving process was aborted by the user, so the current result as csv file" + " is not saved.") + + # Return False, because there is no file name. + return False + + def export_result_to_csv(self, file_name): + """ + Export the result data to csv with the file name. Get the data out of the table model. + """ + + # Open the given file in write mode. + with open(file_name, "w") as file_to_save: + # Get through every data row in the data list. + for data_row in self.data_list: + # Get through every value in the data row. + for data_value_counter in range(len(data_row)): + # Write every value. + file_to_save.write(str(data_row[data_value_counter])) + + # If the value is not the last one, append a comma for comma separated value. + if data_value_counter != len(data_row) - 1: + file_to_save.write(",") + + # Write a newline at the end of a data row. + file_to_save.write("\n") + + def export_and_save_csv_data(self): + """ + Activate the export and save of the csv data. + """ + + if self.file_name is None: + # Get the file name with a file dialog. + self.file_name = self.get_file_name_by_file_dialog() + + # If the file name is False, the process of saving the file has been aborted. + if self.file_name is False: + # End the function with a return. + return + + if self.data_list is None: + self.database_query_executor.submit_and_execute_query() + return + + # Save the current query result data. + self.export_result_to_csv(self.file_name) + + return True diff --git a/pygadmin/widgets/editor.py b/pygadmin/widgets/editor.py index 07dc9fa..8dcc444 100644 --- a/pygadmin/widgets/editor.py +++ b/pygadmin/widgets/editor.py @@ -10,6 +10,7 @@ from PyQt5.QtWidgets import QWidget, QGridLayout, QPushButton, QTableView, QMess QCheckBox, QLabel, qApp from pygadmin.connectionfactory import global_connection_factory +from pygadmin.csv_exporter import CSVExporter from pygadmin.models.tablemodel import TableModel from pygadmin.configurator import global_app_configurator from pygadmin.models.lexer import SQLLexer @@ -1074,60 +1075,12 @@ class EditorWidget(QWidget, SearchReplaceParent, metaclass=MetaEditor): Activate the export and save of the csv data. """ - # Get the file name with a file dialog. - file_name = self.activate_file_dialog_for_csv_export() + # TODO: Docu + csv_exporter = CSVExporter(self, self.table_model.data_list) + success = csv_exporter.export_and_save_csv_data() - # If the file name is None, the process of saving the file has been aborted. - if file_name is None: - # End the function with a return. - return - - # Save the current query result data. - self.export_result_to_csv(file_name) - - def activate_file_dialog_for_csv_export(self): - """ - Create a file dialog for activating the csv export. - """ - - # Get a csv file with the default name result.csv and the file type csv. - file_dialog_with_name_and_type = QFileDialog.getSaveFileName(self, "Save File", "result", "CSV (*.csv)") - - # Get the file name. - file_name = file_dialog_with_name_and_type[0] - - # If the file name is not an empty string, return the file name, because in this case, the user has entered one. - if file_name != "": - return file_name - - # Inform the user in the log about the abort. - else: - logging.info("The current file saving process was aborted by the user, so the current result as csv file" - " is not saved.") - - # Return None, because there is no file name. - return None - - def export_result_to_csv(self, file_name): - """ - Export the result data to csv with the file name. Get the data out of the table model. - """ - - # Open the given file in write mode. - with open(file_name, "w") as file_to_save: - # Get through every data row in the data list. - for data_row in self.table_model.data_list: - # Get through every value in the data row. - for data_value_counter in range(len(data_row)): - # Write every value. - file_to_save.write(str(data_row[data_value_counter])) - - # If the value is not the last one, append a comma for comma separated value. - if data_value_counter != len(data_row) - 1: - file_to_save.write(",") - - # Write a newline at the end of a data row. - file_to_save.write("\n") + if success: + QMessageBox.information(self, "Export Success", "The csv export was successful.") def get_explain_analyze_query(self): """ diff --git a/pygadmin/widgets/tree.py b/pygadmin/widgets/tree.py index 4463cba..0f47f53 100644 --- a/pygadmin/widgets/tree.py +++ b/pygadmin/widgets/tree.py @@ -8,6 +8,7 @@ from PyQt5.QtWidgets import QWidget, QTreeView, QAbstractItemView, QMessageBox, from pygadmin.configurator import global_app_configurator from pygadmin.connectionstore import global_connection_store +from pygadmin.csv_exporter import CSVExporter from pygadmin.models.treemodel import ServerNode, TablesNode, ViewsNode, SchemaNode, AbstractBaseNode, DatabaseNode, \ TableNode, ViewNode from pygadmin.widgets.materialized_view_information import MaterializedViewInformationDialog @@ -311,6 +312,8 @@ class TreeWidget(QWidget): self.context_menu.addAction(show_permission_information_action) edit_single_values_action = QAction("Edit Single Values", self) self.context_menu.addAction(edit_single_values_action) + export_full_table_to_csv_action = QAction("Export Full Table As CSV", self) + self.context_menu.addAction(export_full_table_to_csv_action) # Get the action at the current position of the triggering event. position_action = self.context_menu.exec_(self.tree_view.viewport().mapToGlobal(position)) @@ -334,6 +337,9 @@ class TreeWidget(QWidget): elif position_action == edit_single_values_action: self.show_edit_singles_values_dialog(current_selected_node) + elif position_action == export_full_table_to_csv_action: + self.get_full_data_of_current_table_for_csv_export(current_selected_node) + def append_new_connection_parameters_and_node(self): """ Get new parameters out of the .yaml file, where all connections are stored, because this function should be @@ -978,3 +984,18 @@ class TreeWidget(QWidget): """ self.materialized_view_information_dialog = MaterializedViewInformationDialog(current_node) + + def get_full_data_of_current_table_for_csv_export(self, current_node): + # TODO: Docu + self.csv_exporter = CSVExporter(self, None, {"host": current_node.database_connection_parameters["host"], + "user": current_node.database_connection_parameters["user"], + "database": + current_node.database_connection_parameters["database"], + "port": current_node.database_connection_parameters["port"]}, + current_node.name) + + self.csv_exporter.export_and_save_csv_data() + self.csv_exporter.database_query_executor.result_data.connect(lambda: + QMessageBox.information(self, "Export Success", + "The csv export was " + "successful."))