class ProposalEditor(QWidget):
    """Editor for proposals."""
    def __init__(self, main_widget, parent=None):
        super(ProposalEditor, self).__init__(parent)
        self.main_widget = main_widget

        self.name_edit = QLineEdit()
        self.url_edit = QLineEdit()
        self.start_block_edit = QLineEdit()
        self.end_block_edit = QLineEdit()
        self.amount_edit = QLineEdit()
        self.address_edit = QLineEdit()
        self.txid_edit = QLineEdit()
        for i in [self.name_edit, self.url_edit, self.start_block_edit, self.end_block_edit,
                self.amount_edit, self.address_edit, self.txid_edit]:
            i.setReadOnly(True)

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.main_widget.proxy_model)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)

        self.mapper.addMapping(self.name_edit, ProposalsModel.NAME)
        self.mapper.addMapping(self.url_edit, ProposalsModel.URL)
        self.mapper.addMapping(self.start_block_edit, ProposalsModel.START_BLOCK)
        self.mapper.addMapping(self.end_block_edit, ProposalsModel.END_BLOCK)
        self.mapper.addMapping(self.amount_edit, ProposalsModel.AMOUNT)
        self.mapper.addMapping(self.address_edit, ProposalsModel.ADDRESS)
        self.mapper.addMapping(self.txid_edit, ProposalsModel.TXID)

        block_hbox = QHBoxLayout()
        block_hbox.addWidget(self.start_block_edit)
        block_hbox.addWidget(QLabel(' - '))
        block_hbox.addWidget(self.end_block_edit)

        self.vote_combo = QComboBox()
        self.vote_combo.addItem(_('Yes'))
        self.vote_combo.addItem(_('No'))
        self.vote_button = QPushButton(_('Vote'))
        self.vote_button.clicked.connect(self.cast_vote)

        vote_hbox = util.Buttons(self.vote_combo, self.vote_button)

        form = QFormLayout()
        form.addRow(_('Name:'), self.name_edit)
        form.addRow(_('URL:'), self.url_edit)
        form.addRow(_('Blocks:'), block_hbox)
        form.addRow(_('Monthly Payment:'), self.amount_edit)
        form.addRow(_('Payment Address:'), self.address_edit)
        form.addRow(_('Fee TxID:'), self.txid_edit)

        form.addRow(_('Vote:'), vote_hbox)
        self.setLayout(form)

    def cast_vote(self):
        name = str(self.name_edit.text())
        vote_yes = True if self.vote_combo.currentIndex() == 0 else False
        self.main_widget.dialog.cast_vote(name, vote_yes)
예제 #2
0
class JPMainTableModel(QtSql.QSqlRelationalTableModel):
    # _tp中存放需要添加到数据映射器中的控件类型
    # 要添加的控件,必须用字段名命名(大小写敏感)
    _tp = (QtWidgets.QLineEdit, QtWidgets.QDateEdit, QtWidgets.QComboBox,
           QtWidgets.QTextEdit, QtWidgets.QCheckBox, QtWidgets.QSpinBox)

    def __init__(self,
                 parent: QWidget,
                 tableName: str,
                 filter: str = None,
                 db=QtSql.QSqlDatabase()):
        '''用于窗体模式进行数据编辑时的主窗体数据模型。\n
        会自动增加数据映射器,但是外键字段要使用addComboBoxData方法增加列表文字。
        最后要调用tofirst()方法定位编辑的记录。\n
        注:数据映射器不能增删记录,只能编辑
        '''
        super().__init__(parent=parent, db=db)
        self.parent = parent
        self.setTable(tableName)
        if filter:
            self.setFilter(filter)
        self.select()
        rec = self.record()
        self.mapper = QDataWidgetMapper(parent)
        self.mapper.setModel(self)
        self.mapper.setItemDelegate(_JPRelationalDelegate(parent, self.mapper))
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        for i in range(rec.count()):
            widget = parent.findChild(self._tp, rec.fieldName(i))
            if widget:
                if not isinstance(widget, QComboBox):
                    self.mapper.addMapping(widget, i)

    def toFirst(self):
        # 定位到模型中第一条记录
        self.mapper.toFirst()

    def addComboBoxData(self,
                        fieldName: str,
                        dataList: list,
                        displayColumn: int = 0,
                        modelColumn: int = 1):
        '''给模型中添加一个QComboBox控件的数据源。\n
        dataList为行来源数据源,列表对象.\n
        displayColumn为Combobox中要显示文字位于列表中的列号(首列为0)\n
        modelColumn为要保存到模型中数据在列表中的列号(首列为0)\n
        '''
        widget = self.parent.findChild(QComboBox, fieldName)
        if widget is not None:
            widget.setModel(
                _JPComboBoxModel(widget, dataList, displayColumn, modelColumn))
            self.mapper.addMapping(widget, self.fieldIndex(fieldName))

    def saveData(self):
        pass
예제 #3
0
class NoteEditDialog(QDialog, Ui_Dialog):
    ready = pyqtSignal(bool, int, name='ready')

    def __init__(self, model, row=None, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.init_ui()
        self.init_model(model)

        if row is None:
            # работаем в режиме добавления
            self.__model.insertRow(self.__model.rowCount())
            self.__mapper.toLast()
        else:
            # работаем в режиме редактирования
            self.__mapper.setCurrentIndex(row)

    def init_ui(self):
        # loadUi('ui/notes_edit_dialog.ui', self)
        self.setupUi(self)

        self.plannedDateTimeEdit.setMinimumDate(
            QDateTime.currentDateTime().date()
        )
        self.plannedDateTimeEdit.setDateTime(
            QDateTime.currentDateTime()
        )

    def init_model(self, model):
        self.__model = model

        self.__mapper = QDataWidgetMapper(self)
        self.__mapper.setModel(self.__model)
        self.__mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.__mapper.addMapping(self.titleEdit, 1)
        self.__mapper.addMapping(self.plannedDateTimeEdit, 2)
        self.__mapper.addMapping(self.contentEdit, 3)

    def accept(self): # это стандартный метод
        super().accept()
        self.__mapper.submit()           # отправляем данные в модель
        state = self.__model.submitAll() # отправить изменения в БД
        self.ready.emit(state, self.__mapper.currentIndex())

    def reject(self): # это стандартный метод
        super().reject()
        self.__mapper.revert()
        self.__model.revertAll()
예제 #4
0
class NoteEditDialog(QDialog, Ui_Dialog):
    ready = pyqtSignal(bool, int, name='ready')

    def __init__(self, model, row=None, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.init_ui()
        self.init_model(model)

        if row is None:
            # в режиме добавления
            self.__model.insertRow(self.__model.rowCount())
            self.__mapper.toLast()
        else:
            # работаем в режиме редактирования
            self.__mapper.setCurrentIndex(row)

    def init_ui(self):
        self.setupUi(self)

        self.plannedDateTimeEdit.setMinimumDate(
            QDateTime.currentDateTime().date())

        self.plannedDateTimeEdit.setDateTime(QDateTime.currentDateTime())

    def init_model(self, model):
        self.__model = model

        self.__mapper = QDataWidgetMapper(self)
        self.__mapper.setModel(self.__model)

        self.__mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.__mapper.addMapping(self.titleEdit, 1)
        self.__mapper.addMapping(self.plannedDateTimeEdit, 2)
        self.__mapper.addMapping(self.contentEdit, 3)

    def accept(self):  # это стандартный метод
        super().accept()
        self.__mapper.submit()  # отправили данные в модель
        state = self.__model.submitAll()  # отправить изменения в БД
        self.ready.emit(state, self.__mapper.currentIndex())

    def reject(self):
        super().reject()
        self.__mapper.revert()  # отмена изменений
        self.__model.revertAll()
예제 #5
0
class PhoneLogDlg(QDialog):

    FIRST, PREV, NEXT, LAST = range(4)

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

        callerLabel = QLabel("&Caller:")
        self.callerEdit = QLineEdit()
        callerLabel.setBuddy(self.callerEdit)
        today = QDate.currentDate()
        startLabel = QLabel("&Start:")
        self.startDateTime = QDateTimeEdit()
        startLabel.setBuddy(self.startDateTime)
        self.startDateTime.setDateRange(today, today)
        self.startDateTime.setDisplayFormat(DATETIME_FORMAT)
        endLabel = QLabel("&End:")
        self.endDateTime = QDateTimeEdit()
        endLabel.setBuddy(self.endDateTime)
        self.endDateTime.setDateRange(today, today)
        self.endDateTime.setDisplayFormat(DATETIME_FORMAT)
        topicLabel = QLabel("&Topic:")
        topicEdit = QLineEdit()
        topicLabel.setBuddy(topicEdit)
        outcomeLabel = QLabel("&Outcome:")
        self.outcomeComboBox = QComboBox()
        outcomeLabel.setBuddy(self.outcomeComboBox)
        firstButton = QPushButton()
        firstButton.setIcon(QIcon(":/first.png"))
        prevButton = QPushButton()
        prevButton.setIcon(QIcon(":/prev.png"))
        nextButton = QPushButton()
        nextButton.setIcon(QIcon(":/next.png"))
        lastButton = QPushButton()
        lastButton.setIcon(QIcon(":/last.png"))
        addButton = QPushButton("&Add")
        addButton.setIcon(QIcon(":/add.png"))
        deleteButton = QPushButton("&Delete")
        deleteButton.setIcon(QIcon(":/delete.png"))
        quitButton = QPushButton("&Quit")
        quitButton.setIcon(QIcon(":/quit.png"))
        if not MAC:
            addButton.setFocusPolicy(Qt.NoFocus)
            deleteButton.setFocusPolicy(Qt.NoFocus)

        fieldLayout = QGridLayout()
        fieldLayout.addWidget(callerLabel, 0, 0)
        fieldLayout.addWidget(self.callerEdit, 0, 1, 1, 3)
        fieldLayout.addWidget(startLabel, 1, 0)
        fieldLayout.addWidget(self.startDateTime, 1, 1)
        fieldLayout.addWidget(endLabel, 1, 2)
        fieldLayout.addWidget(self.endDateTime, 1, 3)
        fieldLayout.addWidget(topicLabel, 2, 0)
        fieldLayout.addWidget(topicEdit, 2, 1, 1, 3)
        fieldLayout.addWidget(outcomeLabel, 3, 0)
        fieldLayout.addWidget(self.outcomeComboBox, 3, 1, 1, 3)
        navigationLayout = QHBoxLayout()
        navigationLayout.addWidget(firstButton)
        navigationLayout.addWidget(prevButton)
        navigationLayout.addWidget(nextButton)
        navigationLayout.addWidget(lastButton)
        fieldLayout.addLayout(navigationLayout, 4, 0, 1, 2)
        buttonLayout = QVBoxLayout()
        buttonLayout.addWidget(addButton)
        buttonLayout.addWidget(deleteButton)
        buttonLayout.addStretch()
        buttonLayout.addWidget(quitButton)
        layout = QHBoxLayout()
        layout.addLayout(fieldLayout)
        layout.addLayout(buttonLayout)
        self.setLayout(layout)

        self.model = QSqlRelationalTableModel(self)
        self.model.setTable("calls")
        self.model.setRelation(OUTCOMEID, QSqlRelation("outcomes", "id",
                                                       "name"))
        self.model.setSort(STARTTIME, Qt.AscendingOrder)
        self.model.select()

        self.mapper = QDataWidgetMapper(self)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.setModel(self.model)
        self.mapper.setItemDelegate(QSqlRelationalDelegate(self))
        self.mapper.addMapping(self.callerEdit, CALLER)
        self.mapper.addMapping(self.startDateTime, STARTTIME)
        self.mapper.addMapping(self.endDateTime, ENDTIME)
        self.mapper.addMapping(topicEdit, TOPIC)
        relationModel = self.model.relationModel(OUTCOMEID)
        self.outcomeComboBox.setModel(relationModel)
        self.outcomeComboBox.setModelColumn(relationModel.fieldIndex("name"))
        self.mapper.addMapping(self.outcomeComboBox, OUTCOMEID)
        self.mapper.toFirst()

        firstButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.FIRST))
        prevButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.PREV))
        nextButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.NEXT))
        lastButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.LAST))
        addButton.clicked.connect(self.addRecord)
        deleteButton.clicked.connect(self.deleteRecord)
        quitButton.clicked.connect(self.done)
        self.setWindowTitle("Phone Log")

    def done(self, result=None):
        self.mapper.submit()
        QDialog.done(self, True)

    def addRecord(self):
        row = self.model.rowCount()
        self.mapper.submit()
        self.model.insertRow(row)
        self.mapper.setCurrentIndex(row)
        now = QDateTime.currentDateTime()
        self.startDateTime.setDateTime(now)
        self.endDateTime.setDateTime(now)
        self.outcomeComboBox.setCurrentIndex(
            self.outcomeComboBox.findText("Unresolved"))
        self.callerEdit.setFocus()

    def deleteRecord(self):
        caller = self.callerEdit.text()
        starttime = self.startDateTime.dateTime().toString(DATETIME_FORMAT)
        if (QMessageBox.question(
                self, "Delete",
                "Delete call made by<br>{0} on {1}?".format(caller, starttime),
                QMessageBox.Yes | QMessageBox.No) == QMessageBox.No):
            return
        row = self.mapper.currentIndex()
        self.model.removeRow(row)
        self.model.submitAll()
        self.model.select()
        if row + 1 >= self.model.rowCount():
            row = self.model.rowCount() - 1
        self.mapper.setCurrentIndex(row)

    def saveRecord(self, where):
        row = self.mapper.currentIndex()
        self.mapper.submit()
        if where == PhoneLogDlg.FIRST:
            row = 0
        elif where == PhoneLogDlg.PREV:
            row = 0 if row <= 1 else row - 1
        elif where == PhoneLogDlg.NEXT:
            row += 1
            if row >= self.model.rowCount():
                row = self.model.rowCount() - 1
        elif where == PhoneLogDlg.LAST:
            row = self.model.rowCount() - 1
        self.mapper.setCurrentIndex(row)
