def __init__(self, parent=None):
        super().__init__(parent)

        self.undo_stack = QUndoStack()
        self.statusBar()

        self.view = Ui_MainWindow()
        self.view.setupUi(self)
        self.view.tableView.setSortingEnabled(False)
        self.view.tableView.setItemDelegate(ItemDelegate(self.undo_stack, self.set_undo_redo_text))

        self.filename = None
        self.table_model = CSVTableModel(self, datalist=[], header=[])

        self.view.actionConnect.setEnabled(True)
        self.view.actionDisconnect.setEnabled(False)
        self.view.actionInsert.setEnabled(False)
        self.view.actionReceive.setEnabled(False)
        self.view.actionCalculate_Predictions.setEnabled(False)

        self.view.actionAbout_Qt.triggered.connect(self.about_qt)
        self.view.actionAbout.triggered.connect(self.about)
        self.view.actionConnect.triggered.connect(self.connect)
        self.view.actionDisconnect.triggered.connect(self.disconnect)
        self.view.actionInsert.triggered.connect(self.insert)
        self.view.actionReceive.triggered.connect(self.receive)
        self.view.actionCalculate_Predictions.triggered.connect(self.calculate_predictions)
        self.view.actionUndo.triggered.connect(self.undo)
        self.view.actionRedo.triggered.connect(self.redo)
        self.view.actionCopy.triggered.connect(self.copy)
        self.view.actionPaste.triggered.connect(self.paste)
        self.view.actionInsert_Row_s.triggered.connect(self.insert_rows)
        self.view.actionDuplicate_Row_s.triggered.connect(self.duplicate_rows)
        self.view.actionRemove_Row_s.triggered.connect(self.remove_rows)
        self.view.actionNew.triggered.connect(self.new)
        self.view.actionOpen.triggered.connect(self.open)
        self.view.actionSave.triggered.connect(self.save)
        self.view.actionSave_as.triggered.connect(self.save_as)

        self.db = None
    def __init__(self, parent=None):
        super().__init__(parent)

        self.undo_stack = QUndoStack()
        self.statusBar()

        self.view = Ui_MainWindow()
        self.view.setupUi(self)
        self.view.tableView.setSortingEnabled(False)
        self.view.tableView.setItemDelegate(ItemDelegate(self.undo_stack, self.set_undo_redo_text))

        self.filename = None
        self.table_model = CSVTableModel(self, datalist=[], header=[])

        self.view.actionConnect.setEnabled(True)
        self.view.actionDisconnect.setEnabled(False)
        self.view.actionInsert.setEnabled(False)
        self.view.actionReceive.setEnabled(False)
        self.view.actionCalculate_Predictions.setEnabled(False)

        self.view.actionAbout_Qt.triggered.connect(self.about_qt)
        self.view.actionAbout.triggered.connect(self.about)
        self.view.actionConnect.triggered.connect(self.connect)
        self.view.actionDisconnect.triggered.connect(self.disconnect)
        self.view.actionInsert.triggered.connect(self.insert)
        self.view.actionReceive.triggered.connect(self.receive)
        self.view.actionCalculate_Predictions.triggered.connect(self.calculate_predictions)
        self.view.actionUndo.triggered.connect(self.undo)
        self.view.actionRedo.triggered.connect(self.redo)
        self.view.actionCopy.triggered.connect(self.copy)
        self.view.actionPaste.triggered.connect(self.paste)
        self.view.actionInsert_Row_s.triggered.connect(self.insert_rows)
        self.view.actionDuplicate_Row_s.triggered.connect(self.duplicate_rows)
        self.view.actionRemove_Row_s.triggered.connect(self.remove_rows)
        self.view.actionNew.triggered.connect(self.new)
        self.view.actionOpen.triggered.connect(self.open)
        self.view.actionSave.triggered.connect(self.save)
        self.view.actionSave_as.triggered.connect(self.save_as)

        self.db = None
