示例#1
0
class InvoiceForm(QWidget):
    submitted = Signal(dict)
    
    def __init__(self, parent=None):                                        # + parent=None
        super().__init__(parent)                                            # + parent
        self.setLayout(QFormLayout())
        self.inputs = dict()
        self.inputs['Customer Name'] = QLineEdit()
        self.inputs['Customer Address'] = QPlainTextEdit()
        self.inputs['Invoice Date'] = QDateEdit(date=QDate.currentDate(), calendarPopup=True)
        self.inputs['Days until Due'] = QSpinBox()
        for label, widget in self.inputs.items():
            self.layout().addRow(label, widget)

        self.line_items = QTableWidget(rowCount=10, columnCount=3)
        self.line_items.setHorizontalHeaderLabels(['Job', 'Rate', 'Hours'])
        self.line_items.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.layout().addRow(self.line_items)
        for row in range(self.line_items.rowCount()):
            for col in range(self.line_items.columnCount()):
                if col > 0:
                    w = QSpinBox()
                    self.line_items.setCellWidget(row, col, w)

        submit = QPushButton('Create Invoice', clicked=self.on_submit)
        
# +     vvvvvv                                        vvvvvvvvvvvvv 
        _print = QPushButton('Print Invoice', clicked=self.window().printpreviewDialog)  # + _print, + self.window()
        self.layout().addRow(submit, _print)                                             # + _print

    def on_submit(self):
        data = {'c_name': self.inputs['Customer Name'].text(),
                'c_addr': self.inputs['Customer Address'].toPlainText(),
                'i_date': self.inputs['Invoice Date'].date().toString(),
                'i_due': self.inputs['Invoice Date'].date().addDays(self.inputs['Days until Due'].value()).toString(),
                'i_terms': '{} days'.format(self.inputs['Days until Due'].value()),
                'line_items': list()}

        for row in range(self.line_items.rowCount()):
            if not self.line_items.item(row, 0):
                continue
            job = self.line_items.item(row, 0).text()
            rate = self.line_items.cellWidget(row, 1).value()
            hours = self.line_items.cellWidget(row, 2).value()
            total = rate * hours
            row_data = [job, rate, hours, total]
            if any(row_data):
                data['line_items'].append(row_data)

        data['total_due'] = sum(x[3] for x in data['line_items'])
        self.submitted.emit(data)
        # remove everything else in this function below this point
# +
        return data                                                            # +++
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"
            )
class TableWidget(QWidget):
    @property
    def columns(self):
        return self._columns

    @columns.setter
    def columns(self, columns):
        self._columns = columns
        self.table.setHorizontalHeaderLabels(columns)
        self.table.resizeColumnsToContents()

    def __init__(self, columns, parent=None, callback=None):
        super().__init__(parent)
        self.callback = callback
        self.table = QTableWidget(0, len(columns), self)
        self.columns = columns
        self.table.setMinimumSize(400, 300)
        self.table.setShowGrid(True)

        self.hh = self.table.horizontalHeader()
        self.hh.setStretchLastSection(False)

        self.vh = self.table.verticalHeader()

        layout = QBoxLayout(
            QBoxLayout.Direction(QBoxLayout.LeftToRight
                                 | QBoxLayout.TopToBottom), self)
        layout.addWidget(self.table)
        self.setLayout(layout)
        # self.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum, QSizePolicy.DefaultType))

        self.callback = callback
        if self.callback:
            #self.table.cellEntered.connect(self.enterProcessor)
            #self.vh.activated.connect(self.enterProcessor)
            #self.vh.selected.connect(self.enterProcessor)
            #self.table.clicked.connect(self.enterProcessor)
            self.table.itemSelectionChanged.connect(self.enterProcessor)

    def removeRow(self, rowNo):
        for i in range(len(self.systemColumnsDefs)):
            try:
                self.table.cellWidget(rowNo, i).disconnect()
            except Exception as ex:
                print("DAMN!", ex)
            self.table.removeCellWidget(rowNo, i)
        self.table.removeRow(rowNo)

    def appendRow(self, i, row, isN=False):
        newRowNo = i + 1
        self.table.insertRow(newRowNo)

        for j, cell in enumerate(row):
            w = QLabel()
            w.setText(str(cell))
            self.table.setCellWidget(newRowNo, j, w)

    def clear(self):
        self.table.clearSelection()
        # self.table.disconnect()
        self.table.clearContents()
        self.table.setRowCount(0)

    def enterProcessor(self):
        #rowNo = idx.row()
        rowNo = self.table.currentIndex().row()
        self.callback(self, rowNo)
