Example #1
0
class PredictionsTab(QWidget):
    def __init__(self, patient):
        QWidget.__init__(self)
        self.patient = patient
        self.prediction_views = set()

        self.toolbar = QToolBar()
        self.toolbar.setMovable(False)

        add_prediction = QAction(QIcon("resources/icon/plus.png"),
                                 "Dodaj predykcję", self)
        add_prediction.triggered.connect(self.addPredictionForm)
        add_prediction.setStatusTip("Dodaj pomiary")
        self.toolbar.addAction(add_prediction)

        delete_prediction = QAction(QIcon("resources/icon/trash-bin.png"),
                                    "Usuń predykcję", self)
        delete_prediction.triggered.connect(self.deletePrediction)
        delete_prediction.setStatusTip("Usuń pomiar")
        self.toolbar.addAction(delete_prediction)

        draw_predictions = QAction(QIcon("resources/icon/graph.png"),
                                   "Rysuj predykcje", self)
        draw_predictions.triggered.connect(self.showPredictions)
        draw_predictions.setStatusTip("Rysuj predykcje")
        self.toolbar.addAction(draw_predictions)

        self.table = QTableWidget()
        self.table.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setColumnCount(3)

        self.table.setHorizontalHeaderLabels(["Id", "Data", "Metoda"])
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.table.verticalHeader().setVisible(False)
        self.fillTable()

        main_layout = QHBoxLayout(self)
        main_layout.setMenuBar(self.toolbar)
        main_layout.addWidget(self.table)

    def fillTable(self):
        for p in self.patient.predictions:
            self.addPrediction(p)

    def addPrediction(self, prediction: Prediction):
        row_count = self.table.rowCount()
        print(prediction)
        self.table.insertRow(row_count)
        self.table.setItem(
            row_count,
            0,
            self.tableWidgetItem(str(prediction.db_id)),
        )
        self.table.setItem(
            row_count,
            1,
            self.tableWidgetItem(
                prediction.datetime_created.strftime(DATETIME_FORMAT)),
        )
        self.table.setItem(row_count, 2,
                           self.tableWidgetItem(prediction.method))

    def tableWidgetItem(self, value):
        item = QTableWidgetItem(value)
        item.setFlags(item.flags() & ~Qt.ItemIsEditable)
        return item

    def addPredictionForm(self):
        self.predicion_form = PredictionForm(self, self.patient)
        self.predicion_form.exec()

    def deletePrediction(self):
        current_row = self.table.currentRow()
        if current_row == -1:
            QMessageBox.warning(
                self,
                "Usuwanie predykcji",
                "Brak danych w tabeli",
            )
            return
        prediction_datetime = datetime.fromisoformat(
            self.table.item(current_row, 1).text())
        delete_prediction_for_patient(self.patient, prediction_datetime)
        self.table.removeRow(current_row)

    def showPredictions(self):
        logging.debug(
            "All predictions %s",
            [(p.method, p.datetime_created) for p in self.patient.predictions],
        )
        selected_rows = set(
            [ind.row() for ind in self.table.selectedIndexes()])
        logging.debug("%s", selected_rows)
        chosen_predictions_ids: List[int] = [
            int(self.table.item(ind, 0).text()) for ind in selected_rows
        ]
        logging.debug("Selected db_ids from table: %s", chosen_predictions_ids)
        chosen_predictions: Set[Prediction] = {
            prediction
            for prediction in self.patient.predictions
            if prediction.db_id in chosen_predictions_ids
        }
        logging.debug(
            "Selected predictions to graph: %s %d %s",
            chosen_predictions,
            len(chosen_predictions),
            type(chosen_predictions),
        )
        predictions_view = PredictionsView(
            f"{self.patient.name} {self.patient.surname}",
            self.patient.measurements,
            chosen_predictions,
        )
        predictions_view.show()
        self.prediction_views.add(predictions_view)
        logging.debug("Prediction views %s", self.prediction_views)
class PeopleTab(QWidget):
    def __init__(self, parent):
        QWidget.__init__(self)
        self.Parent = parent

        self.PeoplTitle = 'PEOPLE'

        self.UI()

    @property
    def Title(self):
        return self.PeoplTitle

    def UI(self):
        self.widgets()
        self.layouts()
        self.funcDisplayPeople()

    def widgets(self):
        # People widgets ###########################################################
        # Top layout (search people) widgets
        self.searchPeopleText = QLabel("Search: ")
        self.searchPeopleEntry = QLineEdit()
        self.searchPeopleEntry.setPlaceholderText("Search people..")
        self.searchPeopleBtn = QPushButton("Search")
        self.searchPeopleBtn.clicked.connect(self.searchPeople)
        self.refreshPeopleBtn = QPushButton("Refresh")
        self.refreshPeopleBtn.clicked.connect(self.funcDisplayPeople)

        # Middle layout (list people) widgets with radio buttons
        self.allPeopleRadioBtn = QRadioButton("All people")
        self.employeesPeopleRadioBtn = QRadioButton("Employees")
        self.contractorsPeopleRadioBtn = QRadioButton("Contractors")
        self.subcontractorsPeopleRadioBtn = QRadioButton("Subcontractors")
        self.listPeopleBtn = QPushButton("List")
        self.listPeopleBtn.clicked.connect(self.funcListPeople)

        # Bottom layout widget, a table showing people
        self.peopleTable = QTableWidget()
        self.peopleTable.verticalHeader().hide()
        self.peopleTable.setSortingEnabled(True)
        self.peopleTable.setShowGrid(False)
        self.peopleTable.verticalHeader().setDefaultSectionSize(90)
        self.peopleTable.setColumnCount(10)

        # self.peopleTable.setColumnHidden(0, True)
        self.peopleTable.setHorizontalHeaderItem(0, QTableWidgetItem(""))
        self.peopleTable.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)
        self.peopleTable.setHorizontalHeaderItem(1, QTableWidgetItem("Photo"))
        self.peopleTable.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.ResizeToContents)
        self.peopleTable.setHorizontalHeaderItem(2, QTableWidgetItem("ID"))
        self.peopleTable.setHorizontalHeaderItem(
            3, QTableWidgetItem("First name"))
        self.peopleTable.horizontalHeader().setSectionResizeMode(
            3, QHeaderView.Stretch)
        self.peopleTable.setHorizontalHeaderItem(4,
                                                 QTableWidgetItem("Last name"))
        self.peopleTable.horizontalHeader().setSectionResizeMode(
            4, QHeaderView.Stretch)
        self.peopleTable.setHorizontalHeaderItem(5, QTableWidgetItem("Title"))
        self.peopleTable.setHorizontalHeaderItem(6, QTableWidgetItem("Phone"))
        self.peopleTable.horizontalHeader().setSectionResizeMode(
            6, QHeaderView.Stretch)
        self.peopleTable.setHorizontalHeaderItem(7, QTableWidgetItem("Email"))
        self.peopleTable.horizontalHeader().setSectionResizeMode(
            7, QHeaderView.Stretch)
        self.peopleTable.setHorizontalHeaderItem(8,
                                                 QTableWidgetItem("Location"))
        self.peopleTable.setHorizontalHeaderItem(
            9, QTableWidgetItem("Employment type"))
        self.peopleTable.horizontalHeader().setSectionResizeMode(
            9, QHeaderView.ResizeToContents)

        # Double clicking a row opens a window with person details
        self.peopleTable.doubleClicked.connect(self.selectedPerson)

        # Buttons for actions on selected people
        self.addPerson = QPushButton("Add")
        self.addPerson.clicked.connect(self.funcAddPerson)
        self.viewPerson = QPushButton("View/Edit")
        self.viewPerson.clicked.connect(self.selectedPerson)
        self.deletePerson = QPushButton("Delete")
        self.deletePerson.clicked.connect(self.funcDeletePerson)

        self.exportPeopleCSVBtn = QPushButton("Export CSV")
        self.exportPeopleCSVBtn.setEnabled(False)
        self.exportPeopleCSVBtn.clicked.connect(self.funcPeopleToCSV)

        self.exportPeopleXLSXBtn = QPushButton("Export XLSX")
        self.exportPeopleXLSXBtn.setEnabled(False)
        self.exportPeopleXLSXBtn.clicked.connect(self.funcPeopleToXLSX)

        self.exportPeoplePDFBtn = QPushButton("Export PDF")
        self.exportPeoplePDFBtn.setEnabled(False)
        self.exportPeoplePDFBtn.clicked.connect(self.funcPeopleToPdf)

    def layouts(self):
        # People layouts ###########################################################
        self.peopleMainLayout = QVBoxLayout()
        self.peopleMainTopLayout = QHBoxLayout()
        self.peopleTopLeftLayout = QHBoxLayout()
        self.peopleTopRightLayout = QHBoxLayout()

        # self.peopleMainMiddleLayout = QHBoxLayout()
        self.peopleMainBottomLayout = QHBoxLayout()
        self.peopleBottomRightLayout = QVBoxLayout()
        self.peopleBottomLeftLayout = QHBoxLayout()

        # Groupboxes allows customization using CSS-like syntax
        # self.peopleTopGroupBox = QGroupBox()
        # self.peopleTopGroupBoxRightFiller = QGroupBox()
        # self.peopleMiddleGroupBox = QGroupBox()
        # self.peopleMiddleGroupBoxRightFiller = QGroupBox()

        self.peopleTopLeftGroupBox = QGroupBox()
        self.peopleTopRightGroupBox = QGroupBox()
        self.peopleTopGroupBox = QGroupBox()

        self.peopleBottomGroupBox = QGroupBox()
        self.peopleBottomLeftGroupBox = QGroupBox()

        self.peopleBottomRightGroupBox = QGroupBox()
        self.peopleBottomRightGroupBox.setStyleSheet(
            'QGroupBox {margin-top: 0px;}')
        self.peopleBottomRightGroupBoxFiller = QGroupBox()
        self.peopleBottomRightGroupBoxFiller.setStyleSheet(
            styles.groupBoxFillerStyle())

        # Top layout (search box) widgets
        self.peopleTopLeftLayout.addWidget(self.searchPeopleText, 10)
        self.peopleTopLeftLayout.addWidget(self.searchPeopleEntry, 30)
        self.peopleTopLeftLayout.addWidget(self.searchPeopleBtn, 10)
        self.peopleTopLeftLayout.addItem(
            QSpacerItem(70, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))
        self.peopleTopLeftLayout.addWidget(self.refreshPeopleBtn, 10)
        self.peopleTopLeftGroupBox.setLayout(self.peopleTopLeftLayout)

        # Middle layout (list box) widgets
        self.peopleTopRightLayout.addWidget(self.allPeopleRadioBtn)
        self.peopleTopRightLayout.addWidget(self.employeesPeopleRadioBtn)
        self.peopleTopRightLayout.addWidget(self.contractorsPeopleRadioBtn)
        self.peopleTopRightLayout.addWidget(self.subcontractorsPeopleRadioBtn)
        self.peopleTopRightLayout.addWidget(self.listPeopleBtn)
        self.peopleTopRightGroupBox.setLayout(self.peopleTopRightLayout)

        self.peopleMainTopLayout.addWidget(self.peopleTopLeftGroupBox, 60)
        self.peopleMainTopLayout.addWidget(self.peopleTopRightGroupBox, 40)

        # Bottom layout (table with issues) widgets
        # Bottom left layout with table
        self.peopleBottomLeftLayout.addWidget(self.peopleTable)
        self.peopleBottomLeftGroupBox.setLayout(self.peopleBottomLeftLayout)

        # Bottom right layout with buttons
        self.peopleBottomRightLayout.addWidget(self.addPerson, 5)
        self.peopleBottomRightLayout.addWidget(self.viewPerson, 5)
        self.peopleBottomRightLayout.addWidget(self.deletePerson, 5)
        self.peopleBottomRightLayout.addWidget(
            self.peopleBottomRightGroupBoxFiller, 70)
        self.peopleBottomRightLayout.addWidget(self.exportPeopleCSVBtn, 5)
        self.peopleBottomRightLayout.addWidget(self.exportPeopleXLSXBtn, 5)
        self.peopleBottomRightLayout.addWidget(self.exportPeoplePDFBtn, 5)
        self.peopleBottomRightGroupBox.setLayout(self.peopleBottomRightLayout)

        self.peopleMainBottomLayout.addWidget(self.peopleTable, 90)
        self.peopleMainBottomLayout.addWidget(self.peopleBottomRightGroupBox,
                                              10)

        # self.peopleMainLayout.addWidget(self.peopleTopGroupBox, 10)
        # self.peopleMainLayout.addWidget(self.peopleMiddleGroupBox, 10)
        # self.peopleMainLayout.addLayout(self.peopleMainBottomLayout, 80)

        self.peopleMainLayout.addLayout(self.peopleMainTopLayout, 10)
        self.peopleMainLayout.addLayout(self.peopleMainBottomLayout, 90)

        self.setLayout(self.peopleMainLayout)

    @Slot()
    def funcDisplayPeople(self):
        for i in reversed(range(self.peopleTable.rowCount())):
            self.peopleTable.removeRow(i)

        cur = db.cur
        people = cur.execute("SELECT * FROM people")

        for row_data in people:
            row_number = self.peopleTable.rowCount()
            self.peopleTable.insertRow(row_number)
            # Add checkboxes to the table
            widget = QWidget()
            checkBox = QCheckBox()
            checkBox.setCheckState(Qt.Unchecked)
            checkBox.stateChanged.connect(self.funcActivateBtnsWithCheckbox)
            hBoxLayout = QHBoxLayout(widget)
            hBoxLayout.addWidget(checkBox)
            hBoxLayout.setAlignment(Qt.AlignCenter)
            self.peopleTable.setCellWidget(row_number, 0, widget)
            self.peopleTable.setItem(row_number, 0,
                                     QTableWidgetItem(row_number))
            # Add photo photos_thumbnails to the table
            thumbWidget = QWidget()
            pic = QPixmap(str(row_data[10]))
            thumbLabel = QLabel()
            thumbLabel.setPixmap(pic)
            thumbLayout = QHBoxLayout(thumbWidget)
            thumbLayout.addWidget(thumbLabel)
            self.peopleTable.setCellWidget(row_number, 1, thumbWidget)
            self.peopleTable.setItem(row_number, 0,
                                     QTableWidgetItem(row_number))
            # Fill the rest of the data
            for column_number, data in enumerate(row_data, start=2):
                if column_number == 2:
                    self.peopleTable.setItem(
                        row_number, column_number,
                        QTableWidgetItem("PRN#" + str(data)))
                else:
                    self.peopleTable.setItem(row_number, column_number,
                                             QTableWidgetItem(str(data)))

        self.peopleTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.peopleTable.setSelectionBehavior(QTableView.SelectRows)

    @Slot()
    def funcActivateBtnsWithCheckbox(self):
        indices = self.funcPeopleCheckBox()

        if self.sender().isChecked() or indices:
            self.exportPeopleCSVBtn.setEnabled(True)
            self.exportPeopleXLSXBtn.setEnabled(True)
            self.exportPeoplePDFBtn.setEnabled(True)
        else:
            self.exportPeopleCSVBtn.setEnabled(False)
            self.exportPeopleXLSXBtn.setEnabled(False)
            self.exportPeoplePDFBtn.setEnabled(False)

    @Slot()
    def funcAddPerson(self):
        self.newPerson = AddPerson(self)
        self.newPerson.setObjectName("add_person_popup")
        self.newPerson.setStyleSheet(styles.addPopups())

    @Slot()
    def funcPeopleCheckBox(self):
        checked_list = []
        for i in range(self.peopleTable.rowCount()):
            if self.peopleTable.cellWidget(i, 0).findChild(type(
                    QCheckBox())).isChecked():
                item = self.peopleTable.item(i, 2).text()
                checked_list.append(item.lstrip("PRN#"))
        return checked_list

    @Slot()
    def selectedPerson(self):
        self.displayPerson = DisplayPerson(self)
        self.displayPerson.show()

    @Slot()
    def funcDeletePerson(self):
        indices = self.funcPeopleCheckBox()

        mbox = QMessageBox.question(
            self, "Warning", "Are you sure you want to delete this person?",
            QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel)

        if (mbox == QMessageBox.Yes):
            if indices:
                try:
                    for index in range(len(indices)):
                        query = "DELETE FROM people WHERE person_id = ?"

                        db.cur.execute(query, (indices[index], ))
                        db.conn.commit()

                    QMessageBox.information(self, "Info",
                                            "Selected people were deleted")
                    self.funcDisplayPeople()
                except:
                    QMessageBox.information(self, "Info", "No changes made")
            else:
                row = self.peopleTable.currentRow()
                personId = self.peopleTable.item(row, 0).text()
                personId = personId.lstrip("PRN#")
                try:
                    query = "DELETE FROM people WHERE person_id = ?"

                    db.cur.execute(query, (personId, ))
                    db.conn.commit()

                    QMessageBox.information(self, "Info", "Person was deleted")
                    self.funcDisplayPeople()
                except:
                    QMessageBox.information(self, "Info", "No changes made")

        self.displayPerson.close()

    @Slot()
    def funcListPeople(self):
        if self.allPeopleRadioBtn.isChecked():
            self.funcDisplayPeople()
        elif self.employeesPeopleRadioBtn.isChecked():
            try:
                query = "SELECT * FROM people WHERE person_empl_type = 'Employee'"
                people = db.cur.execute(query).fetchall()

                for i in reversed(range(self.peopleTable.rowCount())):
                    self.peopleTable.removeRow(i)

                for row_data in people:
                    row_number = self.peopleTable.rowCount()
                    self.peopleTable.insertRow(row_number)
                    # Add checkboxes to the table
                    widget = QWidget()
                    checkBox = QCheckBox()
                    checkBox.setCheckState(Qt.Unchecked)
                    hBoxLayout = QHBoxLayout(widget)
                    hBoxLayout.addWidget(checkBox)
                    hBoxLayout.setAlignment(Qt.AlignCenter)
                    self.peopleTable.setCellWidget(row_number, 0, widget)
                    self.peopleTable.setItem(row_number, 0,
                                             QTableWidgetItem(row_number))
                    # Add photo photos_thumbnails to the table
                    thumbWidget = QWidget()
                    pic = QPixmap(
                        "assets/media/people-media/photos_thumbnails/01Aug2020_18h01mtrtgzteuzuspxrp_thumbnail.png"
                    )
                    thumbLabel = QLabel()
                    thumbLabel.setPixmap(pic)
                    thumbLayout = QHBoxLayout(thumbWidget)
                    thumbLayout.addWidget(thumbLabel)
                    self.peopleTable.setCellWidget(row_number, 1, thumbWidget)
                    self.peopleTable.setItem(row_number, 0,
                                             QTableWidgetItem(row_number))
                    # Fill the rest of the data
                    for column_number, data in enumerate(row_data, start=2):
                        if column_number == 2:
                            self.peopleTable.setItem(
                                row_number, column_number,
                                QTableWidgetItem("PRN#" + str(data)))
                        else:
                            self.peopleTable.setItem(
                                row_number, column_number,
                                QTableWidgetItem(str(data)))
            except:
                QMessageBox.information(self, "Info", "Cannot access database")
        elif self.contractorsPeopleRadioBtn.isChecked():
            try:
                query = "SELECT * FROM people WHERE person_empl_type = 'Contractor'"
                people = db.cur.execute(query).fetchall()

                for i in reversed(range(self.peopleTable.rowCount())):
                    self.peopleTable.removeRow(i)

                for row_data in people:
                    row_number = self.peopleTable.rowCount()
                    self.peopleTable.insertRow(row_number)
                    # Add checkboxes to the table
                    widget = QWidget()
                    checkBox = QCheckBox()
                    checkBox.setCheckState(Qt.Unchecked)
                    hBoxLayout = QHBoxLayout(widget)
                    hBoxLayout.addWidget(checkBox)
                    hBoxLayout.setAlignment(Qt.AlignCenter)
                    self.peopleTable.setCellWidget(row_number, 0, widget)
                    self.peopleTable.setItem(row_number, 0,
                                             QTableWidgetItem(row_number))
                    # Add photo photos_thumbnails to the table
                    thumbWidget = QWidget()
                    pic = QPixmap(
                        "assets/media/people-media/photos_thumbnails/01Aug2020_18h01mtrtgzteuzuspxrp_thumbnail.png"
                    )
                    thumbLabel = QLabel()
                    thumbLabel.setPixmap(pic)
                    thumbLayout = QHBoxLayout(thumbWidget)
                    thumbLayout.addWidget(thumbLabel)
                    self.peopleTable.setCellWidget(row_number, 1, thumbWidget)
                    self.peopleTable.setItem(row_number, 0,
                                             QTableWidgetItem(row_number))
                    # Fill the rest of the data
                    for column_number, data in enumerate(row_data, start=2):
                        if column_number == 2:
                            self.peopleTable.setItem(
                                row_number, column_number,
                                QTableWidgetItem("PRN#" + str(data)))
                        else:
                            self.peopleTable.setItem(
                                row_number, column_number,
                                QTableWidgetItem(str(data)))
            except:
                QMessageBox.information(self, "Info", "Cannot access database")
        elif self.subcontractorsPeopleRadioBtn.isChecked():
            try:
                query = "SELECT * FROM people WHERE person_empl_type = 'Subcontractor'"
                people = db.cur.execute(query).fetchall()

                for i in reversed(range(self.peopleTable.rowCount())):
                    self.peopleTable.removeRow(i)

                for row_data in people:
                    row_number = self.peopleTable.rowCount()
                    self.peopleTable.insertRow(row_number)
                    # Add checkboxes to the table
                    widget = QWidget()
                    checkBox = QCheckBox()
                    checkBox.setCheckState(Qt.Unchecked)
                    hBoxLayout = QHBoxLayout(widget)
                    hBoxLayout.addWidget(checkBox)
                    hBoxLayout.setAlignment(Qt.AlignCenter)
                    self.peopleTable.setCellWidget(row_number, 0, widget)
                    self.peopleTable.setItem(row_number, 0,
                                             QTableWidgetItem(row_number))
                    # Add photo photos_thumbnails to the table
                    thumbWidget = QWidget()
                    pic = QPixmap(
                        "assets/media/people-media/photos_thumbnails/01Aug2020_18h01mtrtgzteuzuspxrp_thumbnail.png"
                    )
                    thumbLabel = QLabel()
                    thumbLabel.setPixmap(pic)
                    thumbLayout = QHBoxLayout(thumbWidget)
                    thumbLayout.addWidget(thumbLabel)
                    self.peopleTable.setCellWidget(row_number, 1, thumbWidget)
                    self.peopleTable.setItem(row_number, 0,
                                             QTableWidgetItem(row_number))
                    # Fill the rest of the data
                    for column_number, data in enumerate(row_data, start=2):
                        if column_number == 2:
                            self.peopleTable.setItem(
                                row_number, column_number,
                                QTableWidgetItem("PRN#" + str(data)))
                        else:
                            self.peopleTable.setItem(
                                row_number, column_number,
                                QTableWidgetItem(str(data)))
            except:
                QMessageBox.information(self, "Info", "Cannot access database")

    @Slot()
    def searchPeople(self):
        value = self.searchPeopleEntry.text()
        if value == "":
            QMessageBox.information(self, "Warning",
                                    "Search string cannot be empty")
            self.funcDisplayPeople()
        else:
            # Erase search entry
            self.searchPeopleEntry.setText("")
            try:
                query = "SELECT * FROM people WHERE " \
                        "person_id LIKE ? " \
                        "OR person_first_name LIKE ?" \
                        "OR person_last_name LIKE ?" \
                        "OR person_title LIKE ?" \
                        "OR person_phone LIKE ?" \
                        "OR person_email LIKE ?" \
                        "OR person_location LIKE ?" \
                        "OR person_empl_type LIKE ?"
                results = db.cur.execute(query, (
                    '%' + value + '%',
                    '%' + value + '%',
                    '%' + value + '%',
                    '%' + value + '%',
                    '%' + value + '%',
                    '%' + value + '%',
                    '%' + value + '%',
                    '%' + value + '%',
                )).fetchall()
                if results == []:
                    QMessageBox.information(self, "Info", "Nothing was found")
                    self.displayPeople()
                else:
                    for i in reversed(range(self.peopleTable.rowCount())):
                        self.peopleTable.removeRow(i)

                    for row_data in results:
                        row_number = self.peopleTable.rowCount()
                        self.peopleTable.insertRow(row_number)
                        # Add checkboxes to the table
                        qwidget = QWidget()
                        checkbox = QCheckBox()
                        checkbox.setCheckState(Qt.Unchecked)
                        qhboxlayout = QHBoxLayout(qwidget)
                        qhboxlayout.addWidget(checkbox)
                        qhboxlayout.setAlignment(Qt.AlignCenter)
                        self.peopleTable.setCellWidget(row_number, 0, qwidget)
                        self.peopleTable.setItem(row_number, 0,
                                                 QTableWidgetItem(row_number))
                        # Add photo photos_thumbnails to the table
                        thumbWidget = QWidget()
                        pic = QPixmap(
                            "assets/media/people-media/photos_thumbnails/01Aug2020_18h01mtrtgzteuzuspxrp_thumbnail.png"
                        )
                        thumbLabel = QLabel()
                        thumbLabel.setPixmap(pic)
                        thumbLayout = QHBoxLayout(thumbWidget)
                        thumbLayout.addWidget(thumbLabel)
                        self.peopleTable.setCellWidget(row_number, 1,
                                                       thumbWidget)
                        self.peopleTable.setItem(row_number, 0,
                                                 QTableWidgetItem(row_number))

                        for column_number, data in enumerate(row_data,
                                                             start=2):
                            if column_number == 2:
                                self.peopleTable.setItem(
                                    row_number, column_number,
                                    QTableWidgetItem("PRN#" + str(data)))
                            else:
                                self.peopleTable.setItem(
                                    row_number, column_number,
                                    QTableWidgetItem(str(data)))
            except:
                QMessageBox.information(self, "Info", "Cannot access database")

    @Slot()
    def funcPeopleToCSV(self):
        indices = self.funcPeopleCheckBox()

        if indices:
            CSV(self, "people", indices)
        else:
            QMessageBox.information(
                self, "Info",
                "Nothing selected for export\nUse checkboxes to select issues to export"
            )

    @Slot()
    def funcPeopleToXLSX(self):
        indices = self.funcPeopleCheckBox()

        if indices:
            try:
                date = datetime.datetime.now()

                # Get file location and add timestamp to when it was created to the filename
                fileName, _ = QFileDialog.getSaveFileName(
                    self, "Save as...",
                    "~/PeopleXLSX" + "{:%d%b%Y_%Hh%Mm}".format(date) + ".xlsx",
                    "Excel files (*.xlsx)")
                if fileName:
                    db.cur.execute("SELECT * FROM people")

                    workbook = xlsxwriter.Workbook(fileName)
                    worksheet = workbook.add_worksheet("People")
                    worksheet.set_column('A:C', 12)
                    worksheet.set_row(0, 30)
                    merge_format = workbook.add_format({
                        'bold': 1,
                        'align': 'center',
                        'valign': 'vcenter'
                    })
                    worksheet.merge_range('A1:B1', '', merge_format)
                    worksheet.insert_image(
                        'A1', './assets/logo/logo-full-main.png', {
                            'x_scale': 0.4,
                            'y_scale': 0.4,
                            'x_offset': 15,
                            'y_offset': 10
                        })

                    # Create header row
                    stop = 8
                    col = 0
                    for i, value in enumerate(db.cur.description[:stop]):
                        worksheet.write(1, col, value[0])
                        col += 1

                    # Write date to xlsx file
                    row_number = 2
                    for index in range(len(indices)):
                        query = "SELECT * FROM people WHERE person_id=?"
                        person_record = db.cur.execute(
                            query, (indices[index], )).fetchone()
                        for i, value in enumerate(person_record[:stop]):
                            if person_record[9]:
                                worksheet.set_row(row_number, 185)
                                worksheet.set_column(8, 8, 35)
                                worksheet.insert_image(row_number, 8,
                                                       person_record[9], {
                                                           'x_scale': 0.3,
                                                           'y_scale': 0.3
                                                       })
                            worksheet.write(row_number, i, value)
                        row_number += 1

                    workbook.close()

                    QMessageBox.information(
                        self, "Info",
                        "Data exported successfully into {}".format(fileName))

            except:
                QMessageBox.information(self, "Info", "Export failed")
        else:
            QMessageBox.information(
                self, "Info",
                "Nothing selected for export\nUse checkboxes to select issues to export"
            )

    @Slot()
    def funcPeopleToPdf(self):
        indices = self.funcPeopleCheckBox()

        if indices:
            try:
                date = datetime.datetime.now()

                # Get file location and add timestamp to when it was created to the filename
                fileName, _ = QFileDialog.getSaveFileName(
                    self, "Save as...",
                    "~/PeoplePDF" + "{:%d%b%Y_%Hh%Mm}".format(date) + ".pdf",
                    "PDF files (*.pdf)")

                if fileName:
                    pdf = PDF()
                    pdf.add_page()
                    pdf.set_font('Arial', 'B', 13)

                    for index in range(len(indices)):
                        query = "SELECT * FROM people WHERE person_id=?"
                        person_record = db.cur.execute(
                            query, (indices[index], )).fetchone()

                        # This string allows for text formatting in the pdf, easy to implement and test
                        stringPerson = "\nPerson id: " + str(person_record[0]) + \
                                       "\nFirst name: " + str(person_record[1]) + \
                                       "\nLast name: " + str(person_record[2]) + \
                                       "\nTitle: " + str(person_record[3]) + \
                                       "\nPhone: " + str(person_record[4]) + \
                                       "\nEmail: " + str(person_record[5]) + \
                                       "\nLocation: " + str(person_record[6]) + \
                                       "\nEmployment type: " + str(person_record[7])

                        effectivePageWidth = pdf.w - 2 * pdf.l_margin
                        ybefore = pdf.get_y()
                        pdf.multi_cell(effectivePageWidth / 2, 10,
                                       stringPerson)

                        if person_record[9]:
                            pdf.set_xy(effectivePageWidth / 2 + pdf.l_margin,
                                       ybefore)
                            pdf.image(person_record[9],
                                      effectivePageWidth / 2 + 20,
                                      40,
                                      w=70)
                        pdf.ln(0.5)

                        if index != (len(indices) - 1):
                            pdf.add_page()

                        # pdf.multi_cell(200, 10, stringPerson)
                    pdf.output(fileName, 'F')

                    QMessageBox.information(
                        self, "Info",
                        "Data exported successfully into {}".format(fileName))

            except:
                QMessageBox.information(self, "Info", "Export failed")
        else:
            QMessageBox.information(
                self, "Info",
                "Nothing selected for export\nUse checkboxes to select issues to export"
            )
