Beispiel #1
0
    def __init__(self):
        super(Model, self).__init__()
        self.current_file = None
        self.session = None

        # Setting up SQL relevant stuff
        self.wahl_nummer = 1

        self.undostack = QUndoStack()
    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
Beispiel #3
0
    def __init__(self, parent=None):

        super().__init__(parent)

        self.undoStack = QUndoStack()

        self.view = Ui_MainWindow()
        self.view.setupUi(self)
        self.view.tableView.setSortingEnabled(True)
        self.view.tableView.setItemDelegate(ItemDelegate(self.undoStack, self.set_undo_redo_text))

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

        self.connect_elements()

        try:
            self.db = DBAccess(DBConfig.database, DBConfig.username, DBConfig.password, DBConfig.wahltermin)
        except Exception as e:
            print(e)
            Message.error("Database Error", "Error while trying to establish a database connection.")
    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.undoStack = QUndoStack()

        self.db = DBConnection("172.16.6.137", "root", "password", "wahl")

        self.gui = Ui_MainWindow()
        self.gui.setupUi(self)
        self.gui.actionOpen.triggered.connect(self.open_file)
        self.gui.actionSave.triggered.connect(self.save_file)
        self.gui.actionSave_as.triggered.connect(self.save_file_as)
        self.gui.actionNew.triggered.connect(self.new_file)
        self.gui.actionCopy.triggered.connect(self.copy_cs)
        self.gui.actionAdd_Row.triggered.connect(self.add_rows)
        self.gui.actionSave_DB.triggered.connect(self.open_save_db)
        self.gui.actionOpen_DB.triggered.connect(self.open_load_db)
        self.gui.actionPaste.triggered.connect(self.paste)
        self.gui.actionCut.triggered.connect(self.cut)
        self.gui.actionDelete_Row.triggered.connect(self.remove_rows)
        self.gui.actionDuplicate_Row.triggered.connect(self.duplicate)
        self.gui.actionUndo.triggered.connect(self.undo)
        self.gui.actionRedo.triggered.connect(self.redo)
        self.gui.actionCreate_Prediction.triggered.connect(self.open_create_pred)
        self.gui.actionShow_Prediction.triggered.connect(self.open_choose_pred)

        self.gui.tableView.setSortingEnabled(True)
        self.gui.tableView.setItemDelegate(ItemDelegate(self.undoStack, self.set_unrdo_text))

        self.tbm = DictTableModel(data=[], header=[], parent=self)

        self.sdb_dialog = SaveToDBDialog(self)
        self.ldb_dialog = LoadFromDBDialog(self)
        self.create_pred_dialog = CreatePredDialog(self)
        self.choose_pred_dialog = ChoosePredDialog(self)
        self.show_pred_dialog = ShowPredDialog(self)

        self.file = "."