예제 #6
0
class APISFilm(QDialog, FORM_CLASS):

    FIRST, PREV, NEXT, LAST = range(4)
    OBLIQUE, VERTICAL = range(2)

    def __init__(self, iface, dbm, imageRegistry, apisLayer, parent=None):
        """Constructor."""
        super(APISFilm, self).__init__(parent)

        self.iface = iface
        self.dbm = dbm
        self.imageRegistry = imageRegistry
        self.apisLayer = apisLayer

        self.parent = parent

        self.setupUi(self)

        # Initial window size/pos last saved. Use default values for first time
        if GetWindowSize("film"):
            self.resize(GetWindowSize("film"))
        if GetWindowPos("film"):
            self.move(GetWindowPos("film"))

        self.printingOptionsDlg = None

        self.settings = QSettings(QSettings().value("APIS/config_ini"), QSettings.IniFormat)

        self.editMode = False
        self.addMode = False
        self.initalLoad = True

        #self.uiInitalEntryQgsDate.setCalendarPopup(False)
        #self.uiLastChangesQgsDate.setCalendarPopup(False)

        # Signals/Slot Connections
        self.rejected.connect(self.onReject)
        self.uiOkBtn.clicked.connect(self.onAccept)
        self.uiCancelBtn.clicked.connect(self.cancelEdit)
        self.uiSaveBtn.clicked.connect(self.saveEdits)

        self.uiFilmSelectionBtn.clicked.connect(self.openFilmSelectionDialog)

        self.uiNewFilmBtn.clicked.connect(self.openNewFilmDialog)
        self.uiSearchFilmBtn.clicked.connect(self.openSearchFilmDialog)
        self.uiEditWeatherBtn.clicked.connect(self.openEditWeatherDialog)

        self.uiExportPdfBtn.clicked.connect(self.exportDetailsPdf)

        self.uiShowFlightPathBtn.clicked.connect(lambda: self.openFlightPathDialog([self.uiCurrentFilmNumberEdit.text()]))

        # For LaLe Mode
        if self.settings.value("APIS/disable_site_and_findspot", "0") != "1":
            self.uiListSitesOfFilmBtn.setEnabled(True)
            self.uiListSitesOfFilmBtn.clicked.connect(self.openSiteSelectionListDialog)
        else:
            self.uiListSitesOfFilmBtn.setEnabled(False)

        self.uiListImagesOfFilmBtn.clicked.connect(self.openImageSelectionListDialog)
        self.uiExtractGpsFromImagesBtn.clicked.connect(self.extractGpsFromImages)

        self.uiWeatherCodeEdit.textChanged.connect(self.generateWeatherCode)
        self.uiFilmModeCombo.currentIndexChanged.connect(self.onFilmModeChanged)

        self.uiEditProjectTableBtn.clicked.connect(lambda: self.openSystemTableEditorDialog("projekt", self.uiProjectSelectionCombo))
        self.uiEditCopyrightTableBtn.clicked.connect(lambda: self.openSystemTableEditorDialog("copyright", self.uiCopyrightCombo))
        # self.uiEditProjectTableBtn.clicked.connect(lambda: VersionToCome())
        # self.uiEditCopyrightTableBtn.clicked.connect(lambda: VersionToCome())

        # init Project Btn
        self.uiAddProjectBtn.clicked.connect(self.addProject)
        self.uiRemoveProjectBtn.clicked.connect(self.removeProject)

        # Setup Sub-Dialogs
        self.filmSelectionDlg = APISFilmNumberSelection(self)
        self.newFilmDlg = APISFilmNew(parent=self)
        self.searchFilmDlg = APISFilmSearch(self.dbm, self)  # (self.iface, self.dbm)
        self.editWeatherDlg = APISWeather(self.iface, self.dbm, self)
        self.flightPathDlg = APISFlightPath(self.iface, self.dbm, self.apisLayer, self)
        self.siteSelectionListDlg = APISSiteSelectionList(self.iface, self.dbm, self.imageRegistry, self.apisLayer, self)
        self.imageSelectionListDlg = APISImageSelectionList(self.iface, self.dbm, self.imageRegistry,  self.apisLayer, parent=self)
        self.systemTableEditorDlg = None

        # Setup film model
        self.model = QSqlRelationalTableModel(self, self.dbm.db)
        self.model.setTable("film")
        self.model.select()

        while (self.model.canFetchMore()):
            self.model.fetchMore()

        self.setupMapper()
        self.setupComboBox(self.uiProjectSelectionCombo, "projekt", 0, None)

        self.setupComboBox(self.newFilmDlg.uiProducerCombo, "hersteller", 2, None)

        self.setupNavigation()

        self.mapper.toFirst()

        self.initalLoad = False

    def setupMapper(self):
        self.mapper = QDataWidgetMapper(self)

        self.mapper.currentIndexChanged.connect(self.onCurrentIndexChanged)

        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.setItemDelegate(FilmDelegate())

        self.mapper.setModel(self.model)

        self.mandatoryEditors = [self.uiImageCountEdit, self.uiCameraCombo, self.uiFilmMakeCombo, self.uiFilmModeCombo]
        self.disableEditorsIfOblique = [self.uiCameraNumberEdit, self.uiCalibratedFocalLengthEdit]
        # LineEdits & PlainTextEdits
        self.intValidator = QIntValidator()
        self.doubleValidator = QDoubleValidator()
        self.lineEditMaps = {
            "filmnummer": {
                "editor": self.uiCurrentFilmNumberEdit
            },
            "hersteller": {
                "editor": self.uiProducerEdit
            },
            "anzahl_bilder": {
                "editor": self.uiImageCountEdit,
                "validator": self.intValidator
            },
            "militaernummer": {
                "editor": self.uiMilitaryNumberEdit
            },
            "militaernummer_alt": {
                "editor": self.uiOldMilitaryNumberEdit
            },
            "form1": {
                "editor": self.uiFormat1Edit
            },
            "form2": {
                "editor": self.uiFormat2Edit
            },
            "kalibrierungsnummer": {
                "editor": self.uiCameraNumberEdit
            },
            "kammerkonstante": {
                "editor": self.uiCalibratedFocalLengthEdit,
                "validator": self.doubleValidator
            },
            "kassettennummer": {
                "editor": self.uiCassetteEdit
            },
            "art_ausarbeitung": {
                "editor": self.uiFilmMakeEdit
            },
            "fotograf": {
                "editor": self.uiPhotographerEdit
            },
            "pilot": {
                "editor": self.uiPilotEdit
            },
            "flugzeug": {
                "editor": self.uiAirplaneEdit
            },
            "abflug_flughafen": {
                "editor": self.uiDepartureAirportEdit
            },
            "ankunft_flughafen": {
                "editor": self.uiArrivalAirportEdit
            },
            "flugzeit": {
                "editor": self.uiFlightDurationEdit
            },
            "wetter": {
                "editor": self.uiWeatherCodeEdit
            },
            "kommentar": {
                "editor": self.uiCommentsPTxt
            }
        }
        for key, item in self.lineEditMaps.items():
            self.mapper.addMapping(item["editor"], self.model.fieldIndex(key))
            if "validator" in item:
                item["editor"].setValidator(item["validator"])
            #item["editor"].textChanged.connect(partial(self.onLineEditChanged, item["editor"]))
            item["editor"].textChanged.connect(self.onLineEditChanged)
        #Text
        #self.mapper.addMapping(self.uiCommentsPTxt, self.model.fieldIndex("kommentar"))

        # Date and Times
        self.mapper.addMapping(self.uiFlightDate, self.model.fieldIndex("flugdatum"))
        #self.mapper.addMapping(self.uiFlightQgsDate, self.model.fieldIndex("flugdatum"))
        self.mapper.addMapping(self.uiInitalEntryDate, self.model.fieldIndex("datum_ersteintrag"))
        #self.mapper.addMapping(self.uiInitalEntryQgsDate, self.model.fieldIndex("datum_ersteintrag"))
        self.mapper.addMapping(self.uiLastChangesDate, self.model.fieldIndex("datum_aenderung"))
        #self.mapper.addMapping(self.uiLastChangesQgsDate, self.model.fieldIndex("datum_aenderung"))

        self.mapper.addMapping(self.uiDepartureTime, self.model.fieldIndex("abflug_zeit"))
        self.mapper.addMapping(self.uiArrivalTime, self.model.fieldIndex("ankunft_zeit"))
        self.uiDepartureTime.timeChanged.connect(self.onFlightTimeChanged)
        self.uiArrivalTime.timeChanged.connect(self.onFlightTimeChanged)

        # ComboBox without Model
        self.mapper.addMapping(self.uiFilmModeCombo, self.model.fieldIndex("weise"))
        self.uiFilmModeCombo.editTextChanged.connect(self.onLineEditChanged)
        completer = QCompleter(self.uiFilmModeCombo.model())
        self.uiFilmModeCombo.setCompleter(completer)
        self.uiFilmModeCombo.lineEdit().setValidator(InListValidator([self.uiFilmModeCombo.itemText(i) for i in range(self.uiFilmModeCombo.count())], self.uiFilmModeCombo.lineEdit(), None, self))

        # ComboBox with Model
        self.comboBoxMaps = {
            "archiv": {
                "editor": self.uiArchiveCombo,
                "table": "hersteller",
                "modelcolumn": 2,
                "depend": None
            },
            "kamera": {
                "editor": self.uiCameraCombo,
                "table": "kamera",
                "modelcolumn": 0,
                "depend": [{"form1": self.uiFormat1Edit}, {"form2": self.uiFormat2Edit}]
            },
            "filmfabrikat": {
                "editor": self.uiFilmMakeCombo,
                "table": "film_fabrikat",
                "modelcolumn": 0,
                "depend": [{"art": self.uiFilmMakeEdit}]
            },
            "target": {
                "editor": self.uiTargetCombo,
                "table": "target",
                "modelcolumn": 0,
                "depend": None
            },
            "copyright": {
                "editor": self.uiCopyrightCombo,
                "table": "copyright",
                "modelcolumn": 0,
                "depend": None
            }
        }
        for key, item in self.comboBoxMaps.items():
            self.mapper.addMapping(item["editor"], self.model.fieldIndex(key))
            self.setupComboBox(item["editor"], item["table"], item["modelcolumn"], item["depend"])
            item["editor"].editTextChanged.connect(self.onLineEditChanged)

        self.mapper.addMapping(self.uiProjectList, self.model.fieldIndex("projekt"))

    def fixComboBoxDropDownListSizeAdjustemnt(self, cb):
        scroll = 0 if cb.count() <= cb.maxVisibleItems() else QApplication.style().pixelMetric(QStyle.PM_ScrollBarExtent)
        iconWidth = cb.iconSize().width()
        max = 0

        for i in range(cb.count()):
            width = cb.view().fontMetrics().width(cb.itemText(i))
            if max < width:
                max = width

        QMessageBox.information(self, "info", "scroll: {0}, max: {1}, icon: {2}".format(scroll, max, iconWidth))

        #cb.view().setMinimumWidth(scroll + max)

    def setupComboBox(self, editor, table, modelColumn, depend):
        model = QSqlRelationalTableModel(self, self.dbm.db)
        model.setTable(table)
        model.removeColumn(0)
        model.select()

        tv = QTableView()
        editor.setView(tv)

        tv.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        tv.setSelectionMode(QAbstractItemView.SingleSelection)
        tv.setSelectionBehavior(QAbstractItemView.SelectRows)
        tv.setAutoScroll(False)

        editor.setModel(model)

        editor.setModelColumn(modelColumn)
        editor.setInsertPolicy(QComboBox.NoInsert)

        tv.resizeColumnsToContents()
        tv.resizeRowsToContents()
        tv.verticalHeader().setVisible(False)
        tv.horizontalHeader().setVisible(True)
        #tv.setMinimumWidth(tv.horizontalHeader().length())
        tv.horizontalHeader().setStretchLastSection(True)
        #tv.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        tv.resizeColumnsToContents()
        scroll = 0 if editor.count() <= editor.maxVisibleItems() else QApplication.style().pixelMetric(QStyle.PM_ScrollBarExtent)
        tv.setMinimumWidth(tv.horizontalHeader().length() + scroll)
        #self.fixComboBoxDropDownListSizeAdjustemnt(editor)

        #editor.resize(tv.horizontalHeader().sizeHint())

        completer = QCompleter(editor.model())
        editor.setCompleter(completer)
        #editor.setAutoCompletion(True)
        editor.lineEdit().setValidator(InListValidator([editor.itemText(i) for i in range(editor.count())], editor.lineEdit(), depend, self))

        if depend:
            editor.currentIndexChanged.connect(partial(self.updateDepends, editor, depend))

    def updateDepends(self, editor, depend):
        for dep in depend:
            for key, value in dep.items():
                idx = editor.model().createIndex(editor.currentIndex(), editor.model().fieldIndex(key))
                value.setText(str(editor.model().data(idx)))
                #QMessageBox.warning(None, "Test", str(idx))

    def setupNavigation(self):
        self.uiFirstFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.FIRST))
        self.uiPreviousFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.PREV))
        self.uiNextFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.NEXT))
        self.uiLastFilmBtn.clicked.connect(partial(self.loadRecordByNavigation, APISFilm.LAST))

        self.uiTotalFilmCountLbl.setText(str(self.model.rowCount()))
        self.intRecordValidator = QIntValidator(1, self.model.rowCount())
        self.uiCurrentFilmCountEdit.setValidator(self.intRecordValidator)
        self.uiCurrentFilmCountEdit.setText(str(self.mapper.currentIndex() + 1))
        self.uiCurrentFilmCountEdit.editingFinished.connect(lambda: self.loadRecordById(int(self.uiCurrentFilmCountEdit.text()) - 1))
        # QMessageBox.warning(None, "Test", str(self.mapper.itemDelegate()))

    def enableItemsInLayout(self, layout, enable):
        for i in range(layout.count()):
            if layout.itemAt(i).widget():
                layout.itemAt(i).widget().setEnabled(enable)

    def loadRecordByNavigation(self, mode):
        #self.mapper.submit()
        #self.submitChanges()
        self.initalLoad = True
        if mode == APISFilm.FIRST:
            self.mapper.toFirst()
        elif mode == APISFilm.PREV:
            self.mapper.toPrevious()
        elif mode == APISFilm.NEXT:
            self.mapper.toNext()
        elif mode == APISFilm.LAST:
            self.mapper.toLast()
        self.initalLoad = False

    def loadRecordById(self, id):
        #self.submitChanges
        self.initalLoad = True
        self.mapper.setCurrentIndex(id)
        self.initalLoad = False

    def loadRecordByKeyAttribute(self, attribute, value):
        #self.model.setFilter(attribute + " = '" + value + "'")
        #self.model.select()
        # self.mapper.toFirst()

        query = QSqlQuery(self.dbm.db)
        #qryStr = "select {0} from film where {0} = '{1}' limit 1".format(attribute, value)
        #qryStr = "SELECT rowid FROM film WHERE {0} = '{1}' limit 1".format(attribute, value)
        qryStr = "SELECT" \
                 "  (SELECT COUNT(*)" \
                 "       FROM film AS t2" \
                 "       WHERE t2.rowid < t1.rowid" \
                 "      ) + (" \
                 "         SELECT COUNT(*)" \
                 "         FROM film AS t3" \
                 "        WHERE t3.rowid = t1.rowid AND t3.rowid < t1.rowid" \
                 "      ) AS rowNum" \
                 "   FROM film AS t1" \
                 "   WHERE {0} = '{1}'" \
                 "   ORDER BY t1.rowid ASC".format(attribute, value)

        query.exec_(qryStr)

        #QMessageBox.warning(None, "Test", str(query.size()) + ',' + str(query.numRowsAffected()))

        query.first()
        fn = query.value(0)

        if fn is not None:
            self.loadRecordById(fn)
            return True
        else:
            # Film does not exist
            QMessageBox.warning(None, "Film Nummer", str("Der Film mit der Nummer {0} existiert nicht!".format(value)))
            return False

        #self.model.setFilter('')
        #self.model.select()
        #while (self.model.canFetchMore()):
            #self.model.fetchMore()

    def submitChanges(self):
        self.mapper.submit()

    def onCurrentIndexChanged(self):
        self.uiCurrentFilmCountEdit.setText(str(self.mapper.currentIndex() + 1))
        self.onFilmModeChanged()

    def onFlightTimeChanged(self):
        dTime = self.uiDepartureTime.time()
        aTime = self.uiArrivalTime.time()
        flightDuration = dTime.secsTo(aTime)
        self.uiFlightDurationEdit.setText(str(flightDuration / 60))

    def disableIfOblique(self, isOblique):
        for editor in self.disableEditorsIfOblique:
            editor.setDisabled(isOblique)

    def onFilmModeChanged(self):
        if self.uiFilmModeCombo.currentText() == u'schräg':
            self.disableIfOblique(True)
        else:
            self.disableIfOblique(False)

    def onLineEditChanged(self):
        sender = self.sender()
        if not self.editMode and not self.initalLoad:
            self.startEditMode()
        if not self.initalLoad:
            sender.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(sender.metaObject().className()))
            self.editorsEdited.append(sender)

    def onComboBoxChanged(self, editor):
        pass

    def addProject(self):
        editor = self.uiProjectList
        value = self.uiProjectSelectionCombo.currentText()
        notInList = True
        for row in range(editor.count()):
            if value == editor.item(row).data(0):
                notInList = False
                break
        if notInList:
            editor.addItem(value)
            editor.sortItems()
            if not self.editMode and not self.initalLoad:
                self.startEditMode()
            if not self.initalLoad:
                editor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(editor.metaObject().className()))
                self.editorsEdited.append(editor)

    def removeProject(self):
        editor = self.uiProjectList
        editor.takeItem(self.uiProjectList.currentRow())
        if not self.editMode and not self.initalLoad:
            self.startEditMode()
        if not self.initalLoad:
            editor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(editor.metaObject().className()))
            self.editorsEdited.append(editor)

    def onAccept(self):
        '''
        Check DB
        Save options when pressing OK button
        Update Plugin Status
        '''
        self.accept()

    def onReject(self):
        '''
        Run some actions when
        the user closes the dialog
        '''
        if self.editMode:
            res = self.cancelEdit()
            if res:
                self.close()
            else:
                self.show()
        else:
            self.close()

    def closeEvent(self, e):
        # Write window size and position to QSettings
        if self.editMode:
            self.onReject()
        else:
            SetWindowSizeAndPos("film", self.size(), self.pos())
            e.accept()

    def extractGpsFromImages(self):
        key = self.uiCurrentFilmNumberEdit.text()
        e2p = Exif2Points(self.iface, key)
        layer = e2p.run()
        if layer:
            self.apisLayer.requestShapeFile(layer, groupName="Flugwege", addToCanvas=True)

    def exportDetailsPdf(self):
        if self.printingOptionsDlg is None:
            self.printingOptionsDlg = APISPrintingOptions(self)
            self.printingOptionsDlg.setWindowTitle("Druck Optionen: Film")
            self.printingOptionsDlg.configure(False, False, visPersonalDataChk=True)

        self.printingOptionsDlg.show()

        if self.printingOptionsDlg.exec_():
            printPersonalData = self.printingOptionsDlg.printPersonalData()
            APISPrinterQueue([{'type': APISTemplatePrinter.FILM, 'idList': [self.uiCurrentFilmNumberEdit.text()], 'options': {'personalData': printPersonalData}}],
                             OutputMode.MergeNone,
                             openFile=self.printingOptionsDlg.uiOpenFilesChk.isChecked(),
                             openFolder=self.printingOptionsDlg.uiOpenFolderChk.isChecked(),
                             dbm=self.dbm,
                             parent=self)

    def openSearchFilmDialog(self):
        """Run method that performs all the real work"""
        # show the dialog
        self.searchFilmDlg.show()
        #self.filmSelectionDlg.uiFilmNumberEdit.setFocus()
        # Run the dialog event loop and See if OK was pressed
        if self.searchFilmDlg.exec_():
            # QMessageBox.warning(None, "FilmNumber", self.searchFilmDlg.generateSearchQuery())

            model = QSqlRelationalTableModel(self, self.dbm.db)
            model.setTable("film")
            searchMode, searchFilter = self.searchFilmDlg.generateSearchFilter()
            # QMessageBox.information(self, "info", searchFilter)

            model.setFilter(searchFilter)
            model.select()
            rc = model.rowCount()
            while (model.canFetchMore()):
                model.fetchMore()
                rc = model.rowCount()

            query = QSqlQuery(self.dbm.db)
            searchQuery = "select filmnummer, substr(filmnummer, 3, 8) as 'ohne_hersteller', flugdatum, anzahl_bilder, weise, art_ausarbeitung, militaernummer, militaernummer_alt from film where {0}".format(searchFilter)
            query.exec_(searchQuery)
            querySize = 0
            while(query.next()):
                querySize += 1
            query.seek(-1)
            # if model.rowCount():
            if querySize > 0:
                # open film selection list dialog
                searchListDlg = APISFilmSelectionList(self.iface, model, self.dbm, self.imageRegistry, parent=self)
                searchListDlg.uiFilmCountLbl.setText(str(rc))
                searchListDlg.uiFilmCountDescriptionLbl.setText(u"Film gefunden" if model.rowCount() == 1 else u"Filme gefunden")
                searchListDlg.uiFilmSearchModeLbl.setText(searchMode)
                res = searchListDlg.loadFilmListBySqlQuery(query)
                if res and searchListDlg.exec_():
                    #QMessageBox.warning(None, "FilmNumber", unicode(searchListDlg.filmNumberToLoad))
                    self.loadRecordByKeyAttribute("filmnummer", searchListDlg.filmNumberToLoad)
            else:
                QMessageBox.warning(self, u"Film Suche", u"Keine Ergebnisse mit den angegebenen Suchkriterien.")
                self.openSearchFilmDialog()

            #QMessageBox.warning(None, "FilmNumber", u"{0}, rows: {1}".format(self.searchFilmDlg.generateSearchQuery(), model.rowCount()))

            # Get Search String/Query
            #if not self.loadRecordByKeyAttribute("filmnummer", self.filmSelectionDlg.filmNumber()):
                #self.openFilmSelectionDialog()

    def openFilmSelectionDialog(self):
        """Run method that performs all the real work"""
        self.filmSelectionDlg.show()
        self.filmSelectionDlg.uiFilmNumberEdit.setFocus()
        if self.filmSelectionDlg.exec_():
            if not self.loadRecordByKeyAttribute("filmnummer", self.filmSelectionDlg.filmNumber()):
                self.openFilmSelectionDialog()

    def openNewFilmDialog(self):
        """Run method that performs all the real work"""
        self.newFilmDlg.show()
        if self.newFilmDlg.exec_():
            self.addNewFilm(self.newFilmDlg.flightDate(), self.newFilmDlg.useLastEntry(), self.newFilmDlg.producer(), self.newFilmDlg.producerCode())

    def openEditWeatherDialog(self):
        self.editWeatherDlg.setWeatherCode(self.uiWeatherCodeEdit.text())
        self.editWeatherDlg.show()

        if self.editWeatherDlg.exec_():
            self.uiWeatherCodeEdit.setText(self.editWeatherDlg.weatherCode())
            #self.uiWeatherPTxt.setPlainText(self.editWeatherDlg.weatherDescription())

    def generateWeatherCode(self):
        weatherDescription = self._generateWeatherCode(self.uiWeatherCodeEdit.text())
        self.uiWeatherPTxt.setPlainText(weatherDescription)

    def _generateWeatherCode(self, weatherCode):
        categories = ["Low Cloud Amount", "Visibility Kilometres", "Low Cloud Height", "Weather", "Remarks Mission", "Remarks Weather"]
        query = QSqlQuery(self.dbm.db)
        pos = 0
        help = 0
        weatherDescription = ""
        for c in weatherCode:
            qryStr = "select description from wetter where category = '{0}' and code = '{1}' limit 1".format(categories[pos - help], c)
            query.exec_(qryStr)
            query.first()
            fn = query.value(0)
            if pos <= 5:
                weatherDescription += categories[pos] + ': ' + fn
                if pos < 5:
                    weatherDescription += '\n'
            else:
                weatherDescription += '; ' + fn

            if pos >= 5:
                help += 1
            pos += 1
        return weatherDescription

    def openSystemTableEditorDialog(self, table, updateEditor):
        if self.dbm:
            self.systemTableEditorDlg = APISAdvancedInputDialog(self.dbm, table, False, parent=self)

            if self.systemTableEditorDlg.tableExists:
                if self.systemTableEditorDlg.exec_():
                    # See if OK was pressed
                    # rec = self.systemTableEditorDlg.getRecord()
                    # Update updateEditor
                    # self.setupComboBox(self.uiProjectSelectionCombo, "projekt", 0, None)
                    self.updateComboBox(updateEditor)

            else:
                QMessageBox.warning(self, "Tabelle nicht vorhanden", "Die Tabelle {0} ist in der APIS Datenbank nicht vorhanden".format(table))

        else:
            QMessageBox.warning(self, "Warning Database", "Die APIS Datenbank konnte nicht gefunden werden.")

    def updateComboBox(self, updateEditor):
        updateEditor.model().select()
        tv = updateEditor.view()
        tv.resizeRowsToContents()
        tv.resizeColumnsToContents()
        scroll = 0 if updateEditor.count() <= updateEditor.maxVisibleItems() else QApplication.style().pixelMetric(
            QStyle.PM_ScrollBarExtent)
        tv.setMinimumWidth(tv.horizontalHeader().length() + scroll)
        updateEditor.setCurrentIndex(updateEditor.count() - 1)
        if updateEditor.validator():
            updateEditor.lineEdit().setValidator(
                InListValidator([updateEditor.itemText(i) for i in range(updateEditor.count())],
                                updateEditor.lineEdit(), None, self))

    def openFlightPathDialog(self, filmList, toClose=None):
        self.flightPathDlg.viewFilms(filmList)  # DEBUG
        self.flightPathDlg.show()

        if self.flightPathDlg.exec_():
            #TODO load Data in TOC, Close Windows
            if toClose:
                toClose.close()
            self.close()

    def openSiteSelectionListDialog(self):
        if self.uiFilmModeCombo.currentIndex() == APISFilm.VERTICAL:
            fromTable = "luftbild_senk_fp"
        elif self.uiFilmModeCombo.currentIndex() == APISFilm.OBLIQUE:
            fromTable = "luftbild_schraeg_fp"

        query = QSqlQuery(self.dbm.db)
        query.prepare("SELECT fundortnummer, flurname, katastralgemeinde, fundgewinnung, sicherheit FROM fundort WHERE fundortnummer IN (SELECT DISTINCT fo.fundortnummer FROM fundort fo, {0} WHERE fo.geometry IS NOT NULL AND {0}.geometry IS NOT NULL AND {0}.filmnummer = '{1}' AND Intersects({0}.geometry, fo.geometry) AND fo.ROWID IN (SELECT ROWID FROM SpatialIndex WHERE f_table_name = 'fundort' AND search_frame = {0}.geometry)) ORDER BY katastralgemeindenummer, land, fundortnummer_nn".format(fromTable, self.uiCurrentFilmNumberEdit.text()))
        query.exec_()
        info = u"gefunden, die vom Film {0} abgedeckt/geschnitten werden.".format(self.uiCurrentFilmNumberEdit.text())
        res = self.siteSelectionListDlg.loadSiteListBySpatialQuery(query, info)
        if res:
            self.siteSelectionListDlg.show()
            if self.siteSelectionListDlg.exec_():
                pass

    def openImageSelectionListDialog(self):
        if self.uiFilmModeCombo.currentIndex() == APISFilm.VERTICAL:
            fromTable = 'luftbild_senk_cp'
            spatialIndicator = 'massstab'
        elif self.uiFilmModeCombo.currentIndex() == APISFilm.OBLIQUE:
            fromTable = 'luftbild_schraeg_cp'
            spatialIndicator = 'radius'

        query = QSqlQuery(self.dbm.db)
        query.prepare("SELECT cp.bildnummer AS bildnummer, cp.filmnummer AS filmnummer, cp.{2} AS mst_radius, f.weise AS weise, f.art_ausarbeitung AS art FROM {0} AS cp, film AS f WHERE cp.filmnummer = '{1}' AND f.filmnummer = '{1}'".format(fromTable, self.uiCurrentFilmNumberEdit.text(), spatialIndicator))
        query.exec_()
        res = self.imageSelectionListDlg.loadImageListBySqlQuery(query)
        if res:
            self.imageSelectionListDlg.show()
            if self.imageSelectionListDlg.exec_():
                pass

    def addNewFilm(self, flightDate, useLastEntry, producer, producerCode):
        self.initalLoad = True
        self.addMode = True
        self.startEditMode()
        row = self.model.rowCount()
        self.mapper.submit()
        while (self.model.canFetchMore()):
            self.model.fetchMore()

        self.model.insertRow(row)

        if useLastEntry:
            #copy last row
            for c in range(1, self.model.columnCount()):
                value = self.model.data(self.model.createIndex(row - 1, c))
                self.model.setData(self.model.createIndex(row, c), value)
                editor = self.mapper.mappedWidgetAt(c)

                if editor and not (value == 'NULL' or value == ''):
                    cName = editor.metaObject().className()
                    if (cName == "QLineEdit" or cName == "QDateEdit") and editor.isReadOnly():
                        pass
                    else:
                        editor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(editor.metaObject().className()))
                        self.editorsEdited.append(editor)

        self.mapper.setCurrentIndex(row)

        self.uiTotalFilmCountLbl.setText(str(self.model.rowCount()))
        self.uiFlightDate.setDate(flightDate)
        #self.uiFlightQgsDate.setDate(flightDate)
        self.uiProducerEdit.setText(producer)
        self.uiArchiveCombo.lineEdit().setText(producer)
        if not useLastEntry:
            self.uiWeatherCodeEdit.setText("9990X")

        #now = QDateTime.currentDateTime()
        now = QDate.currentDate()
        self.uiInitalEntryDate.setDate(now)
        #self.uiInitalEntryQgsDate.setDateTime(now)
        self.uiLastChangesDate.setDate(now)
        #self.uiLastChangesQgsDate.setDateTime(now)
        self.uiFilmModeCombo.setEnabled(True)

        #Filmnummer
        hh = producerCode
        yyyy = flightDate.toString("yyyy")
        mm = flightDate.toString("MM")

        query = QSqlQuery(self.dbm.db)
        qryStr = "select max(filmnummer_nn) from film where filmnummer_hh_jjjj_mm = '{0}{1}{2}' limit 1".format(hh, yyyy, mm)
        query.exec_(qryStr)
        query.first()
        fn = query.value(0)

        if isinstance(fn, int):
            nn = str(fn + 1).zfill(2)
        else:
            nn = "01"
        self.uiCurrentFilmNumberEdit.setText("{0}{1}{2}{3}".format(hh, yyyy, mm, nn))

        self.initalLoad = False

    def removeNewFilm(self):
        self.initalLoad = True
        row = self.mapper.currentIndex()
        self.model.removeRow(row)
        self.model.submitAll()
        while (self.model.canFetchMore()):
            self.model.fetchMore()
        self.uiTotalFilmCountLbl.setText(str(self.model.rowCount()))
        self.mapper.toLast()
        self.initalLoad = False

    def saveEdits(self):
        # Check Mandatory fields
        flag = False
        for mEditor in self.mandatoryEditors:
            cName = mEditor.metaObject().className()
            if cName == 'QLineEdit':
                value = mEditor.text()
            elif cName == 'QComboBox':
                value = mEditor.lineEdit().text()
            if value.strip() == "":
                flag = True
                mEditor.setStyleSheet("{0} {{background-color: rgb(240, 160, 160);}}".format(cName))
                if mEditor not in self.editorsEdited:
                    self.editorsEdited.append(mEditor)
            else:
                if mEditor in self.editorsEdited:
                    mEditor.setStyleSheet("{0} {{background-color: rgb(153, 204, 255);}}".format(cName))
                #else:
                    #mEditor.setStyleSheet("")
        if flag:
            QMessageBox.warning(self, self.tr(u"Benötigte Felder Ausfüllen"), self.tr(u"Füllen Sie bitte alle Felder aus, die mit * gekennzeichnet sind."))
            return False

        #saveToModel
        currIdx = self.mapper.currentIndex()
        #now = QDateTime.currentDateTime()
        now = QDate.currentDate()
        self.uiLastChangesDate.setDate(now)
        #self.uiLastChangesQgsDate.setDateTime(now)

        res = self.mapper.submit()

        if not res:
            sqlError = self.mapper.model().lastError()
            QMessageBox.information(self, "Submit", u"Error: {0}, {1}".format(res, sqlError.text()))

        while (self.model.canFetchMore()):
            self.model.fetchMore()

        self.mapper.setCurrentIndex(currIdx)
        self.endEditMode()
        return True

    def cancelEdit(self):
        if self.editMode:
            result = QMessageBox.question(self,
                                          self.tr(u"Änderungen wurden vorgenommen!"),
                                          self.tr(u"Möchten Sie die Änerungen speichern?"),
                                          QMessageBox.Yes | QMessageBox.No,
                                          QMessageBox.Yes)

            #save or not save
            if result == QMessageBox.Yes:
                res = self.saveEdits()
                if res:
                    return True
                else:
                    return False
            elif result == QMessageBox.No:
                if self.addMode:
                    self.removeNewFilm()

                self.mapper.setCurrentIndex(self.mapper.currentIndex())
                self.endEditMode()
                return True

    def startEditMode(self):
        self.editMode = True
        self.enableItemsInLayout(self.uiTopHorizontalLayout, False)
        self.enableItemsInLayout(self.uiBottomHorizontalLayout, False)
        self.uiOkBtn.setEnabled(False)
        self.uiSaveBtn.setEnabled(True)
        self.uiCancelBtn.setEnabled(True)
        self.editorsEdited = []

    def endEditMode(self):
        self.editMode = False
        self.addMode = False
        self.enableItemsInLayout(self.uiTopHorizontalLayout, True)
        self.enableItemsInLayout(self.uiBottomHorizontalLayout, True)
        self.uiOkBtn.setEnabled(True)
        self.uiSaveBtn.setEnabled(False)
        self.uiCancelBtn.setEnabled(False)
        for editor in self.editorsEdited:
            cName = editor.metaObject().className()
            if (cName == "QLineEdit" or cName == "QDateEdit") and editor.isReadOnly():
                editor.setStyleSheet("{0} {{background-color: rgb(218, 218, 218);}}".format(cName))
            else:
                editor.setStyleSheet("")
        self.editorsEdited = []

        self.uiFilmModeCombo.setEnabled(False)

    def showEvent(self, evnt):
        # QMessageBox.information(self, "info", "db requires update: {0}".format(self.dbm.dbRequiresUpdate))

        if self.dbm.dbRequiresUpdate:
            self.initalLoad = True
            for editor in [self.uiArchiveCombo, self.uiCameraCombo, self.uiFilmMakeCombo, self.uiCopyrightCombo, self.uiProjectSelectionCombo, self.newFilmDlg.uiProducerCombo]:
                self.updateComboBox(editor)
            currIdx = self.mapper.currentIndex()
            self.model.select()
            while (self.model.canFetchMore()):
                self.model.fetchMore()
            self.mapper.setCurrentIndex(currIdx)
            self.dbm.dbRequiresUpdate = False
            self.initalLoad = False
예제 #7
0
class QmyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  #创建UI对象
        self.ui.setupUi(self)  #构造UI界面

        self.setCentralWidget(self.ui.splitter)

        ##   tableView显示属性设置
        self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectItems)
        self.ui.tableView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.ui.tableView.setAlternatingRowColors(True)
        self.ui.tableView.verticalHeader().setDefaultSectionSize(22)
        self.ui.tableView.horizontalHeader().setDefaultSectionSize(60)

##  ==============自定义功能函数============

    def __getFieldNames(self):  ##获取所有字段名称
        emptyRec = self.tabModel.record()  #获取空记录,只有字段名
        self.fldNum = {}  #字段名与序号的字典
        for i in range(emptyRec.count()):
            fieldName = emptyRec.fieldName(i)
            self.ui.comboFields.addItem(fieldName)
            self.fldNum.setdefault(fieldName)
            self.fldNum[fieldName] = i
        print(self.fldNum)

    def __openTable(self):  ##打开数据表
        self.tabModel = QSqlTableModel(self, self.DB)  #数据模型
        self.tabModel.setTable("employee")  #设置数据表
        self.tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit
                                      )  #数据保存方式,OnManualSubmit , OnRowChange
        self.tabModel.setSort(self.tabModel.fieldIndex("empNo"),
                              Qt.AscendingOrder)  #排序
        if (self.tabModel.select() == False):  #查询数据失败
            QMessageBox.critical(
                self, "错误信息",
                "打开数据表错误,错误信息\n" + self.tabModel.lastError().text())
            return

        self.__getFieldNames()  #获取字段名和序号

        ##字段显示名
        self.tabModel.setHeaderData(self.fldNum["empNo"], Qt.Horizontal, "工号")
        self.tabModel.setHeaderData(self.fldNum["Name"], Qt.Horizontal, "姓名")
        self.tabModel.setHeaderData(self.fldNum["Gender"], Qt.Horizontal, "性别")
        self.tabModel.setHeaderData(self.fldNum["Birthday"], Qt.Horizontal,
                                    "出生日期")
        self.tabModel.setHeaderData(self.fldNum["Province"], Qt.Horizontal,
                                    "省份")
        self.tabModel.setHeaderData(self.fldNum["Department"], Qt.Horizontal,
                                    "部门")
        self.tabModel.setHeaderData(self.fldNum["Salary"], Qt.Horizontal, "工资")

        self.tabModel.setHeaderData(self.fldNum["Memo"], Qt.Horizontal,
                                    "备注")  #这两个字段不在tableView中显示
        self.tabModel.setHeaderData(self.fldNum["Photo"], Qt.Horizontal, "照片")

        ##      self.tabModel.setHeaderData(self.tabModel.fieldIndex("empNo"),  Qt.Horizontal, "工号")
        ##      self.tabModel.setHeaderData(self.tabModel.fieldIndex("Name"),   Qt.Horizontal, "姓名")
        ##      self.tabModel.setHeaderData(self.tabModel.fieldIndex("Gender"), Qt.Horizontal, "性别")
        ##      self.tabModel.setHeaderData(self.tabModel.fieldIndex("Birthday"),  Qt.Horizontal, "出生日期")
        ##      self.tabModel.setHeaderData(self.tabModel.fieldIndex("Province"),  Qt.Horizontal, "省份")
        ##      self.tabModel.setHeaderData(self.tabModel.fieldIndex("Department"),Qt.Horizontal, "部门")
        ##      self.tabModel.setHeaderData(self.tabModel.fieldIndex("Salary"), Qt.Horizontal, "工资")
        ##      self.tabModel.setHeaderData(self.tabModel.fieldIndex("Memo"),   Qt.Horizontal, "备注")   #这两个字段不在tableView中显示
        ##      self.tabModel.setHeaderData(self.tabModel.fieldIndex("Photo"),  Qt.Horizontal, "照片")

        ##创建界面组件与数据模型的字段之间的数据映射
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.tabModel)  #设置数据模型
        self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit)

        ##界面组件与tabModel的具体字段之间的联系
        self.mapper.addMapping(self.ui.dbSpinEmpNo, self.fldNum["empNo"])
        self.mapper.addMapping(self.ui.dbEditName, self.fldNum["Name"])
        self.mapper.addMapping(self.ui.dbComboSex, self.fldNum["Gender"])
        self.mapper.addMapping(self.ui.dbEditBirth, self.fldNum["Birthday"])
        self.mapper.addMapping(self.ui.dbComboProvince,
                               self.fldNum["Province"])
        self.mapper.addMapping(self.ui.dbComboDep, self.fldNum["Department"])
        self.mapper.addMapping(self.ui.dbSpinSalary, self.fldNum["Salary"])
        self.mapper.addMapping(self.ui.dbEditMemo, self.fldNum["Memo"])
        self.mapper.toFirst()  #移动到首记录

        self.selModel = QItemSelectionModel(self.tabModel)  #选择模型
        self.selModel.currentChanged.connect(self.do_currentChanged)  #当前项变化时触发
        self.selModel.currentRowChanged.connect(
            self.do_currentRowChanged)  #选择行变化时

        self.ui.tableView.setModel(self.tabModel)  #设置数据模型
        self.ui.tableView.setSelectionModel(self.selModel)  #设置选择模型

        self.ui.tableView.setColumnHidden(self.fldNum["Memo"], True)  #隐藏列
        self.ui.tableView.setColumnHidden(self.fldNum["Photo"], True)  #隐藏列

        ##tableView上为“性别”和“部门”两个字段设置自定义代理组件
        strList = ("男", "女")
        self.__delegateSex = QmyComboBoxDelegate()
        self.__delegateSex.setItems(strList, False)
        self.ui.tableView.setItemDelegateForColumn(
            self.fldNum["Gender"], self.__delegateSex)  #Combbox选择型

        strList = ("销售部", "技术部", "生产部", "行政部")
        self.__delegateDepart = QmyComboBoxDelegate()
        self.__delegateDepart.setItems(strList, True)
        self.ui.tableView.setItemDelegateForColumn(self.fldNum["Department"],
                                                   self.__delegateDepart)

        ##更新actions和界面组件的使能状态
        self.ui.actOpenDB.setEnabled(False)

        self.ui.actRecAppend.setEnabled(True)
        self.ui.actRecInsert.setEnabled(True)
        self.ui.actRecDelete.setEnabled(True)
        self.ui.actScan.setEnabled(True)

        self.ui.groupBoxSort.setEnabled(True)
        self.ui.groupBoxFilter.setEnabled(True)