Example #3
0
class App(QMainWindow):
    # ------------------------------------------
    # -- Initialize the Class
    # ------------------------------------------
    def __init__(self):
        super(App, self).__init__()

        # -- Home Directory
        self.home_path = expanduser("~")

        # -- Base Path
        # self.app_path = os.path.abspath(__file__)
        self.app_path = sys.argv[0]
        self.base_path_split = self.app_path.split('/')
        self.base_path = str('/').join(self.base_path_split[0:-1])

        # -- Files under config
        self.config_file = self.base_path + '/config/config.json'
        self.connect_file = self.base_path + '/config/connect.sh'
        self.table_file = self.base_path + '/config/table.csv'

        self.delimiter_table_row = ';'

        # -- Data of Config File (with Default Values)
        self.config_data_file = {
            'Message': {
                'FileReadSuccess': True,
                'FileReadFailed': True,
                'ColorRedefinition': True
            },
            'Window': {
                'Left': 100,
                'Top': 100,
                'Width': 640,
                'Height': 480
            },
            'Margin': {
                'Left': 11,
                'Top': 11,
                'Right': 11,
                'Bottom': 11
            },
            'Title': {
                'Label': 'SLT - Simple Login Tool - ' + __version__
            },
            'Button': {
                'Connect': {
                    'Label': 'Connect'
                },
                'Message': {
                    'Label': 'X'
                }
            },
            'Table': {
                'Header': [],
                'Column': {
                    'Color':
                    1,  # -- Number of column which used for text matching
                    'Connect': [
                        9, 1
                    ]  # -- These are those column numbers which data picked from the selected row and will be used as connection parameters
                },
                'Cell': {
                    'Color': {}
                }
            }
        }

        # -- Data of Table File
        self.table_data_file = []

        # -- Dictionary of Colors with QColor Elements
        self.color_data = {}

        # -- Central Widget
        self.central_widget = None

        # -- Main Layout
        self.main_layout = None

        # -- Input Box
        self.input_box = None

        # -- Connect Button
        self.connect_button = None

        # -- Message Button
        self.message_button = None

        # -- Message Label
        self.message_label = None
        self.message_label_count = None

        # -- Message List
        self.message_list = []

        # -- Main Table
        self.main_table = None

        # -- Status Bar
        self.status_bar = None

        # -- Messages
        self.messages = {
            'FileReadSuccess': 'INFO: File is opened for read: ',
            'FileReadFailed': 'ERROR: File could not be opened for read: ',
            'ColorRedefinition': 'WARN: Color Redefinition: '
        }

        # -- Initialize the UI
        self.initUI()

    # ------------------------------------------
    # -- Create Main Window
    # ------------------------------------------
    # def createMainWindow(self):
    #     if (self.main_window is None):
    #         self.main_window = QMainWindow(self)

    # ------------------------------------------
    # -- Create Central Widget
    # ------------------------------------------
    def createCentralWidget(self):
        if (self.central_widget is None):
            self.central_widget = QWidget()

        # -- Set Central Widget for QMainWindow
        self.setCentralWidget(self.central_widget)

    # ------------------------------------------
    # -- Create Layout
    # ------------------------------------------
    def createLayout(self):
        if (self.main_layout is None):
            self.main_layout = QGridLayout()

    # ------------------------------------------
    # -- Create Input Box
    # ------------------------------------------
    def createInputBox(self):
        if (self.input_box is None):
            self.input_box = QLineEdit()

        # -- Enable Clear Button
        self.input_box.setClearButtonEnabled(True)

        # -- Create Event if enter pressed
        # self.input_box.editingFinished.connect(self.eventSearchInTable)
        self.input_box.editingFinished.connect(self.eventConnectButtonClicked)

        # -- Create Event if text changed
        self.input_box.textChanged.connect(self.eventSearchInTable)

    # ------------------------------------------
    # -- Search Event
    # ------------------------------------------
    def eventSearchInTable(self):
        # print('Search Event. Look up text is: %s' %(self.input_box.text()))  # -- Debug
        self.refreshTable(self.input_box.text().strip())

    # ------------------------------------------
    # -- Create Connect Button
    # ------------------------------------------
    def createConnectButton(self, text):
        if (self.connect_button is None):
            self.connect_button = QPushButton(text)

        # -- Add Clicked Event
        self.connect_button.clicked.connect(self.eventConnectButtonClicked)

    # ------------------------------------------
    # -- Event for Connect Button Clicked
    # ------------------------------------------
    def eventConnectButtonClicked(self):
        connectParameters = ''
        row = 0

        # print('Connect Button Pressed')  # -- Debug

        if (self.main_table.rowCount() == 1):
            for column in self.config_data_file['Table']['Column']['Connect']:
                cellTable = self.main_table.item(row, column)
                connectParameters += ' ' + str(cellTable.text())

            self.connectExecute(connectParameters)
        # else:
        # print('More than one item in table, therefore cannot decide which one to choose')  # -- Debug

    # ------------------------------------------
    # -- Create Status Bar
    # ------------------------------------------
    def createStatusBar(self):
        if (self.status_bar is None):
            self.status_bar = QStatusBar()

        self.status_bar.addWidget(self.message_label_count, 0)
        self.status_bar.addWidget(VLine(), 0)
        self.status_bar.addWidget(self.message_label, 1)
        self.status_bar.addWidget(self.message_button, 0)

    # ------------------------------------------
    # -- Update Status Bar
    # ------------------------------------------
    def updateStatusBar(self):
        if (self.status_bar is not None):
            # -- Hide the Status Bar if the Message List is empty
            if (len(self.message_list) > 0):
                self.status_bar.show()
            else:
                self.status_bar.hide()

    # ------------------------------------------
    # -- Get Latest Message
    # ------------------------------------------
    def getLatestMessage(self):
        result = None
        length = len(self.message_list)

        if (length > 0):
            result = self.message_list[length - 1]

        return result

    # ------------------------------------------
    # -- Create Message Label
    # ------------------------------------------
    def createMessageLabel(self):
        if (self.message_label is None):
            self.message_label = QLabel(self)

        # -- Add a Text to Message Label
        # self.message_label.setText(self.getLatestMessage())
        self.updateMessageLabel()

    # ------------------------------------------
    # -- Update Message Label with Latest Entry
    # ------------------------------------------
    def updateMessageLabel(self):
        message = ''
        length = len(self.message_list)

        if (self.message_label is not None):
            if (length > 0):
                message = self.message_list[-1]

            self.message_label.setText(message)

    # ------------------------------------------
    # -- Create Message Label Count
    # ------------------------------------------
    def createMessageLabelCount(self):
        if (self.message_label_count is None):
            self.message_label_count = QLabel(self)

        self.updateMessageLabelCount()

    # ------------------------------------------
    # -- Update Message Label Count
    # ------------------------------------------
    def updateMessageLabelCount(self):
        message = ''
        length = len(self.message_list)

        if (self.message_label_count is not None):
            if (length > 0):
                message = '  ' + str(length)

            self.message_label_count.setText(message)

    # ------------------------------------------
    # -- Create Message Button
    # ------------------------------------------
    def createMessageButton(self, text):
        if (self.message_button is None):
            self.message_button = QPushButton(text)

        # -- Add Clicked Event
        self.message_button.clicked.connect(self.eventMessageButtonClicked)

    # ------------------------------------------
    # -- Event for Message Button Clicked
    # ------------------------------------------
    def eventMessageButtonClicked(self):
        length = len(self.message_list)

        # -- Remove the latest item in Message List
        if (length > 0):
            del self.message_list[length - 1]

        # -- Update Message Labels
        self.updateMessageLabel()
        self.updateMessageLabelCount()

        # -- Update the Status Bar
        self.updateStatusBar()

    # ------------------------------------------
    # -- Add a New Message to List
    # ------------------------------------------
    def addNewMessage(self, message):
        self.message_list.append(message)
        self.updateMessageLabel()

        # -- Update Status Bar
        self.updateStatusBar()

    # ------------------------------------------
    # -- Check Table Header
    # ------------------------------------------
    def checkMainTableHeader(self, hostsList):
        # -- Length of the Header defined in the config file
        lengthHeaderconfig_file = len(self.config_data_file['Table']['Header'])

        # -- Length of the First Record
        if (len(hostsList) > 0):
            lengthFirstRecord = len(hostsList[0])
        else:
            lengthFirstRecord = 0

        # -- Append the Header if the list in config file is too short
        if (lengthHeaderconfig_file < lengthFirstRecord):
            for header in range(lengthHeaderconfig_file + 1,
                                lengthFirstRecord + 1):
                self.config_data_file['Table']['Header'].append(str(header))

    # ------------------------------------------
    # -- Create Table
    # ------------------------------------------
    def createMainTable(self, hostsList):
        numCell = 0

        maxTableRow = len(hostsList)
        maxTableColumn = len(self.config_data_file['Table']['Header'])

        if (self.main_table is None):
            self.main_table = QTableWidget()

        # -- Set the Maximum Size of Table
        self.main_table.setColumnCount(maxTableColumn)
        self.main_table.setRowCount(maxTableRow)

        # -- Create the Horizontal Header of Table
        headerTableWidget = self.main_table.horizontalHeader()

        # -- Set the Table Header
        self.main_table.setHorizontalHeaderLabels(
            self.config_data_file['Table']['Header'])

        # -- Hide The Horizontal Table Header
        # self.main_table.horizontalHeader().setVisible(False)

        # -- Set the Cells to Read Only
        self.main_table.setEditTriggers(QTableWidget.NoEditTriggers)

        # -- Set Table Header Properties
        for numCell in range(0, len(self.config_data_file['Table']['Header'])):
            headerTableWidget.setSectionResizeMode(
                numCell, QHeaderView.ResizeToContents)

        # -- Set the First Column to Resizeable
        # headerTableWidget.setSectionResizeMode(0, QHeaderView.Stretch)

        # -- Set the Last Column to Resizeable
        headerTableWidget.setSectionResizeMode(maxTableColumn - 1,
                                               QHeaderView.Stretch)

        # -- Add Double Clicked Event on Table
        self.main_table.itemDoubleClicked.connect(
            self.eventMainTableDoubleClickedOnCell)

        # -- Insert Data into Table
        self.insertDataIntoTable(self.main_table, hostsList)

    # ------------------------------------------
    # -- Double Clicked on Cell Event
    # ------------------------------------------
    def eventMainTableDoubleClickedOnCell(self):
        connectParameters = ''
        row = self.main_table.currentRow()

        # print('Double Clicked on a Table Cell')  # -- Debug

        for column in self.config_data_file['Table']['Column']['Connect']:
            cellTable = self.main_table.item(row, column)
            connectParameters += ' ' + str(cellTable.text())

        self.connectExecute(connectParameters)

    # ------------------------------------------
    # -- Insert Data into the Table
    # ------------------------------------------
    def insertDataIntoTable(self, inputTable, inputRecords):
        maxHeaderColumn = len(self.config_data_file['Table']['Header'])
        maxTableColumn = len(self.config_data_file['Table']['Header'])
        maxTableRow = len(inputRecords)
        colorColumn = self.config_data_file['Table']['Column']['Color']
        numRecord = 0
        numCell = 0

        # -- Set the Maximum size of Table
        inputTable.setColumnCount(maxTableColumn)
        inputTable.setRowCount(maxTableRow)

        for record in inputRecords:
            # print('Record : %s' %(str(record)))  # -- Debug
            for cell in record:
                # print('Cell : %s' %(cell))  # -- Debug
                if (numCell < maxHeaderColumn):
                    inputTable.setItem(numRecord, numCell,
                                       QTableWidgetItem(cell))

                    # -- Set the Background Color of Cells
                    # if (record[colorColumn] in self.colorCell):
                    #     inputTable.item(numRecord, numCell).setBackground(self.colorCell[record[colorColumn]])
                    if (record[colorColumn] in self.config_data_file['Table']
                        ['Cell']['Color']):
                        nameColor = self.config_data_file['Table']['Cell'][
                            'Color'][record[colorColumn]]

                        # print('Cell: %s, %s, %s' %(record[colorColumn], nameColor, self.color_data[nameColor]))  # -- Debug

                        inputTable.item(numRecord, numCell).setBackground(
                            self.color_data[nameColor])

                numCell += 1
            numCell = 0
            numRecord += 1

        inputTable.move(0, 0)

    # ------------------------------------------
    # -- Refresh Table
    # ------------------------------------------
    def refreshTable(self, searchText):
        found = False
        filteredHostsList = []

        # print('Refresh table data.')  # -- Debug

        # -- Clean the Table
        for row in range(self.main_table.rowCount() - 1, -1, -1):
            # print('Remove row: %s' %(str(row))) # -- Debug
            self.main_table.removeRow(row)

        self.main_table.show()

        # -- Update the table_data_file with searchText
        for record in self.table_data_file:
            found = False
            for cell in record:
                if (searchText == ''
                        or cell.lower().find(searchText.lower()) != -1):
                    # print('Found: %s' %(str(cell)))  # -- Debug
                    found = True

            if (found):
                filteredHostsList.append(record)

        # -- Recreate Table Data with filtered Values
        self.insertDataIntoTable(self.main_table, filteredHostsList)

        # -- Refresh the QTableWidget (required due to screen artifact)
        self.main_table.hide()
        self.main_table.show()

    # ------------------------------------------
    # -- Read Config File
    # ------------------------------------------
    def readConfigFile(self, filename):
        fileHandle = None
        message = ''

        try:
            fileHandle = open(filename, 'r')
        except IOError:
            message = self.messages['FileReadFailed'] + filename
            print(message)

            # -- Message
            if (self.config_data_file['Message']['FileReadFailed'] is True):
                self.addNewMessage(message)
        else:
            message = self.messages['FileReadSuccess'] + filename
            print(message)

            # -- Update the Default Data Values with the New Ones
            # self.config_data_file = json.load(fileHandle)
            self.config_data_file.update(json.load(fileHandle))

            # -- Add Colors to the List
            for key, value in self.config_data_file['Color'].items():
                # -- Check the Length of Value (must have 3 elements [R,G,B])
                if (len(value) == 3):
                    self.addColor(key, value[0], value[1], value[2])

            # -- Message
            if (self.config_data_file['Message']['FileReadSuccess'] is True):
                self.addNewMessage(message)

            # print('JSON: %s' %(self.config_data_file))  # -- Debug
        finally:
            if (fileHandle):
                fileHandle.close()

    # ------------------------------------------
    # -- Add Color to the Dictionary
    # ------------------------------------------
    def addColor(self, name, red, green, blue):
        # print('Add Color: %s [%d,%d,%d]' %(name, red, green, blue))  # -- Debug

        # -- Check Red
        if (type(red) is int):
            if (red < 0 or red > 255):
                red = 255
        else:
            red = 255

        # -- Check Green
        if (type(green) is int):
            if (green < 0 or green > 255):
                green = 255
        else:
            green = 255

        # -- Check Blue
        if (type(blue) is int):
            if (blue < 0 or blue > 255):
                blue = 255
        else:
            blue = 255

        # print('Add Color: %s [%d,%d,%d]' %(name, red, green, blue))  # -- Debug

        # -- Add the Color to the Dictionary
        if (name not in self.color_data):
            self.color_data[name] = QColor(red, green, blue)
        else:
            # -- Message
            if (self.config_data_file['Message']['ColorRedefinition'] is True):
                self.addNewMessage(self.messages['ColorRedefinition'] + name)

    # ------------------------------------------
    # -- Read CSV File
    # ------------------------------------------
    def readCsvFile(self, filename):
        fileHandle = None
        result = []
        message = ''

        try:
            fileHandle = open(filename, 'r')
        except IOError:
            message = self.messages['FileReadFailed'] + filename
            print(message)

            # -- Message
            if (self.config_data_file['Message']['FileReadFailed'] is True):
                self.addNewMessage(message)
        else:
            message = self.messages['FileReadSuccess'] + filename
            print(message)

            # -- Message
            if (self.config_data_file['Message']['FileReadSuccess'] is True):
                self.addNewMessage(message)

            fileContent = fileHandle.readlines()

            for line in fileContent:
                strippedLine = line.strip()

                if (strippedLine != ''):
                    if (strippedLine[0] != '#'):
                        # result.append(list(strippedLine.split(self.delimiter_table_row)))  # -- List Items are not Stripped
                        result.append(
                            list(item.strip() for item in strippedLine.split(
                                self.delimiter_table_row))
                        )  # -- List Items are Stripped
                        # print(strippedLine)  # -- Debug

            # -- Debug
            # for line in result:
            #    for column in line:
            #        print('[\'%s\']' %(str(column)), end='')
            #    print('')
        finally:
            if (fileHandle):
                fileHandle.close()

        return result

    # ------------------------------------------
    # -- Execute the Connect Command in Shell
    # ------------------------------------------
    def connectExecute(self, parameters):
        # print('Run: %s %s' %(self.connect_file, parameters))  # -- Debug

        os.system(self.connect_file + ' ' + parameters)

    # ------------------------------------------
    # -- UI Initialization
    # ------------------------------------------
    def initUI(self):
        # -- Read the Config File
        self.readConfigFile(self.config_file)

        # -- Read the Table CSV File
        self.table_data_file = self.readCsvFile(self.table_file)

        # -- Create GUI Elements
        self.createCentralWidget()
        self.createLayout()

        self.createInputBox()
        self.createConnectButton(
            self.config_data_file['Button']['Connect']['Label'])
        self.checkMainTableHeader(self.table_data_file)
        self.createMainTable(self.table_data_file)

        self.createMessageLabel()
        self.createMessageLabelCount()
        self.createMessageButton(
            self.config_data_file['Button']['Message']['Label'])

        self.createStatusBar()
        self.updateStatusBar()

        # -- Set Window Title
        self.setWindowTitle(self.config_data_file['Title']['Label'])

        # -- Set Window Geometry
        self.setGeometry(self.config_data_file['Window']['Left'],
                         self.config_data_file['Window']['Top'],
                         self.config_data_file['Window']['Width'],
                         self.config_data_file['Window']['Height'])

        # -- Set Layout Margins
        self.main_layout.setContentsMargins(
            self.config_data_file['Margin']['Left'],
            self.config_data_file['Margin']['Top'],
            self.config_data_file['Margin']['Right'],
            self.config_data_file['Margin']['Bottom'])

        # -- Set Layout
        self.central_widget.setLayout(self.main_layout)

        # -- Add Widgets to Layout
        self.main_layout.addWidget(self.input_box, 0, 0, 1, 1)
        self.main_layout.addWidget(self.connect_button, 0, 1, 1, 1)
        self.main_layout.addWidget(self.main_table, 1, 0, 1, 2)

        # -- Set Status Bar for QMainWindow
        self.setStatusBar(self.status_bar)