class WahlAnalyse(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.undoStack = QUndoStack()

        self.db = DBConnection("172.16.6.137", "root", "password", "wahl")

        self.gui = Ui_MainWindow()
        self.gui.setupUi(self)
        self.gui.actionOpen.triggered.connect(self.open_file)
        self.gui.actionSave.triggered.connect(self.save_file)
        self.gui.actionSave_as.triggered.connect(self.save_file_as)
        self.gui.actionNew.triggered.connect(self.new_file)
        self.gui.actionCopy.triggered.connect(self.copy_cs)
        self.gui.actionAdd_Row.triggered.connect(self.add_rows)
        self.gui.actionSave_DB.triggered.connect(self.open_save_db)
        self.gui.actionOpen_DB.triggered.connect(self.open_load_db)
        self.gui.actionPaste.triggered.connect(self.paste)
        self.gui.actionCut.triggered.connect(self.cut)
        self.gui.actionDelete_Row.triggered.connect(self.remove_rows)
        self.gui.actionDuplicate_Row.triggered.connect(self.duplicate)
        self.gui.actionUndo.triggered.connect(self.undo)
        self.gui.actionRedo.triggered.connect(self.redo)
        self.gui.actionCreate_Prediction.triggered.connect(self.open_create_pred)
        self.gui.actionShow_Prediction.triggered.connect(self.open_choose_pred)

        self.gui.tableView.setSortingEnabled(True)
        self.gui.tableView.setItemDelegate(ItemDelegate(self.undoStack, self.set_unrdo_text))

        self.tbm = DictTableModel(data=[], header=[], parent=self)

        self.sdb_dialog = SaveToDBDialog(self)
        self.ldb_dialog = LoadFromDBDialog(self)
        self.create_pred_dialog = CreatePredDialog(self)
        self.choose_pred_dialog = ChoosePredDialog(self)
        self.show_pred_dialog = ShowPredDialog(self)

        self.file = "."

    def open_file(self):
        self.file = QFileDialog.getOpenFileName(self, "Choose File", filter="CSV-File (*.csv)")[0]
        if self.file != '':
            data, header = CSVUtil.read(self.file)
            self.tbm.set_data(data, header)
            self.gui.tableView.reset()
            self.gui.tableView.setModel(self.tbm)

    def save_file(self):
        if self.file != '' and self.file is not None:
            CSVUtil.write(self.file, self.tbm.get_data())

    def save_file_as(self):
        self.file = QFileDialog.getSaveFileName(self, "CSV-Datei speichern", dir=self.file, filter="CSV-Datei (*.csv)")[
            0]
        if self.file != '':
            self.save_file()

    def new_file(self):
        self.file = "."
        self.tbm.set_data([], [])
        self.gui.tableView.reset()
        self.gui.tableView.setModel(self.tbm)
        self.undoStack.clear()
        self.set_unrdo_text()

    def copy_cs(self):
        if len(self.gui.tableView.selectionModel().selectedIndexes()) == 0:
            return

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

    def save_data_db(self, date):
        self.db.write_data(self.tbm.get_data(), date)

    def load_data_db(self, date):
        data, header = self.db.read_data(date)
        self.tbm.set_data(data, header)
        self.gui.tableView.reset()
        self.gui.tableView.setModel(self.tbm)
        self.undoStack.clear()
        self.set_unrdo_text()

    def create_prediction(self, termin, time):
        self.db.create_prediction(termin, time)

    def open_save_db(self):
        self.setDisabled(True)
        self.sdb_dialog.setEnabled(True)
        self.sdb_dialog.show()

    def open_load_db(self):
        self.ldb_dialog.update_dates(self.db.get_termine())
        self.setDisabled(True)
        self.ldb_dialog.setEnabled(True)
        self.ldb_dialog.show()

    def open_create_pred(self):
        self.create_pred_dialog.update_dates(self.db.get_termine())
        self.setDisabled(True)
        self.create_pred_dialog.setEnabled(True)
        self.create_pred_dialog.show()

    def open_choose_pred(self):
        self.choose_pred_dialog.update_predictions(self.db.get_predictions())
        self.setDisabled(True)
        self.choose_pred_dialog.setEnabled(True)
        self.choose_pred_dialog.show()

    def show_prediction(self, date, time):
        data, header = self.db.get_prediction_data(date, time)
        self.show_pred_dialog.update_prediction(data, header, date, time)
        self.setDisabled(True)
        self.show_pred_dialog.setEnabled(True)
        self.show_pred_dialog.show()

    def set_unrdo_text(self):
        undo = "Undo"
        redo = "Redo"
        undo_txt = self.undoStack.undoText()
        redo_txt = self.undoStack.redoText()
        if undo_txt:
            undo += " \"" + undo_txt + "\""
        if redo_txt:
            redo += " \"" + redo_txt + "\""
        self.gui.actionUndo.setText(undo)
        self.gui.actionRedo.setText(redo)

    def get_sel_indexes(self):
        sel_indexes = self.gui.tableView.selectedIndexes()
        if sel_indexes:
            return [index for index in sel_indexes if not index.column()]

    def get_sel(self):
        sel_indexes = self.get_sel_indexes()
        if not sel_indexes:
            return self.tbm.rowCount(self), 1
        first_sel_index = sel_indexes[0]
        sel_indexes = self.get_sel_indexes()

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

        return startingrow, len(sel_indexes)

    def remove_rows(self):
        if len(self.tbm.get_data()) == 0:
            return
        start, amount = self.get_sel()
        if start != len(self.tbm.get_data()):
            self.undoStack.beginMacro("Remove Rows")
            self.undoStack.push(RemoveRowsCommand(self.tbm, start, amount))
            self.undoStack.endMacro()
            self.set_unrdo_text()

    def add_rows(self):
        if len(self.tbm.get_header()) == 0:
            return
        start, amount = self.get_sel()

        self.undoStack.beginMacro("Add Row")
        self.undoStack.push(InsertRowsCommand(self.tbm, start, 1))
        self.undoStack.endMacro()
        self.set_unrdo_text()

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

        clipboard = QApplication.clipboard()
        index = self.gui.tableView.selectionModel().selectedIndexes()[0]
        command = EditCommand(self.tbm, index)
        command.newVal(str(clipboard.text()))

        self.undoStack.beginMacro("Paste")
        self.undoStack.push(command)
        self.undoStack.endMacro()
        self.set_unrdo_text()
        self.gui.tableView.reset()

    def cut(self):
        self.copy()
        index = self.gui.tableView.selectionModel().selectedIndexes()[0]
        command = EditCommand(self.tbm, index)
        command.newVal("")
        self.undoStack.beginMacro("Cut")
        self.undoStack.push(command)
        self.undoStack.endMacro()
        self.set_unrdo_text()
        self.gui.tableView.reset()

    def duplicate(self):
        if len(self.gui.tableView.selectionModel().selectedIndexes()) == 0:
            return

        start, amount = self.get_sel()
        self.undoStack.beginMacro("Duplicate Row")
        self.undoStack.push(DuplicateRowCommand(self.tbm, start))
        self.undoStack.endMacro()
        self.set_unrdo_text()
        self.gui.tableView.reset()

    def undo(self):
        self.undoStack.undo()
        self.set_unrdo_text()
        self.gui.tableView.reset()

    def redo(self):
        self.undoStack.redo()
        self.set_unrdo_text()
        self.gui.tableView.reset()
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)
Beispiel #9
0
    pixmap, icon = resources_cache[filename]
    b = QToolButton()
    b.setIcon(icon)
    b.setIconSize(pixmap.rect().size())
    b.setMaximumWidth(pixmap.rect().width())  # 6
    if name:
        b.setObjectName(name)

    return b