##  ==========由connectSlotsByName() 自动连接的槽函数==================

    @pyqtSlot()  ##选择数据库,打开数据表
    def on_actOpenDB_triggered(self):
        dbFilename, flt = QFileDialog.getOpenFileName(
            self, "选择数据库文件", "", "SQL Lite数据库(*.db *.db3)")
        if (dbFilename == ''):
            return

        #打开数据库
        self.DB = QSqlDatabase.addDatabase("QSQLITE")  #添加 SQLITE数据库驱动
        self.DB.setDatabaseName(dbFilename)  #设置数据库名称
        ##    DB.setHostName()
        ##    DB.setUserName()
        ##    DB.setPassword()
        if self.DB.open():  #打开数据库
            self.__openTable()  #打开数据表
        else:
            QMessageBox.warning(self, "错误", "打开数据库失败")

    @pyqtSlot()  ##保存修改
    def on_actSubmit_triggered(self):
        res = self.tabModel.submitAll()
        if (res == False):
            QMessageBox.information(
                self, "消息", "数据保存错误,错误信息\n" + self.tabModel.lastError().text())
        else:
            self.ui.actSubmit.setEnabled(False)
            self.ui.actRevert.setEnabled(False)

    @pyqtSlot()  ##取消修改
    def on_actRevert_triggered(self):
        self.tabModel.revertAll()
        self.ui.actSubmit.setEnabled(False)
        self.ui.actRevert.setEnabled(False)

    @pyqtSlot()  ##添加记录
    def on_actRecAppend_triggered(self):
        self.tabModel.insertRow(self.tabModel.rowCount(),
                                QModelIndex())  #在末尾添加一个记录

        curIndex = self.tabModel.index(self.tabModel.rowCount() - 1,
                                       1)  #创建最后一行的ModelIndex
        self.selModel.clearSelection()  #清空选择项
        self.selModel.setCurrentIndex(
            curIndex, QItemSelectionModel.Select)  #设置刚插入的行为当前选择行

        currow = curIndex.row()  #获得当前行
        self.tabModel.setData(self.tabModel.index(currow,
                                                  self.fldNum["empNo"]),
                              2000 + self.tabModel.rowCount())  #自动生成编号
        self.tabModel.setData(
            self.tabModel.index(currow, self.fldNum["Gender"]), "男")

    @pyqtSlot()  ##插入记录
    def on_actRecInsert_triggered(self):
        curIndex = self.ui.tableView.currentIndex()  #QModelIndex
        self.tabModel.insertRow(curIndex.row(), QModelIndex())
        self.selModel.clearSelection()  #清除已有选择
        self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select)

    @pyqtSlot()  ##删除记录
    def on_actRecDelete_triggered(self):
        curIndex = self.selModel.currentIndex()  #获取当前选择单元格的模型索引
        self.tabModel.removeRow(curIndex.row())  #删除当前行

    @pyqtSlot()  ##清除照片
    def on_actPhotoClear_triggered(self):
        curRecNo = self.selModel.currentIndex().row()
        curRec = self.tabModel.record(curRecNo)  #获取当前记录,QSqlRecord
        curRec.setNull("Photo")  #设置为空值
        self.tabModel.setRecord(curRecNo, curRec)
        self.ui.dbLabPhoto.clear()  #清除界面上的图片显示

    @pyqtSlot()  ##设置照片
    def on_actPhoto_triggered(self):
        fileName, filt = QFileDialog.getOpenFileName(self, "选择图片文件", "",
                                                     "照片(*.jpg)")
        if (fileName == ''):
            return

        file = QFile(fileName)  #fileName为图片文件名
        file.open(QIODevice.ReadOnly)
        try:
            data = file.readAll()  #QByteArray
        finally:
            file.close()

        curRecNo = self.selModel.currentIndex().row()
        curRec = self.tabModel.record(curRecNo)  #获取当前记录QSqlRecord
        curRec.setValue("Photo", data)  #设置字段数据
        self.tabModel.setRecord(curRecNo, curRec)

        pic = QPixmap()
        pic.loadFromData(data)
        W = self.ui.dbLabPhoto.width()
        self.ui.dbLabPhoto.setPixmap(pic.scaledToWidth(W))  #在界面上显示

    @pyqtSlot()  ##涨工资,遍历数据表所有记录
    def on_actScan_triggered(self):
        if (self.tabModel.rowCount() == 0):
            return

        for i in range(self.tabModel.rowCount()):
            aRec = self.tabModel.record(i)  #获取当前记录
            ##         salary=aRec.value("Salary").toFloat()      #错误,无需再使用toFloat()函数
            salary = aRec.value("Salary")
            salary = salary * 1.1
            aRec.setValue("Salary", salary)
            self.tabModel.setRecord(i, aRec)

        if (self.tabModel.submitAll()):
            QMessageBox.information(self, "消息", "涨工资计算完毕")

    @pyqtSlot(int)  ##排序字段变化
    def on_comboFields_currentIndexChanged(self, index):
        if self.ui.radioBtnAscend.isChecked():
            self.tabModel.setSort(index, Qt.AscendingOrder)
        else:
            self.tabModel.setSort(index, Qt.DescendingOrder)
        self.tabModel.select()

    @pyqtSlot()  ##升序
    def on_radioBtnAscend_clicked(self):
        self.tabModel.setSort(self.ui.comboFields.currentIndex(),
                              Qt.AscendingOrder)
        self.tabModel.select()

    @pyqtSlot()  ##降序
    def on_radioBtnDescend_clicked(self):
        self.tabModel.setSort(self.ui.comboFields.currentIndex(),
                              Qt.DescendingOrder)
        self.tabModel.select()

    @pyqtSlot()  ##过滤,男
    def on_radioBtnMan_clicked(self):
        self.tabModel.setFilter("Gender='男'")

    ##      print(self.tabModel.filter())
    ##      self.tabModel.select()

    @pyqtSlot()  ##数据过滤,女
    def on_radioBtnWoman_clicked(self):
        self.tabModel.setFilter("Gender='女' ")

    ##      print(self.tabModel.filter())
    ##      self.tabModel.select()

    @pyqtSlot()  ##取消数据过滤
    def on_radioBtnBoth_clicked(self):
        self.tabModel.setFilter("")

    ##      print(self.tabModel.filter())
    ##      self.tabModel.select()

##  =============自定义槽函数===============================

    def do_currentChanged(self, current, previous):  ##更新actPost和actCancel 的状态
        self.ui.actSubmit.setEnabled(self.tabModel.isDirty())  #有未保存修改时可用
        self.ui.actRevert.setEnabled(self.tabModel.isDirty())

    def do_currentRowChanged(self, current, previous):  #行切换时的状态控制
        self.ui.actRecDelete.setEnabled(current.isValid())
        self.ui.actPhoto.setEnabled(current.isValid())
        self.ui.actPhotoClear.setEnabled(current.isValid())

        if (current.isValid() == False):
            self.ui.dbLabPhoto.clear()  #清除图片显示
            return

        self.mapper.setCurrentIndex(current.row())  #更新数据映射的行号
        curRec = self.tabModel.record(current.row())  #获取当前记录,QSqlRecord类型

        if (curRec.isNull("Photo")):  #图片字段内容为空
            self.ui.dbLabPhoto.clear()
        else:
            ##         data=bytearray(curRec.value("Photo"))   #可以工作
            data = curRec.value("Photo")  # 也可以工作
            pic = QPixmap()
            pic.loadFromData(data)
            W = self.ui.dbLabPhoto.size().width()
            self.ui.dbLabPhoto.setPixmap(pic.scaledToWidth(W))
예제 #8
0
파일: 0701.py 프로젝트: falomsc/pyqtStudy
class QmyMainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setCentralWidget(self.ui.splitter)

        self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectItems)
        self.ui.tableView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.ui.tableView.setAlternatingRowColors(True)
        self.ui.tableView.verticalHeader().setDefaultSectionSize(22)
        self.ui.tableView.horizontalHeader().setDefaultSectionSize(60)

    def __openTable(self):
        self.tabModel = QSqlTableModel(self, self.DB)
        self.tabModel.setTable("employee")
        self.tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit)
        self.tabModel.setSort(self.tabModel.fieldIndex("empNo"), Qt.AscendingOrder)
        if(self.tabModel.select()==False):
            QMessageBox.critical(self, "错误信息", "打开数据表错误,错误信息\n"+self.tabModel.lastError().text())
            return
        self.__getFieldNames()

        self.tabModel.setHeaderData(self.fldNum["empNo"], Qt.Horizontal, "工号")
        self.tabModel.setHeaderData(self.fldNum["Name"], Qt.Horizontal, "姓名")
        self.tabModel.setHeaderData(self.fldNum["Gender"], Qt.Horizontal, "性别")
        self.tabModel.setHeaderData(self.fldNum["Birthday"], Qt.Horizontal, "出生日期")
        self.tabModel.setHeaderData(self.fldNum["Province"], Qt.Horizontal, "省份")
        self.tabModel.setHeaderData(self.fldNum["Department"], Qt.Horizontal, "部门")
        self.tabModel.setHeaderData(self.fldNum["Salary"], Qt.Horizontal, "工资")
        self.tabModel.setHeaderData(self.fldNum["Memo"], Qt.Horizontal, "备注")
        self.tabModel.setHeaderData(self.fldNum["Photo"], Qt.Horizontal, "照片")

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.tabModel)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit)
        self.mapper.addMapping(self.ui.dbSpinEmpNo, self.fldNum["empNo"])
        self.mapper.addMapping(self.ui.dbEditName, self.fldNum["Name"])
        self.mapper.addMapping(self.ui.dbComboSex, self.fldNum["Gender"])
        self.mapper.addMapping(self.ui.dbEditBirth, self.fldNum["Birthday"])
        self.mapper.addMapping(self.ui.dbComboProvince, self.fldNum["Province"])
        self.mapper.addMapping(self.ui.dbComboDep, self.fldNum["Department"])
        self.mapper.addMapping(self.ui.dbSpinSalary, self.fldNum["Salary"])
        self.mapper.addMapping(self.ui.dbEditMemo, self.fldNum["Memo"])
        self.mapper.toFirst()

        self.selModel = QItemSelectionModel(self.tabModel)
        self.selModel.currentChanged.connect(self.do_currentChanged)
        self.selModel.currentRowChanged.connect(self.do_currentRowChanged)

        self.ui.tableView.setModel(self.tabModel)
        self.ui.tableView.setSelectionModel(self.selModel)

        self.ui.tableView.setColumnHidden(self.fldNum["Memo"], True)
        self.ui.tableView.setColumnHidden(self.fldNum["Photo"], True)


        strList = ("男", "女")
        self.__delegatesex = QmyComboBoxDelegate()
        self.__delegatesex.setItems(strList, False)
        self.ui.tableView.setItemDelegateForColumn(self.fldNum["Gender"], self.__delegatesex)

        strList = ("销售部", "技术部", "生产部", "行政部")
        self.__delegateDepart = QmyComboBoxDelegate()
        self.__delegateDepart.setItems(strList, True)
        self.ui.tableView.setItemDelegateForColumn(self.fldNum["Department"], self.__delegateDepart)

        self.ui.actOpenDB.setEnabled(False)
        self.ui.actOpenDB.setEnabled(False)

        self.ui.actRecAppend.setEnabled(True)
        self.ui.actRecInsert.setEnabled(True)
        self.ui.actRecDelete.setEnabled(True)
        self.ui.actScan.setEnabled(True)

        self.ui.groupBoxSort.setEnabled(True)
        self.ui.groupBoxFilter.setEnabled(True)


    def __getFieldNames(self):
        emptyRec = self.tabModel.record()
        self.fldNum = {}
        for i in range(emptyRec.count()):
            fieldName = emptyRec.fieldName(i)
            self.ui.comboFields.addItem(fieldName)
            self.fldNum.setdefault(fieldName)
            self.fldNum[fieldName]=i
        print(self.fldNum)

    def do_currentChanged(self, current, previous):
        self.ui.actSubmit.setEnabled(self.tabModel.isDirty())
        self.ui.actRevert.setEnabled(self.tabModel.isDirty())

    def do_currentRowChanged(self, current, previous):
        self.ui.actRecDelete.setEnabled(current.isValid())
        self.ui.actPhoto.setEnabled(current.isValid())
        self.ui.actPhotoClear.setEnabled(current.isValid())

        if(current.isValid() == False):
            self.ui.dbLabPhoto.clear()
            return

        self.mapper.setCurrentIndex(current.row())
        curRec = self.tabModel.record(current.row())

        if(curRec.isNull("Photo")):
            self.ui.dbLabPhoto.clear()
        else:
            data = curRec.value("Photo")
            pic = QPixmap()
            pic.loadFromData(data)
            w = self.ui.dbLabPhoto.size().width()
            self.ui.dbLabPhoto.setPixmap(pic.scaledToWidth(w))

    @pyqtSlot()
    def on_actOpenDB_triggered(self):
        dbFilename ,flt = QFileDialog.getOpenFileName(self, "选择数据库文件", "", "SQL Lite数据库(*.db *.db3)")
        if (dbFilename == ''):
            return
        self.DB = QSqlDatabase.addDatabase("QSQLITE")
        self.DB.setDatabaseName(dbFilename)
        if self.DB.open():
            self.__openTable()
        else:
            QMessageBox.warning(self, "错误", "打开数据库失败")

    @pyqtSlot()
    def on_actSubmit_triggered(self):
        res = self.tabModel.submitAll()
        if(res == False):
            QMessageBox.information(self, "消息", "数据保存错误,错误信息\n" + self.tabModel.lastError().text())
        else:
            self.ui.actSubmit.setEnabled(False)
            self.ui.actRevert.setEnabled(False)


    @pyqtSlot()
    def on_actRevert_triggered(self):
        self.tabModel.revertAll()
        self.ui.actSubmit.setEnabled(False)
        self.ui.actRevert.setEnabled(False)

    @pyqtSlot()
    def on_actRecAppend_triggered(self):
        self.tabModel.insertRow(self.tabModel.rowCount(), QModelIndex())
        curIndex = self.tabModel.index(self.tabModel.rowCount()-1, 1)
        self.selModel.clearSelection()
        self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select)
        currow = curIndex.row()
        self.tabModel.setData(self.tabModel.index(currow, self.fldNum["empNo"]), 2000+self.tabModel.rowCount())
        self.tabModel.setData(self.tabModel.index(currow, self.fldNum["Gender"]), "男")

    @pyqtSlot()
    def on_actRecInsert_triggered(self):
        curIndex = self.ui.tableView.currentIndex()
        self.tabModel.insertRow(curIndex.row(), QModelIndex())
        self.selModel.clearSelection()
        self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select)

    @pyqtSlot()
    def on_actRecDelete_triggered(self):
        curIndex = self.selModel.currentIndex()
        self.tabModel.removeRow(curIndex.row())

    @pyqtSlot()
    def on_actPhotoClear_triggered(self):
        curRecNo = self.selModel.currentIndex().row()
        curRec = self.tabModel.record(curRecNo)
        curRec.setNull("Photo")
        self.tabModel.setRecord(curRecNo, curRec)
        self.ui.dbLabPhoto.clear()

    @pyqtSlot()
    def on_actPhoto_triggered(self):
        fileName, filt = QFileDialog.getOpenFileName(self, "选择图片文件", "", "照片(*.jpg")
        if(fileName==''):
            return
        file=QFile(fileName)
        file.open(QIODevice.ReadOnly)
        try:
            data = file.readAll()
        finally:
            file.close()

        curRecNo = self.selModel.currentIndex().row()
        curRec = self.tabModel.record(curRecNo)
        curRec.setValue("Photo", data)
        self.tabModel.setRecord(curRecNo, curRec)

        pic = QPixmap()
        pic.loadFromData(data)
        w = self.ui.dbLabPhoto.width()
        self.ui.dbLabPhoto.setPixmap(pic.scaledToWidth(w))

    @pyqtSlot()
    def on_actScan_triggered(self):
        if(self.tabModel.rowCount()==0):
            return
        for i in range(self.tabModel.rowCount()):
            aRec = self.tabModel.record(i)
            salary = aRec.value("Salary")
            salary = salary*1.1
            aRec.setValue("Salary", salary)
            self.tabModel.setRecord(i, aRec)

        if(self.tabModel.submitAll()):
            QMessageBox.information(self, "消息", "涨工资计算完毕了")

    @pyqtSlot()
    def on_comboFields_currentIndexChanged(self, index):
        if self.ui.radioBtnAscend.isChecked():
            self.tabModel.setSort(index, Qt.AscendingOrder)
        else:
            self.tabModel.setSort(index, Qt.DescendingOrder)
        self.tabModel.select()

    @pyqtSlot()
    def on_radioBtnAscend_clicked(self):
        self.tabModel.setSort(self.ui.comboFields.currentIndex(), Qt.AscendingOrder)
        self.tabModel.select()

    @pyqtSlot()
    def on_radioBtnDescend_clicked(self):
        self.tabModel.setSort(self.ui.comboFields.currentIndex(), Qt.DescendingOrder)
        self.tabModel.select()

    @pyqtSlot()
    def on_radioBtnMan_clicked(self):
        self.tabModel.setFilter("Gender='男'")

    @pyqtSlot()
    def on_radioBtnWoman_clicked(self):
        self.tabModel.setFilter("Gender='女'")

    @pyqtSlot()
    def on_radioBtnBoth_clicked(self):
        self.tabModel.setFilter("")
예제 #9
0
class TaskView(QWidget):
    close = pyqtSignal()

    def __init__(self, model):
        super().__init__()
        self.header = QLabel('')
        self.desc = QLineEdit()
        self.date = QDateEdit()
        self.time = QTimeEdit()
        self.init_ui()

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(model)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.addMapping(self.desc, TaskModel.col_desc)
        self.mapper.addMapping(self.date, TaskModel.col_date)
        self.mapper.addMapping(self.time, TaskModel.col_time)

    def set_task(self, index):
        self.mapper.setCurrentIndex(index)
        self.header.setText('РЕДАКТИРОВАНИЕ ЗАДАЧИ')
        # text = 'НОВАЯ ЗАДАЧА'
        # self.date.setDate(QDate().currentDate())

    def create_date(self):
        self.date.setDisplayFormat('dd.MM.yyyy')
        self.date.setCalendarPopup(True)
        self.date.setFixedWidth(120)

        return self.date

    def create_time(self):
        self.time.setDisplayFormat('hh.mm')
        self.time.setFixedWidth(120)

        return self.time

    def create_date_buttons(self):
        date_lt = QHBoxLayout()

        btn_now = QPushButton('сегодня')
        btn_now.clicked.connect(lambda: self.date.setDate(QDate().currentDate()))
        date_lt.addWidget(btn_now, 0, Qt.AlignCenter)

        btn_tomorrow = QPushButton('завтра')
        btn_tomorrow.clicked.connect(lambda: self.date.setDate(QDate().currentDate().addDays(1)))
        date_lt.addWidget(btn_tomorrow, 0, Qt.AlignCenter)

        btn_week_later = QPushButton('через неделю')
        btn_week_later.clicked.connect(lambda: self.date.setDate(QDate().currentDate().addDays(7)))
        date_lt.addWidget(btn_week_later, 0, Qt.AlignCenter)

        return date_lt

    # def create_time_choice(self):
    #     self.time.setMaxVisibleItems(15)
    #     self.time.setStyleSheet('QComboBox { combobox-popup: 0; }')
    #     for it in range(24):
    #         self.time.insertItem(it * 2 + 0, '%.2d:00' % it)
    #         self.time.insertItem(it * 2 + 1, '%.2d:30' % it)
    #
    #     return self.time

    def save(self):
        print('save', self.mapper.submit())
        self.close.emit()

    def cancel(self):
        self.close.emit()

    def remove(self):
        self.mapper.model().removeRow(self.mapper.currentIndex())
        self.close.emit()

    def create_control_buttons(self):
        control_lt = QHBoxLayout()

        btn_save = QPushButton('Сохранить')
        btn_save.clicked.connect(self.save)
        control_lt.addWidget(btn_save, 0, Qt.AlignCenter)

        btn_cancel = QPushButton('Отменить')
        btn_cancel.clicked.connect(self.cancel)
        control_lt.addWidget(btn_cancel, 0, Qt.AlignCenter)

        btn_remove = QPushButton('Удалить')
        btn_remove.clicked.connect(self.remove)
        control_lt.addWidget(btn_remove, 1, Qt.AlignRight)

        return control_lt

    def create_main_form(self):
        fm = QFormLayout()

        fm.addRow(self.header)
        fm.addRow(QLabel(''))

        fm.addRow(self.desc)
        fm.addRow(QLabel(''))

        fm.addRow(QLabel('Когда это нужно сделать?'))
        fm.addRow(self.create_date())
        fm.addRow(self.create_date_buttons())
        fm.addRow(QLabel(''))

        fm.addRow(QLabel('Во сколько?'))
        fm.addRow(self.create_time())

        return fm

    def init_ui(self):
        layout = QVBoxLayout()
        layout.addLayout(self.create_main_form())
        layout.addStretch()
        layout.addLayout(self.create_control_buttons())
        self.setLayout(layout)
예제 #10
0
class MasternodeOutputsTab(QWidget):
    """Widget that is used to select a masternode output."""
    def __init__(self, parent):
        super(MasternodeOutputsTab, self).__init__(parent)
        self.dialog = parent
        self.manager = parent.manager

        include_frozen_checkbox = QCheckBox(_('Include frozen addresses'))
        include_frozen_checkbox.setChecked(False)
        self.scan_outputs_button = QPushButton(
            _('Scan For Masternode Outputs'))

        def on_scan_outputs():
            """Call scan_for_outputs() with whether to include frozen addresses."""
            self.scan_for_outputs(include_frozen_checkbox.isChecked())

        self.scan_outputs_button.clicked.connect(on_scan_outputs)

        self.status_edit = QLineEdit()
        self.status_edit.setReadOnly(True)
        self.valid_outputs_list = MasternodeOutputsWidget()
        self.valid_outputs_list.outputSelected.connect(self.set_output)

        self.collateral_edit = PrevOutWidget()
        self.collateral_edit.setReadOnly(True)

        self.mapper = QDataWidgetMapper()
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.setModel(self.dialog.masternodes_widget.proxy_model)

        model = self.dialog.masternodes_widget.model
        self.mapper.addMapping(self.collateral_edit, model.VIN, b'string')

        self.save_output_button = QPushButton(_('Save'))
        self.save_output_button.setEnabled(False)
        self.save_output_button.clicked.connect(self.save_output)

        vbox = QVBoxLayout()

        desc = ' '.join([
            'Use this tab to scan for and choose a collateral payment for your masternode.',
            'A valid collateral payment is exactly 15000000 VESTX.'
        ])
        desc = QLabel(_(desc))
        desc.setWordWrap(True)
        vbox.addWidget(desc)

        status_box = QHBoxLayout()
        status_box.setContentsMargins(0, 0, 0, 0)
        status_box.addWidget(QLabel(_('Status:')))
        status_box.addWidget(self.status_edit, stretch=1)
        vbox.addLayout(status_box)

        valid_outputs_box = QVBoxLayout()
        valid_outputs_box.setContentsMargins(0, 0, 0, 0)
        valid_outputs_box.addWidget(QLabel(_('Masternode Outputs:')))
        valid_outputs_box.addWidget(self.valid_outputs_list)

        vbox.addLayout(
            util.Buttons(include_frozen_checkbox, self.scan_outputs_button))
        vbox.addLayout(valid_outputs_box)

        vbox.addWidget(self.collateral_edit)
        vbox.addLayout(util.Buttons(self.save_output_button))
        self.setLayout(vbox)

    def scan_for_outputs(self, include_frozen):
        """Scan for 15000000 VESTX outputs.

        If one or more is found, populate the list and enable the sign button.
        """
        self.valid_outputs_list.clear()
        exclude_frozen = not include_frozen
        coins = list(
            self.manager.get_masternode_outputs(exclude_frozen=exclude_frozen))

        if len(coins) > 0:
            self.valid_outputs_list.add_outputs(coins)
        else:
            self.status_edit.setText(
                _('No 15000000 VESTX outputs were found.'))
            self.status_edit.setStyleSheet(
                util.ColorScheme.RED.as_stylesheet())

    def set_output(self, vin):
        """Set the selected output."""
        self.collateral_edit.set_dict(vin)
        self.save_output_button.setEnabled(True)

    def save_output(self):
        """Save the selected output as the current masternode's collateral."""
        self.mapper.submit()
        # Determine the masternode's collateral key using this output.
        self.dialog.populate_collateral_key()

    def set_mapper_index(self, row):
        """Set the row that the data widget mapper should use."""
        self.valid_outputs_list.clear()
        self.status_edit.clear()
        self.status_edit.setStyleSheet(
            util.ColorScheme.DEFAULT.as_stylesheet())
        self.mapper.setCurrentIndex(row)
        mn = self.dialog.masternodes_widget.masternode_for_row(row)

        status_text = _('Masternode has no collateral payment assigned.')
        can_scan = not mn.announced
        # Disable the scan_outputs button if the masternode already has an assigned output.
        if mn.vin.get('value', 0) == COIN * 15000000:
            can_scan = False
            self.valid_outputs_list.add_output(mn.vin)
            status_text = _('Masternode already has a collateral payment.')

        self.status_edit.setText(_(status_text))

        self.scan_outputs_button.setEnabled(can_scan)