Example #4
0
class PatientListView(QWidget):
    columns = ["Identyfikator", "Imię", "Nazwisko"]

    def __init__(self):
        QWidget.__init__(self)

        self.toolbar = QToolBar()
        self.toolbar.setMovable(False)

        btn_ac_adduser = QAction(QIcon("resources/icon/add-user.png"),
                                 "Add Patient", self)
        btn_ac_adduser.triggered.connect(self.addPatientForm)
        btn_ac_adduser.setStatusTip("Add Student")
        self.toolbar.addAction(btn_ac_adduser)

        btn_ac_delete = QAction(QIcon("resources/icon/remove-user.png"),
                                "Delete Patient", self)
        btn_ac_delete.triggered.connect(self.deleteCurrentPatient)
        btn_ac_delete.setStatusTip("Delete User")
        self.toolbar.addAction(btn_ac_delete)

        self.table = QTableWidget()
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setColumnCount(len(self.columns))
        self.table.verticalHeader().setVisible(False)

        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.table.setHorizontalHeaderLabels(self.columns)

        self.reload()

        layout = QHBoxLayout(self)
        layout.setMenuBar(self.toolbar)
        layout.addWidget(self.table)

    def fillTable(self):
        for patient in self.data:
            self.addPatient(patient)

    def addPatient(self, patient):
        ind = self.table.rowCount()
        self.table.insertRow(ind)
        self.table.setItem(ind, 0, self.tableWidgetItem(str(patient.db_id)))
        self.table.setItem(ind, 1, self.tableWidgetItem(patient.name))
        self.table.setItem(ind, 2, self.tableWidgetItem(patient.surname))

    def tableWidgetItem(self, value):
        item = QTableWidgetItem(value)
        item.setFlags(item.flags() & ~Qt.ItemIsEditable)
        return item

    def addPatientForm(self):
        logging.debug("Entering PatientForm")
        self.patient_form = PatientForm()
        answer = self.patient_form.exec()
        if answer == QDialog.Accepted:
            self.reload()
            logging.debug(f"Patient {self.patient_form.patient} added")

    def deleteCurrentPatient(self):
        if self.table.rowCount() == 0:
            QMessageBox.warning(
                self,
                "Usuwanie pacjenta",
                "Brak danych w tabeli",
            )
            return

        current_row = self.table.currentRow()
        if current_row == -1:
            QMessageBox.warning(
                self,
                "Usuwanie pacjenta",
                "Brak wskazania na pacjenta",
            )
            return

        patient = self.data[current_row]
        answer = QMessageBox.question(
            self,
            "Usuwanie pacjenta",
            f"Czy na pewno chcesz usunąć pacjenta {patient}?",
        )
        if answer == QMessageBox.Yes:
            delete_patient(patient)
            self.reload()
            logging.debug("Deleting PatientForm")

    def reload(self):
        self.table.setRowCount(0)
        self.data = get_all_patients()
        self.fillTable()
Example #5
0
class TreatmentsTab(QWidget):
    def __init__(self, patient):
        QWidget.__init__(self)
        self.patient = patient

        self.toolbar = QToolBar()
        self.toolbar.setMovable(False)

        add_treatment = QAction(
            QIcon("resources/icon/plus.png"), "Podaj lekarstwo", self
        )
        add_treatment.triggered.connect(self.addTreatmentForm)
        add_treatment.setStatusTip("Dodaj pomiary")
        self.toolbar.addAction(add_treatment)

        delete_treatment = QAction(
            QIcon("resources/icon/trash-bin.png"), "Usuń podanie lekarstwa", self
        )
        delete_treatment.triggered.connect(self.deleteCurrentTreatment)
        delete_treatment.setStatusTip("Usuń pomiar")
        self.toolbar.addAction(delete_treatment)

        self.table = QTableWidget()
        self.table.setColumnCount(2)

        self.table.setHorizontalHeaderLabels(["Data", "Zawartość lekarstwa"])

        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.fillTable(patient.treatments)

        main_layout = QHBoxLayout(self)
        main_layout.setMenuBar(self.toolbar)
        main_layout.addWidget(self.table)

    def addTreatmentForm(self):
        logging.debug("Entering TreatmentForm of patient %s", self.patient)
        self.treatment_form = TreatmentForm(self, self.patient)
        self.treatment_form.show()

    def fillTable(self, treatments):
        for tr in treatments:
            self.addTreatment(tr)

    def addTreatment(self, treatment):
        row_count = self.table.rowCount()
        self.table.insertRow(row_count)
        self.table.setItem(
            row_count, 0, self.tableWidgetItem(treatment.date.isoformat())
        )
        self.table.setItem(row_count, 1, self.tableWidgetItem(str(treatment.amount)))

    def tableWidgetItem(self, value):
        item = QTableWidgetItem(value)
        item.setFlags(item.flags() & ~Qt.ItemIsEditable)
        return item

    def deleteCurrentTreatment(self):
        if self.table.rowCount() == 0:
            QMessageBox.warning(
                self,
                "Usuwanie podania lekarstwa",
                "Brak danych w tabeli",
            )
            return
        current_row = self.table.currentRow()
        if current_row == -1:
            QMessageBox.warning(
                self,
                "Usuwanie lekarstwa",
                "Brak wskazania na żaden pomiar",
            )
            return
        treatment = self.patient.treatments[current_row]
        answer = QMessageBox.question(
            self,
            "Usuwanie pomiaru",
            f"Czy na pewno chcesz usunąć podanie lekarstwa {treatment}?",
        )
        if answer == QMessageBox.Yes:
            delete_treatment_for_patient(self.patient, treatment)
            self.table.removeRow(current_row)
            logging.debug(f"Deleting {treatment}")