from PySide.QtGui import QStyledItemDelegate
from PySide.QtGui import QUndoCommand, QUndoStack, QLineEdit

undo_stack = QUndoStack()


class UndoProxyEdit(QUndoCommand):
    def __init__(self, old_value, new_value, proxy_model, index):
        super(UndoProxyEdit, self).__init__()

        self._old_value, self._new_value, self._proxy_model, self._index = old_value, new_value, proxy_model, index
        self.setText("Undo")

    def undo(self):
        mainlog.info("Undo")
        self._proxy_model.setData(self._index, self._old_value)

    def redo(self):
        mainlog.info("Redo")
Beispiel #10
0
class Controller(QtGui.QMainWindow):
    def __init__(self, parent=None):

        super().__init__(parent)

        self.undoStack = QUndoStack()

        self.view = Ui_MainWindow()
        self.view.setupUi(self)
        self.view.tableView.setSortingEnabled(True)
        self.view.tableView.setItemDelegate(ItemDelegate(self.undoStack, self.set_undo_redo_text))

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

        self.connect_elements()

        try:
            self.db = DBAccess(DBConfig.database, DBConfig.username, DBConfig.password, DBConfig.wahltermin)
        except Exception as e:
            print(e)
            Message.error("Database Error", "Error while trying to establish a database connection.")

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

    def connect_elements(self):
        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.view.actionAdd_Row.triggered.connect(self.add_rows)
        self.view.actionRemove_Row_s.triggered.connect(self.remove_rows)
        self.view.actionWrite.triggered.connect(self.write)
        self.view.actionLoad.triggered.connect(self.load)
        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.actionDuplicate_Row.triggered.connect(self.duplicate)
        self.view.actionCut.triggered.connect(self.cut)
        self.view.actionShow_Results.triggered.connect(self.show_results)

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

    def show_results(self):
        # try:
        datalist, header = self.db.create_results()

        ResultsController(datalist, header, "Hochrechnungsergebnis")
        """
        except Exception as e:
            print(e)
            Message.error("Database Error", "Error while accessing the database. Perhaps the schema in the database "
                                            "does not match the ddl-script.")
        """

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

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

    def cut(self):
        self.copy()
        index = self.view.tableView.selectionModel().selectedIndexes()[0]
        command = EditCommand(self.table_model, index)
        command.newValue("")
        self.undoStack.beginMacro("Cut")
        self.undoStack.push(command)
        self.undoStack.endMacro()
        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.undoStack.beginMacro("Paste")
        self.undoStack.push(command)
        self.undoStack.endMacro()
        self.set_undo_redo_text()
        self.view.tableView.reset()

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

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

    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 write(self):
        if self.filename is None or len(self.table_model.get_list()) == 0:
            Message.error("Writing to database not possible", "The table needs to contain of the same column headers "
                                                              "as the original 'wahl.csv'.")
            return
        try:
            current_list = self.table_model.get_list()
            self.db.write_from_csv_list(current_list)
        except Exception as e:
            print(e)
            Message.error("Database Error", "Error while accessing the database. Perhaps the schema in the database "
                                            "does not match the ddl-script or the required table headers (see "
                                            "original 'wahl.csv') are not existing.")

    def load(self):
        try:
            datalist, header = self.db.load_into_csv_list()
            self.update_table_model(datalist, header)
        except Exception as e:
            print(e)
            Message.error("Database Error", "Error while accessing the database. Perhaps the schema in the database "
                                            "does not match the ddl-script.")

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

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

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

    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 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 new(self):
        self.filename = None
        self.table_model.set_list([], [])

    def open(self):
        filename = QFileDialog.getOpenFileName(self, caption="Open CSV-File", filter="CSV-File (*.csv)")[0]
        if len(filename) > 0:
            self.filename = filename
            datalist, header = CSV.read(self.filename)
            self.update_table_model(datalist, header)

    def save(self):
        if self.filename is not None:
            CSV.write(self.filename, self.table_model.get_list())
        else:
            self.save_as()

    def save_as(self):
        filename = QFileDialog.getSaveFileName(self, caption="Save CSV-File", dir=self.filename,
                                               filter="CSV-File (*.csv)")[0]
        if len(filename) > 0:
            self.filename = filename
            self.save()