예제 #11
0
class MainWindow(QMainWindow):
    """
    The main window class
    """
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.ui = uic.loadUi("gui/main_window.ui")

        self.timestamp_filename = None
        self.video_filename = None
        self.media_start_time = None
        self.media_end_time = None
        self.restart_needed = False
        self.timer_period = 100
        self.is_full_screen = False
        self.media_started_playing = False
        self.media_is_playing = False
        self.original_geometry = None
        self.mute = False

        self.timestamp_model = TimestampModel(None, self)
        self.proxy_model = QSortFilterProxyModel(self)
        self.ui.list_timestamp.setModel(self.timestamp_model)
        self.ui.list_timestamp.doubleClicked.connect(
            lambda event: self.ui.list_timestamp.indexAt(event.pos()).isValid()
            and self.run()
        )

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_ui)
        self.timer.timeout.connect(self.timer_handler)
        self.timer.start(self.timer_period)

        self.vlc_instance = vlc.Instance()
        self.media_player = self.vlc_instance.media_player_new()
        # if sys.platform == "darwin":  # for MacOS
        #     self.ui.frame_video = QMacCocoaViewContainer(0)

        self.ui.frame_video.doubleClicked.connect(self.toggle_full_screen)
        self.ui.frame_video.wheel.connect(self.wheel_handler)
        self.ui.frame_video.keyPressed.connect(self.key_handler)

        # Set up buttons
        self.ui.button_run.clicked.connect(self.run)
        self.ui.button_timestamp_browse.clicked.connect(
            self.browse_timestamp_handler
        )
        self.ui.button_video_browse.clicked.connect(
            self.browse_video_handler
        )

        self.play_pause_model = ToggleButtonModel(None, self)
        self.play_pause_model.setStateMap(
            {
                True: {
                    "text": "",
                    "icon": qta.icon("fa.play", scale_factor=0.7)
                },
                False: {
                    "text": "",
                    "icon": qta.icon("fa.pause", scale_factor=0.7)
                }
            }
        )
        self.ui.button_play_pause.setModel(self.play_pause_model)
        self.ui.button_play_pause.clicked.connect(self.play_pause)

        self.mute_model = ToggleButtonModel(None, self)
        self.mute_model.setStateMap(
            {
                True: {
                    "text": "",
                    "icon": qta.icon("fa.volume-up", scale_factor=0.8)
                },
                False: {
                    "text": "",
                    "icon": qta.icon("fa.volume-off", scale_factor=0.8)
                }
            }
        )
        self.ui.button_mute_toggle.setModel(self.mute_model)
        self.ui.button_mute_toggle.clicked.connect(self.toggle_mute)

        self.ui.button_full_screen.setIcon(
            qta.icon("ei.fullscreen", scale_factor=0.6)
        )
        self.ui.button_full_screen.setText("")
        self.ui.button_full_screen.clicked.connect(self.toggle_full_screen)
        self.ui.button_speed_up.clicked.connect(self.speed_up_handler)
        self.ui.button_speed_up.setIcon(
            qta.icon("fa.arrow-circle-o-up", scale_factor=0.8)
        )
        self.ui.button_speed_up.setText("")
        self.ui.button_slow_down.clicked.connect(self.slow_down_handler)
        self.ui.button_slow_down.setIcon(
            qta.icon("fa.arrow-circle-o-down", scale_factor=0.8)
        )
        self.ui.button_slow_down.setText("")
        self.ui.button_mark_start.setIcon(
            qta.icon("fa.quote-left", scale_factor=0.7)
        )
        self.ui.button_mark_start.setText("")
        self.ui.button_mark_end.setIcon(
            qta.icon("fa.quote-right", scale_factor=0.7)
        )
        self.ui.button_mark_end.setText("")
        self.ui.button_add_entry.clicked.connect(self.add_entry)
        self.ui.button_remove_entry.clicked.connect(self.remove_entry)

        self.ui.button_mark_start.clicked.connect(
            lambda: self.set_mark(start_time=int(
                self.media_player.get_position() *
                self.media_player.get_media().get_duration()))
        )
        self.ui.button_mark_end.clicked.connect(
            lambda: self.set_mark(end_time=int(
                self.media_player.get_position() *
                self.media_player.get_media().get_duration()))
        )

        self.ui.slider_progress.setTracking(False)
        self.ui.slider_progress.valueChanged.connect(self.set_media_position)
        self.ui.slider_volume.valueChanged.connect(self.set_volume)
        self.ui.entry_description.setReadOnly(True)

        # Mapper between the table and the entry detail
        self.mapper = QDataWidgetMapper()
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.ui.button_save.clicked.connect(self.mapper.submit)

        # Set up default volume
        self.set_volume(self.ui.slider_volume.value())

        self.vlc_events = self.media_player.event_manager()
        self.vlc_events.event_attach(
            vlc.EventType.MediaPlayerTimeChanged, self.media_time_change_handler
        )

        # Let our application handle mouse and key input instead of VLC
        self.media_player.video_set_mouse_input(False)
        self.media_player.video_set_key_input(False)

        self.ui.show()


    def add_entry(self):
        if not self.timestamp_filename:
            self._show_error("You haven't chosen a timestamp file yet")
        row_num = self.timestamp_model.rowCount()
        self.timestamp_model.insertRow(row_num)
        start_cell = self.timestamp_model.index(row_num, 0)
        end_cell = self.timestamp_model.index(row_num, 1)
        self.timestamp_model.setData(start_cell, TimestampDelta.from_string(""))
        self.timestamp_model.setData(end_cell, TimestampDelta.from_string(""))

    def remove_entry(self):
        if not self.timestamp_filename:
            self._show_error("You haven't chosen a timestamp file yet")
        selected = self.ui.list_timestamp.selectionModel().selectedIndexes()
        if len(selected) == 0:
            return
        self.proxy_model.removeRow(selected[0].row()) and self.mapper.submit()


    def set_media_position(self, position):
        percentage = position / 10000.0
        self.media_player.set_position(percentage)
        absolute_position = percentage * \
            self.media_player.get_media().get_duration()
        if absolute_position > self.media_end_time:
            self.media_end_time = -1

    def set_mark(self, start_time=None, end_time=None):
        if len(self.ui.list_timestamp.selectedIndexes()) == 0:
            blankRowIndex = self.timestamp_model.blankRowIndex()
            if not blankRowIndex.isValid():
                self.add_entry()
            else:
                index = self.proxy_model.mapFromSource(blankRowIndex)
                self.ui.list_timestamp.selectRow(index.row())
        selectedIndexes = self.ui.list_timestamp.selectedIndexes()
        if start_time:
            self.proxy_model.setData(selectedIndexes[0],
                                     TimestampDelta.string_from_int(
                                         start_time))
        if end_time:
            self.proxy_model.setData(selectedIndexes[1],
                                     TimestampDelta.string_from_int(
                                         end_time))

    def update_ui(self):
        self.ui.slider_progress.blockSignals(True)
        self.ui.slider_progress.setValue(
            self.media_player.get_position() * 10000
        )
        # When the video finishes
        self.ui.slider_progress.blockSignals(False)
        if self.media_started_playing and \
           self.media_player.get_media().get_state() == vlc.State.Ended:
            self.play_pause_model.setState(True)
            # Apparently we need to reset the media, otherwise the player
            # won't play at all
            self.media_player.set_media(self.media_player.get_media())
            self.set_volume(self.ui.slider_volume.value())
            self.media_is_playing = False
            self.media_started_playing = False
            self.run()

    def timer_handler(self):
        """
        This is a workaround, because for some reason we can't call set_time()
        inside the MediaPlayerTimeChanged handler (as the video just stops
        playing)
        """
        if self.restart_needed:
            self.media_player.set_time(self.media_start_time)
            self.restart_needed = False

    def key_handler(self, event):
        if event.key() == Qt.Key_Escape and self.is_full_screen:
            self.toggle_full_screen()
        if event.key() == Qt.Key_F:
            self.toggle_full_screen()
        if event.key() == Qt.Key_Space:
            self.play_pause()

    def wheel_handler(self, event):
        self.modify_volume(1 if event.angleDelta().y() > 0 else -1)

    def toggle_mute(self):
        self.media_player.audio_set_mute(not self.media_player.audio_get_mute())
        self.mute = not self.mute
        self.mute_model.setState(not self.mute)

    def modify_volume(self, delta_percent):
        new_volume = self.media_player.audio_get_volume() + delta_percent
        if new_volume < 0:
            new_volume = 0
        elif new_volume > 40:
            new_volume = 40
        self.media_player.audio_set_volume(new_volume)
        self.ui.slider_volume.setValue(self.media_player.audio_get_volume())

    def set_volume(self, new_volume):
        self.media_player.audio_set_volume(new_volume)

    def speed_up_handler(self):
        self.modify_rate(0.1)

    def slow_down_handler(self):
        self.modify_rate(-0.1)

    def modify_rate(self, delta_percent):
        new_rate = self.media_player.get_rate() + delta_percent
        if new_rate < 0.2 or new_rate > 2.0:
            return
        self.media_player.set_rate(new_rate)

    def media_time_change_handler(self, _):
        if self.media_end_time == -1:
            return
        if self.media_player.get_time() > self.media_end_time:
            self.restart_needed = True

    def update_slider_highlight(self):
        if self.ui.list_timestamp.selectionModel().hasSelection():
            selected_row = self.ui.list_timestamp.selectionModel(). \
                selectedRows()[0]
            self.media_start_time = self.ui.list_timestamp.model().data(
                selected_row.model().index(selected_row.row(), 0),
                Qt.UserRole
            )
            self.media_end_time = self.ui.list_timestamp.model().data(
                selected_row.model().index(selected_row.row(), 1),
                Qt.UserRole
            )
            duration = self.media_player.get_media().get_duration()
            self.media_end_time = self.media_end_time \
                if self.media_end_time != 0 else duration
            if self.media_start_time > self.media_end_time:
                raise ValueError("Start time cannot be later than end time")
            if self.media_start_time > duration:
                raise ValueError("Start time not within video duration")
            if self.media_end_time > duration:
                raise ValueError("End time not within video duration")
            slider_start_pos = (self.media_start_time / duration) * \
                               (self.ui.slider_progress.maximum() -
                                self.ui.slider_progress.minimum())
            slider_end_pos = (self.media_end_time / duration) * \
                             (self.ui.slider_progress.maximum() -
                              self.ui.slider_progress.minimum())
            self.ui.slider_progress.setHighlight(
                int(slider_start_pos), int(slider_end_pos)
            )

        else:
            self.media_start_time = 0
            self.media_end_time = -1


    def run(self):
        """
        Execute the loop
        """
        if self.timestamp_filename is None:
            self._show_error("No timestamp file chosen")
            return
        if self.video_filename is None:
            self._show_error("No video file chosen")
            return
        try:
            self.update_slider_highlight()
            self.media_player.play()
            self.media_player.set_time(self.media_start_time)
            self.media_started_playing = True
            self.media_is_playing = True
            self.play_pause_model.setState(False)
        except Exception as ex:
            self._show_error(str(ex))
            print(traceback.format_exc())

    def play_pause(self):
        """Toggle play/pause status
        """
        if not self.media_started_playing:
            self.run()
            return
        if self.media_is_playing:
            self.media_player.pause()
        else:
            self.media_player.play()
        self.media_is_playing = not self.media_is_playing
        self.play_pause_model.setState(not self.media_is_playing)

    def toggle_full_screen(self):
        if self.is_full_screen:
            # TODO Artifacts still happen some time when exiting full screen
            # in X11
            self.ui.frame_media.showNormal()
            self.ui.frame_media.restoreGeometry(self.original_geometry)
            self.ui.frame_media.setParent(self.ui.widget_central)
            self.ui.layout_main.addWidget(self.ui.frame_media, 2, 3, 3, 1)
            # self.ui.frame_media.ensurePolished()
        else:
            self.ui.frame_media.setParent(None)
            self.ui.frame_media.setWindowFlags(Qt.FramelessWindowHint |
                                               Qt.CustomizeWindowHint)
            self.original_geometry = self.ui.frame_media.saveGeometry()
            desktop = QApplication.desktop()
            rect = desktop.screenGeometry(desktop.screenNumber(QCursor.pos()))
            self.ui.frame_media.setGeometry(rect)
            self.ui.frame_media.showFullScreen()
            self.ui.frame_media.show()
        self.ui.frame_video.setFocus()
        self.is_full_screen = not self.is_full_screen

    def browse_timestamp_handler(self):
        """
        Handler when the timestamp browser button is clicked
        """
        tmp_name, _ = QFileDialog.getOpenFileName(
            self, "Choose Timestamp file", None,
            "Timestamp File (*.tmsp);;All Files (*)"
        )
        if not tmp_name:
            return
        self.set_timestamp_filename(QDir.toNativeSeparators(tmp_name))

    def _sort_model(self):
        self.ui.list_timestamp.sortByColumn(0, Qt.AscendingOrder)

    def _select_blank_row(self, parent, start, end):
        self.ui.list_timestamp.selectRow(start)

    def set_timestamp_filename(self, filename):
        """
        Set the timestamp file name
        """
        if not os.path.isfile(filename):
            self._show_error("Cannot access timestamp file " + filename)
            return

        try:
            self.timestamp_model = TimestampModel(filename, self)
            self.timestamp_model.timeParseError.connect(
                lambda err: self._show_error(err)
            )
            self.proxy_model.setSortRole(Qt.UserRole)
            self.proxy_model.dataChanged.connect(self._sort_model)
            self.proxy_model.dataChanged.connect(self.update_slider_highlight)
            self.proxy_model.setSourceModel(self.timestamp_model)
            self.proxy_model.rowsInserted.connect(self._sort_model)
            self.proxy_model.rowsInserted.connect(self._select_blank_row)
            self.ui.list_timestamp.setModel(self.proxy_model)

            self.timestamp_filename = filename
            self.ui.entry_timestamp.setText(self.timestamp_filename)

            self.mapper.setModel(self.proxy_model)
            self.mapper.addMapping(self.ui.entry_start_time, 0)
            self.mapper.addMapping(self.ui.entry_end_time, 1)
            self.mapper.addMapping(self.ui.entry_description, 2)
            self.ui.list_timestamp.selectionModel().selectionChanged.connect(
                self.timestamp_selection_changed)
            self._sort_model()

            directory = os.path.dirname(self.timestamp_filename)
            basename = os.path.basename(self.timestamp_filename)
            timestamp_name_without_ext = os.path.splitext(basename)[0]
            for file_in_dir in os.listdir(directory):
                current_filename = os.path.splitext(file_in_dir)[0]
                found_video = (current_filename == timestamp_name_without_ext
                               and file_in_dir != basename)
                if found_video:
                    found_video_file = os.path.join(directory, file_in_dir)
                    self.set_video_filename(found_video_file)
                    break
        except ValueError as err:
            self._show_error("Timestamp file is invalid")

    def timestamp_selection_changed(self, selected, deselected):
        if len(selected) > 0:
            self.mapper.setCurrentModelIndex(selected.indexes()[0])
            self.ui.button_save.setEnabled(True)
            self.ui.button_remove_entry.setEnabled(True)
            self.ui.entry_start_time.setReadOnly(False)
            self.ui.entry_end_time.setReadOnly(False)
            self.ui.entry_description.setReadOnly(False)
        else:
            self.mapper.setCurrentModelIndex(QModelIndex())
            self.ui.button_save.setEnabled(False)
            self.ui.button_remove_entry.setEnabled(False)
            self.ui.entry_start_time.clear()
            self.ui.entry_end_time.clear()
            self.ui.entry_description.clear()
            self.ui.entry_start_time.setReadOnly(True)
            self.ui.entry_end_time.setReadOnly(True)
            self.ui.entry_description.setReadOnly(True)

    def set_video_filename(self, filename):
        """
        Set the video filename
        """
        if not os.path.isfile(filename):
            self._show_error("Cannot access video file " + filename)
            return

        self.video_filename = filename

        media = self.vlc_instance.media_new(self.video_filename)
        media.parse()
        if not media.get_duration():
            self._show_error("Cannot play this media file")
            self.media_player.set_media(None)
            self.video_filename = None
        else:
            self.media_player.set_media(media)
            if sys.platform.startswith('linux'): # for Linux using the X Server
                self.media_player.set_xwindow(self.ui.frame_video.winId())
            elif sys.platform == "win32": # for Windows
                self.media_player.set_hwnd(self.ui.frame_video.winId())
            elif sys.platform == "darwin": # for MacOS
                self.media_player.set_nsobject(self.ui.frame_video.winId())
            self.ui.entry_video.setText(self.video_filename)
            self.media_started_playing = False
            self.media_is_playing = False
            self.set_volume(self.ui.slider_volume.value())
            self.play_pause_model.setState(True)

    def browse_video_handler(self):
        """
        Handler when the video browse button is clicked
        """
        tmp_name, _ = QFileDialog.getOpenFileName(
            self, "Choose Video file", None,
            "All Files (*)"
        )
        if not tmp_name:
            return
        self.set_video_filename(QDir.toNativeSeparators(tmp_name))

    def _show_error(self, message, title="Error"):
        QMessageBox.warning(self, title, message)
예제 #12
0
class APISSharding(QDialog, FORM_CLASS):

    shardingEditsSaved = pyqtSignal(bool)

    def __init__(self, iface, dbm, parent=None):
        """Constructor."""
        super(APISSharding, self).__init__(parent)
        self.iface = iface
        self.dbm = dbm
        self.setupUi(self)

        # Initial window size/pos last saved. Use default values for first time
        if GetWindowSize("sharding"):
            self.resize(GetWindowSize("sharding"))

        self.settings = QSettings(QSettings().value("APIS/config_ini"),
                                  QSettings.IniFormat)

        self.editMode = False
        self.addMode = False
        self.initalLoad = True

        # Signals/Slot Connections
        self.rejected.connect(self.onReject)
        #self.uiButtonBox.rejected.connect(self.onReject)
        self.uiOkBtn.clicked.connect(self.onAccept)
        self.uiCancelBtn.clicked.connect(self.cancelEdit)
        self.uiSaveBtn.clicked.connect(self.saveEdits)

        mViewPictures = QMenu()
        aViewPicturesPreview = mViewPictures.addAction(
            QIcon(
                os.path.join(QSettings().value("APIS/plugin_dir"), 'ui',
                             'icons', 'image.png')), "in Vorschau")
        aViewPicturesPreview.triggered.connect(self.viewPictures)
        aViewPicturesFolder = mViewPictures.addAction(
            QIcon(
                os.path.join(QSettings().value("APIS/plugin_dir"), 'ui',
                             'icons', 'image.png')), "in Ordner")
        aViewPicturesFolder.triggered.connect(self.openPictures)
        self.uiViewPicturesTBtn.setMenu(mViewPictures)
        self.uiViewPicturesTBtn.clicked.connect(
            self.uiViewPicturesTBtn.showMenu)

        mViewSketches = QMenu()
        aViewSketchesPreview = mViewSketches.addAction(
            QIcon(
                os.path.join(QSettings().value("APIS/plugin_dir"), 'ui',
                             'icons', 'sketch.png')), "in Vorschau")
        aViewSketchesPreview.triggered.connect(self.viewSketches)
        aViewSketchesFolder = mViewSketches.addAction(
            QIcon(
                os.path.join(QSettings().value("APIS/plugin_dir"), 'ui',
                             'icons', 'sketch.png')), "in Ordner")
        aViewSketchesFolder.triggered.connect(self.openSketches)
        self.uiViewSketchesTBtn.setMenu(mViewSketches)
        self.uiViewSketchesTBtn.clicked.connect(
            self.uiViewSketchesTBtn.showMenu)

        self.initalLoad = False

    def openSharding(self, siteNumber, shardingNumber):
        self.initalLoad = True
        self.siteNumber = siteNumber
        self.shardingNumber = shardingNumber

        #QMessageBox.warning(None, self.tr(u"Neu"), self.tr(u"{0}, {1}".format(siteNumber, shardingNumber)))

        # Setup sharding model
        self.model = QSqlRelationalTableModel(self, self.dbm.db)
        self.model.setTable("begehung")
        self.model.setFilter("fundortnummer='{0}' AND begehung='{1}'".format(
            self.siteNumber, self.shardingNumber))
        res = self.model.select()
        self.setupMapper()
        self.mapper.toFirst()
        self.setKgNameAndCode()

        self.initalLoad = False

    def setKgNameAndCode(self):
        query = QSqlQuery(self.dbm.db)
        qryStr = u"select CASE WHEN katastralgemeinde IS NULL AND katastralgemeindenummer IS NULL THEN '--' ELSE katastralgemeindenummer || ' - ' || katastralgemeinde END AS kg FROM fundort WHERE fundortnummer = '{0}'".format(
            self.siteNumber)
        query.exec_(qryStr)
        query.first()
        self.uiCadastralCommunityEdit.setText(query.value(0))

    def setupMapper(self):
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.setItemDelegate(ShardingDelegate())

        self.mapper.setModel(self.model)

        self.mandatoryEditors = [self.uiShardingDate]

        # LineEdits & PlainTextEdits
        self.intValidator = QIntValidator()
        self.doubleValidator = QDoubleValidator()

        self.lineEditMaps = {
            "fundortnummer": {
                "editor": self.uiSiteNumberEdit
            },
            "begehung": {
                "editor": self.uiShardingNumberEdit
            },
            "name": {
                "editor": self.uiNameEdit
            },
            "parzelle": {
                "editor": self.uiPlotPTxt
            },
            "sichtbarkeit": {
                "editor": self.uiVisibilityEdit
            },
            "verbleib": {
                "editor": self.uiWhereaboutsEdit
            },
            "funde": {
                "editor": self.uiFindsPTxt
            },
            "morphologie": {
                "editor": self.uiMorphologyPTxt
            },
            "sonstiges": {
                "editor": self.uiMiscellaneousPTxt
            }
        }
        for key, item in self.lineEditMaps.items():
            self.mapper.addMapping(item["editor"], self.model.fieldIndex(key))
            if "validator" in item:
                item["editor"].setValidator(item["validator"])
            #item["editor"].textChanged.connect(partial(self.onLineEditChanged, item["editor"]))
            item["editor"].textChanged.connect(self.onLineEditChanged)

        # Date and Times
        self.mapper.addMapping(self.uiShardingDate,
                               self.model.fieldIndex("datum"))

        # ComboBox without Model
        self.mapper.addMapping(self.uiShardingTypeCombo,
                               self.model.fieldIndex("begehtyp"))
        self.uiShardingTypeCombo.editTextChanged.connect(
            self.onLineEditChanged)
        # FIXME Pyqt5 AutoCompletion
        #self.uiShardingTypeCombo.setAutoCompletion(True)
        self.uiShardingTypeCombo.lineEdit().setValidator(
            InListValidator([
                self.uiShardingTypeCombo.itemText(i)
                for i in range(self.uiShardingTypeCombo.count())
            ], self.uiShardingTypeCombo.lineEdit(), None, self))

        # ComboBox without Model
        self.mapper.addMapping(self.uiConditionPlantCoverCombo,
                               self.model.fieldIndex("zustand_bewuchs"))
        self.uiConditionPlantCoverCombo.editTextChanged.connect(
            self.onLineEditChanged)
        # FIXME Pyqt5 AutoCompletion
        #self.uiConditionPlantCoverCombo.setAutoCompletion(True)
        self.uiConditionPlantCoverCombo.lineEdit().setValidator(
            InListValidator([
                self.uiConditionPlantCoverCombo.itemText(i)
                for i in range(self.uiConditionPlantCoverCombo.count())
            ], self.uiConditionPlantCoverCombo.lineEdit(), None, self))

        # ComboBox without Model
        self.mapper.addMapping(self.uiConditionLightCombo,
                               self.model.fieldIndex("zustand_licht"))
        self.uiConditionLightCombo.editTextChanged.connect(
            self.onLineEditChanged)
        # FIXME Pyqt5 AutoCompletion
        #self.uiConditionLightCombo.setAutoCompletion(True)
        self.uiConditionLightCombo.lineEdit().setValidator(
            InListValidator([
                self.uiConditionLightCombo.itemText(i)
                for i in range(self.uiConditionLightCombo.count())
            ], self.uiConditionLightCombo.lineEdit(), None, self))

        # ComboBox without Model
        self.mapper.addMapping(self.uiConditionSoilCombo,
                               self.model.fieldIndex("zustand_boden"))
        self.uiConditionSoilCombo.editTextChanged.connect(
            self.onLineEditChanged)
        # FIXME Pyqt5 AutoCompletion
        #self.uiConditionSoilCombo.setAutoCompletion(True)
        self.uiConditionSoilCombo.lineEdit().setValidator(
            InListValidator([
                self.uiConditionSoilCombo.itemText(i)
                for i in range(self.uiConditionSoilCombo.count())
            ], self.uiConditionSoilCombo.lineEdit(), None, self))

        # ComboBox without Model
        self.mapper.addMapping(self.uiConditionMoistureCombo,
                               self.model.fieldIndex("zustand_feuchtigkeit"))
        self.uiConditionMoistureCombo.editTextChanged.connect(
            self.onLineEditChanged)
        # FIXME Pyqt5 AutoCompletion
        #self.uiConditionMoistureCombo.setAutoCompletion(True)
        self.uiConditionMoistureCombo.lineEdit().setValidator(
            InListValidator([
                self.uiConditionMoistureCombo.itemText(i)
                for i in range(self.uiConditionMoistureCombo.count())
            ], self.uiConditionMoistureCombo.lineEdit(), None, self))

        # ComboBox without Model
        self.mapper.addMapping(self.uiConditionRainCombo,
                               self.model.fieldIndex("zustand_abgeregnet"))
        self.uiConditionRainCombo.editTextChanged.connect(
            self.onLineEditChanged)
        # FIXME Pyqt5 AutoCompletion
        #self.uiConditionRainCombo.setAutoCompletion(True)
        self.uiConditionRainCombo.lineEdit().setValidator(
            InListValidator([
                self.uiConditionRainCombo.itemText(i)
                for i in range(self.uiConditionRainCombo.count())
            ], self.uiConditionRainCombo.lineEdit(), None, self))

    def onLineEditChanged(self):
        sender = self.sender()
        if not self.editMode and not self.initalLoad:
            self.startEditMode()
        if not self.initalLoad:
            sender.setStyleSheet(
                "{0} {{background-color: rgb(153, 204, 255);}}".format(
                    sender.metaObject().className()))
            self.editorsEdited.append(sender)

    def onAccept(self):
        '''
        Check DB
        Save options when pressing OK button
        Update Plugin Status
        '''
        # Save Settings
        SetWindowSize("sharding", self.size())
        self.accept()

    def onReject(self):
        '''
        Run some actions when
        the user closes the dialog
        '''
        if self.editMode:
            res = self.cancelEdit()
            if res:
                SetWindowSize("sharding", self.size())
                self.close()
            else:
                self.show()
        else:
            SetWindowSize("sharding", self.size())
            self.close()

    def addNewSharding(self, siteNumber):
        self.initalLoad = True
        self.siteNumber = siteNumber

        # get new sharding number
        query = QSqlQuery(self.dbm.db)
        qryStr = "SELECT CASE WHEN max(begehung) IS NULL THEN 1 ELSE max(begehung)+1 END begehungNeu FROM begehung WHERE fundortnummer='{0}'".format(
            self.siteNumber)
        query.exec_(qryStr)
        query.first()
        self.shardingNumber = query.value(0)

        self.model = QSqlRelationalTableModel(self, self.dbm.db)
        self.model.setTable("begehung")
        self.model.setFilter("fundortnummer='{0}'".format(self.siteNumber))
        res = self.model.select()
        #self.model.submitAll()
        while (self.model.canFetchMore()):
            self.model.fetchMore()

        row = self.model.rowCount()
        #QMessageBox.information(None, "begehung", "{0}".format(row))
        self.model.insertRow(row)

        #QMessageBox.information(None, "begehung", "{0}".format(self.model.rowCount()))

        self.setupMapper()
        self.mapper.toLast()

        self.addMode = True
        self.startEditMode()

        # self.mapper.submit()

        # self.model.insertRow(row)
        # self.mapper.setCurrentIndex(row)

        self.uiSiteNumberEdit.setText(self.siteNumber)
        self.uiShardingNumberEdit.setText(str(self.shardingNumber))
        now = QDate.currentDate()
        self.uiShardingDate.setDate(now)

        self.setKgNameAndCode()

        #QMessageBox.warning(None, self.tr(u"Neu"), self.tr(u"{0}, {1}".format(siteNumber,nn)))

        self.initalLoad = False

    def removeNewSharding(self):
        self.initalLoad = True
        row = self.mapper.currentIndex()
        self.model.removeRow(row + 1)
        self.model.submitAll()
        while (self.model.canFetchMore()):
            self.model.fetchMore()
        self.mapper.toLast()
        self.initalLoad = False

    def saveEdits(self):
        #Check Mandatory fields
        flag = False
        for mEditor in self.mandatoryEditors:
            cName = mEditor.metaObject().className()
            if cName == 'QDateEdit':
                value = mEditor.date().toString("yyyy-MM-dd")
            elif cName == 'QLineEdit':
                value = mEditor.text()
            elif cName == 'QComboBox':
                if mEditor.isEditable():
                    value = mEditor.lineEdit().text()
                else:
                    if mEditor.currentIndex == -1:
                        value = ''
                    else:
                        value = '1'
            if value.strip() == "":
                flag = True
                mEditor.setStyleSheet(
                    "{0} {{background-color: rgb(240, 160, 160);}}".format(
                        cName))
                if mEditor not in self.editorsEdited:
                    self.editorsEdited.append(mEditor)
            else:
                if mEditor in self.editorsEdited:
                    mEditor.setStyleSheet(
                        "{0} {{background-color: rgb(153, 204, 255);}}".format(
                            cName))
                #else:
                #mEditor.setStyleSheet("")
        if flag:
            QMessageBox.warning(
                self, self.tr(u"Benötigte Felder Ausfüllen"),
                self.
                tr(u"Füllen Sie bitte alle Felder aus, die mit * gekennzeichnet sind."
                   ))
            return False

        #saveToModel
        currIdx = self.mapper.currentIndex()
        #QMessageBox.information(None, "begehung", "{0}".format(currIdx))
        #now = QDate.currentDate()
        #self.uiLastChangesDate.setDate(now)
        self.mapper.submit()

        self.mapper.setCurrentIndex(currIdx)

        # emit signal
        self.shardingEditsSaved.emit(True)

        self.endEditMode()
        return True

    def cancelEdit(self):
        currIdx = self.mapper.currentIndex()
        if self.editMode:
            result = QMessageBox.question(
                self, self.tr(u"Änderungen wurden vorgenommen!"),
                self.tr(u"Möchten Sie die Änerungen speichern?"),
                QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)

            #save or not save
            if result == QMessageBox.Yes:
                res = self.saveEdits()
                if res:
                    return True
                else:
                    return False
            elif result == QMessageBox.No:
                if self.addMode:
                    #self.close()
                    self.done(1)
                    self.removeNewSharding()
                    self.endEditMode()

                    return True
                else:
                    self.mapper.setCurrentIndex(currIdx)
                    self.endEditMode()
                    return True

    def startEditMode(self):
        self.editMode = True
        self.uiOkBtn.setEnabled(False)
        self.uiSaveBtn.setEnabled(True)
        self.uiCancelBtn.setEnabled(True)
        self.editorsEdited = []
        self.uiShardingDate.setReadOnly(not self.addMode)
        if self.uiShardingDate.isReadOnly():
            self.uiShardingDate.setStyleSheet(
                "background-color: rgb(218, 218, 218);")
        else:
            self.uiShardingDate.setStyleSheet("")

    def endEditMode(self):
        self.editMode = False
        self.addMode = False
        self.uiOkBtn.setEnabled(True)
        self.uiSaveBtn.setEnabled(False)
        self.uiCancelBtn.setEnabled(False)
        self.uiShardingDate.setReadOnly(not self.addMode)
        self.uiShardingDate.setStyleSheet(
            "background-color: rgb(218, 218, 218);")
        for editor in self.editorsEdited:
            cName = editor.metaObject().className()
            if (cName == "QLineEdit"
                    or cName == "QDateEdit") and editor.isReadOnly():
                editor.setStyleSheet(
                    "{0} {{background-color: rgb(218, 218, 218);}}".format(
                        cName))
            else:
                editor.setStyleSheet("")
        self.editorsEdited = []

    def viewPictures(self):
        dirName = self.settings.value("APIS/insp_image_dir")
        folderNameType = self.settings.value("APIS/insp_image_foto_dir")
        folderNameSite = self.getFolderNameSite(self.siteNumber)
        path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType

        self.loadInImageViewer(path)

    def openPictures(self):
        dirName = self.settings.value("APIS/insp_image_dir")
        folderNameType = self.settings.value("APIS/insp_image_foto_dir")
        folderNameSite = self.getFolderNameSite(self.siteNumber)
        path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType

        if not OpenFileOrFolder(path):
            QMessageBox.information(
                self, u"Begehung",
                u"Das Verzeichnis '{0}' wurde nicht gefunden.".format(path))

    def viewSketches(self):
        dirName = self.settings.value("APIS/insp_image_dir")
        folderNameType = self.settings.value("APIS/insp_image_sketch_dir")
        folderNameSite = self.getFolderNameSite(self.siteNumber)
        path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType

        self.loadInImageViewer(path)

    def openSketches(self):
        dirName = self.settings.value("APIS/insp_image_dir")
        folderNameType = self.settings.value("APIS/insp_image_sketch_dir")
        folderNameSite = self.getFolderNameSite(self.siteNumber)
        path = dirName + u'\\' + folderNameSite + u'\\' + folderNameType

        if not OpenFileOrFolder(path):
            QMessageBox.information(
                None, u"Begehung",
                u"Das Verzeichnis '{0}' wurde nicht gefunden.".format(path))

    def getFolderNameSite(self, siteNumber):
        query = QSqlQuery(self.dbm.db)
        #qryStr = u"SELECT trim(katastralgemeinde) || ' ' || trim(katastralgemeindenummer) || '.' || substr('000' || fundortnummer_nn_legacy, -3, 3) AS folderName FROM fundort f WHERE f.fundortnummer='{0}'".format(siteNumber)
        query.prepare(
            u"SELECT land || '\\'  || CASE WHEN land = 'AUT' THEN replace(replace(replace(replace(lower(trim(katastralgemeinde)), '.',''), '-', ' '), '(', ''), ')', '') || ' ' ELSE '' END || substr('000000' || fundortnummer_nn, -6, 6) AS folderName FROM fundort f WHERE f.fundortnummer='{0}'"
            .format(siteNumber))
        query.exec_()
        query.first()
        return query.value(0)

    def loadInImageViewer(self, path):
        dir = QDir(path)
        if dir.exists():
            entryList = dir.entryList(['*.jpg'], QDir.Files)
            if len(entryList) > 0:
                # load in thumb viewer
                # QMessageBox.information(None, u"Begehung", u",".join(entryList))
                imagePathList = []
                for image in entryList:
                    imagePathList.append(path + u'\\' + image)

                widget = APISThumbViewer()
                widget.load(imagePathList)
                widget.show()
                if widget.exec_():
                    pass
                    # app.exec_()
            else:
                QMessageBox.information(
                    self, u"Begehung",
                    u"Es wurden keine Dateien [*.jpg] für diesen Fundort gefunden."
                )
        else:
            QMessageBox.information(
                self, u"Begehung",
                u"Das Verzeichnis '{0}' wurde nicht gefunden.".format(path))