示例#4
0
class EntityViewer(QWidget):
    def __init__(self, parent, entity):
        self.parent = parent
        QWidget.__init__(self)
        self.entity = entity
        self.initUI()

    def initUI(self):
        self.layout = QGridLayout(self)
        self.setLayout(self.layout)

        self.back = QPushButton("Back")
        self.back.clicked.connect(self.chooseotherentity)
        self.layout.addWidget(self.back, 0, 0)

        self.pullb = QPushButton("Reload from Shotgun")
        self.pullb.clicked.connect(self.pull)
        self.layout.addWidget(self.pullb, 2, 0)

        self.savePage = QPushButton("Save Page")
        self.savePage.clicked.connect(self.setPageSettings)
        self.layout.addWidget(self.savePage, 3, 0)

        self.grid = QTableWidget(self)
        self.layout.addWidget(self.grid, 1, 0)
        self.grid.cellDoubleClicked.connect(self.edit)
        self.grid.cellClicked.connect(self.unedit)
        self.activeCell = None
        self.initData()
        self.grid.horizontalHeader().setSectionsMovable(True)
        self.grid.horizontalHeader().setContextMenuPolicy(Qt.CustomContextMenu)

        self.grid.horizontalHeader().customContextMenuRequested.connect(
            self.hideF)

    def initData(self):
        self.entdata = self.parent.parent.db.get(self.entity)
        self.fieldsToShow = self.sanitizeFields(self.entdata)
        i = 0
        indexMap = {}
        for field in self.fieldsToShow:
            self.grid.insertColumn(self.grid.columnCount())
            self.grid.setHorizontalHeaderItem(i, QTableWidgetItem(field))
            indexMap[field] = i
            i += 1
        for ent in self.entdata.data:
            self.grid.insertRow(self.grid.rowCount())
            for field in ent:
                if field in indexMap:
                    cell = cellmanager.barfCell(ent[field], self.parent)
                    self.grid.setCellWidget(self.grid.rowCount() - 1,
                                            indexMap[field], cell)

    def edit(self, row, column):
        newCell = cellmanager.edit(self.grid.cellWidget(row, column))
        if newCell:
            self.grid.setCellWidget(row, column, newCell)
            self.activeCell = (row, column)

    def unedit(self, row, column):  #pylint:disable=unused-argument
        if self.activeCell:
            self.grid.setCellWidget(
                self.activeCell[0], self.activeCell[1],
                cellmanager.save(
                    self.grid.cellWidget(self.activeCell[0],
                                         self.activeCell[1])))
            self.activeCell = None

    def chooseotherentity(self):
        self.parent.parent.changeState(self.parent)

    def pull(self):
        self.parent.parent.db.reloadTable(self.entity)
        self.parent.parent.changeState(EntityViewer(self.parent, self.entity))

    def hideF(self, position):
        menu = QMenu()
        hideField = menu.addAction("Hide")
        ac = menu.exec_(self.grid.mapToGlobal(position))
        if ac == hideField:
            index = self.grid.horizontalHeader().logicalIndexAt(position)
            self.grid.removeColumn(index)

    def setPageSettings(self):
        rules = []
        for i in range(0, self.grid.columnCount()):
            rules.append(
                self.grid.horizontalHeaderItem(
                    self.grid.horizontalHeader().visualIndex(i)).text())
        json_reader.write(rules, "data/pagesettings/%s" % self.entity)

    def sanitizeFields(self, allData):
        try:
            rules = json_reader.read("data/pagesettings/%s" % self.entity)
        except IOError:
            print("No page settings saved for %ss." % self.entity)
            return allData.data[0]
        return rules