Example #6
0
class TableWidget(QWidget):
    def __init__(self,
                 table,
                 headers,
                 bold=True,
                 mono=True,
                 tooltips=None,
                 align=False,
                 search=True,
                 parent=None):
        super(TableWidget, self).__init__(parent)

        self.table_widget = QTableWidget(len(table), len(table[0]))
        for i, row in enumerate(table):
            for j, item in enumerate(row):
                if item is not None:
                    self.table_widget.setItem(i, j,
                                              QTableWidgetItem(str(item)))
                    if tooltips is not None:
                        self.table_widget.setToolTip(tooltips[i][j])
                    modify_font(self.table_widget.item(i, j),
                                bold=bold and j == 0,
                                mono=mono)
                    if align:
                        self.table_widget.item(i, j).setTextAlignment(
                            Qt.AlignRight)

        self.table_headers = headers
        self.table_widget.setHorizontalHeaderLabels(self.table_headers)
        self.table_widget.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table_widget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table_widget.resizeColumnsToContents()
        self.table_widget.setAlternatingRowColors(True)
        self.table_widget.itemDoubleClicked.connect(self.copy)

        search_layout = QHBoxLayout()
        search_layout.addWidget(QLabel(self.tr('Search:')))
        self.search_edit = QLineEdit()
        self.search_edit.textChanged.connect(self.start)
        self.search_edit.returnPressed.connect(self.next)
        search_layout.addWidget(self.search_edit)

        clear_button = QToolButton()
        clear_button.setIcon(QIcon('icons/clear.svg'))
        clear_button.setShortcut(QKeySequence.DeleteCompleteLine)
        clear_button.setToolTip(self.tr('Clear pattern'))
        clear_button.clicked.connect(self.search_edit.clear)
        search_layout.addWidget(clear_button)

        self.case_button = QToolButton()
        self.case_button.setText(self.tr('Aa'))
        self.case_button.setCheckable(True)
        self.case_button.toggled.connect(self.start)
        self.case_button.setToolTip(self.tr('Case sensitive'))
        search_layout.addWidget(self.case_button)

        self.word_button = QToolButton()
        self.word_button.setText(self.tr('W'))
        self.word_button.setCheckable(True)
        self.word_button.toggled.connect(self.start)
        self.word_button.setToolTip(self.tr('Whole words'))
        search_layout.addWidget(self.word_button)

        self.regex_button = QToolButton()
        self.regex_button.setText(self.tr('.*'))
        self.regex_button.setCheckable(True)
        self.regex_button.toggled.connect(self.start)
        self.regex_button.setToolTip(self.tr('Regular expression'))
        search_layout.addWidget(self.regex_button)

        prev_button = QToolButton()
        prev_button.setIcon(QIcon('icons/up.svg'))
        prev_button.setShortcut(QKeySequence.FindPrevious)
        prev_button.clicked.connect(self.previous)
        prev_button.setToolTip(self.tr('Previous occurence'))
        search_layout.addWidget(prev_button)

        next_button = QToolButton()
        next_button.setIcon(QIcon('icons/down.svg'))
        next_button.setShortcut(QKeySequence.FindNext)
        next_button.clicked.connect(self.next)
        next_button.setToolTip(self.tr('Next occurence'))
        search_layout.addWidget(next_button)

        self.matches_label = QLabel()
        search_layout.addWidget(self.matches_label)
        search_layout.addStretch()

        export_button = QToolButton()
        export_button.setText(self.tr('Export...'))
        export_button.clicked.connect(self.export)
        search_layout.addWidget(export_button)

        main_layout = QVBoxLayout()
        main_layout.addWidget(self.table_widget)
        if search:
            main_layout.addLayout(search_layout)
        self.setLayout(main_layout)

    def start(self):
        self.search(self.search_edit.text(), -1, -1, 1)

    def next(self):
        row = self.table_widget.currentRow()
        col = self.table_widget.currentColumn() + 1
        if col == self.table_widget.columnCount():
            row += 1
            col = 0
        self.search(self.search_edit.text(), row, col, +1)

    def previous(self):
        row = self.table_widget.currentRow()
        col = self.table_widget.currentColumn() - 1
        if col == -1:
            row -= 1
            col = self.table_widget.columnCount() - 1
        self.search(self.search_edit.text(), row, col, -1)

    def search(self, pattern, row, col, direction):
        nocase = not self.case_button.isChecked()
        word = self.word_button.isChecked()
        regex = self.regex_button.isChecked()
        matches = 0
        index = 0
        if direction > 0:
            row_range = range(self.table_widget.rowCount() - 1, -1, -1)
            col_range = range(self.table_widget.columnCount() - 1, -1, -1)
        else:
            row_range = range(self.table_widget.rowCount())
            col_range = range(self.table_widget.columnCount())
        for i in row_range:
            for j in col_range:
                item = self.table_widget.item(i, j)
                if item is not None:
                    text = item.text()
                    if regex:
                        match = QRegularExpression(pattern).match(
                            text).hasMatch()
                    else:
                        if nocase:
                            text = text.lower()
                            pattern = pattern.lower()
                        if word:
                            match = text == pattern
                        else:
                            match = pattern in text
                    if match and pattern:
                        self.table_widget.item(i, j).setBackground(Qt.yellow)
                        if (direction > 0 and (i > row or i == row and j > col)) or \
                                (direction < 0 and (i < row or i == row and j < col)):
                            self.table_widget.setCurrentCell(i, j)
                            index = matches
                        matches += 1
                    else:
                        self.table_widget.item(i,
                                               j).setBackground(Qt.transparent)
        if pattern:
            self.matches_label.setVisible(True)
            if matches > 0:
                match = matches - index if direction > 0 else index + 1
                self.matches_label.setText(
                    self.tr('match #{}/{}'.format(match, matches)))
                self.matches_label.setStyleSheet('color: #000000')
                modify_font(self.matches_label, bold=True)
            else:
                self.matches_label.setText(self.tr('not found!'))
                self.matches_label.setStyleSheet('color: #FF0000')
                modify_font(self.matches_label, italic=True)
        else:
            self.matches_label.setText('')

    def export(self):
        settings = QSettings()
        filename = QFileDialog.getSaveFileName(self,
                                               self.tr('Export metadata'),
                                               settings.value('save_folder'),
                                               self.tr('CSV files (*.csv)'))[0]
        if not filename:
            return
        if not filename.endswith('.csv'):
            filename += '.csv'
        settings.setValue('save_folder', QFileInfo(filename).absolutePath())

        rows = self.table_widget.rowCount()
        cols = self.table_widget.columnCount()
        table = [[None for _ in range(cols)] for __ in range(rows)]
        for i in range(rows):
            for j in range(cols):
                item = self.table_widget.item(i, j)
                if item is not None:
                    table[i][j] = item.text()
        with open(filename, 'w') as file:
            writer = csv.writer(file)
            writer.writerow(self.table_headers)
            writer.writerows(table)
        self.info_message.emit(self.tr('Table contents exported to disk'))

    def copy(self, item):
        QApplication.clipboard().setText(item.text())
        QToolTip.showText(QCursor.pos(),
                          self.tr('Cell contents copied to clipboard'), self,
                          QRect(), 3000)
Example #7
0
class GeneratedCurvePage(DetailsPageBase):
    def __init__(self, parent=None):
        super().__init__(parent, 'synthetic curve')
        self.gen_curve: Optional[WdGeneratedValues] = None
        self.segments_edit_semaphore = Lock()

        layout = QVBoxLayout()
        group_segments = QGroupBox('Segments')
        layout_segments = QVBoxLayout()
        layout_segments_hdr = QHBoxLayout()
        layout_segments_hdr_labels = QVBoxLayout()
        layout_segments_hdr_labels.addWidget(
            QLabel('Segments are calculated in parallel'))
        layout_segments_hdr_labels.addWidget(
            QLabel('and may have different density (PHIN)'))
        layout_segments_hdr.addLayout(layout_segments_hdr_labels)
        layout_segments_hdr.addStretch()
        self.add_segment_button = QToolButton()
        self.add_segment_button.setText('+')
        self.del_segment_button = QToolButton()
        self.del_segment_button.setText('-')
        layout_segments_hdr.addWidget(self.add_segment_button)
        layout_segments_hdr.addWidget(self.del_segment_button)
        layout_segments.addLayout(layout_segments_hdr)
        self.table_segments = QTableWidget(1, 3)
        self.table_segments.setHorizontalHeaderLabels(
            ['phase from', 'phase to', 'PHIN phase incr'])
        layout_segments.addWidget(self.table_segments)
        group_segments.setLayout(layout_segments)
        layout.addWidget(group_segments)
        self.setLayout(layout)

        self.table_segments.itemActivated.connect(self._on_segment_activated)
        self.table_segments.itemChanged.connect(self._on_segment_item_changed)
        self.add_segment_button.clicked.connect(self._on_segment_add_clicked)
        self.del_segment_button.clicked.connect(self._on_segment_del_clicked)

    def is_active_for_item(
            self, item: Optional[Container]) -> (bool, Optional[Container]):
        """Returns pair: should_be_active and item (may be e.g. parent of provided item)"""
        try:
            if isinstance(item, CurveGeneratedContainer):
                return True, item
            elif isinstance(item.parent(), CurveGeneratedContainer):
                return True, item.parent()
            else:
                return False, None
        except AttributeError:
            return False, None

    @Slot(QTableWidgetItem)
    def _on_segment_activated(self, item: QTableWidgetItem):
        self.del_segment_button.setEnabled(self.table_segments.rowCount() > 1)
        self.add_segment_button.setEnabled(
            self.table_segments.rowCount() <= 20)

    @Slot(QTableWidgetItem)
    def _on_segment_item_changed(self, item: QTableWidgetItem):
        """when user enters new value to segments table"""

        if self.segments_edit_semaphore.locked(
        ):  # item is being updated from code rather than by user
            return

        val = float(item.text())
        logger().info(f'Segment value changed: {val}')
        if item.column() == 0:
            self.gen_curve.segment_set_range(segment=item.row(),
                                             from_value=val)
        elif item.column() == 1:
            self.gen_curve.segment_set_range(segment=item.row(), to_value=val)
        elif item.column() == 2:
            self.gen_curve.segment_update_data(segment=item.row(),
                                               data={'PHIN': val})
        self.populate_segments()

    @Slot(bool)
    def _on_segment_add_clicked(self, selected: bool):
        """on delete segment button"""
        row = self.table_segments.currentRow()
        if row is None:
            return
        self.gen_curve.segment_split(row)
        self.populate_segments()

    @Slot(bool)
    def _on_segment_del_clicked(self, selected: bool):
        """on add new segment button"""
        row = self.table_segments.currentRow()
        if self.table_segments.rowCount() < 2 or row is None:
            return
        self.gen_curve.segment_delete(row)
        self.populate_segments()

    def item_changed(self, previous_item: Container):
        """when curved item for which details are displayed hve been changed"""
        super().item_changed(previous_item)
        if self.enabled:
            try:
                if isinstance(self.item.content, WdGeneratedValues):
                    self.gen_curve = self.item.content
                else:
                    self.gen_curve = None
            except AttributeError:
                self.gen_curve = None
            self.populate_segments()
        # try:
        #     df = self.item.get_df()
        # except AttributeError:
        #     df = None
        # self.pandas.setDataFrame(df)

    def populate_segments(self):
        if self.gen_curve is None:
            self.table_segments.setRowCount(0)
            return
        self.table_segments.setRowCount(self.gen_curve.segments_count())
        for n in range(self.gen_curve.segments_count()):
            start, stop = self.gen_curve.segment_range(n)
            phin = self.gen_curve.segment_get_data(n, 'PHIN')
            self.set_segment_text(n, 0, start)
            self.set_segment_text(n, 1, stop)
            self.set_segment_text(n, 2, phin)
        self.table_segments.resizeRowsToContents()

    def set_segment_text(self, row, col, txt):
        with self.segments_edit_semaphore:
            item = self.table_segments.item(row, col)
            if item is None:
                item = QTableWidgetItem()
                self.table_segments.setItem(row, col, item)
            item.setText(str(txt))
class AddRecipeWidget(QWidget):
    def __init__(self, database, parent):
        QWidget.__init__(self)
        self.recipe_ingredients = 0
        self.add_recipe_win = QWidget()
        self.add_recipe_win.setFixedWidth(400)
        self.add_recipe_win.setWindowTitle("Add Recipe")
        add_rec_main_layout = QVBoxLayout()

        self.meal_planner_db = database
        self.setParent(parent)

        self.rec_name_input = QLineEdit()
        self.rec_desc_input = QLineEdit()
        self.rec_source_input = QLineEdit()
        rec_form_layout = QFormLayout()
        rec_form_layout.addRow(QLabel("Recipe Name"), self.rec_name_input)
        rec_form_layout.addRow(QLabel("Recipe Desc"), self.rec_desc_input)
        rec_form_layout.addRow(QLabel("Recipe Source"), self.rec_source_input)
        add_rec_main_layout.addLayout(rec_form_layout)

        rec_info_layout = QHBoxLayout()
        difficulty_layout = QVBoxLayout()
        self.difficulty_spinbox = QSpinBox()
        self.difficulty_spinbox.setRange(1, 5)
        self.difficulty_spinbox.setValue(3)
        difficulty_layout.addWidget(QLabel("Difficulty"))
        difficulty_layout.addWidget(self.difficulty_spinbox)

        prep_time_layout = QVBoxLayout()
        self.prep_time_spinbox = QSpinBox()
        self.prep_time_spinbox.setRange(0, 600)
        self.prep_time_spinbox.setValue(30)
        prep_time_layout.addWidget(QLabel("Prep. Time (min.)"))
        prep_time_layout.addWidget(self.prep_time_spinbox)

        rating_layout = QVBoxLayout()
        self.rating_spinbox = QSpinBox()
        self.rating_spinbox.setRange(1, 5)
        self.rating_spinbox.setValue(3)
        rating_layout.addWidget(QLabel("Rating"))
        rating_layout.addWidget(self.rating_spinbox)

        rec_info_layout.addLayout(difficulty_layout)
        rec_info_layout.addLayout(prep_time_layout)
        rec_info_layout.addLayout(rating_layout)

        add_rec_main_layout.addLayout(rec_info_layout)

        rec_tags_layout = QHBoxLayout()
        rec_cuisine_layout = QVBoxLayout()
        cuisines = [
            "Mexican", "Swedish", "Austrian", "Italian", "Spanish", "American",
            "British", "Thai", "Greek", "Vietnamese", "Caribbean", "Japanese",
            "Chinese", "Indian", "French", "Swiss", "Portuguese", "Korean",
            "Turkish", "Moroccan", "Russian", "Malaysian", "Philippines",
            "Ethiopian", "Lebanese", "Arab", "Peruvian", "Brazilian", "Asian",
            "Middle Eastern", "South American", "African", "-"
        ]
        cuisines.sort()
        self.tag_cuisine = QComboBox()
        self.tag_cuisine.addItems(cuisines)
        rec_cuisine_layout.addWidget(QLabel("Cuisine"))
        rec_cuisine_layout.addWidget(self.tag_cuisine)
        rec_tags_layout.addLayout(rec_cuisine_layout)

        rec_category_layout = QVBoxLayout()
        categories = [
            "Beef & Calf", "Chicken & Poultry", "Lamb", "Pork", "Preservation",
            "Salad", "Sandwich", "Soup", "Stew", "Pasta", "Rice",
            "Grain & Beans", "Fish & Seafood", "Vegetables", "Eggs & Cheese",
            "BBQ", "Fruits", "Cake & Pie (Sweet)", "Pie", "Bread", "Beverage",
            "Cookies & Sweets", "Sauce", "-"
        ]
        categories.sort()
        self.tag_category = QComboBox()
        self.tag_category.addItems(categories)
        rec_category_layout.addWidget(QLabel("Category"))
        rec_category_layout.addWidget(self.tag_category)
        rec_tags_layout.addLayout(rec_category_layout)

        rec_meal_type_layout = QVBoxLayout()
        meal_types = [
            "Breakfast", "Brunch", "Lunch", "Dinner", "Dessert", "Starter",
            "Side", "Buffet", "Snack", "-"
        ]
        meal_types.sort()
        self.tag_meal_types = QComboBox()
        self.tag_meal_types.addItems(meal_types)
        rec_meal_type_layout.addWidget(QLabel("Meal Type"))
        rec_meal_type_layout.addWidget(self.tag_meal_types)
        rec_tags_layout.addLayout(rec_meal_type_layout)

        add_rec_main_layout.addLayout(rec_tags_layout)

        self.ingredient_name_input = QLineEdit()
        self.ingredient_qty_input = QDoubleSpinBox()
        self.ingredient_qty_input.setValue(1.0)
        self.ingredient_qty_input.setMaximum(1000)
        self.ingredient_qty_input.setDecimals(2)
        self.ingredient_unit_input = QComboBox()
        self.ingredient_unit_input.addItems(
            ["g", "ml", "dl", "l", "msk", "tsk", "st", "-"])
        add_ingredient_btn = QPushButton("Create ingredient")
        add_ingredient_btn.clicked.connect(self.create_ingredient)
        add_ingredient_layout = QHBoxLayout()
        add_rec_main_layout.addWidget(QLabel("Ingredient"))
        add_ingredient_layout.addWidget(self.ingredient_name_input)
        add_ingredient_layout.addWidget(self.ingredient_qty_input)
        add_ingredient_layout.addWidget(self.ingredient_unit_input)
        add_ingredient_layout.addWidget(add_ingredient_btn)
        add_rec_main_layout.addLayout(add_ingredient_layout)

        btn_layout = QHBoxLayout()
        add_ingredient_to_recipe_btn = QPushButton("Add ingredient")
        add_ingredient_to_recipe_btn.clicked.connect(
            self.add_ingredient_to_recipe)

        del_ingredient_from_recipe_btn = QPushButton("Remove ingredient")
        del_ingredient_from_recipe_btn.clicked.connect(
            self.del_ingredient_from_recipe)
        btn_layout.addWidget(add_ingredient_to_recipe_btn)
        btn_layout.addWidget(del_ingredient_from_recipe_btn)
        add_rec_main_layout.addLayout(btn_layout)

        self.rec_ingredient_table = QTableWidget()
        self.rec_ingredient_table.setColumnCount(3)
        self.rec_ingredient_table.setHorizontalHeaderLabels(
            ["Amount", "Unit", "Ingredient"])
        header = self.rec_ingredient_table.horizontalHeader()
        header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
        header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
        add_rec_main_layout.addWidget(self.rec_ingredient_table)

        self.step_count = 0
        self.add_recipe_step_btn = QPushButton("Add recipe instruction")
        add_rec_main_layout.addWidget(self.add_recipe_step_btn)
        self.add_recipe_step_btn.clicked.connect(self.add_recipe_step_win)
        self.rec_step_table = QTableWidget()
        self.rec_step_table.setColumnCount(1)
        self.rec_step_table.setHorizontalHeaderLabels(["Instructions"])
        self.rec_step_table.setWordWrap(True)
        header = self.rec_step_table.horizontalHeader()
        header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
        add_rec_main_layout.addWidget(self.rec_step_table)

        bottom_btn_layout = QHBoxLayout()
        self.add_rec_btn = QPushButton("Add recipe")
        self.add_rec_btn.clicked.connect(self.add_recipe_to_db)

        self.back_btn = QPushButton("Cancel")
        self.back_btn.clicked.connect(self.add_recipe_win.close)

        bottom_btn_layout.addWidget(self.add_rec_btn)
        bottom_btn_layout.addWidget(self.back_btn)
        add_rec_main_layout.addLayout(bottom_btn_layout)

        self.add_recipe_win.setLayout(add_rec_main_layout)
        self.add_recipe_win.show()

    @Slot()
    def add_recipe_step_win(self):
        self.rec_step_table.insertRow(self.step_count)
        self.step_count += 1

    @Slot()
    def create_ingredient(self):
        self.add_ingredient_widget = AddIngredientWidget(
            self.meal_planner_db, self, self.ingredient_name_input.text())

    @Slot()
    def add_ingredient_to_recipe(self):
        if self.meal_planner_db.ingredient_exists(
                self.ingredient_name_input.text()):
            self.rec_ingredient_table.insertRow(self.recipe_ingredients)
            self.rec_ingredient_table.setItem(
                self.recipe_ingredients, 0,
                QTableWidgetItem(str(self.ingredient_qty_input.value())))
            self.rec_ingredient_table.setItem(
                self.recipe_ingredients, 1,
                QTableWidgetItem(self.ingredient_unit_input.currentText()))
            self.rec_ingredient_table.setItem(
                self.recipe_ingredients, 2,
                QTableWidgetItem(self.ingredient_name_input.text()))
            self.recipe_ingredients += 1

            self.ingredient_name_input.clear()
            self.ingredient_qty_input.setValue(1.0)
            self.ingredient_unit_input.setCurrentIndex(0)
        else:
            print("Ingredient does not exist in database, please add it first")

    @Slot()
    def del_ingredient_from_recipe(self):
        recipe = self.rec_name_input.text()
        ingredient = self.rec_ingredient_table.currentItem().text()
        self.rec_ingredient_table.removeRow(
            self.rec_ingredient_table.currentRow())
        self.meal_planner_db.del_recipe_ingredient(recipe, ingredient)

    @Slot()
    def add_recipe_to_db(self):
        rec_id = self.meal_planner_db.get_table_len("recipes")
        self.meal_planner_db.add_recipe(rec_id, self.rec_name_input.text(),
                                        self.rec_desc_input.text(),
                                        self.rec_source_input.text(),
                                        self.difficulty_spinbox.value(),
                                        self.prep_time_spinbox.value(),
                                        self.rating_spinbox.value(),
                                        "2000-01-01", 0)

        for row in range(self.rec_ingredient_table.rowCount()):
            qty_id = self.meal_planner_db.get_table_len("measurement_qty")
            qty_id = self.meal_planner_db.add_qty(
                qty_id,
                self.rec_ingredient_table.item(row, 0).text())
            unit_id = self.meal_planner_db.get_table_len("measurement_units")
            unit_id = self.meal_planner_db.add_measurement(
                unit_id,
                self.rec_ingredient_table.item(row, 1).text())
            ing_id = self.meal_planner_db.get_ingredient_id(
                self.rec_ingredient_table.item(row, 2).text())
            if ing_id == -1:
                print("INGREDIENT DOES NOT EXIST! WE F****D UP!")
                break
            self.meal_planner_db.add_recipe_ingredient(rec_id, ing_id, unit_id,
                                                       qty_id)

        for row in range(self.step_count):
            print(row, self.rec_step_table.item(row, 0).text())
            self.meal_planner_db.add_step(
                rec_id, row,
                self.rec_step_table.item(row, 0).text())

        # Cuisine tag
        tag_id = self.meal_planner_db.get_table_len("tags")
        tag_id = self.meal_planner_db.add_tag(tag_id,
                                              self.tag_cuisine.currentText())
        self.meal_planner_db.add_recipe_tag(tag_id, rec_id)
        # Category tag
        tag_id = self.meal_planner_db.get_table_len("tags")
        tag_id = self.meal_planner_db.add_tag(tag_id,
                                              self.tag_category.currentText())
        self.meal_planner_db.add_recipe_tag(tag_id, rec_id)
        # Meal type tag
        tag_id = self.meal_planner_db.get_table_len("tags")
        tag_id = self.meal_planner_db.add_tag(
            tag_id, self.tag_meal_types.currentText())
        self.meal_planner_db.add_recipe_tag(tag_id, rec_id)

        self.rec_name_input.clear()
        self.rec_desc_input.clear()
        self.rec_ingredient_table.setRowCount(0)
        self.rec_step_table.setRowCount(0)
        self.step_count = 0

        self.parent().update_recipe_table()