예제 #13
0
class MainWindow(QMainWindow):
    """
    The main window class
    """
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.ui = uic.loadUi("gui/main_window.ui")

        self.timestamp_filename = None
        self.video_filename = None
        self.media_start_time = None
        self.media_end_time = None
        self.restart_needed = False
        self.timer_period = 100
        self.is_full_screen = False
        self.media_started_playing = False
        self.media_is_playing = False
        self.original_geometry = None
        self.mute = False

        self.timestamp_model = TimestampModel(None, self)
        self.proxy_model = QSortFilterProxyModel(self)
        self.ui.list_timestamp.setModel(self.timestamp_model)
        self.ui.list_timestamp.doubleClicked.connect(
            lambda event: self.ui.list_timestamp.indexAt(event.pos()).isValid()
            and self.run()
        )

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_ui)
        self.timer.timeout.connect(self.timer_handler)
        self.timer.start(self.timer_period)

        self.vlc_instance = vlc.Instance()
        self.media_player = self.vlc_instance.media_player_new()
        # if sys.platform == "darwin":  # for MacOS
        #     self.ui.frame_video = QMacCocoaViewContainer(0)

        self.ui.frame_video.doubleClicked.connect(self.toggle_full_screen)
        self.ui.frame_video.wheel.connect(self.wheel_handler)
        self.ui.frame_video.keyPressed.connect(self.key_handler)

        # Set up Labels:
        # self.ui.lblVideoName.

        # self.displayed_video_title = bind("self.ui.lblVideoName", "text", str)
        self.ui.lblVideoName.setText(self.video_filename)
        self.ui.lblVideoSubtitle.setText("")
        self.ui.dateTimeEdit.setHidden(True)
        self.ui.lblCurrentFrame.setText("")
        self.ui.lblTotalFrames.setText("")

        self.ui.lblCurrentTime.setText("")
        self.ui.lblTotalDuration.setText("")

        self.ui.lblFileFPS.setText("")

        self.ui.spinBoxFrameJumpMultiplier.value = 1



        # Set up buttons
        self.ui.button_run.clicked.connect(self.run)
        self.ui.button_timestamp_browse.clicked.connect(
            self.browse_timestamp_handler
        )
        self.ui.button_timestamp_create.clicked.connect(
            self.create_timestamp_file_handler
        )
        self.ui.button_video_browse.clicked.connect(
            self.browse_video_handler
        )


        # Set up directional buttons
        self.ui.btnSkipLeft.clicked.connect(self.skip_left_handler)
        self.ui.btnSkipRight.clicked.connect(self.skip_right_handler)
        self.ui.btnLeft.clicked.connect(self.seek_left_handler)
        self.ui.btnRight.clicked.connect(self.seek_right_handler)

        self.play_pause_model = ToggleButtonModel(None, self)
        self.play_pause_model.setStateMap(
            {
                True: {
                    "text": "",
                    "icon": qta.icon("fa.play", scale_factor=0.7)
                },
                False: {
                    "text": "",
                    "icon": qta.icon("fa.pause", scale_factor=0.7)
                }
            }
        )
        self.ui.button_play_pause.setModel(self.play_pause_model)
        self.ui.button_play_pause.clicked.connect(self.play_pause)

        self.mute_model = ToggleButtonModel(None, self)
        self.mute_model.setStateMap(
            {
                True: {
                    "text": "",
                    "icon": qta.icon("fa.volume-up", scale_factor=0.8)
                },
                False: {
                    "text": "",
                    "icon": qta.icon("fa.volume-off", scale_factor=0.8)
                }
            }
        )
        self.ui.button_mute_toggle.setModel(self.mute_model)
        self.ui.button_mute_toggle.clicked.connect(self.toggle_mute)

        self.ui.button_full_screen.setIcon(
            qta.icon("ei.fullscreen", scale_factor=0.6)
        )
        self.ui.button_full_screen.setText("")
        self.ui.button_full_screen.clicked.connect(self.toggle_full_screen)
        self.ui.button_speed_up.clicked.connect(self.speed_up_handler)
        self.ui.button_speed_up.setIcon(
            qta.icon("fa.arrow-circle-o-up", scale_factor=0.8)
        )
        self.ui.button_speed_up.setText("")
        self.ui.button_slow_down.clicked.connect(self.slow_down_handler)
        self.ui.button_slow_down.setIcon(
            qta.icon("fa.arrow-circle-o-down", scale_factor=0.8)
        )
        self.ui.button_slow_down.setText("")
        self.ui.button_mark_start.setIcon(
            qta.icon("fa.quote-left", scale_factor=0.7)
        )
        self.ui.button_mark_start.setText("")
        self.ui.button_mark_end.setIcon(
            qta.icon("fa.quote-right", scale_factor=0.7)
        )
        self.ui.button_mark_end.setText("")
        self.ui.button_add_entry.clicked.connect(self.add_entry)
        self.ui.button_remove_entry.clicked.connect(self.remove_entry)

        self.ui.button_mark_start.clicked.connect(
            lambda: self.set_mark(start_time=int(
                self.media_player.get_position() *
                self.media_player.get_media().get_duration()))
        )
        self.ui.button_mark_end.clicked.connect(
            lambda: self.set_mark(end_time=int(
                self.media_player.get_position() *
                self.media_player.get_media().get_duration()))
        )

        self.ui.slider_progress.setTracking(False)
        self.ui.slider_progress.valueChanged.connect(self.set_media_position)
        self.ui.slider_volume.valueChanged.connect(self.set_volume)
        self.ui.entry_description.setReadOnly(True)

        # Mapper between the table and the entry detail
        self.mapper = QDataWidgetMapper()
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.ui.button_save.clicked.connect(self.mapper.submit)

        # Set up default volume
        self.set_volume(self.ui.slider_volume.value())

        self.vlc_events = self.media_player.event_manager()
        self.vlc_events.event_attach(
            vlc.EventType.MediaPlayerTimeChanged, self.media_time_change_handler
        )

        # Let our application handle mouse and key input instead of VLC
        self.media_player.video_set_mouse_input(False)
        self.media_player.video_set_key_input(False)

        self.ui.show()


    def add_entry(self):
        if not self.timestamp_filename:
            self._show_error("You haven't chosen a timestamp file yet")
        row_num = self.timestamp_model.rowCount()
        self.timestamp_model.insertRow(row_num)
        start_cell = self.timestamp_model.index(row_num, 0)
        end_cell = self.timestamp_model.index(row_num, 1)
        self.timestamp_model.setData(start_cell, TimestampDelta.from_string(""))
        self.timestamp_model.setData(end_cell, TimestampDelta.from_string(""))

    def remove_entry(self):
        if not self.timestamp_filename:
            self._show_error("You haven't chosen a timestamp file yet")
        selected = self.ui.list_timestamp.selectionModel().selectedIndexes()
        if len(selected) == 0:
            return
        self.proxy_model.removeRow(selected[0].row()) and self.mapper.submit()


    def set_media_position(self, position):
        percentage = position / 10000.0
        self.media_player.set_position(percentage)
        absolute_position = percentage * \
            self.media_player.get_media().get_duration()
        if absolute_position > self.media_end_time:
            self.media_end_time = -1

    def set_mark(self, start_time=None, end_time=None):
        if len(self.ui.list_timestamp.selectedIndexes()) == 0:
            blankRowIndex = self.timestamp_model.blankRowIndex()
            if not blankRowIndex.isValid():
                self.add_entry()
            else:
                index = self.proxy_model.mapFromSource(blankRowIndex)
                self.ui.list_timestamp.selectRow(index.row())
        selectedIndexes = self.ui.list_timestamp.selectedIndexes()
        if start_time:
            self.proxy_model.setData(selectedIndexes[0],
                                     TimestampDelta.string_from_int(
                                         start_time))
        if end_time:
            self.proxy_model.setData(selectedIndexes[1],
                                     TimestampDelta.string_from_int(
                                         end_time))

    def update_ui(self):
        self.ui.slider_progress.blockSignals(True)
        self.ui.slider_progress.setValue(
            self.media_player.get_position() * 10000
        )
        #print(self.media_player.get_position() * 10000)

        self.update_video_file_play_labels()

        # When the video finishes
        self.ui.slider_progress.blockSignals(False)
        if self.media_started_playing and \
           self.media_player.get_media().get_state() == vlc.State.Ended:
            self.play_pause_model.setState(True)
            # Apparently we need to reset the media, otherwise the player
            # won't play at all
            self.media_player.set_media(self.media_player.get_media())
            self.set_volume(self.ui.slider_volume.value())
            self.media_is_playing = False
            self.media_started_playing = False
            self.run()

    def timer_handler(self):
        """
        This is a workaround, because for some reason we can't call set_time()
        inside the MediaPlayerTimeChanged handler (as the video just stops
        playing)
        """
        if self.restart_needed:
            self.media_player.set_time(self.media_start_time)
            self.restart_needed = False

    def key_handler(self, event):
        if event.key() == Qt.Key_Escape and self.is_full_screen:
            self.toggle_full_screen()
        if event.key() == Qt.Key_F:
            self.toggle_full_screen()
        if event.key() == Qt.Key_Space:
            self.play_pause()

    def wheel_handler(self, event):
        self.modify_volume(1 if event.angleDelta().y() > 0 else -1)

    def toggle_mute(self):
        self.media_player.audio_set_mute(not self.media_player.audio_get_mute())
        self.mute = not self.mute
        self.mute_model.setState(not self.mute)

    def modify_volume(self, delta_percent):
        new_volume = self.media_player.audio_get_volume() + delta_percent
        if new_volume < 0:
            new_volume = 0
        elif new_volume > 40:
            new_volume = 40
        self.media_player.audio_set_volume(new_volume)
        self.ui.slider_volume.setValue(self.media_player.audio_get_volume())

    def set_volume(self, new_volume):
        self.media_player.audio_set_volume(new_volume)

    def speed_up_handler(self):
        self.modify_rate(0.1)

    def slow_down_handler(self):
        self.modify_rate(-0.1)

    def modify_rate(self, delta_percent):
        new_rate = self.media_player.get_rate() + delta_percent
        if new_rate < 0.2 or new_rate > 2.0:
            return
        self.media_player.set_rate(new_rate)

    def media_time_change_handler(self, _):
        if self.media_end_time == -1:
            return
        if self.media_player.get_time() > self.media_end_time:
            self.restart_needed = True

    def update_slider_highlight(self):
        if self.ui.list_timestamp.selectionModel().hasSelection():
            selected_row = self.ui.list_timestamp.selectionModel(). \
                selectedRows()[0]
            self.media_start_time = self.ui.list_timestamp.model().data(
                selected_row.model().index(selected_row.row(), 0),
                Qt.UserRole
            )
            self.media_end_time = self.ui.list_timestamp.model().data(
                selected_row.model().index(selected_row.row(), 1),
                Qt.UserRole
            )
            duration = self.media_player.get_media().get_duration()
            self.media_end_time = self.media_end_time \
                if self.media_end_time != 0 else duration
            if self.media_start_time > self.media_end_time:
                raise ValueError("Start time cannot be later than end time")
            if self.media_start_time > duration:
                raise ValueError("Start time not within video duration")
            if self.media_end_time > duration:
                raise ValueError("End time not within video duration")
            slider_start_pos = (self.media_start_time / duration) * \
                               (self.ui.slider_progress.maximum() -
                                self.ui.slider_progress.minimum())
            slider_end_pos = (self.media_end_time / duration) * \
                             (self.ui.slider_progress.maximum() -
                              self.ui.slider_progress.minimum())
            self.ui.slider_progress.setHighlight(
                int(slider_start_pos), int(slider_end_pos)
            )

        else:
            self.media_start_time = 0
            self.media_end_time = -1


    def run(self):
        """
        Execute the loop
        """
        if self.timestamp_filename is None:
            self._show_error("No timestamp file chosen")
            return
        if self.video_filename is None:
            self._show_error("No video file chosen")
            return
        try:
            self.update_slider_highlight()
            self.media_player.play()
            self.media_player.set_time(self.media_start_time)
            self.media_started_playing = True
            self.media_is_playing = True
            self.play_pause_model.setState(False)
        except Exception as ex:
            self._show_error(str(ex))
            print(traceback.format_exc())

    def play_pause(self):
        """Toggle play/pause status
        """
        if not self.media_started_playing:
            self.run()
            return
        if self.media_is_playing:
            self.media_player.pause()
        else:
            self.media_player.play()
        self.media_is_playing = not self.media_is_playing
        self.play_pause_model.setState(not self.media_is_playing)

    def update_video_file_play_labels(self):
        curr_total_fps = self.media_player.get_fps()
        curr_total_duration = self.media_player.get_length()
        totalNumFrames = int(curr_total_duration * curr_total_fps)
        if totalNumFrames > 0:
            self.ui.lblTotalFrames.setText(str(totalNumFrames))
        else:
            self.ui.lblTotalFrames.setText("--")
        if curr_total_duration > 0:
            self.ui.lblTotalDuration.setText(str(curr_total_duration))  # Gets duration in [ms]
        else:
            self.ui.lblTotalDuration.setText("--")

        # Changing Values: Dynamically updated each time the playhead changes
        curr_percent_complete = self.media_player.get_position()  # Current percent complete between 0.0 and 1.0

        if curr_percent_complete >= 0:
            self.ui.lblPlaybackPercent.setText(str(curr_percent_complete))
        else:
            self.ui.lblPlaybackPercent.setText("--")

        curr_frame = int(round(curr_percent_complete * totalNumFrames))

        if curr_frame >= 0:
            self.ui.lblCurrentFrame.setText(str(curr_frame))
        else:
            self.ui.lblCurrentFrame.setText("--")

        if self.media_player.get_time() >= 0:
            self.ui.lblCurrentTime.setText(str(self.media_player.get_time()) + "[ms]")  # Gets time in [ms]
        else:
            self.ui.lblCurrentTime.setText("-- [ms]")  # Gets time in [ms]






    # Called only when the video file changes:
    def update_video_file_labels_on_file_change(self):
        if self.video_filename is None:
            self.ui.lblVideoName.setText("")
        else:
            self.ui.lblVideoName.setText(self.video_filename)
            # Only updated when the video file is changed:
            curr_total_fps = self.media_player.get_fps()
            self.ui.lblFileFPS.setText(str(curr_total_fps))

            curr_total_duration = self.media_player.get_length()
            totalNumFrames = int(curr_total_duration * curr_total_fps)
            if totalNumFrames > 0:
                self.ui.lblTotalFrames.setText(str(totalNumFrames))
            else:
                self.ui.lblTotalFrames.setText("--")

            if curr_total_duration > 0:
                self.ui.lblTotalDuration.setText(str(curr_total_duration)) # Gets duration in [ms]
            else:
                self.ui.lblTotalDuration.setText("--")

            self.update_video_file_play_labels()

    def get_frame_multipler(self):
        return self.ui.spinBoxFrameJumpMultiplier.value

    # def compute_total_number_frames(self):
    #     self.media_player.get_length()


    def seek_left_handler(self):
        print('seek: left')
        self.seek_frames(-10 * self.get_frame_multipler())

    def skip_left_handler(self):
        print('skip: left')
        self.seek_frames(-1 * self.get_frame_multipler())

    def seek_right_handler(self):
        print('seek: right')
        self.seek_frames(10 * self.get_frame_multipler())

    def skip_right_handler(self):
        print('skip: right')
        self.seek_frames(1 * self.get_frame_multipler())

    def seek_frames(self, relativeFrameOffset):
        """Jump a certain number of frames forward or back
        """
        if self.video_filename is None:
            self._show_error("No video file chosen")
            return
        # if self.media_end_time == -1:
        #     return

        curr_total_fps = self.media_player.get_fps()
        relativeSecondsOffset = relativeFrameOffset / curr_total_fps # Desired offset in seconds
        curr_total_duration = self.media_player.get_length()
        relative_percent_offset = relativeSecondsOffset / curr_total_duration # percent of the whole that we want to skip




        totalNumFrames = int(curr_total_duration * curr_total_fps)

        try:
            didPauseMedia = False
            if self.media_is_playing:
                self.media_player.pause()
                didPauseMedia = True

            newPosition = self.media_player.get_position() + relative_percent_offset
            # newTime = int(self.media_player.get_time() + relativeFrameOffset)

            # self.update_slider_highlight()
            # self.media_player.set_time(newTime)
            self.media_player.set_position(newPosition)

            if (didPauseMedia):
                self.media_player.play()
            # else:
            #     # Otherwise, the media was already paused, we need to very quickly play the media to update the frame with the new time, and then immediately pause it again.
            #     self.media_player.play()
            #     self.media_player.pause()
            self.media_player.next_frame()

            print("Setting media playback time to ", newPosition)
        except Exception as ex:
            self._show_error(str(ex))
            print(traceback.format_exc())


    def toggle_full_screen(self):
        if self.is_full_screen:
            # TODO Artifacts still happen some time when exiting full screen
            # in X11
            self.ui.frame_media.showNormal()
            self.ui.frame_media.restoreGeometry(self.original_geometry)
            self.ui.frame_media.setParent(self.ui.widget_central)
            self.ui.layout_main.addWidget(self.ui.frame_media, 2, 3, 3, 1)
            # self.ui.frame_media.ensurePolished()
        else:
            self.ui.frame_media.setParent(None)
            self.ui.frame_media.setWindowFlags(Qt.FramelessWindowHint |
                                               Qt.CustomizeWindowHint)
            self.original_geometry = self.ui.frame_media.saveGeometry()
            desktop = QApplication.desktop()
            rect = desktop.screenGeometry(desktop.screenNumber(QCursor.pos()))
            self.ui.frame_media.setGeometry(rect)
            self.ui.frame_media.showFullScreen()
            self.ui.frame_media.show()
        self.ui.frame_video.setFocus()
        self.is_full_screen = not self.is_full_screen

    def browse_timestamp_handler(self):
        """
        Handler when the timestamp browser button is clicked
        """
        tmp_name, _ = QFileDialog.getOpenFileName(
            self, "Choose Timestamp file", None,
            "Timestamp File (*.tmsp);;All Files (*)"
        )
        if not tmp_name:
            return
        self.set_timestamp_filename(QDir.toNativeSeparators(tmp_name))

    def create_timestamp_file_handler(self):
        """
        Handler when the timestamp file create button is clicked
        """
        tmp_name, _ = QFileDialog.getSaveFileName(
            self, "Create New Timestamp file", None,
            "Timestamp File (*.tmsp);;All Files (*)"
        )
        if not tmp_name:
            return

        try:
            if (os.stat(QDir.toNativeSeparators(tmp_name)).st_size == 0):
                    # File is empty, create a non-empty one:
                    with open(QDir.toNativeSeparators(tmp_name), "w") as fh:
                        fh.write("[]")  # Write the minimal valid JSON string to the file to allow it to be used
            else:
                pass

            # with open(tmp_name, 'r') as fh:
            #     if fh.__sizeof__()>0:
            #         # File is not empty:
            #         pass
            #     else:
            #         # File is empty, create a non-empty one:
            #         fh.close()
            #         with open(tmp_name, "w") as fh:
            #             fh.write("[]")  # Write the minimal valid JSON string to the file to allow it to be used

        except WindowsError:
            with open(tmp_name, "w") as fh:
                fh.write("[]") # Write the minimal valid JSON string to the file to allow it to be used


        # Create new file:
        self.set_timestamp_filename(QDir.toNativeSeparators(tmp_name))

    def _sort_model(self):
        self.ui.list_timestamp.sortByColumn(0, Qt.AscendingOrder)

    def _select_blank_row(self, parent, start, end):
        self.ui.list_timestamp.selectRow(start)

    def set_timestamp_filename(self, filename):
        """
        Set the timestamp file name
        """
        if not os.path.isfile(filename):
            self._show_error("Cannot access timestamp file " + filename)
            return

        try:
            self.timestamp_model = TimestampModel(filename, self)
            self.timestamp_model.timeParseError.connect(
                lambda err: self._show_error(err)
            )
            self.proxy_model.setSortRole(Qt.UserRole)
            self.proxy_model.dataChanged.connect(self._sort_model)
            self.proxy_model.dataChanged.connect(self.update_slider_highlight)
            self.proxy_model.setSourceModel(self.timestamp_model)
            self.proxy_model.rowsInserted.connect(self._sort_model)
            self.proxy_model.rowsInserted.connect(self._select_blank_row)
            self.ui.list_timestamp.setModel(self.proxy_model)

            self.timestamp_filename = filename
            self.ui.entry_timestamp.setText(self.timestamp_filename)

            self.mapper.setModel(self.proxy_model)
            self.mapper.addMapping(self.ui.entry_start_time, 0)
            self.mapper.addMapping(self.ui.entry_end_time, 1)
            self.mapper.addMapping(self.ui.entry_description, 2)
            self.ui.list_timestamp.selectionModel().selectionChanged.connect(
                self.timestamp_selection_changed)
            self._sort_model()

            directory = os.path.dirname(self.timestamp_filename)
            basename = os.path.basename(self.timestamp_filename)
            timestamp_name_without_ext = os.path.splitext(basename)[0]
            for file_in_dir in os.listdir(directory):
                current_filename = os.path.splitext(file_in_dir)[0]
                found_video = (current_filename == timestamp_name_without_ext
                               and file_in_dir != basename)
                if found_video:
                    found_video_file = os.path.join(directory, file_in_dir)
                    self.set_video_filename(found_video_file)
                    break
        except ValueError as err:
            self._show_error("Timestamp file is invalid")

    def timestamp_selection_changed(self, selected, deselected):
        if len(selected) > 0:
            self.mapper.setCurrentModelIndex(selected.indexes()[0])
            self.ui.button_save.setEnabled(True)
            self.ui.button_remove_entry.setEnabled(True)
            self.ui.entry_start_time.setReadOnly(False)
            self.ui.entry_end_time.setReadOnly(False)
            self.ui.entry_description.setReadOnly(False)
        else:
            self.mapper.setCurrentModelIndex(QModelIndex())
            self.ui.button_save.setEnabled(False)
            self.ui.button_remove_entry.setEnabled(False)
            self.ui.entry_start_time.clear()
            self.ui.entry_end_time.clear()
            self.ui.entry_description.clear()
            self.ui.entry_start_time.setReadOnly(True)
            self.ui.entry_end_time.setReadOnly(True)
            self.ui.entry_description.setReadOnly(True)

    def set_video_filename(self, filename):
        """
        Set the video filename
        """
        if not os.path.isfile(filename):
            self._show_error("Cannot access video file " + filename)
            return

        self.video_filename = filename

        media = self.vlc_instance.media_new(self.video_filename)
        media.parse()
        if not media.get_duration():
            self._show_error("Cannot play this media file")
            self.media_player.set_media(None)
            self.video_filename = None
        else:
            self.media_player.set_media(media)
            if sys.platform.startswith('linux'): # for Linux using the X Server
                self.media_player.set_xwindow(self.ui.frame_video.winId())
            elif sys.platform == "win32": # for Windows
                self.media_player.set_hwnd(self.ui.frame_video.winId())
            elif sys.platform == "darwin": # for MacOS
                self.media_player.set_nsobject(self.ui.frame_video.winId())
            self.ui.entry_video.setText(self.video_filename)

            self.update_video_file_labels_on_file_change()
            self.media_started_playing = False
            self.media_is_playing = False
            self.set_volume(self.ui.slider_volume.value())
            self.play_pause_model.setState(True)

    def browse_video_handler(self):
        """
        Handler when the video browse button is clicked
        """
        tmp_name, _ = QFileDialog.getOpenFileName(
            self, "Choose Video file", None,
            "All Files (*)"
        )
        if not tmp_name:
            return
        self.set_video_filename(QDir.toNativeSeparators(tmp_name))

    def _show_error(self, message, title="Error"):
        QMessageBox.warning(self, title, message)
예제 #14
0
파일: DeviceEdit.py 프로젝트: rodcnx/tdm
class DeviceEditDialog(QDialog):
    def __init__(self, model, row, *args, **kwargs):
        super(DeviceEditDialog, self).__init__(*args, **kwargs)
        self.setMinimumWidth(400)
        self.setWindowTitle("Edit device")

        self.settings = QSettings()
        self.settings.beginGroup("Devices")
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(model)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)

        vl = VLayout()

        gbTopic = QGroupBox("MQTT Topic")
        self.topic = QLineEdit()
        self.topic.setPlaceholderText("unique name of your device")
        self.mapper.addMapping(self.topic, DevMdl.TOPIC)

        self.full_topic = QLineEdit()
        self.full_topic.setPlaceholderText("must contain %prefix% and %topic%")
        self.mapper.addMapping(self.full_topic, DevMdl.FULL_TOPIC)

        tfl = QFormLayout()
        tfl.addRow("Topic", self.topic)
        tfl.addRow("Full topic", self.full_topic)
        gbTopic.setLayout(tfl)

        btnSave = QPushButton("Save")
        btnCancel = QPushButton("Cancel")

        hl_btns = HLayout()
        hl_btns.addStretch(1)
        hl_btns.addWidgets([btnSave, btnCancel])

        vl.addWidgets([gbTopic])
        vl.addLayout(hl_btns)
        self.setLayout(vl)

        self.mapper.setCurrentIndex(row)

        btnSave.clicked.connect(self.accept)
        btnCancel.clicked.connect(self.reject)

    def accept(self):
        full_topic = self.full_topic.text()

        if not full_topic.endswith('/'):
            self.full_topic.setText(full_topic + "/")

        if not len(self.topic.text()) > 0:
            QMessageBox.critical(self, "Error", "Topic is required.")

        elif not "%topic%" in full_topic:
            QMessageBox.critical(self, "Error", "%topic% is required in FullTopic.")

        elif not "%prefix%" in full_topic:
            QMessageBox.critical(self, "Error", "%prefix% is required in FullTopic.")

        elif self.topic.text() not in self.settings.childGroups():
            self.mapper.submit()
            self.done(QDialog.Accepted)

        else:
            QMessageBox.critical(self, "Error", "Device '{}' already on the device list.".format(self.topic.text()))


    def reject(self):
        self.mapper.revert()
        self.done(QDialog.Rejected)