class CSVTableController(QtGui.QMainWindow):

    # noinspection PyCompatibility
    def __init__(self, parent=None):
        super().__init__(parent)

        self.undo_stack = QUndoStack()
        self.statusBar()

        self.view = Ui_MainWindow()
        self.view.setupUi(self)
        self.view.tableView.setSortingEnabled(False)
        self.view.tableView.setItemDelegate(ItemDelegate(self.undo_stack, self.set_undo_redo_text))

        self.filename = None
        self.table_model = CSVTableModel(self, datalist=[], header=[])

        self.view.actionConnect.setEnabled(True)
        self.view.actionDisconnect.setEnabled(False)
        self.view.actionInsert.setEnabled(False)
        self.view.actionReceive.setEnabled(False)
        self.view.actionCalculate_Predictions.setEnabled(False)

        self.view.actionAbout_Qt.triggered.connect(self.about_qt)
        self.view.actionAbout.triggered.connect(self.about)
        self.view.actionConnect.triggered.connect(self.connect)
        self.view.actionDisconnect.triggered.connect(self.disconnect)
        self.view.actionInsert.triggered.connect(self.insert)
        self.view.actionReceive.triggered.connect(self.receive)
        self.view.actionCalculate_Predictions.triggered.connect(self.calculate_predictions)
        self.view.actionUndo.triggered.connect(self.undo)
        self.view.actionRedo.triggered.connect(self.redo)
        self.view.actionCopy.triggered.connect(self.copy)
        self.view.actionPaste.triggered.connect(self.paste)
        self.view.actionInsert_Row_s.triggered.connect(self.insert_rows)
        self.view.actionDuplicate_Row_s.triggered.connect(self.duplicate_rows)
        self.view.actionRemove_Row_s.triggered.connect(self.remove_rows)
        self.view.actionNew.triggered.connect(self.new)
        self.view.actionOpen.triggered.connect(self.open)
        self.view.actionSave.triggered.connect(self.save)
        self.view.actionSave_as.triggered.connect(self.save_as)

        self.db = None

    def show_window(self):
        self.setEnabled(True)
        self.show()
        self.raise_()

    def update_table_model(self, data, header):
        self.table_model.set_list(data, header)
        self.view.tableView.reset()
        self.view.tableView.setModel(self.table_model)

    def set_undo_redo_text(self):
        undo = "Undo"
        redo = "Redo"
        undo_text = self.undo_stack.undoText()
        redo_text = self.undo_stack.redoText()
        if undo_text:
            undo += " \"" + undo_text + "\""
        if redo_text:
            redo += " \"" + redo_text + "\""
        self.view.actionUndo.setText(undo)
        self.view.actionRedo.setText(redo)

    def get_selection(self):
        zero_column_selected_indexes = self.get_zero_column_selected_indexes()
        if not zero_column_selected_indexes:
            return self.table_model.rowCount(self), 1
        first_zero_column_selected_index = zero_column_selected_indexes[0]
        zero_column_selected_indexes = self.get_zero_column_selected_indexes()

        if not first_zero_column_selected_index or not first_zero_column_selected_index.isValid():
            return False
        startingrow = first_zero_column_selected_index.row()

        return startingrow, len(zero_column_selected_indexes)

    def get_zero_column_selected_indexes(self):
        selected_indexes = self.view.tableView.selectedIndexes()
        if not selected_indexes:
            return
        return [index for index in selected_indexes if not index.column()]

    def about_qt(self):
        QtGui.qApp.aboutQt()

    def about(self):
        self.about = AboutWindow()
        self.about.show()

    def connect(self):
        QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)

        connection_string = 'mysql+mysqldb://{username}:{password}@{host}/{database}'.format(username=USERNAME,
                                                                                             password=PASSWORD,
                                                                                             host=HOST,
                                                                                             database=DATABASE)
        try:
            if self.db is None:
                self.db = DatabaseManager(connectionstring=connection_string, electiondate="2015-10-11")
                self.statusBar().showMessage("Successfully connected to database")
                self.view.actionConnect.setEnabled(False)
                self.view.actionDisconnect.setEnabled(True)
                self.view.actionInsert.setEnabled(True)
                self.view.actionReceive.setEnabled(True)
                self.view.actionCalculate_Predictions.setEnabled(True)
        except:
            QtGui.QMessageBox.critical(self, "Connection Error",  "Error connecting to Database:\n" + sys.exc_info()[0], QMessageBox.Close)

        QtGui.QApplication.restoreOverrideCursor()

    def disconnect(self):
        QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)

        if self.db is not None:
            self.db.close()
            self.db = None
            self.view.actionConnect.setEnabled(True)
            self.view.actionDisconnect.setEnabled(False)
            self.view.actionInsert.setEnabled(False)
            self.view.actionReceive.setEnabled(False)
            self.view.actionCalculate_Predictions.setEnabled(False)
            self.statusBar().showMessage("Successfully disconnected from database")


        QtGui.QApplication.restoreOverrideCursor()

    def insert(self):
        if self.filename is None or len(self.table_model.get_list()) == 0:
            self.statusBar().showMessage("You need to have some data to insert")
            return

        try:
            current_list = self.table_model.get_list()
            self.db.write(current_list)
        except Exception as e:
            print(e)
            self.statusBar().showMessage("Error while accessing the database.")

    def receive(self):
        try:
            data = self.db.load()
            self.table_model.set_list(data)
            self.update_table_model(self.table_model.get_list(), self.table_model.get_header())
        except Exception as e:
            print(e)
            self.statusBar().showMessage("Error while accessing the database.")

    def calculate_predictions(self):
        """
        Cudos an Rene Hollander
        """
        projection_data = self.db.create_projection()
        print("Hochrechnung:")
        for key, value in projection_data.items():
            print(key + ": " + str(value))
        print("\n")
        ind = numpy.arange(len(projection_data))
        width = 0.5
        plt.bar(ind, list(projection_data.values()), width, color='r')
        plt.ylabel('%')
        plt.xlabel('Parteien')
        plt.title('Wien Wahl Hochrechnung')
        plt.xticks(ind + width / 2, list(projection_data.keys()))
        plt.yticks(numpy.arange(0, 61, 5))
        plt.show()

    def undo(self):
        self.undo_stack.undo()
        self.set_undo_redo_text()
        self.view.tableView.reset()

    def redo(self):
        self.undo_stack.redo()
        self.set_undo_redo_text()
        self.view.tableView.reset()

    def copy(self):
        if len(self.view.tableView.selectionModel().selectedIndexes()) == 0:
            return

        clipboard = QApplication.clipboard()
        selected_index = self.view.tableView.selectionModel().selectedIndexes()[0]
        selected_text = str(self.table_model.data(selected_index))
        clipboard.setText(selected_text)

    def paste(self):
        if len(self.view.tableView.selectionModel().selectedIndexes()) == 0:
            return

        clipboard = QApplication.clipboard()
        index = self.view.tableView.selectionModel().selectedIndexes()[0]
        command = EditCommand(self.table_model, index)
        command.newValue(str(clipboard.text()))

        self.undo_stack.beginMacro("Paste")
        self.undo_stack.push(command)
        self.undo_stack.endMacro()
        self.set_undo_redo_text()
        self.view.tableView.reset()

    def insert_rows(self):
        if len(self.table_model.get_header()) == 0:
            self.statusBar().showMessage("Adding rows to an empty table without a header is not possible.")
            return
        start, amount = self.get_selection()

        self.undo_stack.beginMacro("Add Row")
        self.undo_stack.push(InsertRowsCommand(self.table_model, start, 1))
        self.undo_stack.endMacro()
        self.set_undo_redo_text()

    def duplicate_rows(self):
        if len(self.view.tableView.selectionModel().selectedIndexes()) == 0:
            self.statusBar().showMessage("You must select the first column of the row you want to duplicate")
            return

        start, amount = self.get_selection()
        self.undo_stack.beginMacro("Duplicate Row")
        self.undo_stack.push(DuplicateRowCommand(self.table_model, start))
        self.undo_stack.endMacro()
        self.set_undo_redo_text()
        self.view.tableView.reset()

    def remove_rows(self):
        if len(self.table_model.get_list()) == 0:
            self.statusBar().showMessage("WARNING: Removing rows from an empty table is not possible")
            return
        start, amount = self.get_selection()
        if start != len(self.table_model.get_list()):
            self.undo_stack.beginMacro("Remove Row(s)")
            self.undo_stack.push(RemoveRowsCommand(self.table_model, start, amount))
            self.undo_stack.endMacro()
            self.set_undo_redo_text()
        else:
            self.statusBar().showMessage("WARNING: You need to choose the rows you want to remove by selecting the cells in the "
                                   "first column")

    def new(self):
        if self.filename is not None:
            save = self.show_new_file_dialog()
            if(save):
                self.save()
                self.filename = None
                self.table_model.set_list([], [])
            else:
                self.filename = None
                self.table_model.set_list([], [])
        else:
            self.filename = None
            self.table_model.set_list([], [])

    def show_append_override_dialog(self):
        msgBox = QtGui.QMessageBox()
        msgBox.setWindowTitle("Append or Override")
        msgBox.setText("Append or override the current entries?")
        msgBox.addButton("Append", QtGui.QMessageBox.YesRole)
        msgBox.addButton("Override", QtGui.QMessageBox.NoRole)
        return msgBox.exec_()

    def show_new_file_dialog(self):
        msgBox = QtGui.QMessageBox()
        msgBox.setWindowTitle("New file")
        msgBox.setText("Do you want to save first?")
        msgBox.addButton("Yes", QtGui.QMessageBox.YesRole)
        msgBox.addButton("No", QtGui.QMessageBox.NoRole)
        return msgBox.exec_()

    def open(self):
        try:
            fileName = QFileDialog.getOpenFileName(self, self.tr("Open CSV File"), os.getcwd(),
                                                   self.tr("CSV Files (*.csv)"))[0]
            if fileName is not None and fileName is not "":
                append_or_override = False
                if self.filename is not None:
                    append_or_override = self.show_append_override_dialog()
                self.filename = fileName
                self.table_model.open(self.filename, clear=append_or_override)
                self.undo_stack.clear()
                self.set_undo_redo_text()
                self.update_table_model(self.table_model.get_list(), self.table_model.get_header())
        except FileNotFoundError:
            QtGui.QMessageBox.critical(self, "Read Error",
                                 "Error reading CSV File:\nFile \"" + self.filename + "\" not found!",
                                 QtGui.QMessageBox.Close)
        except csv.Error:
            QtGui.QMessageBox.critical(self, "Read Error", "Error reading CSV File:\n File is not an valid CSV File!",
                                 QtGui.QMessageBox.Close)
        except:
            QtGui.QMessageBox.critical(self, "Read Error", "Error reading CSV File:\nAn unknown Error occured!",
                                 QtGui.QMessageBox.Close)
            raise

    def save(self):
        if self.filename is not None and self.filename is not "":
            self.table_model.save(self.filename)
        else:
            fileName = QFileDialog.getSaveFileName(self, caption="Save CSV File", dir=os.getcwd(),
                                                   filter="CSV Files (*.csv)")[0]
            if fileName is not None and fileName is not "":
                self.table_model.save(fileName)

    def save_as(self):
        fileName = QFileDialog.getSaveFileName(self, caption="Save CSV File", dir=os.getcwd(), filter="CSV Files (*.csv)")[0]
        if fileName is not None and fileName is not "":
            self.table_model.save(fileName)