Example #9
0
class GameControlPanel(QWidget):
    def __init__(self, first: str, second: str, parent=None):
        super(GameControlPanel, self).__init__(parent)

        # buttons on the top
        self.flipButton = QPushButton("*")
        self.toStartFenButton = QPushButton("<<")
        self.previousMoveButton = QPushButton("<")
        self.nextMoveButton = QPushButton(">")
        self.toCurrentFenButton = QPushButton(">>")

        self.flipButton.setFixedWidth(45)
        self.toStartFenButton.setFixedWidth(45)
        self.previousMoveButton.setFixedWidth(45)
        self.nextMoveButton.setFixedWidth(45)
        self.toStartFenButton.setFixedWidth(45)

        self.toStartFenButton.setDisabled(True)
        self.previousMoveButton.setDisabled(True)
        self.nextMoveButton.setDisabled(True)
        self.toCurrentFenButton.setDisabled(True)

        self.toolButtonsLayout = QHBoxLayout()
        self.toolButtonsLayout.setContentsMargins(0, 0, 0, 0)
        self.toolButtonsLayout.addWidget(self.flipButton)
        self.toolButtonsLayout.addWidget(self.toStartFenButton)
        self.toolButtonsLayout.addWidget(self.previousMoveButton)
        self.toolButtonsLayout.addWidget(self.nextMoveButton)
        self.toolButtonsLayout.addWidget(self.toCurrentFenButton)
        self.toolButtonsLayout.addStretch()
        self.toolButtonsLayout.setSpacing(14)

        # the column that contains the first empty cell.
        self.nextColumn = 0

        self.firstMaterial = QLabel()
        self.firstName = QLabel(first)
        self.secondName = QLabel(second)
        self.secondMaterial = QLabel()

        self.moveTable = QTableWidget()
        self.moveTable.setEditTriggers(QTableWidget.NoEditTriggers)
        self.moveTable.setFocusPolicy(Qt.NoFocus)
        self.moveTable.setSelectionMode(QTableWidget.SingleSelection)
        self.moveTable.currentCellChanged.connect(self.onCurrentChanged)
        self.moveTable.setFixedWidth(320)
        self.moveTable.setColumnCount(2)
        self.moveTable.horizontalHeader().hide()

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)

        layout.addStretch()
        layout.addWidget(self.firstMaterial)
        layout.addLayout(self.toolButtonsLayout)
        layout.addWidget(self.firstName)
        layout.addWidget(self.moveTable)
        layout.addWidget(self.secondName)
        layout.addWidget(self.secondMaterial)
        layout.addStretch()
        layout.setSpacing(0)

        self.setLayout(layout)

    def isLive(self) -> bool:
        if not self.moveTable.rowCount():
            return True
        return (self.moveTable.currentRow() == self.moveTable.rowCount() - 1 and
                self.moveTable.currentColumn() != self.nextColumn)

    def reset(self):
        self.moveTable.setRowCount(0)
        self.nextColumn = 0
        self.toStartFenButton.setDisabled(True)
        self.previousMoveButton.setDisabled(True)
        self.nextMoveButton.setDisabled(True)
        self.toCurrentFenButton.setDisabled(True)

    @Slot(int, int)
    def onCurrentChanged(self, row, column):
        self.toStartFenButton.setDisabled(self.moveTable.currentItem() is None)
        self.previousMoveButton.setDisabled(self.moveTable.currentItem() is None)

    def toPreviousCell(self):
        current = self.moveTable.currentItem()

        if current is not None:
            row = current.row()
            column = current.column()

            if row == column == 0:
                self.moveTable.setCurrentCell(-1, -1)
            else:
                prevCoord = row * 2 + column - 1
                if prevCoord % 2:
                    row -= 1

                self.moveTable.setCurrentCell(row, not column)

    def toNextCell(self):
        current = self.moveTable.currentItem()

        if self.moveTable.rowCount():
            if current is None:
                self.moveTable.setCurrentCell(0, 0)
            else:
                row = current.row()
                column = current.column()

                nextCoord = row * 2 + column + 1
                if nextCoord % 2 == 0:
                    row += 1

                self.moveTable.setCurrentCell(row, not column)

    def addMove(self, move: str) -> QTableWidgetItem:
        if self.isLive():
            if not self.nextColumn:
                self.moveTable.setRowCount(self.moveTable.rowCount() + 1)

        item = QTableWidgetItem(move)
        self.moveTable.setItem(self.moveTable.rowCount()-1, self.nextColumn, item)

        self.nextColumn = not self.nextColumn

        return item

    def popMove(self):
        if self.moveTable.rowCount():
            if self.isLive():
                self.toPreviousCell()

            self.nextColumn = not self.nextColumn

            self.moveTable.takeItem(self.moveTable.rowCount() - 1, self.nextColumn)

            if not self.nextColumn:
                self.moveTable.setRowCount(self.moveTable.rowCount()-1)

    def swapNames(self):
        tempFirstMaterial = self.firstMaterial.text()
        tempFirstName = self.firstName.text()

        self.firstMaterial.setText(self.secondMaterial.text())
        self.secondMaterial.setText(tempFirstMaterial)
        self.firstName.setText(self.secondName.text())
        self.secondName.setText(tempFirstName)