예제 #15
0
class ManagerMainui(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(ManagerMainui, self).__init__()
        self.setupUi(self)
        self.opendb()
        self.show()
        self.lianjie()
        self.setCentralWidget(self.splitter)

        self.table_view.setSelectionBehavior(QAbstractItemView.SelectItems)
        self.table_view.setSelectionMode(
            QAbstractItemView.SingleSelection)  # 一次选择单行还是多行
        self.table_view.setAlternatingRowColors(True)  # 隔行自动改变颜色
        self.table_view.verticalHeader().setDefaultSectionSize(22)
        self.table_view.horizontalHeader().setDefaultSectionSize(60)

        # 为菜单添加动作

        self.filemenu.addAction(self.exit_Act)
        self.Updata_Menu.addAction(self.Updata_Act)

        # 当前页
        self.currentPage = 0
        # 总页数
        self.totalPage = 0
        # 总记录数
        self.totalRecord = 0
        # 每页数据数
        self.pageRecord = 10

    def opendb(self):
        db = QSqlDatabase.addDatabase('QSQLITE')
        db.setDatabaseName('F:/pycharm项目/图书管理系统NEW/AllDataBase/book.db')
        if db.open():
            self._biaocaozuo()
        else:
            QMessageBox.information(self, 'warning', '无法建立与数据库的连接')
            return False

    def _biaocaozuo(self):
        self.model = QtSql.QSqlTableModel()
        self.model.setTable('BookData')

        self.model.setEditStrategy(QSqlTableModel.OnManualSubmit)  # 设置保存策略

        self.table_view.setModel(self.model)
        self.model.select()
        self.model.setHeaderData(0, Qt.Horizontal, 'ISBN')
        self.model.setHeaderData(1, Qt.Horizontal, '书名')
        self.model.setHeaderData(2, Qt.Horizontal, '作者')
        self.model.setHeaderData(3, Qt.Horizontal, '出版社')
        self.model.setHeaderData(4, Qt.Horizontal, '出版日期')
        self.model.setHeaderData(5, Qt.Horizontal, '评分')
        self.model.setHeaderData(6, Qt.Horizontal, '照片')
        self.table_view.setColumnHidden(6, True)

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.model)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit)

        self.mapper.addMapping(self.lineEdit_ISBN, 0)
        self.mapper.addMapping(self.lineEdit_shuming, 1)
        self.mapper.addMapping(self.lineEdit_zuozhe, 2)
        self.mapper.addMapping(self.lineEdit_chubanshe, 3)
        self.mapper.addMapping(self.lineEdit_chubanriqi, 4)
        self.mapper.addMapping(self.lineEdit_pingfen, 5)
        self.mapper.toFirst()

        self.selModel = QItemSelectionModel(self.model)  # 选择模型
        self.table_view.setSelectionModel(self.selModel)
        self.selModel.currentChanged.connect(
            self.do_currentChanged)  # 当前项变化时触发
        self.selModel.currentRowChanged.connect(
            self.do_currentRowChanged)  # 选择行变化时

        # @pyqtSlot()  ##保存修改

    def on_p_baocun_triggered(self):
        result = QMessageBox.question(self, 'warning', '你要保存你的修改吗?',
                                      QMessageBox.Yes | QMessageBox.No,
                                      QMessageBox.No)
        if result == QMessageBox.Yes:
            res = self.model.submitAll()
            if (res == False):
                QMessageBox.information(
                    self, "消息",
                    "数据保存错误,错误信息\n" + self.model.lastError().text())
            else:
                QMessageBox.information(self, "message", "保存成功\n")
                self.p_baocun.setEnabled(False)
                self.p_quxiao.setEnabled(False)
        else:
            QMessageBox.information(self, 'message', 'Thanks')

    # @pyqtSlot()  ##取消修改

    def on_p_quxiao_triggered(self):
        # self.model.revertAll()
        result = QMessageBox.question(self, 'warning', '确认取消之前所有的的操作吗?',
                                      QMessageBox.Yes | QMessageBox.No,
                                      QMessageBox.No)
        if result == QMessageBox.Yes:
            self.model.revertAll()
            self.p_baocun.setEnabled(False)
            self.p_quxiao.setEnabled(False)
        else:
            self.p_baocun.setEnabled(True)
            self.p_quxiao.setEnabled(True)

    # @pyqtSlot()  ##添加记录
    def on_p_zengjia_triggered(self):
        #self.model.insertRows(self.model.rowCount(), 1)
        self.model.insertRow(self.model.rowCount(), QModelIndex())  # 在末尾添加一个记录

        curIndex = self.model.index(self.model.rowCount() - 1,
                                    1)  # 创建最后一行的ModelIndex
        self.selModel.clearSelection()  # 清空选择项
        self.selModel.setCurrentIndex(
            curIndex, QItemSelectionModel.Select)  # 设置刚插入的行为当前选择行

    # 删除记录

    def on_p_sanchu_triggered(self):
        # if self.p_baocun.isEnabled():
        result = QMessageBox.question(self, 'warning', '确认删除该记录吗?',
                                      QMessageBox.Yes | QMessageBox.No,
                                      QMessageBox.No)
        if result == QMessageBox.Yes:
            self.model.removeRow(self.table_view.currentIndex().row())
            self.p_baocun.setEnabled(True)
            self.p_quxiao.setEnabled(True)
        else:
            self.p_baocun.setEnabled(False)
            self.p_quxiao.setEnabled(False)

    # 插入记录

    def on_p_charu_triggered(self):
        curIndex = self.table_view.currentIndex()  # QModelIndex
        self.model.insertRow(curIndex.row(), QModelIndex())
        self.selModel.clearSelection()  # 清除已有选择
        self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select)

    # 对当前行设置图片
    def on_p_photo_triggered(self):
        fileName, filt = QFileDialog.getOpenFileName(self, "选择图片文件", "",
                                                     "照片(*.jpg)")
        if (fileName == ''):
            return

        file = QFile(fileName)  # fileName为图片文件名
        file.open(QIODevice.ReadOnly)
        try:
            data = file.readAll()  # QByteArray
        finally:
            file.close()

        curRecNo = self.selModel.currentIndex().row()
        curRec = self.model.record(curRecNo)  # 获取当前记录QSqlRecord
        curRec.setValue("Photo", data)  # 设置字段数据
        self.model.setRecord(curRecNo, curRec)

        pic = QPixmap()
        pic.loadFromData(data)
        W = self.dbLabPhoto.width()
        self.dbLabPhoto.setPixmap(pic.scaledToWidth(W))  # 在界面上显示

    def closeEvent(self, event):
        """
        提示保存
        """
        if self.p_baocun.isEnabled():
            r = QMessageBox.warning(self, "注意", "你还没有保存,现在保存下?",
                                    QMessageBox.Yes | QMessageBox.No,
                                    QMessageBox.Yes)
            if r == QMessageBox.No:
                event.accept()
            else:
                event.ignore()

    def chaxun_ISBN(self):
        text1 = self.lineEdit_chaxun.text()
        self.model.setFilter(("ISBN='%s'" % (text1)))

    def chaxun_zuozhe(self):
        text2 = self.lineEdit_chaxun.text()
        self.model.setFilter(("author='%s'" % (text2)))

    def chaxun_shumin(self):
        text3 = self.lineEdit_chaxun.text()
        self.model.setFilter(("title='%s'" % (text3)))

    def chaxun_(self):
        """
        查找图书
        """
        searchtext = self.lineEdit_chaxun.text()
        if searchtext:
            if self.comboBox_chaxun.currentText() == "ISBN":
                self.chaxun_ISBN()
            elif self.comboBox_chaxun.currentText() == "书名":
                self.chaxun_shumin()
            elif self.comboBox_chaxun.currentText() == "作者":
                self.chaxun_zuozhe()
        else:
            QMessageBox.information(self, "提示", "请输入搜索关键词!")

    def on_p_quxiaoCX_triggered(self):
        self.lineEdit_chaxun.clear()
        self.model.setFilter("")

    def do_currentChanged(self, current, previous):  # 更新actPost和actCancel 的状态
        self.p_baocun.setEnabled(self.model.isDirty())  # 有未保存修改时可用
        self.p_quxiao.setEnabled(self.model.isDirty())

    def do_currentRowChanged(self, current, previous):  # 行切换时的状态控制
        self.mapper.setCurrentIndex(current.row())

        if (current.isValid() == False):
            self.dbLabPhoto.clear()  # 清除图片显示
            return

        self.mapper.setCurrentIndex(current.row())  # 更新数据映射的行号

        curRec = self.model.record(current.row())  # 获取当前记录,QSqlRecord类型
        if (curRec.isNull("Photo")):  # 图片字段内容为空
            self.dbLabPhoto.clear()
        else:
            # data=bytearray(curRec.value("Photo"))   #可以工作
            data = curRec.value("Photo")  # 也可以工作
            pic = QPixmap()
            pic.loadFromData(data)
            W = self.dbLabPhoto.size().width()
            self.dbLabPhoto.setPixmap(pic.scaledToWidth(W))

    def scrapy(self):
        """启动爬虫,在线更新功能"""

        # cmdline.execute(" scrapy ".split())
        self.hide()
        try:
            run = ScrapyRun()
        finally:
            pass

    def lianjie(self):
        self.p_zengjia.clicked.connect(self.on_p_zengjia_triggered)
        self.p_baocun.clicked.connect(self.on_p_baocun_triggered)
        self.p_quxiao.clicked.connect(self.on_p_quxiao_triggered)
        self.p_sanchu.clicked.connect(self.on_p_sanchu_triggered)
        self.p_charu.clicked.connect(self.on_p_charu_triggered)
        self.p_photo.clicked.connect(self.on_p_photo_triggered)
        self.p_chaxun.clicked.connect(self.chaxun_)
        self.p_quxiaoCX.clicked.connect(self.on_p_quxiaoCX_triggered)
        self.p_tuichu.clicked.connect(self.close)

        self.exit_Act.triggered.connect(self.close)
        self.Updata_Act.triggered.connect(self.scrapy)
예제 #16
0
파일: myMain.py 프로젝트: Chen9811/MES
class MainWindow(QMainWindow):  # 继承主窗口函数的类, 继承编写的主函数
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)  # 初始化运行A窗口类下的 setupUi 函数
        self.open_alltable()
        self.enterList = {}
        self.outList = {}
        self.name_RFID = {
            '直齿轮': '01B0E00000020010B1',
            '斜齿轮': '01B0E00000030010B2',
            '齿轮轴': '01A0E00000010010A1',
            '光轴': '01A0E00000010010A2',
            '曲柄': '01C0E00000020010C1',
            '摇杆': '01C0E00000010010C2'
        }
        self.RFID_kind = dict([(value, key)
                               for (key, value) in self.name_RFID.items()])
        self.capacity = {
            '直齿轮': 18,
            '斜齿轮': 18,
            '齿轮轴': 24,
            '光轴': 24,
            '曲柄': 36,
            '摇杆': 36
        }
        self.nameNum = {
            '直齿轮': 3,
            '斜齿轮': 3,
            '齿轮轴': 4,
            '光轴': 4,
            '曲柄': 6,
            '摇杆': 6
        }
        self.locateName = {
            '直齿轮': ['A', 'B', 1],
            '斜齿轮': ['C', 'D', 1],
            '齿轮轴': ['A', 'B', 2],
            '光轴': ['C', 'D', 2],
            '曲柄': ['A', 'B', 3],
            '摇杆': ['C', 'D', 3]
        }
        self.get_locState()  # 获取所有货位的空闲状态
        # 初始化出入库按钮使能状态
        self.ui.outScan_pushButton.setEnabled(False)
        self.ui.enterScan_pushButton.setEnabled(False)
        self.currentList = self.Absolute_statis('current')  # 获取入库记录里各种工件的数量
        print(self.currentList)

    def open_alltable(self):
        ##   tableView显示属性设置
        self.ui.current_tableView.setSelectionBehavior(
            QAbstractItemView.SelectItems)
        self.ui.current_tableView.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.ui.current_tableView.setAlternatingRowColors(True)  # 设置相邻记录的不同颜色
        self.ui.current_tableView.verticalHeader().setDefaultSectionSize(
            22)  # 单元格高度
        self.ui.current_tableView.horizontalHeader().setDefaultSectionSize(
            160)  # 单元格宽度

        self.ui.enter_tableView.setSelectionBehavior(
            QAbstractItemView.SelectItems)
        self.ui.enter_tableView.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.ui.enter_tableView.setAlternatingRowColors(True)  # 设置相邻记录的不同颜色
        self.ui.enter_tableView.verticalHeader().setDefaultSectionSize(
            22)  # 单元格高度
        self.ui.enter_tableView.horizontalHeader().setDefaultSectionSize(
            160)  # 单元格宽度

        self.ui.out_tableView.setSelectionBehavior(
            QAbstractItemView.SelectItems)
        self.ui.out_tableView.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.ui.out_tableView.setAlternatingRowColors(True)  # 设置相邻记录的不同颜色
        self.ui.out_tableView.verticalHeader().setDefaultSectionSize(
            22)  # 单元格高度
        self.ui.out_tableView.horizontalHeader().setDefaultSectionSize(
            160)  # 单元格宽度

        self.ui.VICEtableView.setSelectionBehavior(
            QAbstractItemView.SelectItems)
        self.ui.VICEtableView.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.ui.VICEtableView.setAlternatingRowColors(True)  # 设置相邻记录的不同颜色
        self.ui.VICEtableView.verticalHeader().setDefaultSectionSize(
            22)  # 单元格高度
        self.ui.VICEtableView.horizontalHeader().setDefaultSectionSize(
            240)  # 单元格宽度

        # 连接到数据库并打开
        self.DB = QSqlDatabase.addDatabase(
            'QSQLITE')  # 建立与数据库的连接,即QSqlDatabase对象
        self.DB.setDatabaseName('MES5.db')  # 设置数据库名称
        self.DB.open()  # 打开数据库
        print('数据库打开成功')
        ## 打开现有库存数据表
        self.current_tabModel = QSqlTableModel(self, self.DB)  # 创建数据表的模型
        self.current_tabModel.setTable('工件信息表')  # 设置需要连接的数据表
        self.current_tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit)
        ## 打开入库记录表
        self.enter_tabModel = QSqlTableModel(self, self.DB)  # 创建数据表的模型
        self.enter_tabModel.setTable('入库记录表')  # 设置需要连接的数据表
        self.enter_tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit)

        ## 打开出库记录表
        self.out_tabModel = QSqlTableModel(self, self.DB)  # 创建数据表的模型
        self.out_tabModel.setTable('出库记录表')  # 设置需要连接的数据表
        self.out_tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit)

        ## 打开固定批RFID表========================================================
        self.vice_tabModel = QSqlTableModel(self, self.DB)  # 创建数据表的模型
        self.vice_tabModel.setTable('新建表')  # 设置需要连接的数据表
        self.vice_tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit)
        self.ui.VICEtableView.setModel(
            self.vice_tabModel)  # 为一个QTableView组件设置一个QSqlTabelModel模型
        self.vice_tabModel.select()
        # 建立RFID与组件的映射关系
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.vice_tabModel)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit)

        ##界面组件与tabelmodel的具体字段之间的联系
        self.mapper.addMapping(self.ui.RFIDlineEdit, 0)
        self.mapper.toFirst()  # 移动到首记录

        # 选中数据时信号的发射
        self.selModel = QItemSelectionModel(self.vice_tabModel)
        self.selModel.currentRowChanged.connect(self.do_currentRowChanged)
        self.ui.VICEtableView.setSelectionModel(self.selModel)  # 设置选择模型
        # ===============================================================================

        self.refresh()
        print('数据表打开成功')

        ##获取字段名和序号的字典数据
        empty = self.current_tabModel.record()  # 得到的是一个空的记录,获取表的字段定义
        self.fldNum = {}
        for i in range(empty.count()):
            filedname = empty.fieldName(i)
            empty.field(filedname).setReadOnly(True)  # 每个字段设置为只读
            self.fldNum.setdefault(
                filedname, i)  # 如果字典中包含有给定键,则返回该键对应的值,否则将键添加到字典中,默认值为None
        print(self.fldNum)
        print(self.current_tabModel.record().count())

    def do_currentRowChanged(self, current):
        self.mapper.setCurrentIndex(current.row())

    def refresh(self):
        self.ui.current_tableView.setModel(self.current_tabModel)
        self.current_tabModel.select()
        self.ui.enter_tableView.setModel(
            self.enter_tabModel)  # 为一个QTableView组件设置一个QSqlTabelModel模型
        self.enter_tabModel.select()
        self.ui.out_tableView.setModel(
            self.out_tabModel)  # 为一个QTableView组件设置一个QSqlTabelModel模型
        self.out_tabModel.select()
        self.inventory_used()

    #################################路径规划与货位分配###########################################
    def get_locState(self):  # 获取所有货位的状态
        self.locationState = {}
        DecodeLoc = {'A': 0, 'B': 1, 'C': 0, 'D': 1}  # 解码字典
        for key, value in self.nameNum.items():
            self.locationState[key] = np.zeros((2, 3, value), dtype=int)
        if self.current_tabModel.record(0).isNull('货位') == True:
            pass
        else:
            currentRow = self.current_tabModel.rowCount()  # 库存的已记录数
            # 根据现有库存更新货位的状态
            for i in range(currentRow):
                curRec = self.current_tabModel.record(i)
                location = curRec.value('货位')
                kindname = curRec.value('种类')
                x = DecodeLoc[location[0]]  # 对已有的工件的货位编码进行解码
                y = int(location[1]) - 1
                z = int(location[5]) - 1
                self.locationState[kindname][x][y][z] = 1

    #货位分配函数
    def allocation(self, name, num, label):  # 输入工件名称和对应的数量
        if label == 'i':
            sign = 0
        else:
            sign = 1
        itsloc = self.locationState[name]
        for i in range(3):
            data = itsloc[:, 0:i + 1]
            data = data.reshape(1, -1)[0]
            itsum = sum(data == sign)
            if itsum >= num:
                forward_double = i + 1
                break
        idle_loc = np.where(
            itsloc[:, 0:forward_double] == sign)  # 寻找前forward_double对货架的空闲货位
        locating = []  # 存放接收工件的货位
        for i in range(num):
            x = idle_loc[0][i]
            y = idle_loc[1][i]
            z = idle_loc[2][i]
            self.locationState[name][x][y][z] = 1 - sign  # 分配好后即更新货位状态
            locating.append([x, y, z])
        EncodeLoc = []
        for i in locating:
            s = self.locateName[name][i[0]] + str(i[1] + 1) + '-' + \
                str(self.locateName[name][2]) + '-' + str(i[2] + 1)
            EncodeLoc.append(s)
        return EncodeLoc, forward_double

    def getLocation(self, outList, direct):
        ALLlocation = []
        forwardLocation = {}
        for key, value in outList.items():
            location, position = self.allocation(key, value, direct)
            ALLlocation = ALLlocation + location
            forwardLocation[key] = position - 1
        return ALLlocation, forwardLocation

    # 表里的工件统计
    def statistics(self, model):
        n = model.rowCount()  # 总行数
        all_list = {}
        for i in range(n):  # 统计入库记录里各种工件的数量
            rec = model.record(i)
            if rec.value('种类') in all_list:
                all_list[rec.value('种类')] += 1
            else:
                all_list[rec.value('种类')] = 1
        return all_list

    def Absolute_statis(self, label):
        myModel = QSqlQueryModel(self)
        if label == 'current':
            myModel.setQuery("select 种类 from 工件信息表")
        elif label == 'enter':
            myModel.setQuery("select 种类 from 入库记录表")
        elif label == 'out':
            myModel.setQuery("select 种类 from 出库记录表")
        allnum = myModel.rowCount()
        all_dict = {}
        for i in range(allnum):
            rec = myModel.record(i)
            if rec.value('种类') in all_dict:
                all_dict[rec.value('种类')] += 1
            else:
                all_dict[rec.value('种类')] = 1
        return all_dict

    #寻找出入库记录的最大批次
    def getMaxbatch(self, label):
        myModel = QSqlQueryModel(self)
        if label == 'enter':
            myModel.setQuery("select 批次 from 入库记录表")
        elif label == 'out':
            myModel.setQuery("select 批次 from 出库记录表")
        n = myModel.rowCount()
        if myModel.record(0).isNull('批次') == True:  # 检测入库记录里的最大批次
            max_batch = 0
        else:
            max_batch = myModel.record(n - 1).value('批次')  # 批次按顺序排列,查找最大批次
            print('共有%d条记录,最大批次为%d' % (n, max_batch))
        return max_batch

    #################################主操作界面####################################################
    # 容量不足信息打印
    def on_enterNum_spinBox_valueChanged(self):
        self.enter_Warning()

    def on_enterKind_comboBox_currentIndexChanged(self):
        self.enter_Warning()

    def enter_Warning(self):
        num = self.ui.enterNum_spinBox.value()
        enterKind = self.ui.enterKind_comboBox.currentText()
        if enterKind not in self.currentList:
            currentNum = 0
        else:
            currentNum = self.currentList[enterKind]
        if num + currentNum > self.capacity[enterKind]:
            self.ui.enterList_pushButton.setEnabled(False)
            # self.ui.enterScan_pushButton.setEnabled(False)
            warningText = '⚠警告!' + enterKind + '已经超出库容上限!'
        else:
            self.ui.enterList_pushButton.setEnabled(True)
            # self.ui.enterScan_pushButton.setEnabled(True)
            warningText = ''
        self.ui.textEdit.setPlainText(warningText)

    #############入库函数
    ##入库添加工件及对应数量
    @pyqtSlot()
    def on_enterList_pushButton_clicked(self):
        enterKind = self.ui.enterKind_comboBox.currentText()
        enterNum = self.ui.enterNum_spinBox.value()
        if enterKind in self.enterList:
            self.enterList[enterKind] += enterNum
        else:
            self.enterList[enterKind] = enterNum
        # 激活出库按钮使能状态
        self.ui.enterScan_pushButton.setEnabled(True)
        print(self.enterList)

    ##扫描入库
    @pyqtSlot()
    def on_enterScan_pushButton_clicked(self):
        # 根据入库记录里的RFID生成新的RFID
        enteredList = self.statistics(self.enter_tabModel)  # 获取入库记录里各种工件的数量
        RFID_list = []
        for key in self.enterList.keys():  # 对要入库的工件种类进行迭代
            for i in range(self.enterList[key]):
                if key not in enteredList:
                    no = i + 6
                else:
                    no = enteredList[key] + i + 6
                RFID = self.name_RFID[key] + str(no).zfill(6)
                RFID_list.append(RFID)
        # 将RFID写入txt文件来模拟货物
        filename = '卸货区'
        if not os.path.isdir(filename):
            os.makedirs(filename)
        with open('卸货区\待入库货工件.txt', 'w', encoding='utf8') as f:
            for s in RFID_list:
                f.write(s + '\n')
        # 从卸货区寻找模拟货物
        dbFilename, flt = QFileDialog.getOpenFileName(self, "寻找入库货物", "",
                                                      "模拟货物(*.txt)")
        if (dbFilename == ''):
            return
        with open(dbFilename, 'r', encoding='utf8') as f:
            enterRFID = f.readlines()

        all_location, forwardLocation = self.getLocation(self.enterList, 'i')
        self.ui.widget.get_path(forwardLocation, 'i')  # 绘制路径
        self.enter(enterRFID, all_location)  # 入库操作

    def enter(self, enterRFID, all_location):
        #print('入库函数,enterRFID=',enterRFID,'all_location=',all_location)
        # 准备写入工件信息表和入库记录表
        currentQuery = QSqlQuery(self.DB)
        enterQuery = QSqlQuery(self.DB)
        currentQuery.prepare('''INSERT INTO 工件信息表 (RFID,种类,货位,生产商,
                      批次,入库日期,入库时间,重量) VALUES(:RFID,:kind,:location,:manufacture,:batch,
                      :enterDate,:enterTime,:weight)''')
        enterQuery.prepare('''INSERT INTO 入库记录表 (RFID,种类,生产商,
                      批次,入库日期,入库时间) VALUES(:RFID,:kind, :manufacture,:batch,
                      :enterDate,:enterTime)''')

        # 准备数据(都是恒量)

        RFID_manufacture = {
            'E0000001': '西安交大一厂',
            'E0000002': '西安交大二厂',
            'E0000003': '西安交大三厂'
        }
        max_batch = self.getMaxbatch('enter')
        enterDate = self.ui.dealdate.date().toString(Qt.ISODate)  # 获取日期
        enterTime = time.strftime('%H:%M:%S',
                                  time.localtime(time.time()))  # 获取时分秒
        weightList = {
            '直齿轮': 15,
            '斜齿轮': 20,
            '齿轮轴': 7,
            '光轴': 5,
            '曲柄': 2,
            '摇杆': 1
        }
        check = True
        # 扫码并写入记录表

        for i in range(len(enterRFID)):
            # 解码
            s = enterRFID[i].rstrip('\n')
            kind = self.RFID_kind[s[0:18]]
            manufacture = RFID_manufacture[s[4:12]]
            weight = weightList[kind]
            # 加入现有库存
            currentQuery.bindValue(":RFID", s)
            currentQuery.bindValue(":kind", kind)
            currentQuery.bindValue(":location", all_location[i])
            currentQuery.bindValue(":manufacture", manufacture)
            currentQuery.bindValue(":batch", max_batch + 1)
            currentQuery.bindValue(":enterDate", enterDate)
            currentQuery.bindValue(":enterTime", enterTime)
            currentQuery.bindValue(":weight", weight)
            res = currentQuery.exec()  # 执行SQL语句
            check = check & res
            # 加入入库记录表
            enterQuery.bindValue(":RFID", s)
            enterQuery.bindValue(":kind", kind)
            enterQuery.bindValue(":manufacture", manufacture)
            enterQuery.bindValue(":batch", max_batch + 1)
            enterQuery.bindValue(":enterDate", enterDate)
            enterQuery.bindValue(":enterTime", enterTime)
            enterQuery.exec()  # 执行SQL语句

        if check == False:
            QMessageBox.critical(
                self, "错误", "添加记录出现错误\n" + currentQuery.lastError().text())
            print('入库异常')
        else:
            self.enterList = {}
            self.refresh()
            self.ui.enterScan_pushButton.setEnabled(False)
            self.ui.textEdit.setPlainText('入库操作成功')

    #############出库函数
    # 库存不足信息打印

    def on_outNum_spinBox_valueChanged(self):
        self.out_Warning()

    def on_outKind_comboBox_currentIndexChanged(self):
        self.out_Warning()

    def out_Warning(self):
        num = self.ui.outNum_spinBox.value()
        outKind = self.ui.outKind_comboBox.currentText()
        self.currentList = self.Absolute_statis('current')
        if outKind not in self.currentList:  # 防止有些工件没有时作为字典的键出错
            currentNum = 0
        else:
            currentNum = self.currentList[outKind]
        if num > currentNum:
            self.ui.outList_pushButton.setEnabled(False)
            # self.ui.outScan_pushButton.setEnabled(False)
            warningText = '⚠警告!' + outKind + '已经超出库存上限!'
        else:
            self.ui.outList_pushButton.setEnabled(True)
            # self.ui.outScan_pushButton.setEnabled(True)
            warningText = ''
        self.ui.textEdit.setPlainText(warningText)

    # 添加出库工件
    @pyqtSlot()
    def on_outList_pushButton_clicked(self):
        outKind = self.ui.outKind_comboBox.currentText()
        outNum = self.ui.outNum_spinBox.value()
        if outKind in self.outList:
            self.outList[outKind] += outNum
        else:
            self.outList[outKind] = outNum
        self.ui.outScan_pushButton.setEnabled(True)
        print("要出库的货物:", self.outList)

    @pyqtSlot()
    def on_outScan_pushButton_clicked(self):
        currentRow = self.current_tabModel.rowCount()  # 库存的已记录数
        RFID_list = []
        outLocation, forwardLocation = self.getLocation(self.outList, 'o')
        # 从现有库存里取符合条件的RFID
        for i in range(currentRow):
            curRec = self.current_tabModel.record(i)
            location = curRec.value('货位')
            if location in outLocation:
                RFID_list.append(curRec.value('RFID'))
        # 将RFID写入模拟货物
        filename = '发货区'
        if not os.path.isdir(filename):
            os.makedirs(filename)
        with open('发货区\待出库货工件.txt', 'w', encoding='utf8') as f:
            for s in RFID_list:
                f.write(s + '\n')
        # 从卸货区寻找模拟货物
        dbFilename, flt = QFileDialog.getOpenFileName(self, "寻找出库货物", "",
                                                      "模拟货物(*.txt)")
        if (dbFilename == ''):
            return

        with open(dbFilename, 'r', encoding='utf8') as f:
            outRFID = f.readlines()
            for i in range(len(outRFID)):  # 去除所有的换行符
                outRFID[i] = outRFID[i].rstrip('\n')

        self.ui.widget.get_path(forwardLocation, 'o')  #出库路径绘制
        self.out(outRFID)

    def out(self, outRFID):  # 出库函数,参数只有RFID列表
        currentRow = self.current_tabModel.rowCount()  # 库存的已记录数
        currentQuery = QSqlQuery(self.DB)  # 准备删除
        outQuery = QSqlQuery(self.DB)  # 准备插入
        outQuery.prepare('''INSERT INTO 出库记录表 (RFID,种类,生产商,
                              批次,出库日期,出库时间) VALUES(:RFID,:kind, :manufacture,:batch,
                              :outDate,:outTime)''')
        currentQuery.prepare('''DELETE FROM 工件信息表 WHERE RFID=:ID''')
        # 获取出库记录表里的最大批次
        batch = self.getMaxbatch('out')
        outDate = self.ui.dealdate.date().toString(Qt.ISODate)
        outTime = time.strftime('%H:%M:%S', time.localtime(time.time()))
        check = True
        # 读取要出库的工件的RFID
        for i in range(currentRow):  # 遍历现有库存找到要出库的RFID
            curRec = self.current_tabModel.record(i)
            if curRec.value('RFID') in outRFID:
                outQuery.bindValue(":RFID", curRec.value('RFID'))
                outQuery.bindValue(":kind", curRec.value('种类'))
                outQuery.bindValue(":manufacture", curRec.value('生产商'))
                outQuery.bindValue(":batch", batch + 1)
                outQuery.bindValue(":outDate", outDate)
                outQuery.bindValue(":outTime", outTime)
                outQuery.exec()  # 执行SQL语句
                currentQuery.bindValue(":ID", curRec.value('RFID'))
                res = currentQuery.exec()
                check = check & res
        if check == False:
            QMessageBox.critical(
                self, "错误", "出库记录出现错误\n" + currentQuery.lastError().text())
        else:
            self.refresh()
            self.outList = {}
            self.ui.outScan_pushButton.setEnabled(False)
            self.ui.textEdit.setPlainText('出库操作成功')
            self.out_Warning()  # 库存不足则打印信息,改变按键使能状态

    # =================================副操作界面==================================================
    def getCurrentNum(self):
        currentQryModel = QSqlQueryModel(self)
        currentQryModel.setQuery("select RFID from 工件信息表")
        allnum = currentQryModel.rowCount()
        return allnum, currentQryModel

    ##单件扫描
    @pyqtSlot()
    def on_emitPushButton_pressed(self):
        RFID = self.ui.RFIDlineEdit.text()
        forwardLocation = {}
        kind = self.RFID_kind[RFID[0:18]]
        kindlist = []
        kindlist.append(RFID)
        allnum, currentQryModel = self.getCurrentNum()
        for i in range(allnum):
            cur = currentQryModel.record(i)
            if RFID == cur.value('RFID'):
                self.out(kindlist)
                self.get_locState()
                return
                # 因为已经指定了RFID,所以出库没有路径规划
        location, position = self.allocation(kind, 1, 'i')
        self.enter(kindlist, location)
        forwardLocation[kind] = position - 1
        self.ui.widget.get_path(forwardLocation, 'i')

    ##多件扫描
    @pyqtSlot()
    def on_ScanPushButton_pressed(self):
        outRFID = []
        inkindNum = {}
        dbFilename, flt = QFileDialog.getOpenFileName(self, "寻找入库货物", "",
                                                      "模拟货物(*.txt)")
        if (dbFilename == ''):
            return
        with open(dbFilename, 'r', encoding='utf8') as f:
            RFID = f.readlines()
            for i in range(len(RFID)):  # 去除所有的换行符
                RFID[i] = RFID[i].rstrip('\n')
        allnum, currentQryModel = self.getCurrentNum()
        for i in range(allnum):
            cur = currentQryModel.record(i)
            if cur.value('RFID') in RFID:
                outRFID.append(cur.value('RFID'))  # 如果现有库存里存在,则添加到出库RFID列表中
                RFID.remove(cur.value('RFID'))  # 移除
        if outRFID != []:
            self.out(outRFID)
            self.get_locState()
        if RFID != []:
            for i in RFID:
                kind = self.RFID_kind[i[0:18]]
                if kind in inkindNum:
                    inkindNum[kind] += 1
                else:
                    inkindNum[kind] = 1
            inLocation, forwardLocation = self.getLocation(inkindNum, 'i')
            self.ui.widget.get_path(forwardLocation, 'i')  #绘制路径
            self.enter(RFID, inLocation)  #入库操作

    #################################现有库存界面####################################################
    ##种类过滤
    def on_currentComboBox_currentIndexChanged(self, curText):
        self.current_filter()

    ##批次过滤
    def on_batchSpinBox_valueChanged(self, num):
        self.current_filter()

    ##是否选择批次
    def on_batchCheckBox_stateChanged(self):
        self.current_filter()

    def current_filter(self):
        kind = self.ui.currentComboBox.currentText()
        batch = self.ui.batchSpinBox.value()
        if kind == '全选':
            if self.ui.batchCheckBox.isChecked() == True:
                self.current_tabModel.setFilter("批次='%d'" % (batch))
            else:
                self.current_tabModel.setFilter("")
        else:

            if self.ui.batchCheckBox.isChecked() == True:
                self.current_tabModel.setFilter("批次='%d' and 种类='%s'" %
                                                (batch, kind))
            else:
                self.current_tabModel.setFilter("种类='%s'" % (kind))

    # 已用库存百分比显示
    def inventory_used(self):
        # 通过进度条表示库存余量
        currentQryModel = QSqlQueryModel(self)
        currentQryModel.setQuery("select RFID from 工件信息表")
        allnum = currentQryModel.rowCount()
        progress = int((100 * allnum / 156) + 0.5)
        self.ui.progressBar.setValue(progress)

    @pyqtSlot()
    def on_delete_pushButton_pressed(self):
        query = QSqlQuery(self.DB)
        print('开始删除')
        query.exec("DELETE FROM 工件信息表 WHERE 批次>=0")
        query.exec("DELETE FROM 出库记录表 WHERE 批次>=0")
        check = query.exec("DELETE FROM 入库记录表 WHERE 批次>=0")
        if check == False:
            QMessageBox.critical(self, "错误",
                                 "删除记录出现错误\n" + query.lastError().text())
        else:
            self.refresh()

    #################################入库记录界面####################################################
    ##种类过滤
    def on_enterComboBox_currentIndexChanged(self):
        self.enter_filter()

    ##日期过滤
    def on_enterDate_dateChanged(self):
        self.enter_filter()

    ##是否选择批次
    def on_enterCheckBox_stateChanged(self):
        self.enter_filter()

    def enter_filter(self):
        kind = self.ui.enterComboBox.currentText()
        date = self.ui.enterDate.date().toString(Qt.ISODate)
        if self.ui.enterCheckBox.isChecked() == True:
            if kind == '全选':
                self.enter_tabModel.setFilter("入库日期='%s'" % (date))
            else:
                self.enter_tabModel.setFilter("入库日期='%s' and 种类='%s'" %
                                              (date, kind))
        else:
            if kind == '全选':
                self.enter_tabModel.setFilter("")
            else:
                self.enter_tabModel.setFilter("种类='%s'" % (kind))

    # 入库记录可视化
    @pyqtSlot()
    def on_drawEnter_pushButton_pressed(self):
        self.recordDemo(self.enter_tabModel)

    #################################出库记录界面####################################################
    ##种类过滤
    def on_outComboBox_currentIndexChanged(self):
        self.out_filter()

    ##日期过滤
    def on_outDate_dateChanged(self):
        self.out_filter()

    ##是否选择批次
    def on_outCheckBox_stateChanged(self):
        self.out_filter()

    def out_filter(self):
        kind = self.ui.outComboBox.currentText()
        date = self.ui.outDate.date().toString(Qt.ISODate)
        if self.ui.outCheckBox.isChecked() == True:
            if kind == '全选':
                self.out_tabModel.setFilter("出库日期='%s'" % (date))
            else:
                self.out_tabModel.setFilter("出库日期='%s' and 种类='%s'" %
                                            (date, kind))
        else:
            if kind == '全选':
                self.out_tabModel.setFilter("")
            else:
                self.out_tabModel.setFilter("种类='%s'" % (kind))

    # 出库记录可视化
    @pyqtSlot()
    def on_drawOut_pushButton_pressed(self):
        self.recordDemo(self.out_tabModel)

    #################################数据可视化################################################
    # 现有库存可视化
    @pyqtSlot()
    def on_drawCurrent_pushButton_pressed(self):
        # def demo(self):
        #self.currentList = self.statistics(self.current_tabModel)
        self.currentList = self.Absolute_statis('current')
        labels = []
        values = []
        for key, value in self.currentList.items():
            labels.append(key)
            values.append(value)
        if self.ui.pie_radioButton.isChecked() == True:
            trace = [go.Pie(labels=labels, values=values)]
            layout = go.Layout(title='工件库存比例配比图', )
        elif self.ui.bar_radioButton.isChecked() == True:
            trace = [go.Bar(x=labels, y=values)]
            layout = go.Layout(title='工件库存直方图', )
        print(labels)
        print(values)
        fig = go.Figure(data=trace, layout=layout)
        file = 'F:\source\python代码\MES库存管理\VisualData'
        if not os.path.isdir(file):
            os.makedirs(file)
        filename = 'F:\source\python代码\MES库存管理\VisualData\\currentDemo.html'
        pyof.plot(fig, filename=filename, auto_open=False)
        win = DemoWindow(filename)
        win.exec()

    def recordDemo(self, model):
        record = {}
        enterRow = model.rowCount()  # 库存的已记录数
        dateName = model.record().fieldName(4)  # 入库日期&出库日期
        TimeName = model.record().fieldName(5)
        for i in range(enterRow):
            curRec = model.record(i)
            kind = curRec.value('种类')
            date = curRec.value(dateName)
            Time = curRec.value(TimeName)
            dateTime = date + ' ' + Time
            dateRecord = {}
            if kind not in record:  # 工件种类第一次检索到,将其添加到reord中
                dateRecord[dateTime] = 1  # 同时将对应的日期添加到record中
                record[kind] = dateRecord
            else:
                if dateTime not in record[kind]:  # 种类存在,但是第一次检索到某个日期时
                    record[kind][dateTime] = 1
                else:
                    record[kind][dateTime] += 1
        traces = []
        for key1 in record.keys():
            x = []
            y = []
            for key2 in record[key1].keys():
                x.append(key2)
                y.append(record[key1][key2])
            trace = go.Scatter(
                x=x,
                y=y,
                # mode = 'markers',
                name=key1)
            traces.append(trace)
        layout = go.Layout(title=dateName[0:2] + '记录', )
        fig = go.Figure(data=traces, layout=layout)
        file = 'F:\source\python代码\MES库存管理\VisualData'
        if not os.path.isdir(file):
            os.makedirs(file)
        filename = 'F:\source\python代码\MES库存管理\VisualData\\recordDemo.html'
        pyof.plot(fig, filename=filename, auto_open=False)
        win = DemoWindow(filename)
        win.exec()