示例#5
0
class FileDownloaderWidget(QWidget):

    def __init__(self):
        super().__init__()
        self.id = 1
        self.TASKID = 0
        self.FILENAME = 1
        self.PROGRESSBAR = 2
        self.SPEED = 3
        self.STATUS = 4
        self.URL = 5
        self.FILEPATH = 6
        self.CANCEL = 7
        self.RETRY = 8
        self.DELETE = 9
        self.signals = FileDownloaderSignals()
        self.tableWidget = QTableWidget()
        self.startDownloadButton = QPushButton('Start Download')
        self.clearListButton = QPushButton('Clear Download List')
        self.hideFinishedCheckBox = QCheckBox('Hide Finished')
        self.startDownloadButton.clicked.connect(self.startDownload)
        self.clearListButton.clicked.connect(self.clearDownloadList)
        self.hideFinishedCheckBox.clicked.connect(self.hideFinished)
        self.createTable()
        layout = QGridLayout()
        layout.addWidget(self.tableWidget, 0, 0, 1, 2)
        layout.addWidget(self.hideFinishedCheckBox, 1, 0, 1, 1)
        layout.addWidget(self.startDownloadButton, 2, 0, 1, 1)
        layout.addWidget(self.clearListButton, 2, 1, 1, 1)
        layout.setMargin(0)
        self.setLayout(layout)
        self.resize(1920, 1080)

    def createTable(self):
        # taskId | fileName | progressBar | speed | status | url | filePath | cancel | retry | delete
        tableItemList = ['Task ID', 'File Name', 'Progress Bar', 'Download Speed',
                         'Download Status', 'Url', 'File Path', 'Cancel', 'Retry', 'Delete']
        self.tableWidget.setColumnCount(len(tableItemList))
        self.tableWidget.setRowCount(0)
        for i in range(len(tableItemList)):
            self.tableWidget.setHorizontalHeaderItem(i, QTableWidgetItem(tableItemList[i]))

    def addDownloadItem(self, taskId: str, fileName: str, filePath: str, url: str):
        row = self.tableWidget.rowCount()
        self.tableWidget.setRowCount(row + 1)

        taskIdItem = QTableWidgetItem(taskId)
        fileNameItem = QTableWidgetItem(fileName)
        progressBarItem = QTableWidgetItem()
        downloadSpeedItem = QTableWidgetItem("0 MB/s")
        downloadStatusItem = QTableWidgetItem("Pending")
        downloadUrlItem = QTableWidgetItem(url)
        filePathItem = QTableWidgetItem(filePath)
        cancelItem = QTableWidgetItem()
        retryItem = QTableWidgetItem()
        deleteItem = QTableWidgetItem()

        taskIdItem.setFlags(Qt.ItemIsEnabled)
        fileNameItem.setFlags(Qt.ItemIsEnabled)
        progressBarItem.setFlags(Qt.ItemIsEnabled)
        downloadSpeedItem.setFlags(Qt.ItemIsEnabled)
        downloadStatusItem.setFlags(Qt.ItemIsEnabled)
        downloadUrlItem.setFlags(Qt.ItemIsEnabled)
        filePathItem.setFlags(Qt.ItemIsEnabled)
        cancelItem.setFlags(Qt.ItemIsEnabled)
        retryItem.setFlags(Qt.ItemIsEnabled)
        deleteItem.setFlags(Qt.ItemIsEnabled)

        progressBar = QProgressBar()
        progressBar.setMinimum(0)
        progressBar.setMaximum(100)
        progressBar.setValue(0)
        progressBar.setAlignment(Qt.AlignCenter)
        progressBar.setFormat(str(progressBar.value()) + ' %')

        cancelButton = QPushButton('Cancel')
        cancelButton.clicked.connect(self.cancelTask)

        retryButton = QPushButton('Retry')
        retryButton.clicked.connect(self.retryTask)

        deleteButton = QPushButton('Delete')
        deleteButton.clicked.connect(self.deleteTask)

        self.tableWidget.setItem(row, 0, taskIdItem)
        self.tableWidget.setItem(row, 1, fileNameItem)
        self.tableWidget.setItem(row, 2, progressBarItem)
        self.tableWidget.setCellWidget(row, 2, progressBar)
        self.tableWidget.setItem(row, 3, downloadSpeedItem)
        self.tableWidget.setItem(row, 4, downloadStatusItem)
        self.tableWidget.setItem(row, 5, downloadUrlItem)
        self.tableWidget.setItem(row, 6, filePathItem)
        self.tableWidget.setItem(row, 7, cancelItem)
        self.tableWidget.setCellWidget(row, 7, cancelButton)
        self.tableWidget.setItem(row, 8, retryItem)
        self.tableWidget.setCellWidget(row, 8, retryButton)
        self.tableWidget.setItem(row, 9, deleteItem)
        self.tableWidget.setCellWidget(row, 9, deleteButton)

    def hideFinished(self):
        """
        hideFinished() is triggered when the hideFinishedCheckbox is clicked
        It will hide all rows with Cancelled or Finished status and leave
        Pending or Downloading items visible.
        """
        rowListCancel = self.rowOfValue('Cancelled', self.STATUS)
        rowListFinished = self.rowOfValue('Finished', self.STATUS)
        rowList = rowListCancel + rowListFinished
        logging.debug("rowList: {}".format(rowList))
        for row in rowList:
            if self.hideFinishedCheckBox.isChecked() is True:
                self.tableWidget.hideRow(row)
            else:
                self.tableWidget.showRow(row)

    def addDownloadTask(self, fileName: str, filePath: str, url: str):
        """
        addDownloadTask(fileName: str, filePath: str, url: str) is an interface
        to be called externally to add a download task to the widget.
        """
        self.addDownloadItem(str(self.id), fileName, filePath, url)
        self.id += 1

    def startDownload(self):
        """
        startTask() will find the first task in the table with Pending
        status and start it.
        """
        row = self.rowOfValue('Pending', self.STATUS)
        if (len(row) > 0):
            row = row[0]
            self.startTask(int(self.tableWidget.item(row, self.TASKID).text()), True)

    def startTask(self, taskId: int, downloadNext: bool):
        """
        startTask(taskId: int) starts a DownloadWorker and starts the task
        with taskId. It will not check if the task has started before
        or has cancelled.
        """
        row = self.rowOfValue(taskId, self.TASKID)
        if (len(row) > 0):
            row = row[0]
            filePath = self.tableWidget.item(row, self.FILEPATH).text()
            url = self.tableWidget.item(row, self.URL).text()
            worker = DownloadWorker(taskId, filePath, url, downloadNext, self)
            worker.start()

    def cancelTask(self):
        row = self.rowOfWidget(self.sender(), self.CANCEL)
        taskId = int(self.tableWidget.item(row, self.TASKID).text())
        self.tableWidget.item(row, 4).setText('Cancelled')
        self.signals.cancelDownload.emit(taskId)

    def retryTask(self):
        row = self.rowOfWidget(self.sender(), self.RETRY)
        taskId = int(self.tableWidget.item(row, self.TASKID).text())
        self.signals.cancelDownload.emit(taskId)
        self.tableWidget.item(row, self.STATUS).setText('Pending')
        self.startTask(taskId, False)

    def deleteTask(self):
        row = self.rowOfWidget(self.sender(), self.DELETE)
        taskId = int(self.tableWidget.item(row, self.TASKID).text())
        self.signals.cancelDownload.emit(taskId)
        self.tableWidget.removeRow(row)

    def clearDownloadList(self):
        """
        clearDownloadList() emits a signal to cancell all downloading
        items and directly recreate the table.
        """
        self.signals.cancelDownload.emit(-1)
        self.createTable()

    def rowOfWidget(self, item: QWidget, itemType: int):
        """
        rowOfWidget(item, itemType) is used to locate the embedded
        widget in self.tableWidget. It will compare item with those
        in the itemType column and return the first row number where
        it finds the matched item.
        """
        for row in range(self.tableWidget.rowCount()):
            if self.tableWidget.cellWidget(row, itemType) == item:
                return row

    def rowOfValue(self, value, itemType: int):
        """
        rowOfValue(value, itemType: str) takes two parameters.
        It will look into self.tableWidget for the itemType(column)
        to find the value. It returns a list of row number where the
        values are.
        """
        rowList = []
        for row in range(self.tableWidget.rowCount()):
            if self.tableWidget.item(row, itemType).text() == str(value):
                rowList.append(row)
        return rowList

    def updateProgressBar(self, taskId: int, value: int):
        row = self.rowOfValue(taskId, self.TASKID)
        if len(row) > 0:
            row = row[0]
            logging.debug("updateProgressBar of row {} with value {}".format(row, value))
            self.tableWidget.cellWidget(row, self.PROGRESSBAR).setValue(value)
            self.tableWidget.cellWidget(row, self.PROGRESSBAR).setFormat(str(value) + " %")

    def updateDownloadSpeed(self, taskId: int, value: str):
        row = self.rowOfValue(taskId, self.TASKID)
        if len(row) > 0:
            row = row[0]
            logging.debug("updateDownloadSpeed of row {} with value {}".format(row, value))
            self.tableWidget.item(row, self.SPEED).setText(value)

    def updateDownloadStatus(self, taskId: int, value: str):
        row = self.rowOfValue(taskId, self.TASKID)
        if len(row) > 0:
            row = row[0]
            logging.debug("updateDownloadStatus of row {} with value {}".format(row, value))
            self.tableWidget.item(row, self.STATUS).setText(value)
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"
            )
示例#8
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)
示例#9
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)