class IssuesTab(QWidget):
    def __init__(self, parent):
        QWidget.__init__(self)
        self.Parent = parent

        self.IssueTitle = 'ISSUES'

        self.UI()

    @property
    def Title(self):
        return self.IssueTitle

    def UI(self):
        self.widgets()
        self.layouts()
        self.funcDisplayIssues()

    def widgets(self):
        # Issues widgets ###########################################################
        # Top layout (search issues) widgets
        self.searchIssuesText = QLabel("Search: ")
        self.searchIssuesEntry = QLineEdit()
        self.searchIssuesEntry.setPlaceholderText("Search issues..")
        self.searchIssuesBtn = QPushButton("Search")
        self.searchIssuesBtn.setObjectName("btn_searchIssues")
        self.searchIssuesBtn.clicked.connect(self.funcSearchIssues)
        self.refreshIssuesBtn = QPushButton("Refresh")
        self.refreshIssuesBtn.clicked.connect(self.funcDisplayIssues)

        # Middle layout (list issues) widgets with radio buttons
        self.allIssuesRadioBtn = QRadioButton("All issues")
        self.ongoingIssuesRadioBtn = QRadioButton("Pending issues")
        self.lateIssuesRadioBtn = QRadioButton("Late issues")
        self.closedIssuesRadioBtn = QRadioButton("Closed issues")
        self.listIssuesBtn = QPushButton("List")
        self.listIssuesBtn.setObjectName("btn_listIssues")
        self.listIssuesBtn.clicked.connect(self.funcListIssues)

        # Bottom layout widget
        # Table showing issues
        self.issuesTable = QTableWidget()
        self.issuesTable.verticalHeader().hide()
        self.issuesTable.setSortingEnabled(True)
        self.issuesTable.setShowGrid(False)
        self.issuesTable.verticalHeader().setDefaultSectionSize(90)
        self.issuesTable.setColumnCount(13)

        self.issuesTable.setHorizontalHeaderItem(0, QTableWidgetItem(""))
        self.issuesTable.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        self.issuesTable.setHorizontalHeaderItem(1, QTableWidgetItem("Status"))
        self.issuesTable.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents)
        self.issuesTable.setHorizontalHeaderItem(2, QTableWidgetItem("ID"))
        self.issuesTable.setHorizontalHeaderItem(3, QTableWidgetItem("Date"))
        self.issuesTable.setHorizontalHeaderItem(4, QTableWidgetItem("Priority"))
        self.issuesTable.setHorizontalHeaderItem(5, QTableWidgetItem("Observer"))
        self.issuesTable.horizontalHeader().setSectionResizeMode(5, QHeaderView.Stretch)
        self.issuesTable.setHorizontalHeaderItem(6, QTableWidgetItem("Inspection name"))
        self.issuesTable.horizontalHeader().setSectionResizeMode(6, QHeaderView.Stretch)
        self.issuesTable.setHorizontalHeaderItem(7, QTableWidgetItem("Theme"))
        self.issuesTable.horizontalHeader().setSectionResizeMode(7, QHeaderView.Stretch)
        self.issuesTable.setHorizontalHeaderItem(8, QTableWidgetItem("Facility"))
        self.issuesTable.setHorizontalHeaderItem(9, QTableWidgetItem("Insp. Dept"))
        self.issuesTable.setHorizontalHeaderItem(10, QTableWidgetItem("Deadline"))
        self.issuesTable.setHorizontalHeaderItem(11, QTableWidgetItem("Status"))
        self.issuesTable.setHorizontalHeaderItem(12, QTableWidgetItem("Created on"))

        # Double clicking a row opens a window with issue details
        self.issuesTable.doubleClicked.connect(self.funcSelectedIssue)

        # Buttons for actions on selected issues
        self.addIssue = QPushButton("Add")
        self.addIssue.setObjectName("btn_addIssue")
        self.addIssue.clicked.connect(self.funcAddIssue)
        self.viewIssue = QPushButton("View/Edit")
        self.viewIssue.setObjectName("btn_viewIssue")
        self.viewIssue.clicked.connect(self.funcSelectedIssue)
        self.closeIssueBtn = QPushButton("Close")
        self.closeIssueBtn.setObjectName("btn_closeIssue")
        self.closeIssueBtn.clicked.connect(self.funcCloseIssue)
        self.deleteIssue = QPushButton("Delete")
        self.deleteIssue.setObjectName("btn_deleteIssue")
        self.deleteIssue.clicked.connect(self.funcDeleteIssue)

        self.exportIssuesCSVBtn = QPushButton("Export CSV")
        self.exportIssuesCSVBtn.setEnabled(False)
        self.exportIssuesCSVBtn.setObjectName("btn_exportIssuesCSV")
        self.exportIssuesCSVBtn.clicked.connect(self.funcIssuesToCSV)

        self.exportIssuesXLSXBtn = QPushButton("Export XLSX")
        self.exportIssuesXLSXBtn.setEnabled(False)
        self.exportIssuesXLSXBtn.setObjectName("btn_exportIssuesXLSX")
        self.exportIssuesXLSXBtn.clicked.connect(self.funcIssuestoXLSX)

        self.exportIssuesPDFBtn = QPushButton("Export PDF")
        self.exportIssuesPDFBtn.setEnabled(False)
        self.exportIssuesPDFBtn.setObjectName("btn_exportIssuesPDF")
        self.exportIssuesPDFBtn.clicked.connect(self.funcIssuesToPdf)

    def layouts(self):
        # Issues layouts ###########################################################
        self.issuesMainLayout = QVBoxLayout()
        self.issuesMainTopLayout = QHBoxLayout()
        self.issuesTopLeftLayout = QHBoxLayout()
        self.issuesTopRightLayout = QHBoxLayout()
        # self.issuesMainMiddleLayout = QHBoxLayout()
        self.issuesMainBottomLayout = QHBoxLayout()
        self.issuesBottomRightLayout = QVBoxLayout()
        self.issuesBottomLeftLayout = QHBoxLayout()
        # Groupboxes allow customization using CSS-like syntax
        # self.issuesTopGroupBox = QGroupBox()
        # self.issuesTopGroupBoxRightFiller = QGroupBox()
        # self.issuesTopGroupBoxRightFiller.setStyleSheet(styles.groupBoxFillerStyle())
        #
        # self.issuesMiddleGroupBox = QGroupBox()
        # self.issuesMiddleGroupBoxRightFiller = QGroupBox()
        # self.issuesMiddleGroupBoxRightFiller.setStyleSheet(styles.groupBoxFillerStyle())

        self.issuesTopLeftGroupBox = QGroupBox()
        self.issuesTopRightGroupBox = QGroupBox()
        self.issuesTopGroupBox = QGroupBox()

        self.issuesBottomGroupBox = QGroupBox()
        self.issuesBottomLeftGroupBox = QGroupBox()
        self.issuesBottomRightGroupBox = QGroupBox()
        self.issuesBottomRightGroupBox.setStyleSheet('QGroupBox {margin-top: 0px;}')
        self.issuesBottomRightGroupBoxFiller = QGroupBox()
        self.issuesBottomRightGroupBoxFiller.setStyleSheet(styles.groupBoxFillerStyle())

        # Add widgets
        # Top layout (search box) widgets
        self.issuesTopLeftLayout.addWidget(self.searchIssuesText, 10)
        self.issuesTopLeftLayout.addWidget(self.searchIssuesEntry, 30)
        self.issuesTopLeftLayout.addWidget(self.searchIssuesBtn, 10)
        self.issuesTopLeftLayout.addItem(QSpacerItem(70, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))
        self.issuesTopLeftLayout.addWidget(self.refreshIssuesBtn, 10)
        self.issuesTopLeftGroupBox.setLayout(self.issuesTopLeftLayout)

        # layout (list box) widgets
        self.issuesTopRightLayout.addWidget(self.allIssuesRadioBtn)
        self.issuesTopRightLayout.addWidget(self.ongoingIssuesRadioBtn)
        self.issuesTopRightLayout.addWidget(self.lateIssuesRadioBtn)
        self.issuesTopRightLayout.addWidget(self.closedIssuesRadioBtn)
        self.issuesTopRightLayout.addWidget(self.listIssuesBtn)
        self.issuesTopRightGroupBox.setLayout(self.issuesTopRightLayout)

        self.issuesMainTopLayout.addWidget(self.issuesTopLeftGroupBox, 60)
        self.issuesMainTopLayout.addWidget(self.issuesTopRightGroupBox, 40)

        # Bottom layout (table with facilities) widgets
        # Bottom left layout with table
        self.issuesBottomLeftLayout.addWidget(self.issuesTable)
        self.issuesBottomLeftGroupBox.setLayout(self.issuesBottomLeftLayout)

        # Bottom right layout with buttons
        self.issuesBottomRightLayout.addWidget(self.addIssue, 5)
        self.issuesBottomRightLayout.addWidget(self.viewIssue, 5)
        self.issuesBottomRightLayout.addWidget(self.closeIssueBtn, 5)
        self.issuesBottomRightLayout.addWidget(self.deleteIssue, 5)
        self.issuesBottomRightLayout.addWidget(self.issuesBottomRightGroupBoxFiller, 65)
        self.issuesBottomRightLayout.addWidget(self.exportIssuesCSVBtn, 5)
        self.issuesBottomRightLayout.addWidget(self.exportIssuesXLSXBtn, 5)
        self.issuesBottomRightLayout.addWidget(self.exportIssuesPDFBtn, 5)
        self.issuesBottomRightGroupBox.setLayout(self.issuesBottomRightLayout)

        self.issuesMainBottomLayout.addWidget(self.issuesTable, 90)
        self.issuesMainBottomLayout.addWidget(self.issuesBottomRightGroupBox, 10)

        self.issuesMainLayout.addLayout(self.issuesMainTopLayout, 10)
        self.issuesMainLayout.addLayout(self.issuesMainBottomLayout, 90)

        self.setLayout(self.issuesMainLayout)

    # Populating the table
    @Slot()
    def funcDisplayIssues(self):
        for i in reversed(range(self.issuesTable.rowCount())):
            self.issuesTable.removeRow(i)

        issues = db.cur.execute("SELECT "
                                "issue_id, "
                                "issue_date, "
                                "issue_priority, "
                                "issue_observer,"
                                "issue_inspection, "
                                "issue_theme, "
                                "issue_facility, "
                                "issue_insp_dept,"
                                "issue_deadline, "
                                "status, "
                                "created_on "
                                "FROM issues")

        for row_data in issues:
            row_number = self.issuesTable.rowCount()
            self.issuesTable.insertRow(row_number)
            # Add checkboxes to the table
            qwidget = QWidget()
            checkbox = QCheckBox()
            checkbox.setCheckState(Qt.Unchecked)
            checkbox.stateChanged.connect(self.funcActivateBtnsWithCheckbox)
            qhboxlayout = QHBoxLayout(qwidget)
            qhboxlayout.addWidget(checkbox)
            qhboxlayout.setAlignment(Qt.AlignCenter)
            self.issuesTable.setCellWidget(row_number, 0, qwidget)
            self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number))
            # Add status photos_thumbnails to the table
            thumbStatusWidget = QWidget()
            # Assign proper status thumbnails based on deadline
            if row_data[9] == "Closed":
                pic = QPixmap('assets/icons/issue_icons/issue_closed_icon.png')
            elif row_data[8] > str(datetime.datetime.now()):
                pic = QPixmap('assets/icons/issue_icons/issue_pending_icon.png')
            elif row_data[8] < str(datetime.datetime.now()):
                pic = QPixmap('assets/icons/issue_icons/issue_late_icon.png')

            thumbStatusLabel = QLabel()
            thumbStatusLabel.setPixmap(pic)
            thumbStatusLayout = QHBoxLayout(thumbStatusWidget)
            thumbStatusLayout.addWidget(thumbStatusLabel)
            self.issuesTable.setCellWidget(row_number, 1, thumbStatusWidget)
            self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number))

            thumbPriorityWidget = QWidget()
            # Assign priority thumbnails
            if row_data[2] == "Low":
                pic = QPixmap('assets/icons/issue_priority_icons/low_priority.png')
            elif row_data[2] == "Medium":
                pic = QPixmap('assets/icons/issue_priority_icons/medium_priority.png')
            elif row_data[2] == "High":
                pic = QPixmap('assets/icons/issue_priority_icons/high_priority.png')

            thumbPriorityLabel = QLabel()
            thumbPriorityLabel.setAlignment(Qt.AlignCenter)
            thumbPriorityLabel.setPixmap(pic)
            thumbPriorityLayout = QHBoxLayout(thumbPriorityWidget)
            thumbPriorityLayout.addWidget(thumbPriorityLabel)
            self.issuesTable.setCellWidget(row_number, 4, thumbPriorityWidget)
            self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number))

            for column_number, data in enumerate(row_data, start=2):
                if column_number == 2:
                    self.issuesTable.setItem(row_number, column_number, QTableWidgetItem("ISS#" + str(data)))
                elif column_number == 4:
                    # Do not print priority in the table
                    self.issuesTable.setItem(row_number, column_number, QTableWidgetItem(""))
                else:
                    self.issuesTable.setItem(row_number, column_number, QTableWidgetItem(str(data)))

        self.issuesTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.issuesTable.setSelectionBehavior(QTableView.SelectRows)

    @Slot()
    def funcActivateBtnsWithCheckbox(self):
        indices = self.funcIssuesCheckBox()

        if self.sender().isChecked() or indices:
            self.exportIssuesCSVBtn.setEnabled(True)
            self.exportIssuesXLSXBtn.setEnabled(True)
            self.exportIssuesPDFBtn.setEnabled(True)
        else:
            self.exportIssuesCSVBtn.setEnabled(False)
            self.exportIssuesXLSXBtn.setEnabled(False)
            self.exportIssuesPDFBtn.setEnabled(False)

    @Slot()
    def funcAddIssue(self):
        self.newIssue = AddIssue(self)
        self.newIssue.setObjectName("add_issue_popup")
        self.newIssue.setStyleSheet(styles.addPopups())

    @Slot()
    def funcIssuesCheckBox(self):
        checked_list = []
        for i in range(self.issuesTable.rowCount()):
            if self.issuesTable.cellWidget(i, 0).findChild(type(QCheckBox())).isChecked():
                item = self.issuesTable.item(i, 2).text()
                checked_list.append(item.lstrip("ISS#"))
        return checked_list


    @Slot()
    def funcSelectedIssue(self):
        self.displayIssue = DisplayIssue(self)

    @Slot()
    def funcSearchIssues(self):
        value = self.searchIssuesEntry.text()
        if value == "":
            QMessageBox.information(self, "Warning", "Search string cannot be empty")
            self.funcDisplayIssues()
        else:
            # Erase search entry
            self.searchIssuesEntry.setText("")
            try:
                query = "SELECT * FROM issues WHERE " \
                        "issue_id LIKE ? " \
                        "OR issue_date LIKE ?" \
                        "OR issue_priority LIKE ?" \
                        "OR issue_observer LIKE ?" \
                        "OR issue_team LIKE ?" \
                        "OR issue_inspection LIKE ?" \
                        "OR issue_theme LIKE ?" \
                        "OR issue_facility LIKE ?" \
                        "OR issue_fac_supervisor LIKE ?" \
                        "OR issue_spec_loc LIKE ?" \
                        "OR issue_insp_dept LIKE ?" \
                        "OR issue_insp_contr LIKE ?" \
                        "OR issue_insp_subcontr LIKE ?" \
                        "OR issue_deadline LIKE ?"
                results = db.cur.execute(query,
                                         ('%' + value + '%', '%' + value + '%',
                                          '%' + value + '%', '%' + value + '%',
                                          '%' + value + '%', '%' + value + '%',
                                          '%' + value + '%', '%' + value + '%',
                                          '%' + value + '%', '%' + value + '%',
                                          '%' + value + '%', '%' + value + '%',
                                          '%' + value + '%', '%' + value + '%',)).fetchall()
                if results == []:
                    QMessageBox.information(self, "Info", "Nothing was found")
                    self.funcDisplayIssues()
                else:
                    for i in reversed(range(self.issuesTable.rowCount())):
                        self.issuesTable.removeRow(i)

                    for row_data in results:
                        row_number = self.issuesTable.rowCount()
                        self.issuesTable.insertRow(row_number)
                        # Add checkboxes to the table
                        qwidget = QWidget()
                        checkbox = QCheckBox()
                        checkbox.setCheckState(Qt.Unchecked)
                        qhboxlayout = QHBoxLayout(qwidget)
                        qhboxlayout.addWidget(checkbox)
                        qhboxlayout.setAlignment(Qt.AlignCenter)
                        self.issuesTable.setCellWidget(row_number, 0, qwidget)
                        self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number))
                        for column_number, data in enumerate(row_data, start=1):
                            if column_number == 1:
                                self.issuesTable.setItem(row_number, column_number,
                                                         QTableWidgetItem("ISS#" + str(data)))
                            else:
                                self.issuesTable.setItem(row_number, column_number, QTableWidgetItem(str(data)))
            except:
                QMessageBox.information(self, "Info", "Cannot access database")

    @Slot()
    def funcListIssues(self):
        try:
            if self.allIssuesRadioBtn.isChecked():
                self.funcDisplayIssues()
            elif self.ongoingIssuesRadioBtn.isChecked():
                query = "SELECT " \
                        "issue_id, " \
                        "issue_date, " \
                        "issue_priority, " \
                        "issue_observer," \
                        "issue_inspection, " \
                        "issue_theme, " \
                        "issue_facility, " \
                        "issue_insp_dept," \
                        "issue_deadline, " \
                        "status, " \
                        "created_on " \
                        "FROM issues WHERE status='Open' " \
                        "AND issue_deadline > DATETIME('now')"
                issues = db.cur.execute(query).fetchall()

                for i in reversed(range(self.issuesTable.rowCount())):
                    self.issuesTable.removeRow(i)

                for row_data in issues:
                    row_number = self.issuesTable.rowCount()
                    self.issuesTable.insertRow(row_number)
                    # Add checkboxes to the table
                    qwidget = QWidget()
                    checkbox = QCheckBox()
                    checkbox.setCheckState(Qt.Unchecked)
                    qhboxlayout = QHBoxLayout(qwidget)
                    qhboxlayout.addWidget(checkbox)
                    qhboxlayout.setAlignment(Qt.AlignCenter)
                    self.issuesTable.setCellWidget(row_number, 0, qwidget)
                    self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number))
                    for column_number, data in enumerate(row_data, start=1):
                        if column_number == 1:
                            self.issuesTable.setItem(row_number, column_number,
                                                     QTableWidgetItem("ISS#" + str(data)))
                        else:
                            self.issuesTable.setItem(row_number, column_number, QTableWidgetItem(str(data)))
            elif self.lateIssuesRadioBtn.isChecked():
                query = "SELECT issue_id, " \
                        "issue_date, " \
                        "issue_priority, " \
                        "issue_observer," \
                        "issue_inspection, " \
                        "issue_theme, " \
                        "issue_facility, " \
                        "issue_insp_dept," \
                        "issue_deadline, " \
                        "status, " \
                        "created_on " \
                        "FROM issues " \
                        "WHERE status='Open' AND issue_deadline < DATETIME('now')"
                issues = db.cur.execute(query).fetchall()

                for i in reversed(range(self.issuesTable.rowCount())):
                    self.issuesTable.removeRow(i)

                for row_data in issues:
                    row_number = self.issuesTable.rowCount()
                    self.issuesTable.insertRow(row_number)
                    # Add checkboxes to the table
                    qwidget = QWidget()
                    checkbox = QCheckBox()
                    checkbox.setCheckState(Qt.Unchecked)
                    qhboxlayout = QHBoxLayout(qwidget)
                    qhboxlayout.addWidget(checkbox)
                    qhboxlayout.setAlignment(Qt.AlignCenter)
                    self.issuesTable.setCellWidget(row_number, 0, qwidget)
                    self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number))
                    for column_number, data in enumerate(row_data, start=1):
                        if column_number == 1:
                            self.issuesTable.setItem(row_number, column_number,
                                                     QTableWidgetItem("ISS#" + str(data)))
                        else:
                            self.issuesTable.setItem(row_number, column_number, QTableWidgetItem(str(data)))
            elif self.closedIssuesRadioBtn.isChecked():
                query = "SELECT " \
                        "issue_id, " \
                        "issue_date, " \
                        "issue_priority, " \
                        "issue_observer," \
                        "issue_inspection, " \
                        "issue_theme, " \
                        "issue_facility, " \
                        "issue_insp_dept," \
                        "issue_deadline, " \
                        "status, " \
                        "created_on " \
                        "FROM issues WHERE status='Closed'"
                issues = db.cur.execute(query).fetchall()

                for i in reversed(range(self.issuesTable.rowCount())):
                    self.issuesTable.removeRow(i)

                for row_data in issues:
                    row_number = self.issuesTable.rowCount()
                    self.issuesTable.insertRow(row_number)
                    # Add checkboxes to the table
                    qwidget = QWidget()
                    checkbox = QCheckBox()
                    checkbox.setCheckState(Qt.Unchecked)
                    qhboxlayout = QHBoxLayout(qwidget)
                    qhboxlayout.addWidget(checkbox)
                    qhboxlayout.setAlignment(Qt.AlignCenter)
                    self.issuesTable.setCellWidget(row_number, 0, qwidget)
                    self.issuesTable.setItem(row_number, 0, QTableWidgetItem(row_number))
                    for column_number, data in enumerate(row_data, start=1):
                        if column_number == 1:
                            self.issuesTable.setItem(row_number, column_number,
                                                     QTableWidgetItem("ISS#" + str(data)))
                        else:
                            self.issuesTable.setItem(row_number, column_number, QTableWidgetItem(str(data)))
        except:
            QMessageBox.information(self, "Info", "Cannot access database")

    @Slot()
    def funcCloseIssue(self):
        indices = self.funcIssuesCheckBox()
        # Close issues with selected checkboxes
        if indices:
            try:
                for index in range(len(indices)):
                    statusQuery = "SELECT status FROM issues WHERE issue_id=?"
                    currentStatus = db.cur.execute(statusQuery, (indices[index],)).fetchone()

                    if currentStatus[0] == "Open":
                        query = "UPDATE issues SET status='Closed' WHERE issue_id=?"

                        db.cur.execute(query, (indices[index],))
                        db.conn.commit()
                    else:
                        QMessageBox.information(self, "Info", "Issue(s) is already closed")

                QMessageBox.information(self, "Info", "Operation completed successfully")
                self.funcDisplayIssues()

            except:
                QMessageBox.information(self, "Info", "Something went wrong")
        else:
            row = self.issuesTable.currentRow()
            issueId = self.issuesTable.item(row, 2).text()
            issueId = issueId.lstrip("ISS#")

            try:
                statusQuery = "SELECT status FROM issues WHERE issue_id=?"
                currentStatus = db.cur.execute(statusQuery, (issueId,)).fetchone()

                if currentStatus[0] == "Open":
                    query = "UPDATE issues SET status='Closed' WHERE issue_id=?"

                    db.cur.execute(query, (issueId,))
                    db.conn.commit()

                    QMessageBox.information(self, "Info", "Issue closed successfully")
                    self.funcDisplayIssues()
                else:
                    QMessageBox.information(self, "Info", "Issue is already closed")

            except:
                QMessageBox.information(self, "Info", "Something went wrong")

    @Slot()
    def funcDeleteIssue(self):
        indices = self.funcIssuesCheckBox()

        mbox = QMessageBox.question(self, "Warning", "Are you sure you want to delete selected issue(s)?",
                                    QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel)

        if (mbox == QMessageBox.Yes):
            if indices:
                try:
                    for index in range(len(indices)):
                        query = "DELETE FROM issues WHERE issue_id = ?"

                        db.cur.execute(query, (indices[index],))
                        db.conn.commit()

                    QMessageBox.information(self, "Info", "Issues were deleted")
                    self.funcDisplayIssues()
                except:
                    QMessageBox.information(self, "Info", "No changes made")
            else:
                row = self.issuesTable.currentRow()
                issueId = self.issuesTable.item(row, 2).text()
                issueId = issueId.lstrip("ISS#")
                try:
                    query = "DELETE FROM issues WHERE issue_id = ?"

                    db.cur.execute(query, (issueId,))
                    db.conn.commit()

                    QMessageBox.information(self, "Info", "Issue was deleted")
                    self.funcDisplayIssues()
                except:
                    QMessageBox.information(self, "Info", "No changes made")

            self.displayIssue.close()

    @Slot()
    def funcIssuesToCSV(self):
        indices = self.funcIssuesCheckBox()

        if indices:
            CSV(self, "issues", indices)
        else:
            QMessageBox.information(
                self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export")


    @Slot()
    def funcIssuestoXLSX(self):
        indices = self.funcIssuesCheckBox()

        if indices:
            try:
                date = datetime.datetime.now()

                # Get file location and add timestamp to when it was created to the filename
                fileName, _ = QFileDialog.getSaveFileName(
                    self, "Save as...", "~/IssuesXLSX" + "{:%d%b%Y_%Hh%Mm}".format(date) + ".xlsx",
                    "Excel files (*.xlsx)")
                if fileName:
                    db.cur.execute("SELECT * FROM issues")

                    workbook = xlsxwriter.Workbook(fileName)
                    worksheet = workbook.add_worksheet("Issues")
                    worksheet.set_column('A:C', 12)
                    worksheet.set_row(0, 30)
                    merge_format = workbook.add_format({
                        'bold': 1,
                        'align': 'center',
                        'valign': 'vcenter'})
                    worksheet.merge_range('A1:B1', '', merge_format)
                    worksheet.insert_image('A1', './assets/logo/logo-full-main.png',
                                           {'x_scale': 0.4, 'y_scale': 0.4, 'x_offset': 15, 'y_offset': 10})

                    # Create header row
                    stop = 17
                    col = 0
                    for i, value in enumerate(db.cur.description[:stop]):
                        worksheet.write(1, col, value[0])
                        col += 1

                    # Write data to xlsx file
                    row_number = 2
                    for index in range(len(indices)):
                        query = "SELECT * FROM issues WHERE issue_id=?"
                        issue_record = db.cur.execute(query, (indices[index],)).fetchone()
                        for i, value in enumerate(issue_record[:stop]):
                            if issue_record[18]:
                                worksheet.set_row(row_number, 185)
                                worksheet.set_column(17, 17, 35)
                                worksheet.insert_image(
                                    row_number, 17, issue_record[18],
                                    {'x_scale': 0.3, 'y_scale': 0.3})
                            worksheet.write(row_number, i, value)
                        row_number += 1

                    workbook.close()

                    QMessageBox.information(self, "Info", "Data exported successfully into {}".format(fileName))
            except:
                QMessageBox.information(self, "Info", "Export failed")
        else:
            QMessageBox.information(
                self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export")

    @Slot()
    def funcIssuesToPdf(self):
        indices = self.funcIssuesCheckBox()

        if indices:
            try:
                date = datetime.datetime.now()

                # Get file location and add timestamp it was created on to the filename
                fileName, _ = QFileDialog.getSaveFileName(
                    self, "Save as...", "~/IssuesPDF" + "{:%d%b%Y_%Hh%Mm}".format(date) + ".pdf",
                    "PDF files (*.pdf)")

                if fileName:
                    pdf = PDF()
                    pdf.add_page()
                    pdf.set_font('Arial', 'B', 13)

                    for index in range(len(indices)):
                        query = "SELECT * FROM issues WHERE issue_id=?"
                        issue_record = db.cur.execute(query, (indices[index],)).fetchone()

                        # This string allows for text formatting in the pdf, easy to implement and test
                        stringIssue = "\nIssue id: " + str(issue_record[0]) + \
                                      "\nIssue date: " + str(issue_record[1]) + \
                                      "\nPriority: " + str(issue_record[2]) + \
                                      "\nObserver: " + str(issue_record[3]) + \
                                      "\nRevision team: " + str(issue_record[4]) + \
                                      "\nInspection name: " + str(issue_record[5]) + \
                                      "\nHSE theme: " + str(issue_record[6]) + \
                                      "\nFacility: " + str(issue_record[7]) + \
                                      "\nFacility supervisor: " + str(issue_record[8]) + \
                                      "\nSpecific location: " + str(issue_record[9]) + \
                                      "\nInspected department: " + str(issue_record[10]) + \
                                      "\nInspected contractor: " + str(issue_record[11]) + \
                                      "\nInspected subcontractor: " + str(issue_record[12]) + \
                                      "\nDeadline: " + str(issue_record[13]) + \
                                      "\nStatus: " + str(issue_record[14]) + \
                                      "\nCreated on: " + str(issue_record[15]) + \
                                      "\nClosed on: " + str(issue_record[16])

                        effectivePageWidth = pdf.w - 2 * pdf.l_margin

                        ybefore = pdf.get_y()
                        pdf.multi_cell(effectivePageWidth / 2, 10, stringIssue)

                        if issue_record[18]:
                            pdf.set_xy(effectivePageWidth / 2 + pdf.l_margin, ybefore)
                            pdf.image(issue_record[18], effectivePageWidth / 2 + 20, 40, w=70)
                        pdf.ln(0.5)

                        # Page break is achieved by adding a new page
                        # after all items except for the last one
                        if index != (len(indices) - 1):
                            pdf.add_page()

                    pdf.output(fileName, 'F')

                    QMessageBox.information(self, "Info", "Data exported successfully into {}".format(fileName))

            except:
                QMessageBox.information(self, "Info", "Export failed")
        else:
            QMessageBox.information(
                self, "Info", "Nothing selected for export\nUse checkboxes to select issues to export")
class FacilityTab(QWidget):
    def __init__(self, parent):
        QWidget.__init__(self)
        self.Parent = parent

        self.FcltyTitle = 'FACILITIES'

        self.UI()

    @property
    def Title(self):
        return self.FcltyTitle

    def UI(self):
        self.widgets()
        self.layouts()
        self.funcDisplayFacilities()

    def widgets(self):
        # Facilities widgets ###########################################################
        # Top layout (search facilities) widgets
        self.searchFacilitiesText = QLabel("Search: ")
        self.searchFacilitesEntry = QLineEdit()
        self.searchFacilitesEntry.setPlaceholderText("Search facilities..")
        self.searchFacilitiesBtn = QPushButton("Search")
        self.searchFacilitiesBtn.clicked.connect(self.funcSearchFacilities)
        self.refreshFacilitiesBtn = QPushButton("Refresh")
        self.refreshFacilitiesBtn.clicked.connect(self.funcDisplayFacilities)

        # Middle layout (list people) widgets with radio buttons
        self.allFacilitiesRadioBtn = QRadioButton("All facilities")
        self.withOngoingIssuesFacilitiesRadioBtn = QRadioButton(
            "With pending issues")
        self.withLateIssuesRadioBtn = QRadioButton("With late issues")
        self.listFacilitiesBtn = QPushButton("List")

        # Bottom layout widget, a table showing people
        self.facilitiesTable = QTableWidget()
        self.facilitiesTable.verticalHeader().hide()
        self.facilitiesTable.setSortingEnabled(True)
        self.facilitiesTable.setShowGrid(False)
        self.facilitiesTable.verticalHeader().setDefaultSectionSize(40)
        self.facilitiesTable.setColumnCount(11)
        # self.peopleTable.setColumnHidden(0, True)
        self.facilitiesTable.setHorizontalHeaderItem(0, QTableWidgetItem(""))
        self.facilitiesTable.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)
        self.facilitiesTable.setHorizontalHeaderItem(1, QTableWidgetItem("ID"))
        self.facilitiesTable.setHorizontalHeaderItem(2,
                                                     QTableWidgetItem("Name"))
        self.facilitiesTable.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.Stretch)
        self.facilitiesTable.setHorizontalHeaderItem(
            3, QTableWidgetItem("Location"))
        self.facilitiesTable.horizontalHeader().setSectionResizeMode(
            2, QHeaderView.Stretch)
        self.facilitiesTable.setHorizontalHeaderItem(4,
                                                     QTableWidgetItem("Phone"))
        self.facilitiesTable.horizontalHeader().setSectionResizeMode(
            3, QHeaderView.Stretch)
        self.facilitiesTable.setHorizontalHeaderItem(5,
                                                     QTableWidgetItem("Email"))
        self.facilitiesTable.horizontalHeader().setSectionResizeMode(
            4, QHeaderView.Stretch)
        self.facilitiesTable.setHorizontalHeaderItem(
            6, QTableWidgetItem("Supervisor"))
        self.facilitiesTable.setHorizontalHeaderItem(
            7, QTableWidgetItem("Ongoing issues"))
        self.facilitiesTable.setHorizontalHeaderItem(
            8, QTableWidgetItem("Late issues"))
        self.facilitiesTable.setHorizontalHeaderItem(
            9, QTableWidgetItem("Total issues"))
        self.facilitiesTable.setHorizontalHeaderItem(
            10, QTableWidgetItem("Total inspections"))

        # Double clicking a row opens a window with person details
        self.facilitiesTable.doubleClicked.connect(self.funcSelectedFacility)

        # Buttons for actions on selected facilities
        self.addFacility = QPushButton("Add")
        self.addFacility.clicked.connect(self.funcAddFacility)
        self.viewFacility = QPushButton("View/Edit")
        self.viewFacility.clicked.connect(self.funcSelectedFacility)
        self.deleteFacility = QPushButton("Delete")
        self.deleteFacility.clicked.connect(self.funcDeleteFacility)

        self.exportFacilitiesCSVBtn = QPushButton("Export CSV")
        self.exportFacilitiesCSVBtn.setEnabled(False)
        self.exportFacilitiesCSVBtn.clicked.connect(self.funcFacilitiesToCSV)

        self.exportFacilitiesXSLXBtn = QPushButton("Export XLSX")
        self.exportFacilitiesXSLXBtn.setEnabled(False)
        self.exportFacilitiesXSLXBtn.clicked.connect(self.funcFacilitiesToXLSX)

        self.exportFacilitiesPDFBtn = QPushButton("Export PDF")
        self.exportFacilitiesPDFBtn.setEnabled(False)
        self.exportFacilitiesPDFBtn.clicked.connect(self.funcFacilitiesToPdf)

    def layouts(self):
        # Facilities layouts ###########################################################
        self.facilitiesMainLayout = QVBoxLayout()
        self.facilitiesMainTopLayout = QHBoxLayout()
        self.facilitiesTopLeftLayout = QHBoxLayout()
        self.facilitiesTopRightLayout = QHBoxLayout()

        self.facilitiesMainBottomLayout = QHBoxLayout()
        self.facilitiesBottomRightLayout = QVBoxLayout()
        self.facilitiesBottomLeftLayout = QHBoxLayout()

        # Groupboxes allows customization using CSS-like syntax

        self.facilitiesTopLeftGroupBox = QGroupBox()
        self.facilitiesTopRightGroupBox = QGroupBox()
        self.facilitiesTopGroupBox = QGroupBox()

        self.facilitiesBottomGroupBox = QGroupBox()
        self.facilitiesBottomLeftGroupBox = QGroupBox()
        self.facilitiesBottomRightGroupBox = QGroupBox()
        self.facilitiesBottomRightGroupBox.setStyleSheet(
            'QGroupBox {margin-top: 0px;}')
        self.facilitiesBottomRightGroupBoxFiller = QGroupBox()
        self.facilitiesBottomRightGroupBoxFiller.setStyleSheet(
            styles.groupBoxFillerStyle())

        # Top layout (search box) widgets
        self.facilitiesTopLeftLayout.addWidget(self.searchFacilitiesText, 10)
        self.facilitiesTopLeftLayout.addWidget(self.searchFacilitesEntry, 30)
        self.facilitiesTopLeftLayout.addWidget(self.searchFacilitiesBtn, 10)
        self.facilitiesTopLeftLayout.addItem(
            QSpacerItem(70, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))
        self.facilitiesTopLeftLayout.addWidget(self.refreshFacilitiesBtn, 10)
        self.facilitiesTopLeftGroupBox.setLayout(self.facilitiesTopLeftLayout)

        # layout (list box) widgets
        self.facilitiesTopRightLayout.addWidget(self.allFacilitiesRadioBtn)
        self.facilitiesTopRightLayout.addWidget(
            self.withOngoingIssuesFacilitiesRadioBtn)
        self.facilitiesTopRightLayout.addWidget(self.withLateIssuesRadioBtn)
        self.facilitiesTopRightLayout.addWidget(self.listFacilitiesBtn)
        self.facilitiesTopRightGroupBox.setLayout(
            self.facilitiesTopRightLayout)

        self.facilitiesMainTopLayout.addWidget(self.facilitiesTopLeftGroupBox,
                                               60)
        self.facilitiesMainTopLayout.addWidget(self.facilitiesTopRightGroupBox,
                                               40)

        # Bottom layout (table with facilities) widgets
        # Bottom left layout with table
        self.facilitiesBottomLeftLayout.addWidget(self.facilitiesTable)
        self.facilitiesBottomLeftGroupBox.setLayout(
            self.facilitiesBottomLeftLayout)

        # Bottom right layout with buttons
        self.facilitiesBottomRightLayout.addWidget(self.addFacility, 5)
        self.facilitiesBottomRightLayout.addWidget(self.viewFacility, 5)
        self.facilitiesBottomRightLayout.addWidget(self.deleteFacility, 5)
        self.facilitiesBottomRightLayout.addWidget(
            self.facilitiesBottomRightGroupBoxFiller, 70)
        self.facilitiesBottomRightLayout.addWidget(self.exportFacilitiesCSVBtn,
                                                   5)
        self.facilitiesBottomRightLayout.addWidget(
            self.exportFacilitiesXSLXBtn, 5)
        self.facilitiesBottomRightLayout.addWidget(self.exportFacilitiesPDFBtn,
                                                   5)
        self.facilitiesBottomRightGroupBox.setLayout(
            self.facilitiesBottomRightLayout)

        self.facilitiesMainBottomLayout.addWidget(self.facilitiesTable, 90)
        self.facilitiesMainBottomLayout.addWidget(
            self.facilitiesBottomRightGroupBox, 10)

        self.facilitiesMainLayout.addLayout(self.facilitiesMainTopLayout, 10)
        self.facilitiesMainLayout.addLayout(self.facilitiesMainBottomLayout,
                                            90)

        self.setLayout(self.facilitiesMainLayout)

    @Slot()
    def funcAddFacility(self):
        self.newFacility = AddFacility(self)
        self.newFacility.setObjectName("add_facility_popup")
        self.newFacility.setStyleSheet(styles.addPopups())

    @Slot()
    def funcDisplayFacilities(self):
        for i in reversed(range(self.facilitiesTable.rowCount())):
            self.facilitiesTable.removeRow(i)

        cur = db.cur
        facilities = cur.execute("SELECT * FROM facilities")

        for row_data in facilities:
            row_number = self.facilitiesTable.rowCount()
            self.facilitiesTable.insertRow(row_number)
            # Add checkboxes to the table
            qwidget = QWidget()
            checkbox = QCheckBox()
            checkbox.setCheckState(Qt.Unchecked)
            checkbox.stateChanged.connect(self.funcActivateBtnsWithCheckbox)
            qhboxlayout = QHBoxLayout(qwidget)
            qhboxlayout.addWidget(checkbox)
            qhboxlayout.setAlignment(Qt.AlignCenter)
            self.facilitiesTable.setCellWidget(row_number, 0, qwidget)
            self.facilitiesTable.setItem(row_number, 0,
                                         QTableWidgetItem(row_number))

            for column_number, data in enumerate(row_data, start=1):
                if column_number == 1:
                    self.facilitiesTable.setItem(
                        row_number, column_number,
                        QTableWidgetItem("FCL#" + str(data)))
                else:
                    self.facilitiesTable.setItem(row_number, column_number,
                                                 QTableWidgetItem(str(data)))

        self.facilitiesTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.facilitiesTable.setSelectionBehavior(QTableView.SelectRows)

    @Slot()
    def funcActivateBtnsWithCheckbox(self):
        indices = self.funcFacilitiesCheckBox()

        if self.sender().isChecked() or indices:
            self.exportFacilitiesCSVBtn.setEnabled(True)
            self.exportFacilitiesXSLXBtn.setEnabled(True)
            self.exportFacilitiesPDFBtn.setEnabled(True)
        else:
            self.exportFacilitiesCSVBtn.setEnabled(False)
            self.exportFacilitiesXSLXBtn.setEnabled(False)
            self.exportFacilitiesPDFBtn.setEnabled(False)

    @Slot()
    def funcFacilitiesCheckBox(self):
        checked_list = []
        for i in range(self.facilitiesTable.rowCount()):
            if self.facilitiesTable.cellWidget(i, 0).findChild(
                    type(QCheckBox())).isChecked():
                item = self.facilitiesTable.item(i, 1).text()
                checked_list.append(item.lstrip("FCL#"))
        return checked_list

    @Slot()
    def funcSelectedFacility(self):
        self.displayFacility = DisplayFacility(self)
        self.displayFacility.show()

    @Slot()
    def funcDeleteFacility(self):
        indices = self.funcFacilitiesCheckBox()

        mbox = QMessageBox.question(
            self, "Warning", "Are you sure you want to delete this facility?",
            QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel)

        if (mbox == QMessageBox.Yes):
            if indices:
                try:
                    for index in range(len(indices)):
                        query = "DELETE FROM facilities WHERE facility_id = ?"

                        db.cur.execute(query, (indices[index], ))
                        db.conn.commit()

                    QMessageBox.information(self, "Info",
                                            "Facilites were deleted")
                    self.funcDisplayFacilities()
                except:
                    QMessageBox.information(self, "Info", "No changes made")
            else:
                row = self.facilitiesTable.currentRow()
                facilityId = self.facilitiesTable.item(row, 0).text()
                facilityId = facilityId.lstrip("FCL#")
                try:
                    query = "DELETE FROM facilities WHERE facility_id = ?"

                    db.cur.execute(query, (facilityId, ))
                    db.conn.commit()

                    QMessageBox.information(self, "Info",
                                            "Facility was deleted")
                    self.funcDisplayFacilities()
                except:
                    QMessageBox.information(self, "Info", "No changes made")
        self.displayFacility.close()

    @Slot()
    def funcSearchFacilities(self):
        value = self.searchFacilitesEntry.text()
        if value == "":
            QMessageBox.information(self, "Warning",
                                    "Search string cannot be empty")
            self.displayFacilities()
        else:
            # Erase search entry
            self.searchFacilitesEntry.setText("")
            try:
                query = "SELECT * FROM facilities WHERE " \
                        "facility_id LIKE ? " \
                        "OR facility_name LIKE ?" \
                        "OR facility_location LIKE ?" \
                        "OR facility_phone LIKE ?" \
                        "OR facility_email LIKE ?" \
                        "OR facility_supervisor LIKE ?"
                results = db.cur.execute(
                    query, ('%' + value + '%', '%' + value + '%',
                            '%' + value + '%', '%' + value + '%',
                            '%' + value + '%', '%' + value + '%')).fetchall()
                if results == []:
                    QMessageBox.information(self, "Info", "Nothing was found")
                    self.funcDisplayFacilities()
                else:
                    for i in reversed(range(self.facilitiesTable.rowCount())):
                        self.facilitiesTable.removeRow(i)

                    for row_data in results:
                        row_number = self.facilitiesTable.rowCount()
                        self.facilitiesTable.insertRow(row_number)
                        # Add checkboxes to the table
                        qwidget = QWidget()
                        checkbox = QCheckBox()
                        checkbox.setCheckState(Qt.Unchecked)
                        qhboxlayout = QHBoxLayout(qwidget)
                        qhboxlayout.addWidget(checkbox)
                        qhboxlayout.setAlignment(Qt.AlignCenter)
                        self.facilitiesTable.setCellWidget(
                            row_number, 0, qwidget)
                        self.facilitiesTable.setItem(
                            row_number, 0, QTableWidgetItem(row_number))
                        for column_number, data in enumerate(row_data,
                                                             start=1):
                            if column_number == 1:
                                self.facilitiesTable.setItem(
                                    row_number, column_number,
                                    QTableWidgetItem("FCL#" + str(data)))
                            else:
                                self.facilitiesTable.setItem(
                                    row_number, column_number,
                                    QTableWidgetItem(str(data)))
            except:
                QMessageBox.information(self, "Info", "Cannot access database")

    @Slot()
    def funcFacilitiesToCSV(self):
        indices = self.funcFacilitiesCheckBox()

        if indices:
            CSV(self, "facilities", indices)
        else:
            QMessageBox.information(
                self, "Info",
                "Nothing selected for export\nUse checkboxes to select issues to export"
            )

    @Slot()
    def funcFacilitiesToXLSX(self):
        indices = self.funcFacilitiesCheckBox()

        if indices:
            try:
                date = datetime.datetime.now()

                # Get file location and add timestamp to when it was created to the filename
                fileName, _ = QFileDialog.getSaveFileName(
                    self, "Save as...", "~/FacilitiesXLSX" +
                    "{:%d%b%Y_%Hh%Mm}".format(date) + ".xlsx",
                    "Excel files (*.xlsx)")
                if fileName:
                    db.cur.execute("SELECT * FROM facilities")

                    workbook = xlsxwriter.Workbook(fileName)
                    worksheet = workbook.add_worksheet("Facilities")
                    worksheet.set_column('A:C', 12)
                    worksheet.set_row(0, 30)
                    merge_format = workbook.add_format({
                        'bold': 1,
                        'align': 'center',
                        'valign': 'vcenter'
                    })
                    worksheet.merge_range('A1:B1', '', merge_format)
                    worksheet.insert_image(
                        'A1', './assets/logo/logo-full-main.png', {
                            'x_scale': 0.4,
                            'y_scale': 0.4,
                            'x_offset': 15,
                            'y_offset': 10
                        })

                    # Create header row
                    col = 0
                    for value in db.cur.description:
                        worksheet.write(1, col, value[0])
                        col += 1

                    # Write date to xlsx file
                    row_number = 2
                    for index in range(len(indices)):
                        query = "SELECT * FROM facilities WHERE facility_id=?"
                        facility_record = db.cur.execute(
                            query, (indices[index], )).fetchone()
                        for i, value in enumerate(facility_record):
                            worksheet.write(row_number, i, value)
                        row_number += 1

                    workbook.close()

                    QMessageBox.information(
                        self, "Info",
                        "Data exported successfully into {}".format(fileName))

            except:
                QMessageBox.information(self, "Info", "Export failed")
        else:
            QMessageBox.information(
                self, "Info",
                "Nothing selected for export\nUse checkboxes to select issues to export"
            )

    @Slot()
    def funcFacilitiesToPdf(self):
        indices = self.funcFacilitiesCheckBox()

        if indices:
            try:
                date = datetime.datetime.now()

                # Get file location and add timestamp to when it was created to the filename
                fileName, _ = QFileDialog.getSaveFileName(
                    self, "Save as...", "~/FacilitiesPDF" +
                    "{:%d%b%Y_%Hh%Mm}".format(date) + ".pdf",
                    "PDF files (*.pdf)")

                if fileName:
                    pdf = PDF()
                    pdf.add_page()
                    pdf.set_font('Arial', 'B', 13)

                    for index in range(len(indices)):
                        query = "SELECT * FROM facilities WHERE facility_id=?"
                        facility_record = db.cur.execute(
                            query, (indices[index], )).fetchone()

                        # This string allows for text formatting in the pdf, easy to implement and test
                        stringFacility = "\nFacility id: " + str(facility_record[0]) + \
                                         "\nFacility name: " + str(facility_record[1]) + \
                                         "\nLocation: " + str(facility_record[2]) + \
                                         "\nPhone: " + str(facility_record[3]) + \
                                         "\nEmail: " + str(facility_record[4]) + \
                                         "\nSupervisor: " + str(facility_record[5])

                        pdf.multi_cell(200, 10, stringFacility)
                    pdf.output(fileName, 'F')

                    QMessageBox.information(
                        self, "Info",
                        "Data exported successfully into {}".format(fileName))

            except:
                QMessageBox.information(self, "Info", "Export failed")
        else:
            QMessageBox.information(
                self, "Info",
                "Nothing selected for export\nUse checkboxes to select issues to export"
            )