예제 #17
0
class QmyMainWindow(QMainWindow):
    def __init__(self, parent=None, dbFilename='None'):
        super().__init__(parent)  # Call the parent class. Create window.
        self.ui = Ui_MainWindow()  # Create UI object
        self.ui.setupUi(self)  # Create UI interface

        self.ui.tabWidget.setVisible(True)
        self.setCentralWidget(self.ui.tabWidget)

        # tableView setting
        self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectItems)
        self.ui.tableView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.ui.tableView.setAlternatingRowColors(True)
        self.ui.tableView.verticalHeader().setDefaultSectionSize(44)
        self.ui.tableView.horizontalHeader().setDefaultSectionSize(70)
        self.ui.tableView.setSortingEnabled(True)

        # Initialize chart
        self.__iniPieChart()  # Initialize pie chart
        self.__iniStackedBar()  # Stacked bar

        mpl.rcParams['font.sans-serif'] = ['Calibri']
        mpl.rcParams['font.size'] = 8

        # Choose the SQLITE database drive
        self.DB = QSqlDatabase.addDatabase("QSQLITE")
        self.DB.setDatabaseName(dbFilename)  # Set the name of database
        if self.DB.open():  # Open database
            self.__openTable()  # Open tables
        else:
            QMessageBox.warning(self, "Warning",
                                "Failed to open the database.")

# ==============Self-defined Fuctions============

    def __getFieldNames(self):  # Get names of all fields.
        # Get empty records, only field name.
        emptyRec = self.tabModel.record()
        self.fldNum = {}  # Dictionary of field name and index.
        for i in range(emptyRec.count()):
            fieldName = emptyRec.fieldName(i)
            self.fldNum.setdefault(fieldName)
            self.fldNum[fieldName] = i

    def __openTable(self):  # Open the table of database
        self.tabModel = QSqlTableModel(self, self.DB)  # Data model
        # Set the table of database TODO: Can user insert their own tables from
        # the database?
        self.tabModel.setTable("battery")
        # Data storage,OnManualSubmit , OnRowChange
        self.tabModel.setEditStrategy(QSqlTableModel.OnManualSubmit)
        # self.tabModel.setSort(
        #     self.tabModel.fieldIndex("RANDOM"),
        #     Qt.DescendingOrder)  # Sorting
        if (self.tabModel.select() == False):  # Failed to query the data
            QMessageBox.critical(
                self, "Wrong",
                "Something wrong. Failed to open the database\n" +
                self.tabModel.lastError().text())
            return
        # self.tabModel.setFilter("NUM_RECORDS LIKE 'NONE'")
        self.__getFieldNames()  # Get the field name and index

        # Field name shown
        for i in self.fldNum:
            self.tabModel.setHeaderData(self.fldNum[i], Qt.Horizontal,
                                        i.capitalize())

# Create mappings between interface widget and the field name of data model
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.tabModel)  # Setting data model
        self.mapper.setSubmitPolicy(QDataWidgetMapper.AutoSubmit)

        # The relations between interface widget and field name of tabModel
        self.mapper.addMapping(self.ui.dbEditValue, self.fldNum["Value"])
        self.mapper.addMapping(self.ui.dbEditRunit, self.fldNum["Raw_unit"])
        self.mapper.addMapping(self.ui.dbComboProperty,
                               self.fldNum["Property"])
        self.mapper.addMapping(self.ui.dbEditUnit, self.fldNum["Unit"])
        self.mapper.addMapping(self.ui.dbEditName, self.fldNum["Name"])
        self.mapper.addMapping(self.ui.dbEditEname,
                               self.fldNum["Extracted_name"])
        self.mapper.addMapping(self.ui.dbEditRvalue, self.fldNum["Raw_value"])
        self.mapper.addMapping(self.ui.dbEditDOI_2, self.fldNum["DOI"])
        self.mapper.addMapping(self.ui.dbEditDOI_4, self.fldNum["Date"])
        self.mapper.addMapping(self.ui.dbEditDOI_3, self.fldNum["Title"])
        self.mapper.addMapping(self.ui.dbEditDOI, self.fldNum["Journal"])
        self.mapper.addMapping(self.ui.dbEditTag, self.fldNum["Tag"])
        self.mapper.addMapping(self.ui.dbEditInfo, self.fldNum["Info"])
        self.mapper.addMapping(self.ui.dbEditType, self.fldNum["Type"])
        self.mapper.addMapping(self.ui.dbEditWarning, self.fldNum["Warning"])
        self.mapper.addMapping(self.ui.dbEditSpecifier,
                               self.fldNum["Specifier"])
        self.mapper.toFirst()  # Move to the first record

        self.selModel = QItemSelectionModel(self.tabModel)  # Select model
        self.selModel.currentChanged.connect(
            self.do_currentChanged)  # Trigger when the current changed
        self.selModel.currentRowChanged.connect(
            self.do_currentRowChanged)  # Trigger when the current row changed

        self.ui.tableView.setModel(self.tabModel)  # Setting the data model
        self.ui.tableView.setSelectionModel(
            self.selModel)  # Setting the selection model

        #      self.ui.tableView.setColumnHidden(self.fldNum["TAG"],   True)  #Hide columns
        # self.ui.tableView.setColumnHidden(self.fldNum["INFO"],  True)  #Hide
        # columns
        self.ui.tableView.setColumnHidden(self.fldNum["Extracted_name"],
                                          True)  # Hide columns
        self.ui.tableView.setColumnHidden(self.fldNum["Unit"],
                                          True)  # Hide columns
        self.ui.tableView.setColumnHidden(self.fldNum["Num_records"],
                                          True)  # Hide columns
        # self.ui.tableView.setColumnHidden(
        #     self.fldNum["RAW_VALUE"], True)  # Hide columns

        # Update the conditions of actions of interface widget
        self.ui.actRecAppend.setEnabled(True)
        self.ui.actRecInsert.setEnabled(True)
        self.ui.actRecDelete.setEnabled(True)

        self.ui.btnDrawPieChart.setEnabled(True)  # Pie Chart
        self.ui.spinPieSize.setEnabled(True)
        self.ui.spinHoleSize.setEnabled(True)
        self.ui.chkBox_PieLegend.setEnabled(True)

        self.ui.generateButton_3.setEnabled(True)
        self.ui.searchButton_3.setEnabled(True)
        self.ui.clearButton_3.setEnabled(True)

        self.ui.frame_4.setEnabled(True)
        self.ui.frame_3.setEnabled(True)

        self.ui.searchInput.returnPressed.connect(self.ui.searchButton.click)
        self.ui.searchInput_3.returnPressed.connect(
            self.ui.searchButton_3.click)

    def __iniPieChart(self):  # Initialize pie chart
        chart = QChart()
        # chart.setTitle("Piechart")
        chart.setAnimationOptions(QChart.SeriesAnimations)
        chart.setTheme(QChart.ChartTheme(0))
        self.ui.chartViewPie.setChart(chart)  # Setting chart for chart view
        self.ui.chartViewPie.setRenderHint(QPainter.Antialiasing)
        self.ui.chartViewPie.setCursor(Qt.CrossCursor)  # Setting cross cursor

    def __iniStackedBar(self):  # Initialize stacked bar chart
        chart = QChart()
        # chart.setTitle("Number of property records for each chemical")
        chart.setAnimationOptions(QChart.SeriesAnimations)
        chart.setTheme(QChart.ChartTheme(0))
        self.ui.chartViewStackedBar.setChart(chart)  # Set chart
        self.ui.chartViewStackedBar.setRenderHint(QPainter.Antialiasing)
        self.ui.chartViewStackedBar.setCursor(Qt.CrossCursor)  # Set mouse

# ==========Table tab slot function==================

    @pyqtSlot()  # Save changes
    def on_actSubmit_triggered(self):
        res = self.tabModel.submitAll()
        if (res == False):
            QMessageBox.information(
                self, "Information",
                "Failed to store the changes. Wrong information. \n" +
                self.tabModel.lastError().text())
        else:
            self.ui.actSubmit.setEnabled(False)
            self.ui.actRevert.setEnabled(False)

    @pyqtSlot()  # Cancel changes
    def on_actRevert_triggered(self):
        self.tabModel.revertAll()
        self.ui.actSubmit.setEnabled(False)
        self.ui.actRevert.setEnabled(False)

    @pyqtSlot()  # Add records
    def on_actRecAppend_triggered(self):
        self.tabModel.insertRow(
            self.tabModel.rowCount(),
            QModelIndex())  # Add one record in the last row
        curIndex = self.tabModel.index(self.tabModel.rowCount() - 1,
                                       1)  # Create ModelIndex of the last row
        self.selModel.clearSelection()  # Clear selections
        # Choosing the current row when selection.
        self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select)

        currow = curIndex.row()  # Get current row

    @pyqtSlot()  # Insert records
    def on_actRecInsert_triggered(self):
        curIndex = self.ui.tableView.currentIndex()  # QModelIndex
        self.tabModel.insertRow(curIndex.row(), QModelIndex())
        self.selModel.clearSelection()  # Clear selections
        self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select)

    @pyqtSlot()  # Delete records
    def on_actRecDelete_triggered(self):
        # Get the current index of current model
        curIndex = self.selModel.currentIndex()
        self.tabModel.removeRow(curIndex.row(),
                                QModelIndex())  # Delete the current row
        self.tabModel.submit()

    @pyqtSlot()  # Help message box
    def on_actHelp_triggered(self):
        msg = QMessageBox()
        msg.about(
            self, "Help", '<div>'
            '<h3>Table:&nbsp;Query&nbsp;the&nbsp;database&nbsp;according&nbsp;to&nbsp;data&nbsp;types&nbsp;and&nbsp;name&nbsp;or&nbsp;DOI.</h3>'
            '<ul>'
            '<li>Search&nbsp;the&nbsp;exact&nbsp;compound&nbsp;name&nbsp;in&nbsp;"<em>Exact&nbsp;Match</em>". Search&nbsp;the&nbsp;element&nbsp;or&nbsp;part&nbsp;of&nbsp;compound&nbsp;name&nbsp;in&nbsp;"<em>Generic&nbsp;Match</em>".&nbsp;</li>'
            '<li>Click the "<em>Home</em>" or "<em>All</em>" button to view the full database</li>'
            '<li>Refer&nbsp;to&nbsp;"<em>Correctness</em>"&nbsp;column&nbsp;for&nbsp;database&nbsp;evaluation&nbsp;details.&nbsp;</li>'
            '<li>You can add your own database entries using the "<em>Insert</em>" tab; click "<em>Save</em>" to save the changes.</li>'
            '</ul>'
            '<h3>Figure:&nbsp;Statistical&nbsp;analysis&nbsp;of&nbsp;the&nbsp;database.</h3>'
            '<ul>'
            '<li><em>Pie&nbsp;chart</em>&nbsp;shows&nbsp;the&nbsp;proportion&nbsp;of&nbsp;data&nbsp;records.</li>'
            '<li><em>Stacked&nbsp;bar&nbsp;chart</em>&nbsp;shows&nbsp;the&nbsp;data&nbsp;types&nbsp;for&nbsp;each&nbsp;compound. First&nbsp;input&nbsp;the&nbsp;compound&nbsp;name,&nbsp;click&nbsp;"<em>Add</em>"&nbsp;and&nbsp;then&nbsp;"<em>Generate</em>"&nbsp;data&nbsp;for&nbsp;overview.&nbsp;</li>'
            '<li><em>Histogram&nbsp;</em>shows&nbsp;the&nbsp;distribution&nbsp;of&nbsp;each&nbsp;data&nbsp;type.</li>'
            '<li><em>Venn&nbsp;diagram</em>&nbsp;shows&nbsp;the&nbsp;correlation&nbsp;of&nbsp;each&nbsp;data&nbsp;type.</li>'
            '</ul>'
            '</div>')

    @pyqtSlot()  # Filtering
    def on_radioBtnVoltage_clicked(self):
        flag, sqlmerge = self.merged_or_not()
        print(sqlmerge)
        self.tabModel.setFilter("PROPERTY LIKE 'Voltage' AND %s" % sqlmerge)

    @pyqtSlot()  # Filtering
    def on_radioBtnCoulombic_clicked(self):
        flag, sqlmerge = self.merged_or_not()
        self.tabModel.setFilter("PROPERTY LIKE 'Coulombic Efficiency' AND %s" %
                                sqlmerge)

    @pyqtSlot()  # Filtering
    def on_radioBtnConductivity_clicked(self):
        flag, sqlmerge = self.merged_or_not()
        self.tabModel.setFilter("PROPERTY LIKE 'Conductivity' AND %s" %
                                sqlmerge)

    @pyqtSlot()  # Filetering
    def on_radioBtnCapacity_clicked(self):
        flag, sqlmerge = self.merged_or_not()
        self.tabModel.setFilter("PROPERTY LIKE 'Capacity' AND %s" % sqlmerge)

    @pyqtSlot()  # Filtering
    def on_radioBtnEnergy_clicked(self):
        flag, sqlmerge = self.merged_or_not()
        self.tabModel.setFilter("PROPERTY LIKE 'Energy' AND %s" % sqlmerge)

    @pyqtSlot()  # Cancel Filetering
    def on_radioBtnAll_clicked(self):
        flag, sqlmerge = self.merged_or_not()
        self.tabModel.setFilter("%s" % sqlmerge)

    # print(self.tabModel.filter())
    # self.tabModel.select()

    def get_elements(self):
        element_dic = {
            "Hydrogen": "H",
            "Helium": "He",
            "Lithium": "Li",
            "Beryllium": "Be",
            "Boron": "B",
            "Carbon": "C",
            "Nitrogen": "N",
            "Oxygen": "O",
            "Fluorine": "F",
            "Neon": "Ne",
            "Sodium": "Na",
            "Magnesium": "Mg",
            "Aluminum": "Al",
            "Silicon": "Si",
            "Phosphorus": "P",
            "Sulfur": "S",
            "Chlorine": "Cl",
            "Argon": "Ar",
            "Potassium": "K",
            "Calcium": "Ca",
            "Scandium": "Sc",
            "Titanium": "Ti",
            "Vanadium": "V",
            "Chromium": "Cr",
            "Manganese": "Mn",
            "Iron": "Fe",
            "Cobalt": "Co",
            "Nickel": "Ni",
            "Copper": "Cu",
            "Zinc": "Zn",
            "Gallium": "Ga",
            "Germanium": "Ge",
            "Arsenic": "As",
            "Selenium": "Se",
            "Bromine": "Br",
            "Krypton": "Kr",
            "Rubidium": "Rb",
            "Strontium": "Sr",
            "Yttrium": "Y",
            "Zirconium": "Zr",
            "Niobium": "Nb",
            "Molybdenum": "Mo",
            "Technetium": "Tc",
            "Ruthenium": "Ru",
            "Rhodium": "Rh",
            "Palladium": "Pd",
            "Silver": "Ag",
            "Cadmium": "Cd",
            "Indium": "In",
            "Tin": "Sn",
            "Antimony": "Sb",
            "Tellurium": "Te",
            "Iodine": "I",
            "Xenon": "Xe",
            "Cesium": "Cs",
            "Barium": "Ba",
            "Lanthanum": "La",
            "Cerium": "Ce",
            "Praseodymium": "Pr",
            "Neodymium": "Nd",
            "Promethium": "Pm",
            "Samarium": "Sm",
            "Europium": "Eu",
            "Gadolinium": "Gd",
            "Terbium": "Tb",
            "Dysprosium": "Dy",
            "Holmium": "Ho",
            "Erbium": "Er",
            "Thulium": "Tm",
            "Ytterbium": "Yb",
            "Lutetium": "Lu",
            "Hafnium": "Hf",
            "Tantalum": "Ta",
            "Tungsten": "W",
            "Rhenium": "Re",
            "Osmium": "Os",
            "Iridium": "Ir",
            "Platinum": "Pt",
            "Gold": "Au",
            "Mercury": "Hg",
            "Thallium": "Tl",
            "Lead": "Pb",
            "Bismuth": "Bi",
            "Polonium": "Po",
            "Astatine": "At",
            "Radon": "Rn",
            "Francium": "Fr",
            "Radium": "Ra",
            "Actinium": "Ac",
            "Thorium": "Th",
            "Protactinium": "Pa",
            "Uranium": "U",
            "Neptunium": "Np",
            "Plutonium": "Pu",
            "Americium": "Am",
            "Curium": "Cm",
            "Berkelium": "Bk",
            "Californium": "Cf",
            "Einsteinium": "Es",
            "Fermium": "Fm",
            "Mendelevium": "Md",
            "Nobelium": "No",
            "Lawrencium": "Lr",
            "Rutherfordium": "Rf",
            "Dubnium": "Db",
            "Seaborgium": "Sg",
            "Bohrium": "Bh",
            "Hassium": "Hs",
            "Meitnerium": "Mt",
            "Darmstadtium": "Ds",
            "Roentgenium": "Rg",
            "Copernicium": "Cn",
            "Nihonium": "Nh",
            "Flerovium": "Fl",
            "Moscovium": "Mc",
            "Livermorium": "Lv",
            "Tennessine": "Ts",
            "Oganesson": "Og"
        }
        return element_dic

    def merged_or_not(self):
        flag = self.ui.mergeBox.isChecked()
        if flag:
            sqlmerge = "NUM_RECORDS NOT LIKE 'NONE'"
        else:
            sqlmerge = "NUM_RECORDS LIKE 'NONE'"
        return flag, sqlmerge

    @pyqtSlot()
    def on_homeButton_clicked(self):
        self.tabModel.setFilter("NUM_RECORDS LIKE 'NONE'")
        self.ui.mergeBox.setChecked(False)

    @pyqtSlot()
    def on_mergeButton_clicked(self):
        self.tabModel.setFilter("NUM_RECORDS NOT LIKE 'NONE'")
        self.ui.mergeBox.setChecked(True)

    @pyqtSlot()
    def on_searchButton_clicked(self):
        searchtext = self.ui.searchInput.text()
        searchclass = self.ui.searchClass.currentText()
        matchtype = self.ui.matchType.currentText()
        flag, sqlmerge = self.merged_or_not()

        if searchclass == "DOI":
            if matchtype == "Exact Match":
                self.tabModel.setFilter("DOI LIKE '%s' AND %s" %
                                        (searchtext, sqlmerge))
            elif matchtype == "Generic Match":
                self.tabModel.setFilter("DOI LIKE '%%%s%%' AND %s" %
                                        (searchtext, sqlmerge))

            if self.tabModel.rowCount() == 0:
                self.tabModel.setFilter("")
                QMessageBox.warning(
                    self, "Warning",
                    "No such DOIs in the database. Please search new DOI.")

        elif searchclass == "Warning":
            if matchtype == "Exact Match":
                self.tabModel.setFilter("WARNING LIKE '%s' AND %s" %
                                        (searchtext, sqlmerge))
            elif matchtype == "Generic Match":
                self.tabModel.setFilter("WARNING LIKE '%%%s%%' AND %s" %
                                        (searchtext, sqlmerge))

            if self.tabModel.rowCount() == 0:
                self.tabModel.setFilter("")
                QMessageBox.warning(
                    self, "Warning",
                    "No such DOIs in the database. Please search new DOI.")

        elif searchclass == 'Name':
            try:
                searchtext = self.get_elements()[searchtext.capitalize()]
            except BaseException:
                pass
            if matchtype == "Exact Match":
                if self.ui.radioBtnAll.isChecked():
                    self.tabModel.setFilter("%s LIKE '%s' " %
                                            (searchclass, searchtext))
                elif self.ui.radioBtnVoltage.isChecked():
                    self.tabModel.setFilter(
                        "%s LIKE '%s' AND PROPERTY LIKE 'VOLTAGE' AND %s" %
                        (searchclass, searchtext, sqlmerge))
                elif self.ui.radioBtnCapacity.isChecked():
                    self.tabModel.setFilter(
                        "%s LIKE '%s' AND PROPERTY LIKE 'CAPACITY' AND %s" %
                        (searchclass, searchtext, sqlmerge))
                elif self.ui.radioBtnConductivity.isChecked():
                    self.tabModel.setFilter(
                        "%s LIKE '%s' AND PROPERTY LIKE 'CONDUCTIVITY' AND %s"
                        % (searchclass, searchtext, sqlmerge))
                elif self.ui.radioBtnCoulombic.isChecked():
                    self.tabModel.setFilter(
                        "%s LIKE '%s' AND PROPERTY LIKE 'COULOMBIC EFFICIENCY' AND %s "
                        % (searchclass, searchtext, sqlmerge))
                elif self.ui.radioBtnEnergy.isChecked():
                    self.tabModel.setFilter(
                        "%s LIKE '%s' AND PROPERTY LIKE 'ENERGY'AND %s " %
                        (searchclass, searchtext, sqlmerge))

            elif matchtype == "Generic Match":
                if self.ui.radioBtnAll.isChecked():
                    self.tabModel.setFilter(
                        "(EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s') AND %s"
                        % (searchtext, searchtext, sqlmerge))
                elif self.ui.radioBtnVoltage.isChecked():
                    self.tabModel.setFilter(
                        "EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s' AND %s"
                        % (searchtext, searchtext, sqlmerge))
                elif self.ui.radioBtnCapacity.isChecked():
                    self.tabModel.setFilter(
                        "EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s' AND %s"
                        % (searchtext, searchtext, sqlmerge))
                elif self.ui.radioBtnConductivity.isChecked():
                    self.tabModel.setFilter(
                        "EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s' AND %s"
                        % (searchtext, searchtext, sqlmerge))
                elif self.ui.radioBtnCoulombic.isChecked():
                    self.tabModel.setFilter(
                        "EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s' AND %s"
                        % (searchtext, searchtext, sqlmerge))
                elif self.ui.radioBtnEnergy.isChecked():
                    self.tabModel.setFilter(
                        "EXTRACTED_NAME LIKE '%%''%s''%%' OR NAME LIKE '%s' AND %s"
                        % (searchtext, searchtext, sqlmerge))

            if self.tabModel.rowCount() == 0:
                self.tabModel.setFilter("")
                QMessageBox.warning(
                    self, "Warning",
                    "No such compounds in the database. Please search new compounds."
                )