class CSVTableController(QtGui.QMainWindow):

    # noinspection PyCompatibility
    def __init__(self, parent=None):
        super().__init__(parent)

        self.undo_stack = QUndoStack()
        self.statusBar()

        self.view = Ui_MainWindow()
        self.view.setupUi(self)
        self.view.tableView.setSortingEnabled(False)
        self.view.tableView.setItemDelegate(ItemDelegate(self.undo_stack, self.set_undo_redo_text))

        self.filename = None
        self.table_model = CSVTableModel(self, datalist=[], header=[])

        self.view.actionConnect.setEnabled(True)
        self.view.actionDisconnect.setEnabled(False)
        self.view.actionInsert.setEnabled(False)
        self.view.actionReceive.setEnabled(False)
        self.view.actionCalculate_Predictions.setEnabled(False)

        self.view.actionAbout_Qt.triggered.connect(self.about_qt)
        self.view.actionAbout.triggered.connect(self.about)
        self.view.actionConnect.triggered.connect(self.connect)
        self.view.actionDisconnect.triggered.connect(self.disconnect)
        self.view.actionInsert.triggered.connect(self.insert)
        self.view.actionReceive.triggered.connect(self.receive)
        self.view.actionCalculate_Predictions.triggered.connect(self.calculate_predictions)
        self.view.actionUndo.triggered.connect(self.undo)
        self.view.actionRedo.triggered.connect(self.redo)
        self.view.actionCopy.triggered.connect(self.copy)
        self.view.actionPaste.triggered.connect(self.paste)
        self.view.actionInsert_Row_s.triggered.connect(self.insert_rows)
        self.view.actionDuplicate_Row_s.triggered.connect(self.duplicate_rows)
        self.view.actionRemove_Row_s.triggered.connect(self.remove_rows)
        self.view.actionNew.triggered.connect(self.new)
        self.view.actionOpen.triggered.connect(self.open)
        self.view.actionSave.triggered.connect(self.save)
        self.view.actionSave_as.triggered.connect(self.save_as)

        self.db = None

    def show_window(self):
        self.setEnabled(True)
        self.show()
        self.raise_()

    def update_table_model(self, data, header):
        self.table_model.set_list(data, header)
        self.view.tableView.reset()
        self.view.tableView.setModel(self.table_model)

    def set_undo_redo_text(self):
        undo = "Undo"
        redo = "Redo"
        undo_text = self.undo_stack.undoText()
        redo_text = self.undo_stack.redoText()
        if undo_text:
            undo += ' "' + undo_text + '"'
        if redo_text:
            redo += ' "' + redo_text + '"'
        self.view.actionUndo.setText(undo)
        self.view.actionRedo.setText(redo)

    def get_selection(self):
        zero_column_selected_indexes = self.get_zero_column_selected_indexes()
        if not zero_column_selected_indexes:
            return self.table_model.rowCount(self), 1
        first_zero_column_selected_index = zero_column_selected_indexes[0]
        zero_column_selected_indexes = self.get_zero_column_selected_indexes()

        if not first_zero_column_selected_index or not first_zero_column_selected_index.isValid():
            return False
        startingrow = first_zero_column_selected_index.row()

        return startingrow, len(zero_column_selected_indexes)

    def get_zero_column_selected_indexes(self):
        selected_indexes = self.view.tableView.selectedIndexes()
        if not selected_indexes:
            return
        return [index for index in selected_indexes if not index.column()]

    def about_qt(self):
        QtGui.qApp.aboutQt()

    def about(self):
        self.about = AboutWindow()
        self.about.show()

    def connect(self):
        QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)

        connection_string = "mysql+mysqldb://{username}:{password}@{host}/{database}".format(
            username=USERNAME, password=PASSWORD, host=HOST, database=DATABASE
        )
        try:
            if self.db is None:
                self.db = DatabaseManager(connectionstring=connection_string, electiondate="2015-10-11")
                self.statusBar().showMessage("Successfully connected to database")
                self.view.actionConnect.setEnabled(False)
                self.view.actionDisconnect.setEnabled(True)
                self.view.actionInsert.setEnabled(True)
                self.view.actionReceive.setEnabled(True)
                self.view.actionCalculate_Predictions.setEnabled(True)
        except:
            QtGui.QMessageBox.critical(
                self, "Connection Error", "Error connecting to Database:\n" + sys.exc_info()[0], QMessageBox.Close
            )

        QtGui.QApplication.restoreOverrideCursor()

    def disconnect(self):
        QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)

        if self.db is not None:
            self.db.close()
            self.db = None
            self.view.actionConnect.setEnabled(True)
            self.view.actionDisconnect.setEnabled(False)
            self.view.actionInsert.setEnabled(False)
            self.view.actionReceive.setEnabled(False)
            self.view.actionCalculate_Predictions.setEnabled(False)
            self.statusBar().showMessage("Successfully disconnected from database")

        QtGui.QApplication.restoreOverrideCursor()

    def insert(self):
        if self.filename is None or len(self.table_model.get_list()) == 0:
            self.statusBar().showMessage("You need to have some data to insert")
            return

        try:
            current_list = self.table_model.get_list()
            self.db.write(current_list)
        except Exception as e:
            print(e)
            self.statusBar().showMessage("Error while accessing the database.")

    def receive(self):
        try:
            data = self.db.load()
            self.table_model.set_list(data)
            self.update_table_model(self.table_model.get_list(), self.table_model.get_header())
        except Exception as e:
            print(e)
            self.statusBar().showMessage("Error while accessing the database.")

    def calculate_predictions(self):
        """
        Cudos an Rene Hollander
        """
        projection_data = self.db.create_projection()
        print("Hochrechnung:")
        for key, value in projection_data.items():
            print(key + ": " + str(value))
        print("\n")
        ind = numpy.arange(len(projection_data))
        width = 0.5
        plt.bar(ind, list(projection_data.values()), width, color="r")
        plt.ylabel("%")
        plt.xlabel("Parteien")
        plt.title("Wien Wahl Hochrechnung")
        plt.xticks(ind + width / 2, list(projection_data.keys()))
        plt.yticks(numpy.arange(0, 61, 5))
        plt.show()

    def undo(self):
        self.undo_stack.undo()
        self.set_undo_redo_text()
        self.view.tableView.reset()

    def redo(self):
        self.undo_stack.redo()
        self.set_undo_redo_text()
        self.view.tableView.reset()

    def copy(self):
        if len(self.view.tableView.selectionModel().selectedIndexes()) == 0:
            return

        clipboard = QApplication.clipboard()
        selected_index = self.view.tableView.selectionModel().selectedIndexes()[0]
        selected_text = str(self.table_model.data(selected_index))
        clipboard.setText(selected_text)

    def paste(self):
        if len(self.view.tableView.selectionModel().selectedIndexes()) == 0:
            return

        clipboard = QApplication.clipboard()
        index = self.view.tableView.selectionModel().selectedIndexes()[0]
        command = EditCommand(self.table_model, index)
        command.newValue(str(clipboard.text()))

        self.undo_stack.beginMacro("Paste")
        self.undo_stack.push(command)
        self.undo_stack.endMacro()
        self.set_undo_redo_text()
        self.view.tableView.reset()

    def insert_rows(self):
        if len(self.table_model.get_header()) == 0:
            self.statusBar().showMessage("Adding rows to an empty table without a header is not possible.")
            return
        start, amount = self.get_selection()

        self.undo_stack.beginMacro("Add Row")
        self.undo_stack.push(InsertRowsCommand(self.table_model, start, 1))
        self.undo_stack.endMacro()
        self.set_undo_redo_text()

    def duplicate_rows(self):
        if len(self.view.tableView.selectionModel().selectedIndexes()) == 0:
            self.statusBar().showMessage("You must select the first column of the row you want to duplicate")
            return

        start, amount = self.get_selection()
        self.undo_stack.beginMacro("Duplicate Row")
        self.undo_stack.push(DuplicateRowCommand(self.table_model, start))
        self.undo_stack.endMacro()
        self.set_undo_redo_text()
        self.view.tableView.reset()

    def remove_rows(self):
        if len(self.table_model.get_list()) == 0:
            self.statusBar().showMessage("WARNING: Removing rows from an empty table is not possible")
            return
        start, amount = self.get_selection()
        if start != len(self.table_model.get_list()):
            self.undo_stack.beginMacro("Remove Row(s)")
            self.undo_stack.push(RemoveRowsCommand(self.table_model, start, amount))
            self.undo_stack.endMacro()
            self.set_undo_redo_text()
        else:
            self.statusBar().showMessage(
                "WARNING: You need to choose the rows you want to remove by selecting the cells in the " "first column"
            )

    def new(self):
        if self.filename is not None:
            save = self.show_new_file_dialog()
            if save:
                self.save()
                self.filename = None
                self.table_model.set_list([], [])
            else:
                self.filename = None
                self.table_model.set_list([], [])
        else:
            self.filename = None
            self.table_model.set_list([], [])

    def show_append_override_dialog(self):
        msgBox = QtGui.QMessageBox()
        msgBox.setWindowTitle("Append or Override")
        msgBox.setText("Append or override the current entries?")
        msgBox.addButton("Append", QtGui.QMessageBox.YesRole)
        msgBox.addButton("Override", QtGui.QMessageBox.NoRole)
        return msgBox.exec_()

    def show_new_file_dialog(self):
        msgBox = QtGui.QMessageBox()
        msgBox.setWindowTitle("New file")
        msgBox.setText("Do you want to save first?")
        msgBox.addButton("Yes", QtGui.QMessageBox.YesRole)
        msgBox.addButton("No", QtGui.QMessageBox.NoRole)
        return msgBox.exec_()

    def open(self):
        try:
            fileName = QFileDialog.getOpenFileName(
                self, self.tr("Open CSV File"), os.getcwd(), self.tr("CSV Files (*.csv)")
            )[0]
            if fileName is not None and fileName is not "":
                append_or_override = False
                if self.filename is not None:
                    append_or_override = self.show_append_override_dialog()
                self.filename = fileName
                self.table_model.open(self.filename, clear=append_or_override)
                self.undo_stack.clear()
                self.set_undo_redo_text()
                self.update_table_model(self.table_model.get_list(), self.table_model.get_header())
        except FileNotFoundError:
            QtGui.QMessageBox.critical(
                self,
                "Read Error",
                'Error reading CSV File:\nFile "' + self.filename + '" not found!',
                QtGui.QMessageBox.Close,
            )
        except csv.Error:
            QtGui.QMessageBox.critical(
                self, "Read Error", "Error reading CSV File:\n File is not an valid CSV File!", QtGui.QMessageBox.Close
            )
        except:
            QtGui.QMessageBox.critical(
                self, "Read Error", "Error reading CSV File:\nAn unknown Error occured!", QtGui.QMessageBox.Close
            )
            raise

    def save(self):
        if self.filename is not None and self.filename is not "":
            self.table_model.save(self.filename)
        else:
            fileName = QFileDialog.getSaveFileName(
                self, caption="Save CSV File", dir=os.getcwd(), filter="CSV Files (*.csv)"
            )[0]
            if fileName is not None and fileName is not "":
                self.table_model.save(fileName)

    def save_as(self):
        fileName = QFileDialog.getSaveFileName(
            self, caption="Save CSV File", dir=os.getcwd(), filter="CSV Files (*.csv)"
        )[0]
        if fileName is not None and fileName is not "":
            self.table_model.save(fileName)