Example #12
0
class defaultRepos(confStack):
    def __init_stack__(self):
        self.dbg = False
        self._debug("confDefault Load")
        self.menu_description = (_("Choose the default repositories"))
        self.description = (_("Default repositories"))
        self.icon = ('go-home')
        self.tooltip = (_(
            "From here you can activate/deactivate the default repositories"))
        self.index = 1
        self.enabled = True
        self.defaultRepos = {}
        self.changed = []
        self.level = 'user'

    #def __init__

    def _load_screen(self):
        box = QVBoxLayout()
        lbl_txt = QLabel(_("Enable or disable default repositories"))
        lbl_txt.setAlignment(Qt.AlignTop)
        box.addWidget(lbl_txt, 0)
        self.table = QTableWidget(1, 2)
        Hheader = self.table.horizontalHeader()
        Vheader = self.table.verticalHeader()
        Hheader.setSectionResizeMode(0, QHeaderView.Stretch)
        Vheader.setSectionResizeMode(QHeaderView.ResizeToContents)
        self.table.setShowGrid(False)
        self.table.setSelectionBehavior(QTableWidget.SelectRows)
        self.table.setSelectionMode(QTableWidget.NoSelection)
        self.table.setEditTriggers(QTableWidget.NoEditTriggers)
        self.table.horizontalHeader().hide()
        self.table.verticalHeader().hide()
        box.addWidget(self.table)
        self.setLayout(box)
        self.updateScreen()

    #def _load_screen

    def updateScreen(self):
        self.table.clearContents()
        self.changed = []
        while self.table.rowCount():
            self.table.removeRow(0)
        config = self.getConfig()
        try:
            n4dclass = "RepoManager"
            n4dmethod = "list_default_repos"
            repos = self.n4dQuery(n4dclass, n4dmethod)
            if isinstance(repos, str):
                #It's a string, something went wrong. Perhaps a llx16 server?
                if (repos == "METHOD NOT ALLOWED FOR YOUR GROUPS"):
                    #Server is a llx16 so switch to localhost
                    self._debug("LLX16 server detected. Switch to localhost")
                    self.errServer = True
                    repos = self.n4dQuery(n4dclass, n4dmethod)
            if repos.get('status', 0) != -1:
                self.defaultRepos = repos.copy()
        except Exception as e:
            self._debug(self.n4dQuery(n4dclass, n4dmethod))
        states = {}
        row = 0
        for repo, data in self.defaultRepos.items():
            self.table.insertRow(row)
            state = data.get('enabled', 'false')
            if state == 'true':
                state = True
            else:
                state = False
            description = data.get('desc', '')
            lbl = QLabelDescription(repo, _(description))
            self.table.setCellWidget(row, 0, lbl)
            chk = QCheckBox()
            chk.setTristate(False)
            chk.setStyleSheet("margin-left:50%;margin-right:50%")
            chk.stateChanged.connect(lambda x: self.setChanged(True))
            chk.stateChanged.connect(self.changeState)
            self.table.setCellWidget(row, 1, chk)
            chk.setChecked(state)
            row += 1

    #def _udpate_screen

    def changeState(self):
        row = self.table.currentRow()
        repoWidget = self.table.cellWidget(row, 0)
        stateWidget = self.table.cellWidget(row, 1)
        if repoWidget == None:
            self._debug("Item not found at %s,%s" % (row, 0))
            return
        repo = repoWidget.text()[0]
        #Check mirror
        if repo.lower() == "lliurex mirror":
            #Mirror must be checked against server
            ret = self.appConfig.n4dQuery("MirrorManager",
                                          "is_mirror_available")
            if isinstance(ret, dict):
                if ret.get('status') == -1:
                    self._debug("Mirror not available")
                    self.showMsg(_("Mirror not available"), 'RepoMan')
                    self.defaultRepos[repo]['enabled'] = "False"
                    self.updateScreen()
                    return

            if (type(ret) == type("")):
                if ret != "Mirror available":
                    self._debug("Mirror not available")
                    self.showMsg(_("Mirror not available"), 'RepoMan')
                    self.defaultRepos[repo]['enabled'] = "False"
                    self.updateScreen()
                    return
            elif not (ret.get('status', False)):
                self._debug("Mirror not available")
                self.showMsg(_("Mirror not available"), 'RepoMan')
                self.defaultRepos[repo]['enabled'] = "False"
                self.updateScreen()
                return
        state = str(stateWidget.isChecked()).lower()
        self.defaultRepos[repo]['enabled'] = "%s" % state
        if repo not in self.changed:
            self.changed.append(repo)

    #def changeState

    def writeConfig(self):
        ret = True
        for repo in self.changed:
            self._debug("Updating %s" % repo)
            ret = self.n4dQuery("RepoManager", "write_repo_json",
                                {repo: self.defaultRepos[repo]})
            if ret:
                ret = self.n4dQuery("RepoManager", "write_repo",
                                    {repo: self.defaultRepos[repo]})
                if ret == False:
                    self.showMsg(
                        _("Couldn't write repo") + " {}".format(repo), 'error')
            else:
                self.showMsg(
                    _("Couldn't write info for") + " {}".format(repo), 'error')
        if ret == True:
            self._updateRepos()
        self.updateScreen()

    #def writeConfig

    def _updateRepos(self):
        cursor = QtGui.QCursor(Qt.WaitCursor)
        self.setCursor(cursor)
        self._debug("Updating repos")
        ret = self.appConfig.n4dQuery("RepoManager", "update_repos")
        errList = []
        for line in ret.split("\n"):
            if line.startswith("E: ") or line.startswith("W:"):
                for name, data in self.defaultRepos.items():
                    for repoLine in data.get('repos', []):
                        repoItems = repoLine.split(" ")
                        if repoItems:
                            if repoItems[0] in line:
                                if "NODATA" in line:
                                    continue
                                err = " *{}".format(name)
                                if err not in errList:
                                    errList.append(err)
        ret = ("\n").join(errList)
        if ret:
            #self.showMsg(_("Repositories updated succesfully"))
            self._debug("Error updating: %s" % ret)
            ret = _("Failed to update: ") + "\n" + "{}".format(ret)
            self.showMsg("{}".format(ret), 'RepoMan')
            self.refresh = True
            self.changes = False
        else:
            self.showMsg(_("Repositories updated succesfully"))
        cursor = QtGui.QCursor(Qt.PointingHandCursor)
        self.setCursor(cursor)