Beispiel #11
0
class Model(QObject):
    """
    MVC - Pattern: Represents the entities class

    """
    tableModelChangedSignal = Signal(QAbstractTableModel, QModelIndex, str, str)

    def __init__(self):
        super(Model, self).__init__()
        self.current_file = None
        self.session = None

        # Setting up SQL relevant stuff
        self.wahl_nummer = 1

        self.undostack = QUndoStack()

    def find_indeces(self, header):
        """
        find the indeces for some items in the given header and returns them as a dictionary

        :param header: Array Header of the table model
        :return:
        """
        indeces = {'T': None, 'WV': None, 'WK': None, 'BZ': None, 'SPR': None,
                   'WBER': None, 'ABG.': None, 'UNG.': None, 'SPOE': None,
                   'FPOE': None, 'OEVP': None, 'GRUE': None, 'NEOS': None,
                   'WWW': None, 'ANDAS': None, 'GFW': None, 'SLP': None,
                   'WIFF': None, 'M': None, 'FREIE': None}
        for index, item in enumerate(header):
            indeces[item] = index
        return indeces

    def create_session(self, username, password, hostname, database, port=3306):
        """
        Creates a session to the given creadentials

        :param username: str
        :param password: str
        :param hostname: str
        :param database: str
        :param port: int Default is 3306
        """
        engine = create_engine("mysql+mysqlconnector://%s:%s@%s:%s/%s" %
                               (username, password, hostname, port, database))
        if self.session is not None:
            self.session.close()
        Session = sessionmaker(bind=engine, autoflush=False)
        self.session = Session()

    def insert_into_db(self, table_model):
        tmp = []
        if table_model is not None:
            arr = table_model.get_data_as_2d_array()
            # Remove spaces
            for x in range(0, len(arr)):
                for y in range(0, len(arr[x])):
                    arr[x][y] = arr[x][y].replace(" ", "")
            indeces = self.find_indeces(arr[0])
            partei_index = indeces['UNG.']+1
            parteien = self.session.query(Partei).all()

            progress = 1
            tmp = []
            for data in arr[1:]:
                print("%f" % (progress/(len(arr)-1)*100) + " %")
                # Sprengel
                sprengel = Sprengel()
                sprengel.nummer = data[indeces['SPR']]
                sprengel.wahlberechtigte = data[indeces['WBER']]
                sprengel.ungueltige = data[indeces['UNG.']]
                sprengel.abgegebene = data[indeces['ABG.']]
                sprengel.bznr = data[indeces['BZ']]
                sprengel.whnr = self.wahl_nummer
                for actual_partei_index in range(partei_index, len(arr[0])-1):
                    if data[indeces['T']] == '4' and data[indeces['WV']] == '1':
                        # Stimmen
                        stimmen = Stimmen()
                        stimmen.anzahl = data[actual_partei_index]
                        for partei in parteien:
                            if partei.bezeichnung == arr[0][actual_partei_index]:
                                stimmen.parteinr = partei.nummer
                        stimmen.spnr = sprengel.nummer
                        stimmen.bznr = data[indeces['BZ']]
                        stimmen.whnr = self.wahl_nummer
                        self.session.add(stimmen)
                    else:
                        raise Exception("Wrong CSV Format, expected Column T to be 4 and Column WV to be 1")
                self.session.add(sprengel)
                progress += 1
            try:
                print("Sending to database...")
                self.session.commit()
            except Exception as e:
                print("Could'nt insert into database, there are duplicate entries.")

    def undo(self):
        self.undostack.undo()

    def redo(self):
        self.undostack.redo()

    def copy(self, table_model, index):
        """
        Copies the data from the given TableModel at the current index to the clipboard

        :param table_model: QAbstractTableModel
        :param index: QModelIndex
        """
        pyperclip.copy(table_model.data(index, Qt.DisplayRole))

    def paste(self, table_model, index):
        """
        Pastes the data from the clipboard to the TableModel at the given index

        :param table_model: QAbstractTableModel
        :param index: QModelIndex
        """
        old_value = table_model.data(index, Qt.DisplayRole)
        new_value = pyperclip.paste()
        self.undostack.push(EditCommand(table_model, index, old_value, new_value))
        del old_value, new_value

    def cut(self, table_model, index):
        """
        Cuts the data from the given TableModel at the current index to the clipboard

        :param table_model: QAbstractTableModel
        :param index: QModelIndex
        """
        old_value = table_model.data(index, Qt.DisplayRole)
        new_value = ""
        self.copy(table_model, index)
        self.undostack.push(EditCommand(table_model, index, old_value, new_value))
        del old_value, new_value

    def show_from_database(self, table_model):
        """
        Loads the data from the database into the TableModel

        """
        arr = [4, 1]
        # TODO

    def duplicate_row(self, table_model, row):
        """
        Duplicates row at the current row

        :param row: Row number
        """
        # TODO undostack
        self.undostack.push(DuplicateRowCommand(table_model, row, table_model.get_rows(row)))
        # table_model.duplicateRow(row)

    def delete_rows(self, table_model, row, count):
        """
        Deletes the current focused row

        :param count:
        :param row:
        :param table_model:
        """
        self.undostack.push(DeleteRowCommand(table_model, row, table_model.get_rows(row, count=count)))

    def insert_row(self, table_model, row, count):
        """
        Inserts a blank row at the current row index

        :param table_model: QAbstractTableModel
        :param row: int
        :param count: int
        """
        self.undostack.push(InsertRowCommand(table_model, row, count))

    @Slot(QAbstractTableModel, QModelIndex, str, str)
    def table_model_changed(self, table_model, index, old, new):
        """
        Will be executed when data in the table model has been changed

        :param table_model: QAbstractTableModel TableModel where data has been changed
        :param index: QModelIndex
        :param old: QVariant Old TableModel data
        :param new: QVariant New TableModel data
        """
        self.undostack.push(EditCommand(table_model, index, old, new))
        # print("TableModel changed at [%s, %s]" % (index.row(), index.column()))
        # print("Old Value: %s | New Value: %s" % (old, new))

    def exit_handler(self):
        if self.session is not None:
            self.session.close()