# ============Picture Tab 1, Pie Chart=====================

    @pyqtSlot()  # Draw the pie chart
    def on_btnDrawPieChart_clicked(self):
        self.draw_pieChart()

    @pyqtSlot(float)  # Set holeSize
    def on_spinHoleSize_valueChanged(self, arg1):
        seriesPie = self.ui.chartViewPie.chart().series()[0]
        seriesPie.setHoleSize(arg1)

    @pyqtSlot(float)  # Set pieSize
    def on_spinPieSize_valueChanged(self, arg1):
        seriesPie = self.ui.chartViewPie.chart().series()[0]
        seriesPie.setPieSize(arg1)

    @pyqtSlot(bool)  # Set legend checkbox
    def on_chkBox_PieLegend_clicked(self, checked):
        self.ui.chartViewPie.chart().legend().setVisible(checked)

    def pie_data(
            self):  # Return a list of property name and the number of property
        num_list = []
        pro_list = [
            "CAPACITY", "CONDUCTIVITY", "COULOMBIC EFFICIENCY", "ENERGY",
            "VOLTAGE"
        ]
        for i in range(len(pro_list)):
            query = QSqlQuery(
                db=self.DB,
                query=
                "SELECT COUNT(NAME) FROM BATTERY WHERE PROPERTY LIKE '%s' AND NUM_RECORDS LIKE 'NONE'"
                % pro_list[i])  # Query database
            while query.next():
                num_value = query.value(0)  # Returned value for each query

                item = self.ui.treeWidget_2.topLevelItem(i)  # The ith row
                # The 2nd column
                item.setText(1, str(num_value))
                item.setTextAlignment(1, Qt.AlignHCenter)

                num_list.append(num_value)
        return pro_list, num_list

    def draw_pieChart(self):  # Draw the pie chart
        chart = self.ui.chartViewPie.chart()

        chart.legend().setAlignment(Qt.AlignRight)  # AlignRight,AlignBottom
        chart.removeAllSeries()  # Delete all series

        seriesPie = QPieSeries()  # Pie chart series
        seriesPie.setHoleSize(self.ui.spinHoleSize.value())  # Hole size
        seriesPie.setPieSize(self.ui.spinPieSize.value())  # Pie size
        sec_count = 5  # Number of properties
        seriesPie.setLabelsVisible(True)  # Label

        pro, num = self.pie_data()
        for i in range(sec_count):
            seriesPie.append(pro[i], num[i])

        seriesPie.setLabelsVisible(True)  # Label

        # Pie hoverd when mouse selected
        seriesPie.hovered.connect(self.do_pieHovered)
        chart.addSeries(seriesPie)
        chart.setTitle("Proportion of data records for each property")
        font = QFont()
        font.setPointSize(12)
        font.setWeight(75)
        chart.setTitleFont(font)

        font = QFont()
        font.setPointSize(12)
        font.setBold(False)
        font.setWeight(35)
        legend = chart.legend()
        legend.setFont(font)

# =========Picture tab 2. StackedBar=========

    @pyqtSlot()  # Draw StackedBar
    def on_btnStackedBar_clicked(self):
        self.draw_stackedBar()

    @pyqtSlot()  # Draw horizontal StackedBar
    def on_btnStackedBarH_clicked(self):
        self.draw_stackedBar(False)

    # Search button in the Stacked bar chart tab. Add name to the first column
    # of the table.
    @pyqtSlot()
    def on_searchButton_3_clicked(self):
        searchtext = self.ui.searchInput_3.text()

        current_index = self.ui.stackedWidget.topLevelItemCount()
        item_0 = QtWidgets.QTreeWidgetItem(self.ui.stackedWidget)
        item_0.setText(0, searchtext)

    @pyqtSlot()  # Generate data using the input chemical names
    def on_generateButton_3_clicked(self):
        self.ui.zoominButton.setEnabled(True)
        self.ui.zoomoutButton.setEnabled(True)
        self.ui.originalButton.setEnabled(True)
        self.ui.btnStackedBar.setEnabled(True)  # Stacked bar chart
        self.ui.btnStackedBarH.setEnabled(True)

        current_index = self.ui.stackedWidget.topLevelItemCount()
        chemical_list = [
            self.ui.stackedWidget.topLevelItem(index).text(0)
            for index in range(current_index)
        ]  # Get a list of the inputed chemical name
        pro_list = [
            "CAPACITY", "CONDUCTIVITY", "COULOMBIC EFFICIENCY", "ENERGY",
            "VOLTAGE"
        ]
        for row, chemical in enumerate(chemical_list):
            for index, pro in enumerate(pro_list):
                query = QSqlQuery(
                    db=self.DB,
                    query=
                    "SELECT SUM(NUM_RECORDS) FROM BATTERY WHERE PROPERTY LIKE '%s' AND NAME LIKE '%s' "
                    % (pro, chemical))
                while query.next():
                    num_value = query.value(0)
                    print(num_value)
                    if num_value == "":
                        num_value = 0
                    item = self.ui.stackedWidget.topLevelItem(
                        row)  # The row'th row
                    item.setText(index + 1, str(num_value))
                    item.setTextAlignment(index + 1, Qt.AlignHCenter)

    @pyqtSlot()  # Clear button
    def on_clearButton_3_clicked(self):
        self.ui.stackedWidget.clear()

    @pyqtSlot()  # Zoom in
    def on_zoominButton_clicked(self):
        self.ui.chartViewStackedBar.chart().zoom(1.2)

    @pyqtSlot()  # Zoom out
    def on_zoomoutButton_clicked(self):
        self.ui.chartViewStackedBar.chart().zoom(0.8)

    @pyqtSlot()  # Reset original size
    def on_originalButton_clicked(self):
        self.ui.chartViewStackedBar.chart().zoomReset()

    def draw_stackedBar(self, isVertical=True):  # Stacked bar chart
        chart = self.ui.chartViewStackedBar.chart()
        chart.removeAllSeries()  # Remove all series
        chart.removeAxis(chart.axisX())  # remove axis
        chart.removeAxis(chart.axisY())
        if isVertical:  # Vertical
            chart.setTitle("Number of property records for each chemical ")
            chart.legend().setAlignment(Qt.AlignBottom)
        else:  # Horizontal
            chart.setTitle("Number of property records for each chemical")
            chart.legend().setAlignment(Qt.AlignRight)

        # Create data sets
        setCapacity = QBarSet("Capacity")
        setConductivity = QBarSet("Conductivity")
        setCoulombic = QBarSet("Coulombic")
        setEnergy = QBarSet("Energy")
        setVoltage = QBarSet("Voltage")

        chemical_Count = self.ui.stackedWidget.topLevelItemCount()
        nameList = []  # Chemical lists
        for i in range(chemical_Count):
            item = self.ui.stackedWidget.topLevelItem(i)
            # print(item.text(1))
            nameList.append(item.text(0))
            setCapacity.append(float(item.text(1)))
            setConductivity.append(float(item.text(2)))
            setCoulombic.append(float(item.text(3)))
            setEnergy.append(float(item.text(4)))
            setVoltage.append(float(item.text(5)))

        # Create series
        if isVertical:
            seriesBar = QStackedBarSeries()
        else:
            seriesBar = QHorizontalStackedBarSeries()

        seriesBar.append(setCapacity)
        seriesBar.append(setConductivity)
        seriesBar.append(setCoulombic)
        seriesBar.append(setEnergy)
        seriesBar.append(setVoltage)

        seriesBar.setLabelsVisible(True)  # Show labels for each bar
        seriesBar.setLabelsFormat("@value")
        seriesBar.setLabelsPosition(QAbstractBarSeries.LabelsCenter)

        seriesBar.setBarWidth(0.3)

        chart.addSeries(seriesBar)

        axisStud = QBarCategoryAxis()  # Category axis
        axisStud.append(nameList)
        axisStud.setRange(nameList[0], nameList[chemical_Count - 1])

        axisValue = QValueAxis()  # Value axis
        # axisValue.setRange(0, 300)
        axisValue.setTitleText("Number of records")
        # axisValue.setTickCount(6)
        axisValue.applyNiceNumbers()

        if isVertical:
            chart.setAxisX(axisStud, seriesBar)
            chart.setAxisY(axisValue, seriesBar)
        else:
            chart.setAxisY(axisStud, seriesBar)
            chart.setAxisX(axisValue, seriesBar)

        for marker in chart.legend().markers():  # QLegendMarker lists
            marker.clicked.connect(self.do_LegendMarkerClicked)

# =========Picture tab 3. Histogram=========

    @pyqtSlot(bool)  # Show toolbar
    def on_gBoxHist_toolbar_2_clicked(self, checked):
        self.ui.widgetHist_2.setToolbarVisible(checked)

    @pyqtSlot()  # Draw
    def on_histButton_clicked(self):
        self.__drawHist()

    def hist_data(self, pro):
        query = QSqlQuery(
            db=self.DB,
            query=
            "SELECT VALUE FROM BATTERY WHERE PROPERTY LIKE '%s' AND NUM_RECORDS LIKE 'NONE'"
            % pro)
        data = []
        while query.next():
            num_value = query.value(0)
            data.append(num_value)
        return data

    def __drawHist(self):  # Histogram
        pro = self.ui.propertycomboBox_2.currentText()
        data = self.hist_data(pro)
        self.ui.widgetHist_2.figure.clear()  # Clear figure

        ax = self.ui.widgetHist_2.figure.add_subplot(1, 1, 1)

        if pro == 'Capacity':
            M, bins, patches = ax.hist(
                [5000 if float(i) > 4999 else float(i) for i in data],
                bins='auto',
                color='darkgreen',
                alpha=0.5,
                rwidth=1)
            ax.set_xlim(0, 5001)
            # ax.set_ylim(0,15000)
            ax.tick_params(labelsize=12)
            ax.set_xticklabels(['0', '1000', '2000', '3000', '4000', '5000+'])
            ax.set_xlabel('Capacity (mAh/g)', fontsize=14)
            ax.set_ylabel('Frequency', fontsize=14)
            ax.set_title('Battery Capacity Distrbution', fontsize=14)
            ax.figure.canvas.draw()

        elif pro == "Voltage":
            count1 = []
            for i in data:
                count1.append(float(i))

            n, bins, patches = ax.hist(x=count1,
                                       bins='auto',
                                       range=(0, 8),
                                       color='r',
                                       alpha=0.5,
                                       rwidth=1)
            ax.set_xticklabels(['0', '1', '2', '3', '4', '5', '6', '7', '8+'])

            ax.set_xlim(0, 8)
            ax.tick_params(labelsize=12)
            ax.set_xlabel('Voltage (V)', fontsize=14)
            ax.set_ylabel('Frequency', fontsize=14)
            ax.set_title('Battery Voltage Distrbution', fontsize=14)
            ax.figure.canvas.draw()

        elif pro == "Energy":
            n, bins, patches = ax.hist(
                [3000 if float(i) > 2999 else float(i) for i in data],
                bins='auto',
                color='y',
                alpha=0.5,
                rwidth=1)
            ax.set_xticklabels(
                ['0', '500', '1000', '1500', '2000', '2500', '3000+'])
            ax.set_xlim(0, 3001)
            ax.tick_params(labelsize=12)
            ax.set_xlabel('Energy (Wh/kg)', fontsize=14)
            ax.set_ylabel('Frequency', fontsize=14)
            ax.set_title('Battery Energy Distrbution', fontsize=14)
            ax.figure.canvas.draw()

        elif pro == "Coulombic Efficiency":
            dataplot = [float(i) for i in data]
            n, bins, patches = ax.hist(x=dataplot,
                                       bins='auto',
                                       color='c',
                                       alpha=0.5,
                                       rwidth=1)
            ax.set_xlim(0, 100)
            ax.tick_params(labelsize=12)
            ax.set_xlabel('Coulombic Effciency (%)', fontsize=14)
            ax.set_ylabel('Frequency', fontsize=14)
            ax.set_title('Battery Coulombic Effciency Distrbution',
                         fontsize=14)
            ax.figure.canvas.draw()

        elif pro == "Conductivity":
            dataplot = [float(i) for i in data]
            n, bins, patches = ax.hist(x=dataplot,
                                       bins=np.logspace(
                                           np.log10(1e-15), np.log10(1)),
                                       color='k',
                                       alpha=0.5,
                                       rwidth=1)
            ax.set_xlim(1e-20, 10)
            ax.set_xscale('log')
            ax.tick_params(labelsize=12)
            ax.set_xlabel('log10 (Conductivity (S/cm))', fontsize=14)
            ax.set_ylabel('Frequency', fontsize=14)
            ax.set_title('Battery Conductivity Distrbution', fontsize=14)
            ax.figure.canvas.draw()

# =========Picture tab 4. Venn diagram=========

    @pyqtSlot()  # Draw
    def on_btnVenn_clicked(self):
        self.__drawVenn()

    @pyqtSlot(bool)  # Show toolbar
    def on_gBoxHist_toolbar_3_clicked(self, checked):
        self.ui.widgetVenn.setToolbarVisible(checked)

    def __drawVenn(self):
        self.ui.widgetVenn.figure.clear()  # Clear figure

        pro_list = [
            "Capacity", "Conductivity", "Coulombic Efficiency", "Energy",
            "Voltage"
        ]
        data_dic = {}
        color_dic = dict(zip(pro_list, ['C0', 'C2', 'C6', 'C8', 'C9']))

        for i in pro_list:
            query = QSqlQuery(
                db=self.DB,
                query=
                "SELECT COUNT(DISTINCT NAME) FROM BATTERY WHERE PROPERTY LIKE '%s' AND NUM_RECORDS LIKE 'NONE'"
                % i)
            while query.next():
                num_value = query.value(0)
                data_dic[i] = num_value

        for i, combo in enumerate(itertools.combinations(pro_list, 2)):

            query = QSqlQuery(
                db=self.DB,
                query=
                "SELECT COUNT() FROM (SELECT DISTINCT NAME AS PRO1 FROM BATTERY WHERE PROPERTY LIKE '%s'AND NUM_RECORDS LIKE 'NONE') INNER JOIN (SELECT DISTINCT NAME AS PRO2 FROM BATTERY WHERE PROPERTY LIKE '%s'AND NUM_RECORDS LIKE 'NONE') ON PRO1 = PRO2"
                % combo)
            while query.next():
                num = query.value(0)
            x3 = num
            x1 = data_dic[combo[0]] - x3
            x2 = data_dic[combo[1]] - x3

            hf = self.ui.widgetVenn.figure
            # hf.set_figheight(30)
            # hf.set_figwidth(30)
            # print(dir(hf))

            hf.set_size_inches((10, 10))
            ax1 = hf.add_subplot(5, 2, i + 1)
            v = venn2(subsets=(x1, x2, x3),
                      set_labels=(combo[0], combo[1]),
                      ax=ax1)

            v.get_patch_by_id('A').set_alpha(1)
            v.get_patch_by_id('A').set_color(color_dic[combo[0]])
            v.get_patch_by_id('B').set_color(color_dic[combo[1]])

            ax1.figure.canvas.draw()

# =============Self-defined slot function===============================

# Update the conditions of actPost and actCancel

    def do_currentChanged(self, current, previous):
        self.ui.actSubmit.setEnabled(
            self.tabModel.isDirty())  # Use when not saving changes
        self.ui.actRevert.setEnabled(self.tabModel.isDirty())

    def do_currentRowChanged(self, current,
                             previous):  # Control during row changes
        self.ui.actRecDelete.setEnabled(current.isValid())

        # Update current row index of mapping
        self.mapper.setCurrentIndex(current.row())
        # Get current record,QSqlRecord
        curRec = self.tabModel.record(current.row())

    def do_pieHovered(self, pieSlice,
                      state):  # Mouse move in and out in the pie chart
        pieSlice.setExploded(state)  # Pop-up animation
        if state:  # Show the tab of percentages
            self.__oldLabel = pieSlice.label()  # Save original labels
            pieSlice.setLabel(self.__oldLabel + ": %.1f%%" %
                              (pieSlice.percentage() * 100))
            font = QFont()
            font.setPointSize(10)
            font.setBold(False)
            font.setWeight(25)
            pieSlice.setLabelFont(font)
        else:  # show original labels
            pieSlice.setLabel(self.__oldLabel)
            font = QFont()
            font.setPointSize(10)
            font.setBold(False)
            font.setWeight(25)
            pieSlice.setLabelFont(font)

    def do_LegendMarkerClicked(self):  # Click legend marker
        marker = self.sender()  # QLegendMarker

        marker.series().setVisible(not marker.series().isVisible())
        marker.setVisible(True)
        alpha = 1.0
        if not marker.series().isVisible():
            alpha = 0.5

        brush = marker.labelBrush()  # QBrush
        color = brush.color()  # QColor
        color.setAlphaF(alpha)
        brush.setColor(color)
        marker.setLabelBrush(brush)

        brush = marker.brush()
        color = brush.color()
        color.setAlphaF(alpha)
        brush.setColor(color)
        marker.setBrush(brush)

        pen = marker.pen()  # QPen
        color = pen.color()
        color.setAlphaF(alpha)
        pen.setColor(color)
        marker.setPen(pen)
예제 #18
0
class SignAnnounceWidget(QWidget):
    """Widget that displays information about signing a Masternode Announce."""
    def __init__(self, parent):
        super(SignAnnounceWidget, self).__init__(parent)
        self.dialog = parent
        self.manager = parent.manager

        # Displays the status of the masternode.
        self.status_edit = QLineEdit()
        self.status_edit.setReadOnly(True)

        self.alias_edit = QLineEdit()
        self.collateral_edit = PrevOutWidget()
        self.delegate_edit = QLineEdit()
        self.delegate_edit.setFont(QFont(util.MONOSPACE_FONT))

        for i in [self.alias_edit, self.collateral_edit, self.delegate_edit]:
            i.setReadOnly(True)

        self.mapper = QDataWidgetMapper()
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.setModel(self.dialog.masternodes_widget.proxy_model)

        model = self.dialog.masternodes_widget.model
        self.mapper.addMapping(self.alias_edit, model.ALIAS)
        self.mapper.addMapping(self.collateral_edit, model.VIN, b'string')
        self.mapper.addMapping(self.delegate_edit, model.DELEGATE)

        self.sign_button = QPushButton(_('Activate Masternode'))
        self.sign_button.setEnabled(False)
        self.sign_button.clicked.connect(self.sign_announce)

        status_box = QHBoxLayout()
        status_box.setContentsMargins(0, 0, 0, 0)
        status_box.addWidget(QLabel(_('Status:')))
        status_box.addWidget(self.status_edit, stretch=1)

        vbox = QVBoxLayout()
        vbox.addLayout(status_box)

        form = QFormLayout()
        form.addRow(_('Alias:'), self.alias_edit)
        form.addRow(_('Collateral vestx Output:'), self.collateral_edit)
        form.addRow(_('Masternode Private Key:'), self.delegate_edit)
        vbox.addLayout(form)
        vbox.addLayout(util.Buttons(self.sign_button))
        self.setLayout(vbox)

    def set_mapper_index(self, row):
        """Set the row that the data widget mapper should use."""
        self.status_edit.clear()
        self.status_edit.setStyleSheet(
            util.ColorScheme.DEFAULT.as_stylesheet())
        self.mapper.setCurrentIndex(row)
        mn = self.dialog.masternodes_widget.masternode_for_row(row)

        # Disable the sign button if the masternode can't be signed (for whatever reason).
        status_text = '%s can be activated' % mn.alias
        can_sign = True
        try:
            self.manager.check_can_sign_masternode(mn.alias)
        except Exception as e:
            status_text = str(e)
            can_sign = False

        self.status_edit.setText(_(status_text))
        self.sign_button.setEnabled(can_sign)

    def sign_announce(self):
        """Set the masternode's vin and sign an announcement."""
        self.mapper.submit()
        self.dialog.sign_announce(str(self.alias_edit.text()))
예제 #19
0
파일: main.py 프로젝트: fayzut/invent_L79
class EditForm(QWidget, Ui_EditForm):
    def __init__(self, current_index, model):
        super().__init__()
        # uic.loadUi('editForm.ui', self)
        self.setupUi(self)
        # self.db = database

        self.db_map = QDataWidgetMapper(self)
        self.db_map.setModel(model)
        self.db_map.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.db_map.addMapping(self.lineEdit_name, 1)
        self.db_map.addMapping(self.lineEdit_inv_number, 2)
        self.db_map.addMapping(self.textEdit_comments, 3)
        self.db_map.addMapping(self.checkBox_on_balance,
                               model.fieldIndex('is_on_balance'))

        relModel_status = model.relationModel(5)
        self.comboBox_status.setModel(relModel_status)
        self.comboBox_status.setModelColumn(
            relModel_status.fieldIndex("status_name"))
        self.db_map.setItemDelegate(QSqlRelationalDelegate(self))
        self.db_map.addMapping(self.comboBox_status, 5)

        relModel_type = model.relationModel(6)
        self.comboBox_type.setModel(relModel_type)
        self.comboBox_type.setModelColumn(
            relModel_type.fieldIndex("goods_type_name"))
        self.db_map.setItemDelegate(QSqlRelationalDelegate(self))
        self.db_map.addMapping(self.comboBox_type, 6)

        relModel_subtype = model.relationModel(7)
        self.comboBox_subtype.setModel(relModel_subtype)
        self.comboBox_subtype.setModelColumn(
            relModel_subtype.fieldIndex("goods_subtype_name"))
        self.db_map.setItemDelegate(QSqlRelationalDelegate(self))
        self.db_map.addMapping(self.comboBox_subtype, 7)

        relModel_location = model.relationModel(8)
        self.comboBox_location.setModel(relModel_location)
        self.comboBox_location.setModelColumn(
            relModel_location.fieldIndex("location_name"))
        self.db_map.setItemDelegate(QSqlRelationalDelegate(self))
        self.db_map.addMapping(self.comboBox_location, 8)

        relModel_responsible = model.relationModel(9)
        self.comboBox_responsible.setModel(relModel_responsible)
        self.comboBox_responsible.setModelColumn(
            relModel_responsible.fieldIndex("FIO"))
        self.db_map.setItemDelegate(QSqlRelationalDelegate(self))
        self.db_map.addMapping(self.comboBox_responsible, 9)

        self.pushBtn_save.clicked.connect(self.save_item)
        self.pushBtn_cancel.clicked.connect(self.cancel)
        self.pushBtn_next.clicked.connect(self.db_map.toNext)
        self.pushBtn_prev.clicked.connect(self.db_map.toPrevious)
        self.pushBtn_close.clicked.connect(self.close)

        self.db_map.setCurrentIndex(current_index.row())

    def save_item(self):
        self.db_map.submit()

    def cancel(self):
        self.db_map.setCurrentIndex(self.db_map.currentIndex())