Example #13
0
class customRepos(confStack):
	def __init_stack__(self):
		self.dbg=False
		self._debug("confDefault Load")
		self.menu_description=(_("Manage custom repositories"))
		self.description=(_("Custom repositories"))
		self.icon=('menu_new')
		self.tooltip=(_("From here you can manage your custom repositories"))
		self.index=2
		self.enabled=True
		self.defaultRepos={}
		self.level='user'
		self.changed=[]
	#def __init__
	
	def _load_screen(self):
		box=QVBoxLayout()
		info=QWidget()
		infoBox=QHBoxLayout()
		lbl_txt=QLabel(_("Manage extra repositories"))
		lbl_txt.setAlignment(Qt.AlignTop)
		infoBox.addWidget(lbl_txt,1)
		icn_add=QtGui.QIcon().fromTheme('document-new')
		btn_add=QPushButton()
		btn_add.clicked.connect(self._addRepo)
		btn_add.setIcon(icn_add)
		btn_add.setToolTip(_("Add new repository"))
		infoBox.addWidget(btn_add,0)
		info.setLayout(infoBox)
		box.addWidget(info,0)
		self.table=QTableWidget(1,2)
		Hheader=self.table.horizontalHeader()
		Vheader=self.table.verticalHeader()
		Hheader.setSectionResizeMode(0,QHeaderView.Stretch)
		Vheader.setSectionResizeMode(QHeaderView.ResizeToContents)
		self.table.setShowGrid(False)
		self.table.setSelectionBehavior(QTableWidget.SelectRows)
		self.table.setSelectionMode(QTableWidget.NoSelection)
		self.table.setEditTriggers(QTableWidget.NoEditTriggers)
		self.table.horizontalHeader().hide()
		self.table.verticalHeader().hide()
		box.addWidget(self.table)
		self.setLayout(box)
		self.updateScreen()
	#def _load_screen

	def updateScreen(self):
		self.table.clearContents()
		self.changed=[]
		while self.table.rowCount():
			self.table.removeRow(0)
		config=self.getConfig()
		repos=self.appConfig.n4dQuery("RepoManager","list_sources")
		if isinstance(repos,str):
		#It's a string, something went wrong. Perhaps a llx16 server?
			#Server is a llx16 so switch to localhost
			self._debug("LLX16 server detected. Switch to localhost")
			self.appConfig.n4d.server='localhost'
			self.appConfig.n4d.n4dClient=None
			repos=self.appConfig.n4dQuery("RepoManager","list_sources")
		elif isinstance(repos,dict):
			status=repos.get('status',None)
			if status!=0 and status!=None:
				self.showMsg(_("N4d is down. Check the state of N4d server"))
				return

		self.defaultRepos=repos.copy()
		states={}
		row=0
		orderedKeys=sorted(self.defaultRepos,key=str.casefold)
		for repo in orderedKeys:
			data=self.defaultRepos[repo]
			self.table.insertRow(row)
			state=data.get('enabled','false').lower()
			if state=='true':
				state=True
			else:
				state=False
			description=data.get('desc','')
			lbl=QLabelDescription(repo,description)
			locked=data.get('protected','false')
			locked=str(locked).lower()
			lbl.click_on.connect(self.editRepo)
			if locked=='false':
				lbl.showEdit()
			if not state:
				lbl.stateEdit(False)
			self.table.setCellWidget(row,0,lbl)
			chk=QCheckBox()
			chk.setStyleSheet("margin-left:50%;margin-right:50%")
			chk.stateChanged.connect(lambda x:self.setChanged(True))
			chk.stateChanged.connect(self.changeState)
			self.table.setCellWidget(row,1,chk)
			chk.setChecked(state)
			row+=1
	#def _update_screen

	def editRepo(self,repo,*args):
		sfile=repo.replace(' ','_')
		self._debug("Editing {}.list".format(sfile))
		fpath="{}.list".format(os.path.join(APT_SRC_DIR,sfile))
		if os.path.isfile(fpath) or os.path.isfile(fpath.lower()):
			if os.path.isfile(fpath.lower()):
				fpath=fpath.lower()
			edit=True
			try:
				display=os.environ['DISPLAY']
				subprocess.run(["xhost","+"])
				subprocess.run(["pkexec","scite",fpath],check=True)
				subprocess.run(["xhost","-"])
			except Exception as e:
				self._debug("_edit_source_file error: %s"%e)
				edit=False
			if edit:
				newrepos=[]
				wrkfile=os.path.join(APT_SRC_DIR,"{}.list".format(sfile))
				if not os.path.isfile(wrkfile):
					wrkfile=wrkfile.lower()
				try:
					with open(wrkfile,'r') as f:
						for line in f:
							newrepos.append(line.strip())
				except Exception as e:
					self._debug("_edit_source_file failed: {}".format(e))
				if sorted(self.defaultRepos[repo]['repos'])!=sorted(newrepos):
					self.defaultRepos[repo]['repos']=newrepos
					self.appConfig.n4dQuery("RepoManager","write_repo_json",{repo:self.defaultRepos[repo]})
					self._updateRepos()
		else:
			self._debug("File {} not found".format(fpath))
	#def _edit_source_file

	def changeState(self):
		row=self.table.currentRow()
		repoWidget=self.table.cellWidget(row,0)
		stateWidget=self.table.cellWidget(row,1)
		if repoWidget==None:
			self._debug("Item not found at {},0".format(row))
			return
		repo=repoWidget.text()[0]
		state=str(stateWidget.isChecked()).lower()
		self.defaultRepos[repo]['enabled']="%s"%state
		if repo not in self.changed:
			self.changed.append(repo)
	#def changeState(self)

	def _addRepo(self):
		self.stack.gotoStack(idx=4,parms="")
	#def _addRepo

	def writeConfig(self):
		ret=True
		for repo in self.changed:
			self._debug("Updating {}".format(repo))
			self._debug("Updating %s"%self.defaultRepos[repo])
			ret=self.appConfig.n4dQuery("RepoManager","write_repo_json",{repo:self.defaultRepos[repo]})
			if ret:
				ret=self.appConfig.n4dQuery("RepoManager","write_repo",{repo:self.defaultRepos[repo]})
				if ret==False:
					self.showMsg(_("Couldn't write repo")+" {}".format(repo),'error')
			else:
				self.showMsg(_("Couldn't write info for")+" {}".format(repo),'error')
		if ret==True:
			self._updateRepos()
		self.updateScreen()
	#def writeConfig

	def _updateRepos(self):
		cursor=QtGui.QCursor(Qt.WaitCursor)
		self.setCursor(cursor)
		self._debug("Updating repos")
		ret=self.appConfig.n4dQuery("RepoManager","update_repos")
		errList=[]
		for line in ret.split("\n"):
			if line.startswith("E: ") or line.startswith("W:"):
				for name,data in self.defaultRepos.items():
					for repoLine in data.get('repos',[]):
						repoItems=repoLine.split(" ")
						if repoItems:
							if repoItems[0] in line:
								err=" *{}".format(name)
								if err not in errList:
									errList.append(err)
		ret=("\n").join(errList)
		if ret:
				#self.showMsg(_("Repositories updated succesfully"))
			self._debug("Error updating: {}".format(ret))
			ret=_("Failed to update: ")+"\n"+"{}".format(ret)
			self.showMsg("{}".format(ret),'RepoMan')
			self.refresh=True
			self.changes=False
		else:
			self.showMsg(_("Repositories updated succesfully"))
		cursor=QtGui.QCursor(Qt.PointingHandCursor)
		self.setCursor(cursor)