Exemple #1
0
class ProductDetailsWidget(ProwlerSqlWidget):
    """Base class for the AmzProductDetailsWidget and VndProductDetailsWidget classes. Doesn't have it's own
    UI, but depends on certain UI elements (like self.titleLine) to be available.
    """
    def __init__(self, parent=None):
        super(ProductDetailsWidget, self).__init__(parent=parent)
        self.setupUi(self)

        # Populate the columns
        self.set_source(None)

        # Set up the data widget mapper
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setModel(self.model)
        self.mapper.setItemDelegate(DataMapperDelegate(self))
        self.mapper.currentIndexChanged.connect(self.rewind_lines)

        self.mapper.addMapping(self.titleLine, self.model.fieldIndex('title'))
        self.mapper.addMapping(self.brandLine, self.model.fieldIndex('brand'))
        self.mapper.addMapping(self.modelLine, self.model.fieldIndex('model'))
        self.mapper.addMapping(self.skuLine, self.model.fieldIndex('sku'))
        self.mapper.addMapping(self.upcLine, self.model.fieldIndex('upc'))
        self.mapper.addMapping(self.priceBox, self.model.fieldIndex('price'))
        self.mapper.addMapping(self.quantityBox,
                               self.model.fieldIndex('quantity'))

        self.model.modelReset.connect(self.mapper.toFirst)

    def rewind_lines(self):
        """Reset text lines to home position."""
        self.titleLine.home(False)
        self.brandLine.home(False)
        self.modelLine.home(False)
Exemple #2
0
def schema_ui_map(schema, model, form):
    """Construct a QDataWidgetMapper from the given ``schema`` class.
    (Function 4)

    :param schema: The schema to create field-to-widget mappings from.
    :param model: The model that the QDataWidgetMapper observes.
    :param form: The UI widget containing stuff to bind to. It is also set as
                 the parent for the widget mapper.
    """
    assert isinstance(model, QAbstractItemModel)
    mapper = QDataWidgetMapper(form)
    mapper.setModel(model)

    s = schema()

    for i, (name, field) in enumerate(s.fields.items()):
        try:
            widget_classes = _widget_type(type(field))
            widget = form.findChild(widget_classes, name)
            if not widget:
                raise ValueError
            prop = _widget_property(type(widget))
            log.debug("adding map from (`%s', col = %d) to %s (prop = `%s')",
                      name, i, widget, prop)
            mapper.addMapping(widget, i, bytes(prop, encoding='utf8'))
            assert mapper.mappedWidgetAt(i) == widget
        except KeyError:
            log.error("unknown field type %s", type(field))
        except ValueError:  # FIXME: is this the correct exception type?
            log.error("failed to find widget for field `%s'", name)

    mapper.toFirst()
    return mapper
Exemple #3
0
    def __init__(self, tag_number):
        super().__init__()
        print('processing query...')
        qry = QSqlQuery(db)
        query = 'SELECT name, ename, startno, starttime FROM name WHERE ecard = %i OR ecard2 = %i' % (
            tag_number, tag_number)
        qry.prepare(query)
        qry.exec()

        model = QSqlQueryModel()
        model.setQuery(qry)
        print(model.rowCount())
        mapper = QDataWidgetMapper()
        form = QFormLayout()
        layout = QVBoxLayout()

        first_name = QLineEdit()
        start_number = QLineEdit()
        form.addRow(QLabel("Startnummer"), start_number)
        form.addRow(QLabel("Fornavn"), first_name)
        mapper.setModel(model)
        mapper.addMapping(first_name, 0)
        mapper.addMapping(start_number, 2)
        mapper.toFirst()
        layout.addLayout(form)
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)
        #controls = QHBoxLayout()
        '''
class DynamicVariableEditor(DynVarForm, DynVarBase):
    def __init__(self, parent=None):
        super(DynamicVariableEditor, self).__init__()
        self.setupUi(self)
        self._model = None
        self._data_mapper = QDataWidgetMapper(self)

    @property
    def model(self):
        return self._model

    @model.setter
    def model(self, model):
        self._model = model
        self._data_mapper.setModel(model)

        self._data_mapper.addMapping(self.dyn_var_name, 0)
        self._data_mapper.addMapping(self.dyn_var_default, 1)
        self._data_mapper.addMapping(self.dyn_var_start, 2)
        self._data_mapper.addMapping(self.dyn_var_end, 3)
        self._data_mapper.addMapping(self.dyn_var_log, 4)
        self._data_mapper.addMapping(self.dyn_var_send, 5)
        self._data_mapper.addMapping(self.dyn_var_stepsize, 6, 'text')

        self.dyn_var_log.clicked.connect(self.dyn_var_log.clearFocus)
        self.dyn_var_send.clicked.connect(self.dyn_var_send.clearFocus)

    def selectionChanged(self, current_index, old_index):
        self._data_mapper.setCurrentIndex(current_index.row())
Exemple #5
0
class cMainWindow(QMainWindow):
    def __init__(self):
        super(cMainWindow, self).__init__()
        loadUi('MainWindow.ui', self)
        self.mModel = Model.cModel()
        self.mainList.setModel( self.mModel )
        self.treeView.setModel( self.mModel )

        self.mMapper = QDataWidgetMapper()
        self.mMapper.setModel( self.mModel )
        self.mMapper.setOrientation( Qt.Vertical )
        self.mMapper.addMapping( self.nameLineEdit, 0)
        self.mMapper.addMapping( self.weaponComboBox, 1, b"currentText" )
        self.mMapper.addMapping( self.shiledSpinBox, 2)

        self.mainList.selectionModel().currentChanged.connect( self.CombattantSelected )

        self.shiledSpinBox.valueChanged.connect( self.SubmitToModel )
        self.weaponComboBox.currentIndexChanged.connect( self.SubmitToModel )

        weaponList = "Fist", "Dagger", "Sword", "Pike"
        self.weaponComboBox.addItems( weaponList )
    # --------------------------------


    def CombattantSelected(self, iIndex):
        self.mMapper.setRootIndex( iIndex )
        self.mMapper.toFirst()
    # --------------------------------


    def  SubmitToModel(self, iValue):
        self.mMapper.submit()
    # --------------------------------
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)
Exemple #7
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
    def __init__(self, contact_list_model, contact_index):
        super().__init__()
        ui_file = BASE_UI_PATH / "edit_contact_window.ui"
        uic.loadUi(ui_file, self)
        self.gender_editbox.addItems(GENDER_LIST)

        contact = contact_list_model.contact_by_index(contact_index)

        mapper = QDataWidgetMapper(self)
        mapper.setModel(contact_list_model)
        for section, name in enumerate(contact.field_names()):
            mapper.addMapping(getattr(self, f"{name}_editbox"), section)
        mapper.setCurrentIndex(contact_index)
Exemple #9
0
class TaskDetails(DetailScreen):
    """ Displays all current Research Plans """
    def __init__(self, data_context):
        super().__init__(data_context)

        form_layout = QFormLayout()
        self.source = LinkedLineEdit(
            self.data_context.sources_model,
            SourcesModelColumns.AUTOCOMPLETE,
            SourcesModelColumns.POINTER,
        )
        self.source.link_updated.connect(self.link_updated)
        form_layout.addRow(QLabel("Source:"), self.source)

        self.description = QTextEdit()
        form_layout.addRow(QLabel("Description:"), self.description)

        self.result = ResultWidget()
        form_layout.addRow(QLabel("Results:"), self.result)

        form_group = QGroupBox("Task")
        form_group.setLayout(form_layout)

        layout = QVBoxLayout()
        layout.addWidget(form_group)

        # Don't add this, we just want to get/set the value
        self.link = QLineEdit()

        self.setLayout(layout)

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.data_context.data_model)
        self.mapper.addMapping(self.source, TreeModelCols.TEXT)
        self.mapper.addMapping(self.description, TreeModelCols.DESCRIPTION,
                               b"plainText")
        self.mapper.addMapping(self.result, TreeModelCols.RESULT)
        self.mapper.addMapping(self.link, TreeModelCols.LINK)
        self.result.result_changed.connect(self.mapper.submit)
        self.mapper.currentIndexChanged.connect(
            lambda _: self.source.set_link_visible(self.link.text() != ""))
        self.data_context.data_model.dataChanged.connect(
            lambda _, __: self.source.set_link_visible(self.link.text() != ""))
        self.mapper.toFirst()

    def link_updated(self, text: str):
        """ Called when the link needs updating from the LineEdit """
        self.link.setText(text)
        self.mapper.submit()
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()
Exemple #11
0
class VnTreeView(QTreeView):
    tree_clicked = pyqtSignal(str)
    def __init__(self, parent=None, treerootNode=None):
        super().__init__(parent)
        self.setHeaderHidden(True)
        self.rootIsDecorated = True
        #self.setup_treemodel(treerootNode)

    def setup_treemodel(self, treerootNode=None, treetype='FsTree'):
        if treetype=='FsTree':
            treemodel = FsTreeModel(treerootNode)
        else:
            treemodel = VnTreeModel(treerootNode)
        self.setModel(treemodel)
        self.dataMapper = QDataWidgetMapper()
        self.dataMapper.setModel(treemodel)
Exemple #12
0
class PlanDetails(DetailScreen):
    """ Displays all current Research Plans """

    def __init__(self, data_context):
        super(PlanDetails, self).__init__(data_context)

        form_layout = QFormLayout()
        self.ancestor = LinkedLineEdit(
            self.data_context.individuals_model,
            IndividualsModelColumns.AUTOCOMPLETE,
            IndividualsModelColumns.POINTER,
        )
        self.ancestor.link_updated.connect(self.link_updated)
        form_layout.addRow(QLabel("Ancestor:"), self.ancestor)

        self.goal = QTextEdit()
        form_layout.addRow(QLabel("Goal:"), self.goal)

        form_group = QGroupBox("Plan")
        form_group.setLayout(form_layout)

        layout = QVBoxLayout()
        layout.addWidget(form_group)

        # Don't add this, we just want to get/set the value
        self.link = QLineEdit()

        self.setLayout(layout)

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.data_context.data_model)
        self.mapper.addMapping(self.ancestor, TreeModelCols.TEXT)
        self.mapper.addMapping(self.goal, TreeModelCols.DESCRIPTION, b"plainText")
        self.mapper.addMapping(self.link, TreeModelCols.LINK)
        self.mapper.currentIndexChanged.connect(
            lambda _: self.ancestor.set_link_visible(self.link.text() != "")
        )
        self.data_context.data_model.dataChanged.connect(
            lambda _, __: self.ancestor.set_link_visible(self.link.text() != "")
        )
        self.mapper.toFirst()

    def link_updated(self, text: str):
        """ Called when the link needs updating from the LineEdit """
        self.link.setText(text)
        self.mapper.submit()
Exemple #13
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()
class CommitDateMaxFilterEditor(QWidget, Ui_CommitDateMaxFilter):

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

        self._data_mapper = QDataWidgetMapper()

    def setModel(self, model):
        self._model = model
        self._data_mapper.setModel(model)
        self._data_mapper.addMapping(self.uiCommitDateMax, 2)

    def setSelection(self, current: QModelIndex) -> None:
        parent = current.parent()
        self._data_mapper.setRootIndex(parent)
        self._data_mapper.setCurrentModelIndex(current)
class NodeEditor(QWidget, Ui_FilterNodeProperties):

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

        self._data_mapper = QDataWidgetMapper()

    def setModel(self, model):
        self._model = model
        self._data_mapper.setModel(model)
        self._data_mapper.addMapping(self.uiName, 0)
        self._data_mapper.addMapping(self.uiComment, 1)

    def setSelection(self, current: QModelIndex) -> None:
        parent = current.parent()
        self._data_mapper.setRootIndex(parent)
        self._data_mapper.setCurrentModelIndex(current)
class CommitDateDeltaMinFilterEditor(QWidget, Ui_CommitDateDeltaMinFilter):

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

        self._data_mapper = QDataWidgetMapper()
        self.uiHelp.clicked.connect(_showTimeDurationHelp)

    def setModel(self, model):
        self._model = model
        self._data_mapper.setModel(model)
        self._data_mapper.addMapping(self.uiCommitDateDeltaMin, 2)

    def setSelection(self, current: QModelIndex) -> None:
        parent = current.parent()
        self._data_mapper.setRootIndex(parent)
        self._data_mapper.setCurrentModelIndex(current)
class AuthorFilterEditor(QWidget, Ui_AuthorFilterProperties):

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

        self._data_mapper = QDataWidgetMapper()

    def setModel(self, model):
        self._model = model
        self._data_mapper.setModel(model)
        self._data_mapper.addMapping(self.uiAuthorName, 2)
        self._data_mapper.addMapping(self.uiAuthorEmail, 3)

    def setSelection(self, current: QModelIndex) -> None:
        parent = current.parent()
        self._data_mapper.setRootIndex(parent)
        self._data_mapper.setCurrentModelIndex(current)
Exemple #18
0
def setMappings(mappings):
    """Set the mappings between the model and widgets.
    TODO: - Should this be extended to accept other columns?
          - Check if the already has the model.
    """
    column = 1
    mappers = list()
    for widget, obj in mappings:
        mapper = QDataWidgetMapper(widget)
        # logger.debug(obj.model())
        mapper.setModel(obj.model())
        mapper.addMapping(widget, column)
        delegate = Delegate(widget)
        mapper.setItemDelegate(delegate)
        mapper.setRootIndex(obj.parent().index())
        mapper.setCurrentModelIndex(obj.index())
        # QDataWidgetMapper needs a focus event to notice a change in the data.
        # To make sure the model is informed about the change, I connected the
        # stateChanged signal of the QCheckBox to the submit slot of the
        # QDataWidgetMapper. The same idea goes for the QComboBox.
        # https://bugreports.qt.io/browse/QTBUG-1818
        if isinstance(widget, QCheckBox):
            signal = widget.stateChanged
            try:
                signal.disconnect()
            except TypeError:
                pass
            signal.connect(mapper.submit)
        elif isinstance(widget, QComboBox):
            signal = widget.currentTextChanged
            try:
                signal.disconnect()
            except TypeError:
                pass
            signal.connect(mapper.submit)
        mappers.append(mapper)
    return mappers
Exemple #19
0
class RecordFormView(QMainWindow):

    ui_file = ''  # type: str
    model = None

    def __init__(self, model=None, ui_file: str = None) -> None:
        super().__init__()
        loadUi(ui_file or self.ui_file, self)

        self.model = model or self.model

        self.data_mapper = QDataWidgetMapper()
        self.data_mapper.setModel(self.model)

        for field in model.fields:
            if hasattr(self, field.name):
                self.data_mapper.addMapping(getattr(self, field.name),
                                            field.index)

        if hasattr(self, 'setup_ui'):
            self.setup_ui()

    def set_record_index(self, index: QModelIndex) -> None:
        self.data_mapper.setCurrentModelIndex(index)
Exemple #20
0
class Soduku(QtWidgets.QMainWindow, soduku_window.Ui_MainWindow):
    def __init__(self, parent=None):
        super(Soduku, self).__init__(parent)
        self.setupUi(self)
        self.pushButton_2.clicked.connect(self.solve)
        self.initLine()
        self.colums = ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
        self.progressBar.setMaximum(100)
        self.progressBar.setMinimum(0)
        self.progressBar.setValue(0)
        # self.progressBar.hide()
        self.pushButton.clicked.connect(self.clear)

        data = {}

        for column in self.colums:
            data[column] = [
                v for k, v in sorted({
                    x.objectName(): x.text()
                    for x in self.findChildren(QtWidgets.QLineEdit,
                                               QtCore.QRegExp(f"{column}"))
                }.items())
            ]
        self.df = pd.DataFrame.from_dict(json.load(open("test.json")))

        # self.df = pd.DataFrame.from_dict(data, dtype="int")
        self.model = manager(self.df)

        self.mapperA = QDataWidgetMapper()
        self.mapperA.setModel(self.model)
        self.mapperA.setCurrentIndex(0)
        self.mapperA.addMapping(self.A1, 0)
        self.mapperA.addMapping(self.B1, 1)
        self.mapperA.addMapping(self.C1, 2)
        self.mapperA.addMapping(self.D1, 3)
        self.mapperA.addMapping(self.E1, 4)
        self.mapperA.addMapping(self.F1, 5)
        self.mapperA.addMapping(self.G1, 6)
        self.mapperA.addMapping(self.H1, 7)
        self.mapperA.addMapping(self.I1, 8)

        self.mapperB = QDataWidgetMapper()
        self.mapperB.setModel(self.model)
        self.mapperB.setCurrentIndex(1)
        self.mapperB.addMapping(self.A2, 0)
        self.mapperB.addMapping(self.B2, 1)
        self.mapperB.addMapping(self.C2, 2)
        self.mapperB.addMapping(self.D2, 3)
        self.mapperB.addMapping(self.E2, 4)
        self.mapperB.addMapping(self.F2, 5)
        self.mapperB.addMapping(self.G2, 6)
        self.mapperB.addMapping(self.H2, 7)
        self.mapperB.addMapping(self.I2, 8)

        self.mapperC = QDataWidgetMapper()
        self.mapperC.setModel(self.model)
        self.mapperC.setCurrentIndex(2)
        self.mapperC.addMapping(self.A3, 0)
        self.mapperC.addMapping(self.B3, 1)
        self.mapperC.addMapping(self.C3, 2)
        self.mapperC.addMapping(self.D3, 3)
        self.mapperC.addMapping(self.E3, 4)
        self.mapperC.addMapping(self.F3, 5)
        self.mapperC.addMapping(self.G3, 6)
        self.mapperC.addMapping(self.H3, 7)
        self.mapperC.addMapping(self.I3, 8)

        self.mapperD = QDataWidgetMapper()
        self.mapperD.setModel(self.model)
        self.mapperD.setCurrentIndex(3)
        self.mapperD.addMapping(self.A4, 0)
        self.mapperD.addMapping(self.B4, 1)
        self.mapperD.addMapping(self.C4, 2)
        self.mapperD.addMapping(self.D4, 3)
        self.mapperD.addMapping(self.E4, 4)
        self.mapperD.addMapping(self.F4, 5)
        self.mapperD.addMapping(self.G4, 6)
        self.mapperD.addMapping(self.H4, 7)
        self.mapperD.addMapping(self.I4, 8)

        self.mapperE = QDataWidgetMapper()
        self.mapperE.setModel(self.model)
        self.mapperE.setCurrentIndex(4)
        self.mapperE.addMapping(self.A5, 0)
        self.mapperE.addMapping(self.B5, 1)
        self.mapperE.addMapping(self.C5, 2)
        self.mapperE.addMapping(self.D5, 3)
        self.mapperE.addMapping(self.E5, 4)
        self.mapperE.addMapping(self.F5, 5)
        self.mapperE.addMapping(self.G5, 6)
        self.mapperE.addMapping(self.H5, 7)
        self.mapperE.addMapping(self.I5, 8)

        self.mapperF = QDataWidgetMapper()
        self.mapperF.setModel(self.model)
        self.mapperF.setCurrentIndex(5)
        self.mapperF.addMapping(self.A6, 0)
        self.mapperF.addMapping(self.B6, 1)
        self.mapperF.addMapping(self.C6, 2)
        self.mapperF.addMapping(self.D6, 3)
        self.mapperF.addMapping(self.E6, 4)
        self.mapperF.addMapping(self.F6, 5)
        self.mapperF.addMapping(self.G6, 6)
        self.mapperF.addMapping(self.H6, 7)
        self.mapperF.addMapping(self.I6, 8)

        self.mapperG = QDataWidgetMapper()
        self.mapperG.setModel(self.model)
        self.mapperG.setCurrentIndex(6)
        self.mapperG.addMapping(self.A7, 0)
        self.mapperG.addMapping(self.B7, 1)
        self.mapperG.addMapping(self.C7, 2)
        self.mapperG.addMapping(self.D7, 3)
        self.mapperG.addMapping(self.E7, 4)
        self.mapperG.addMapping(self.F7, 5)
        self.mapperG.addMapping(self.G7, 6)
        self.mapperG.addMapping(self.H7, 7)
        self.mapperG.addMapping(self.I7, 8)

        self.mapperH = QDataWidgetMapper()
        self.mapperH.setModel(self.model)
        self.mapperH.setCurrentIndex(7)
        self.mapperH.addMapping(self.A8, 0)
        self.mapperH.addMapping(self.B8, 1)
        self.mapperH.addMapping(self.C8, 2)
        self.mapperH.addMapping(self.D8, 3)
        self.mapperH.addMapping(self.E8, 4)
        self.mapperH.addMapping(self.F8, 5)
        self.mapperH.addMapping(self.G8, 6)
        self.mapperH.addMapping(self.H8, 7)
        self.mapperH.addMapping(self.I8, 8)

        self.mapperI = QDataWidgetMapper()
        self.mapperI.setModel(self.model)
        self.mapperI.setCurrentIndex(8)
        self.mapperI.addMapping(self.A9, 0)
        self.mapperI.addMapping(self.B9, 1)
        self.mapperI.addMapping(self.C9, 2)
        self.mapperI.addMapping(self.D9, 3)
        self.mapperI.addMapping(self.E9, 4)
        self.mapperI.addMapping(self.F9, 5)
        self.mapperI.addMapping(self.G9, 6)
        self.mapperI.addMapping(self.H9, 7)
        self.mapperI.addMapping(self.I9, 8)
        self.threadpool = QThreadPool()

        index1 = self.model.createIndex(0, 0)
        index2 = self.model.createIndex(8, 8)
        self.model.dataChanged.emit(index1, index2)

        self.view = QtWidgets.QTableView()
        self.view.setModel(self.model)

    def clear(self):
        self.model.clearData()

    def initLine(self):
        for child in self.findChildren(QtWidgets.QLineEdit):
            validator = NotEmptyValidator(child)
            child.setValidator(validator)

    def solve(self):
        self.start = time.time()

        # Do a easy solve
        solve = Solve(self.model._data)
        solve.signals.result.connect(self.result)
        solve.signals.finished.connect(self.finished)
        self.threadpool.start(solve)

        # If easy solved gave no solution, try to to guess one number and solve!
    def solve_2(self, dataframe):
        self.progressBar.show()
        solve2 = Solve2(dataframe)
        solve2.signals.result.connect(self.result2)
        solve2.signals.finished.connect(self.finished)
        solve2.signals.progress.connect(self.progress)
        self.threadpool.start(solve2)

    def progress(self, progress):
        self.progressBar.setValue(progress)

    def result(self, dataframe):
        print(dataframe)
        self.model._data = dataframe
        index1 = self.model.createIndex(0, 0)
        index2 = self.model.createIndex(8, 8)
        self.model.dataChanged.emit(index1, index2)

        if "" in dataframe.values:
            pass
            # If easy solved gave no solution, try to to guess one number and solve!
            # self.solve_2(dataframe)

    def result2(self, dataframe):
        self.model._data = dataframe
        index1 = self.model.createIndex(0, 0)
        index2 = self.model.createIndex(8, 8)
        self.model.dataChanged.emit(index1, index2)

        if "" in dataframe.values:
            self.progressBar.setTextVisible(True)
            self.progressBar.setFormat("Failed to solve current soduku")
            self.progressBar.setAlignment(Qt.AlignCenter)

    def finished(self):
        self.progressBar.setValue(100)
        self.progressBar.setFormat(
            f"Solved in {(time.time() - self.start):.2f} s ")
        self.progressBar.setAlignment(Qt.AlignCenter)

    def thread_complete(self):
        print("Done")

    def product_dict(self, inp):
        return (dict(zip(inp.keys(), values))
                for values in product(*inp.values()))
class Window(QWidget):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        # Set up the model.
        self.setupModel()

        # Set up the widgets.
        nameLabel = QLabel("Na&me:")
        nameEdit = QLineEdit()
        addressLabel = QLabel("&Address:")
        addressEdit = QTextEdit()
        typeLabel = QLabel("&Type:")
        typeComboBox = QComboBox()
        self.nextButton = QPushButton("&Next")
        self.previousButton = QPushButton("&Previous")
        nameLabel.setBuddy(nameEdit)
        addressLabel.setBuddy(addressEdit)
        typeLabel.setBuddy(typeComboBox)
        typeComboBox.setModel(self.typeModel)

        # Set up the mapper.
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setModel(self.model)
        self.mapper.addMapping(nameEdit, 0)
        self.mapper.addMapping(addressEdit, 1)
        self.mapper.addMapping(typeComboBox, 2, 'currentIndex')

        # Set up connections and layouts.
        self.previousButton.clicked.connect(self.mapper.toPrevious)
        self.nextButton.clicked.connect(self.mapper.toNext)
        self.mapper.currentIndexChanged.connect(self.updateButtons)

        layout = QGridLayout()
        layout.addWidget(nameLabel, 0, 0, 1, 1)
        layout.addWidget(nameEdit, 0, 1, 1, 1)
        layout.addWidget(self.previousButton, 0, 2, 1, 1)
        layout.addWidget(addressLabel, 1, 0, 1, 1)
        layout.addWidget(addressEdit, 1, 1, 2, 1)
        layout.addWidget(self.nextButton, 1, 2, 1, 1)
        layout.addWidget(typeLabel, 3, 0, 1, 1)
        layout.addWidget(typeComboBox, 3, 1, 1, 1)
        self.setLayout(layout)

        self.setWindowTitle("Delegate Widget Mapper")
        self.mapper.toFirst()
 
    def setupModel(self):
        items = ("Home", "Work", "Other")
        self.typeModel = QStringListModel(items, self)

        self.model = QStandardItemModel(5, 3, self)

        names = ("Alice", "Bob", "Carol", "Donald", "Emma")
        addresses = ("<qt>123 Main Street<br/>Market Town</qt>",
                     "<qt>PO Box 32<br/>Mail Handling Service"
                     "<br/>Service City</qt>",
                     "<qt>The Lighthouse<br/>Remote Island</qt>",
                     "<qt>47338 Park Avenue<br/>Big City</qt>",
                     "<qt>Research Station<br/>Base Camp<br/>Big Mountain</qt>")
        types = ("0", "1", "2", "0", "2")
        
        for row, name in enumerate(names):
            item = QStandardItem(name)
            self.model.setItem(row, 0, item)
            item = QStandardItem(addresses[row])
            self.model.setItem(row, 1, item)
            item = QStandardItem(types[row])
            self.model.setItem(row, 2, item)
 
    def updateButtons(self, row):
        self.previousButton.setEnabled(row > 0)
        self.nextButton.setEnabled(row < self.model.rowCount() - 1)
Exemple #22
0
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()
Exemple #23
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.SelectRows)
        self.ui.tableView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.ui.tableView.setAlternatingRowColors(True)
        self.ui.tableView.verticalHeader().setDefaultSectionSize(22)
        self.ui.tableView.horizontalHeader().setDefaultSectionSize(60)
##      self.ui.tableView.resizeColumnsToContents()

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

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

    def __openTable(self):  ##查询数据
        self.qryModel = QSqlQueryModel(self)
        self.qryModel.setQuery(
            '''SELECT empNo, Name, Gender,  Birthday,  Province,
                             Department, Salary FROM employee ORDER BY empNo'''
        )

        if self.qryModel.lastError().isValid():
            QMessageBox.critical(
                self, "错误",
                "数据表查询错误,错误信息\n" + self.qryModel.lastError().text())
            return

        self.ui.statusBar.showMessage("记录条数:%d" % self.qryModel.rowCount())
        self.__getFieldNames()  #获取字段名和序号

        ##设置字段显示名,直接使用序号
        self.qryModel.setHeaderData(0, Qt.Horizontal, "工号")
        self.qryModel.setHeaderData(1, Qt.Horizontal, "姓名")
        self.qryModel.setHeaderData(2, Qt.Horizontal, "性别")
        self.qryModel.setHeaderData(3, Qt.Horizontal, "出生日期")
        self.qryModel.setHeaderData(4, Qt.Horizontal, "省份")
        self.qryModel.setHeaderData(5, Qt.Horizontal, "部门")
        self.qryModel.setHeaderData(6, Qt.Horizontal, "工资")

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

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

        ##界面组件与qryModel的具体字段之间的联系
        ##      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.dbSpinEmpNo, 0)
        self.mapper.addMapping(self.ui.dbEditName, 1)
        self.mapper.addMapping(self.ui.dbComboSex, 2)
        self.mapper.addMapping(self.ui.dbEditBirth, 3)
        self.mapper.addMapping(self.ui.dbComboProvince, 4)
        self.mapper.addMapping(self.ui.dbComboDep, 5)
        self.mapper.addMapping(self.ui.dbSpinSalary, 6)
        self.mapper.toFirst()  #移动到首记录

        self.selModel = QItemSelectionModel(self.qryModel)  #关联选择模型
        self.selModel.currentRowChanged.connect(
            self.do_currentRowChanged)  #选择行变化时

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

        self.ui.actOpenDB.setEnabled(False)

    def __refreshTableView(self):  ##刷新tableView显示
        index = self.mapper.currentIndex()
        curIndex = self.qryModel.index(index, 1)  #QModelIndex
        self.selModel.clearSelection()  #清空选择项
        self.selModel.setCurrentIndex(curIndex, QItemSelectionModel.Select)

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

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

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

    @pyqtSlot()  ##首记录
    def on_actRecFirst_triggered(self):
        self.mapper.toFirst()
        self.__refreshTableView()

    @pyqtSlot()  ##前一记录
    def on_actRecPrevious_triggered(self):
        self.mapper.toPrevious()
        self.__refreshTableView()

    @pyqtSlot()  ##后一条记录
    def on_actRecNext_triggered(self):
        self.mapper.toNext()
        self.__refreshTableView()

    @pyqtSlot()  ##最后一条记录
    def on_actRecLast_triggered(self):
        self.mapper.toLast()
        self.__refreshTableView()

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

    def do_currentRowChanged(self, current, previous):  ##记录移动时触发
        if (current.isValid() == False):
            self.ui.dbLabPhoto.clear()  #清除图片显示
            return

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

        first = (current.row() == 0)  #是否首记录
        last = (current.row() == self.qryModel.rowCount() - 1)  #是否尾记录
        self.ui.actRecFirst.setEnabled(not first)  #更新使能状态
        self.ui.actRecPrevious.setEnabled(not first)
        self.ui.actRecNext.setEnabled(not last)
        self.ui.actRecLast.setEnabled(not last)

        curRec = self.qryModel.record(current.row())  #获取当前记录,QSqlRecord类型
        empNo = curRec.value("EmpNo")  #不需要加 toInt()函数

        query = QSqlQuery(self.DB)
        query.prepare(
            '''SELECT EmpNo, Memo, Photo FROM employee WHERE EmpNo = :ID''')
        query.bindValue(":ID", empNo)
        ##      if not query.exec_():  #注意,在PyQt5.11.2之前的版本里只能使用exec_()函数
        if not query.exec(
        ):  #注意,在PyQt5.11.2添加了遗漏的overload型exec()函数,在PyQt5.11.2里没问题了
            QMessageBox.critical(self, "错误",
                                 "执行SQL语句错误\n" + query.lastError().text())
            return
        else:
            query.first()

        picData = query.value("Photo")
        if (picData == None):  #图片字段内容为空
            self.ui.dbLabPhoto.clear()
        else:  #显示照片
            pic = QPixmap()
            pic.loadFromData(picData)
            W = self.ui.dbLabPhoto.size().width()
            self.ui.dbLabPhoto.setPixmap(pic.scaledToWidth(W))

        memoData = query.value("Memo")  #显示备注
        self.ui.dbEditMemo.setPlainText(memoData)
Exemple #24
0
class MyMainWindow(VCPMainWindow):
    """Main window class for the VCP."""
    def __init__(self, *args, **kwargs):
        super(MyMainWindow, self).__init__(*args, **kwargs)

        self.threadFormFwdBtn.clicked.connect(self.threadFormFwd)
        self.threadFormBackBtn.clicked.connect(self.threadFormBack)
        self.threadClassFwdBtn.clicked.connect(self.threadClassFwd)
        self.threadClassBackBtn.clicked.connect(self.threadClassBack)
        self.threadSizeFwdBtn.clicked.connect(self.threadSizeFwd)
        self.threadSizeBackBtn.clicked.connect(self.threadSizeBack)
        self.sptmSizeFwdBtn.clicked.connect(self.sptmSizeFwd)
        self.sptmSizeBackBtn.clicked.connect(self.sptmSizeBack)
        self.drillSizeFwdBtn.clicked.connect(self.drillSizeFwd)
        self.drillSizeBackBtn.clicked.connect(self.drillSizeBack)
        self.numPassesSP.valueChanged.connect(self.numPassesCalc)
        self.holeDiaSb.valueChanged.connect(self.holeDiaCalc)
        self.linearFeedSb.valueChanged.connect(self.linearFeedCalc)
        self.genGcodeBtn.clicked.connect(self.genGcode)
        self.threadCountSb.valueChanged.connect(self.threadHeightCalc)


        self.testFwdBtn.clicked.connect(self.testFwd)
        self.testBackBtn.clicked.connect(self.testBack)
        self.saveFilePb.clicked.connect(self.saveFile)


        if not self.open_db():
            print('Failed to Open Database')

        self.sptmSizeInit()
        self.threadFormInit()
        self.numPassesCalc()

    def open_db(self):
        db = QSqlDatabase.addDatabase('QSQLITE')
        db.setDatabaseName(current_path + 'threads.db')
        db.open()
        return db

    def threadFormInit(self):
        self.formMapper = QDataWidgetMapper(self)
        self.formModel = QSqlQueryModel(self)
        self.formModel.setQuery('SELECT DISTINCT form FROM internal_threads')
        self.formMapper.setModel(self.formModel)
        self.formMapper.addMapping(self.threadFormLbl, 0, b'text')
        self.formMapper.toLast()
        self.formsLast = self.formMapper.currentIndex()
        self.formMapper.toFirst()
        self.threadClassInit()

    def threadFormFwd(self):
        if self.formMapper.currentIndex() != self.formsLast:
            self.formMapper.toNext()
        else:
            self.formMapper.toFirst()
        self.threadClassInit()

    def threadFormBack(self):
        if self.formMapper.currentIndex() != 0:
            self.formMapper.toPrevious()
        else:
            self.formMapper.toLast()
        self.threadClassInit()

    def threadClassInit(self):
        self.classMapper = QDataWidgetMapper(self)
        self.classModel = QSqlQueryModel(self)
        form = self.threadFormLbl.text()
        classSelect = "SELECT DISTINCT class FROM internal_threads \
            WHERE form = '{}'".format(form)
        self.classModel.setQuery(classSelect)
        self.classMapper.setModel(self.classModel)
        self.classMapper.addMapping(self.threadClassLbl, 0, b'text')
        self.classMapper.toLast()
        self.classLast = self.classMapper.currentIndex()
        self.classMapper.toFirst()
        self.threadSizeInit()

    def threadClassFwd(self):
        if self.classMapper.currentIndex() != self.classLast:
            self.classMapper.toNext()
        else:
            self.classMapper.toFirst()
        self.threadSizeInit(self.sizeMapper.currentIndex())

    def threadClassBack(self):
        if self.classMapper.currentIndex() != 0:
            self.classMapper.toPrevious()
        else:
            self.classMapper.toLast()
        self.threadSizeInit(self.sizeMapper.currentIndex())

    def threadSizeInit(self, index = 0):
        self.sizeMapper = QDataWidgetMapper(self)
        self.sizeModel = QSqlQueryModel(self)
        form = self.threadFormLbl.text()
        threadClass = self.threadClassLbl.text()
        sizeSelect = "SELECT size, pitch, major_dia, \
            min_major_dia, max_minor_dia, min_minor_dia, \
            max_pitch_dia, min_pitch_dia FROM internal_threads WHERE form \
            = '{}' AND class = '{}'".format(form, threadClass)
        self.sizeModel.setQuery(sizeSelect)
        self.sizeMapper.setModel(self.sizeModel)
        self.sizeMapper.addMapping(self.threadSizeLbl, 0, b'text')
        self.sizeMapper.addMapping(self.threadTPILbl, 1, b'text')
        self.sizeMapper.addMapping(self.threadMajorDiaLbl, 2, b'text')
        self.sizeMapper.addMapping(self.minMajorDiaLbl, 3, b'text')
        self.sizeMapper.addMapping(self.maxMinorDiaLbl, 4, b'text')
        self.sizeMapper.addMapping(self.minMinorDiaLbl, 5, b'text')
        self.sizeMapper.addMapping(self.maxPitchDiaLbl, 6, b'text')
        self.sizeMapper.addMapping(self.minPitchDiaLbl, 7, b'text')
        self.sizeMapper.toLast()
        self.sizeLast = self.sizeMapper.currentIndex()
        self.sizeMapper.setCurrentIndex(index)
        self.drillSizeInit()
        self.threadSizeCalc()
        self.numPassesCalc()
        self.threadHeightCalc()

    def threadSizeFwd(self):
        if self.sizeMapper.currentIndex() != self.sizeLast:
            self.sizeMapper.toNext()
        else:
            self.sizeMapper.toFirst()
        self.drillSizeInit()
        self.threadSizeCalc()
        self.numPassesCalc()
        self.threadHeightCalc()

    def threadSizeBack(self):
        if self.sizeMapper.currentIndex() != 0:
            self.sizeMapper.toPrevious()
        else:
            self.sizeMapper.toLast()
        self.drillSizeInit()
        self.threadSizeCalc()
        self.numPassesCalc()
        self.threadHeightCalc()

    def threadSizeCalc(self):
        # PDO calculations
        threadMajorDia = float(self.threadMajorDiaLbl.text())
        drillDia = float(self.holeDiaSb.value())
        standardPDO = threadMajorDia - drillDia
        self.sptmThreadingPDOLbl.setText('{:.04f}'.format(standardPDO))
        # Actual thread height = 1/2 PDO
        threadHeightStandard = standardPDO / 2
        self.threadHeightStdLbl.setText('{:.04f}'.format(threadHeightStandard))
        threadTrangleHeight = threadHeightStandard / 0.625
        self.threadTriangleHeightLbl.setText('{:.04f}'.format(threadTrangleHeight))
        threadPushOutAdj = threadTrangleHeight * 0.125
        self.threadPushOutAdjLbl.setText('{:.04f}'.format(threadPushOutAdj))
        threadPDOAdjustOut = threadPushOutAdj * 2
        self.threadPDOAdjustOutLbl.setText('{:.04f}'.format(threadPDOAdjustOut))
        # -2*(Crest*(SQRT(3)/2))
        sptmCrest = float(self.sptmCrestLbl.text())
        threadPDOCrestAdj = -2 * (sptmCrest * (sqrt(3)/2))
        self.threadPDOCrestAdjLbl.setText('{:.04f}'.format(threadPDOCrestAdj))
        finalPDO = standardPDO + threadPDOAdjustOut + threadPDOCrestAdj
        self.threadFinalPDOLbl.setText('{:.04f}'.format(finalPDO))
        # if final PDO is greater than tip height check
        if self.sptmTipHeight > finalPDO:
            self.sptmTipOkLbl.setText('OK')
        else:
            self.sptmTipOkLbl.setText('Tip Too Small')
        # set maximum number of threads
        threadTPI = float(self.threadTPILbl.text())
        threadPitch = 1.0 / threadTPI
        maxDepth = float(self.sptmMaxDepthLbl.text())
        maxThreads = int(maxDepth / threadPitch)

    def sptmSizeInit(self):
        self.sptmMapper = QDataWidgetMapper(self)
        self.sptmModel = QSqlQueryModel(self)
        self.sptmModel.setQuery('SELECT * FROM sptm')
        self.sptmMapper.setModel(self.sptmModel)
        self.sptmMapper.addMapping(self.sptmSizeLbl, 0, b'text')
        self.sptmMapper.addMapping(self.sptmDiaLbl, 1, b'text')
        self.sptmMapper.addMapping(self.sptmCrestLbl, 2, b'text')
        self.sptmMapper.addMapping(self.sptmMaxDepthLbl, 3, b'text')
        self.sptmMapper.addMapping(self.sptmFlutesLbl, 4, b'text')
        self.sptmMapper.addMapping(self.sptmNeckDiaLbl, 5, b'text')
        self.sptmMapper.toLast()
        self.sptmLast = self.sptmMapper.currentIndex()
        self.sptmMapper.toFirst()

    def sptmSizeFwd(self):
        if self.sptmMapper.currentIndex() != self.sptmLast:
            self.sptmMapper.toNext()
        else:
            self.sptmMapper.toFirst()
        self.sptmCalc()

    def sptmSizeBack(self):
        if self.sptmMapper.currentIndex() != 0:
            self.sptmMapper.toPrevious()
        else:
            self.sptmMapper.toLast()
        self.sptmCalc()

    def sptmCalc(self):
        drillDiameter = float(self.holeDiaSb.value())
        sptmCutterDia = float(self.sptmDiaLbl.text())
        if sptmCutterDia < drillDiameter:
            self.sptmDiaOkLbl.setText('Ok')
        else:
            self.sptmDiaOkLbl.setText('TOO BIG!')
        sptmNeckDia = float(self.sptmNeckDiaLbl.text())
        self.sptmTipHeight = sptmCutterDia - sptmNeckDia
        self.sptmTipHeightLbl.setText('{:.4f}'.format(self.sptmTipHeight))

    def drillSizeInit(self):
        self.drillMapper = QDataWidgetMapper(self)
        self.drillQueryModel = QSqlQueryModel(self)
        minMinorDia = str(self.minMinorDiaLbl.text())
        maxMinorDia = str(self.maxMinorDiaLbl.text())
        drillSelect = "SELECT * FROM drills WHERE dia >= '{}' \
            AND dia <= '{}'".format(minMinorDia, maxMinorDia)
        self.drillQueryModel.setQuery(drillSelect)
        self.drillMapper.setModel(self.drillQueryModel)
        self.drillMapper.addMapping(self.drillTypeLbl, 0, b'text')
        self.drillMapper.addMapping(self.drillSizeLbl, 1, b'text')
        self.drillMapper.addMapping(self.drillDiaLbl, 2, b'text')
        self.drillMapper.toLast()
        self.drillLast = self.drillMapper.currentIndex()
        self.drillMapper.toFirst()
        # setup hole dia spinbox
        self.holeDiaSb.setMinimum(float(self.minMinorDiaLbl.text()))
        self.holeDiaSb.setMaximum(float(self.maxMinorDiaLbl.text()))
        # setup pitch dia spinbox
        self.pitchDiaSb.setMinimum(float(self.minPitchDiaLbl.text()))
        self.pitchDiaSb.setMaximum(float(self.maxPitchDiaLbl.text()))

        self.sptmCalc()
        self.threadPercent()

    def drillSizeFwd(self):
        if self.drillMapper.currentIndex() != self.drillLast:
            self.drillMapper.toNext()
        else:
            self.drillMapper.toFirst()
        self.sptmCalc()
        self.threadPercent()
        self.threadSizeCalc()

    def drillSizeBack(self):
        if self.drillMapper.currentIndex() != 0:
            self.drillMapper.toPrevious()
        else:
            self.drillMapper.toLast()
        self.sptmCalc()
        self.threadPercent()
        self.threadSizeCalc()

    def threadPercent(self):
        majorDia = float(self.threadMajorDiaLbl.text())
        minorDia = float(self.drillDiaLbl.text())
        # note for metric convert to TPI
        threadPitch = float(self.threadTPILbl.text())
        threadEngagement = ((majorDia - minorDia) * threadPitch) / 0.01299
        self.threadPercentLbl.setText('{:.0f}%'.format(threadEngagement))

    def threadHeightCalc(self):
        pitch = 1.0 / float(self.threadTPILbl.text())
        height = self.threadCountSb.value() * pitch
        self.threadsHeight.setText('{:.4f}"'.format(height))

    def numPassesCalc(self):
        majorDia = float(self.threadMajorDiaLbl.text())
        minorDia = float(self.holeDiaSb.value())
        threadDepth = (majorDia - minorDia)
        if self.numPassesSP.value() == 1:
            self.passDiaLbl_0.setText('{:.4f}'.format(majorDia))
            self.passDiaLbl_1.setText('')
            self.passDiaLbl_2.setText('')
            self.passDiaLbl_3.setText('')

            self.passPercentLbl_1.setText('100%')
            self.passPercentLbl_2.setText('')
            self.passPercentLbl_3.setText('')
            self.passPercentLbl_4.setText('')

        if self.numPassesSP.value() == 2:

            self.passDiaLbl_0.setText('{:.4f}'.format(minorDia \
                + (threadDepth * 0.65)))
            self.passDiaLbl_1.setText('{:.4f}'.format(majorDia))
            self.passDiaLbl_2.setText('')
            self.passDiaLbl_3.setText('')

            self.passPercentLbl_1.setText('65%')
            self.passPercentLbl_2.setText('35%')
            self.passPercentLbl_3.setText('')
            self.passPercentLbl_4.setText('')

        if self.numPassesSP.value() == 3:
            self.passDiaLbl_0.setText('{:.4f}'.format(minorDia \
                + (threadDepth * 0.50)))
            self.passDiaLbl_1.setText('{:.4f}'.format(minorDia \
                + (threadDepth * 0.80)))
            self.passDiaLbl_2.setText('{:.4f}'.format(majorDia))
            self.passDiaLbl_3.setText('')

            self.passPercentLbl_1.setText('50%')
            self.passPercentLbl_2.setText('30%')
            self.passPercentLbl_3.setText('20%')
            self.passPercentLbl_4.setText('')

        if self.numPassesSP.value() == 4:
            self.passDiaLbl_0.setText('{:.4f}'.format(minorDia \
                + (threadDepth * 0.40)))
            self.passDiaLbl_1.setText('{:.4f}'.format(minorDia \
                + (threadDepth * 0.67)))
            self.passDiaLbl_2.setText('{:.4f}'.format(minorDia \
                + (threadDepth * 0.87)))
            self.passDiaLbl_3.setText('{:.4f}'.format(majorDia))

            self.passPercentLbl_1.setText('40%')
            self.passPercentLbl_2.setText('27%')
            self.passPercentLbl_3.setText('20%')
            self.passPercentLbl_4.setText('13%')

    def holeDiaCalc(self):
        majorDia = float(self.threadMajorDiaLbl.text())
        minorDia = self.holeDiaSb.value()
        # note for metric convert to TPI
        threadPitch = float(self.threadTPILbl.text())
        threadEngagement = ((majorDia - minorDia) * threadPitch) / 0.01299
        self.threadPerLbl.setText('{:.1f}%'.format(threadEngagement))


    def genGcode(self):
        # make sure your using the hole size as the starting point
        self.gcodeText.setPlainText("; JT's Thread Mill Wizard")
        self.gcodeText.append('; Thread {}'.format(self.threadSizeLbl.text()))
        self.gcodeText.append('F25')
        xCoord = self.xCoord.text()
        yCoord = self.yCoord.text()
        self.gcodeText.append('G0 X{} Y{} Z0.125'.format(xCoord, yCoord))
        zStart = self.zStart.text()
        pitch = 1.0 / float(self.threadTPILbl.text())
        threadsHeight = (self.threadCountSb.value() + 1) * pitch
        zEnd = float(zStart) + threadsHeight
        self.gcodeText.append('G1 Z{}'.format(zEnd))
        self.gcodeText.append('G91')
        self.gcodeText.append('; Number of thread passes {}' \
            .format(self.numPassesSP.value()))
        for i in range(self.numPassesSP.value()):
            passDiameter = float(getattr(self, 'passDiaLbl_' + str(i)).text())
            # go to hole bottom
            threadTPI = float(self.threadTPILbl.text())
            threadPitch = 1.0 / threadTPI
            self.gcodeText.append('G0 Z-{}'.format(threadsHeight))
            # go to start of lead in arc
            cutterClearance = 0.020
            minorDia = float(self.holeDiaSb.value())
            toolDia = float(self.sptmDiaLbl.text())
            yStartLeadIn = -((minorDia - (cutterClearance * 2)) - toolDia) / 2
            self.gcodeText.append('G1 Y{:.4f}'.format(yStartLeadIn))
            # lead in arc
            sptmCutterDia = float(self.sptmDiaLbl.text())
            leadInYEnd = ((passDiameter - sptmCutterDia) / 2) + abs(yStartLeadIn)
            leadInZEnd = threadPitch / 2
            leadInJOffset = leadInYEnd / 2
            self.gcodeText.append('G3 X0.0 Y{:.4f} Z{:.4f} J{:.4f}' \
                .format(leadInYEnd, leadInZEnd, leadInJOffset))
            # spiral up
            threadCount = int(self.threadCountSb.text())
            finalZ = threadPitch * threadCount
            jOffset = -(passDiameter - sptmCutterDia) / 2
            self.gcodeText.append('G3 J{} Z{} P{}'. \
                format(jOffset, finalZ, threadCount))
            # lead out arc
            leadOutYEnd = -((passDiameter - sptmCutterDia) / 2) - abs(yStartLeadIn)
            leadOutZEnd = threadPitch / 2
            leadOutJOffset = -(leadInYEnd / 2)
            self.gcodeText.append('G3 X0.0 Y{:.4f} Z{:.4f} J{:.4f}' \
                .format(leadOutYEnd, leadOutZEnd, leadOutJOffset))
            # go to center
            yCenter = ((minorDia - (cutterClearance * 2)) - toolDia) / 2
            self.gcodeText.append('G1 Y{:.4f}'.format(yCenter))

        self.gcodeText.append('G90')
        #self.gcodeText.append('G0 X2 Y2')
        self.gcodeText.append('M2')

    def linearFeedCalc(self):
        # Internal Threads
        # Linear feed * ((Major thread dia - Tool dia) / Major thread dia)
        minorDia = float(self.holeDiaSb.value())
        majorDia = float(self.threadMajorDiaLbl.text())
        cutterDia = float(self.sptmDiaLbl.text())
        linearFeed = self.linearFeedSb.value()
        circularFeed = ((majorDia - cutterDia) / majorDia) * linearFeed
        self.circularFeedLbl.setText('{:.1f}'.format(circularFeed))

    def testFwd(self):
        self.gcodeText.append('line du')

    def testBack(self):
        pass

    def saveFile(self):
        ngcFile = os.path.join(os.getenv("HOME"), 'linuxcnc/nc_files', 'jt.ngc')
        with open(ngcFile, 'w') as f:
           f.write(str(self.gcodeText.toPlainText()))

    """ 
Exemple #25
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)
class ArmorEditor(ArmorEditorWidgetBase, ArmorEditorWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        self.model = None
        self.parts_tree_model = ArmorSetTreeModel()
        self.skill_model = SkillTranslationModel()
        self.armor_item_mapper = QDataWidgetMapper(self)
        self.armor_item_mapper.setItemDelegate(ItemDelegate())
        self.armor_item_mapper.setModel(self.parts_tree_model)
        self.parts_tree_view.setModel(self.parts_tree_model)
        self.parts_tree_view.activated.connect(
            self.handle_parts_tree_activated)
        self.import_export_manager = ImportExportManager(self.parts_tree_view)
        self.import_export_manager.connect_custom_context_menu()
        for it in ("set_skill1_value", "set_skill2_value", "skill1_value",
                   "skill2_value", "skill3_value"):
            getattr(self, it).setModel(self.skill_model)
        mappings = [
            (self.id_value, Column.id, b"text"),
            (self.name_value, Column.gmd_name_index, b"text"),
            (self.description_value, Column.gmd_desc_index, b"text"),
            (self.setid_value, Column.set_id),
            (self.set_group_value, Column.set_group),
            (self.type_value, Column.type, b"currentIndex"),
            (self.order_value, Column.order),
            (self.variant_value, Column.variant, b"currentIndex"),
            (self.equip_slot_value, Column.equip_slot, b"currentIndex"),
            (self.gender_value, Column.gender, b"currentIndex"),
            (self.mdl_main_id_value, Column.mdl_main_id),
            (self.mdl_secondary_id_value, Column.mdl_secondary_id),
            (self.icon_color_value, Column.icon_color),
            (self.defense_value, Column.defense),
            (self.rarity_value, Column.rarity),
            (self.cost_value, Column.cost),
            (self.fire_res_value, Column.fire_res),
            (self.water_res_value, Column.water_res),
            (self.thunder_res_value, Column.thunder_res),
            (self.ice_res_value, Column.ice_res),
            (self.dragon_res_value, Column.dragon_res),
            (self.set_skill1_value, Column.set_skill1),
            (self.set_skill1_lvl_value, Column.set_skill1_lvl),
            (self.set_skill2_value, Column.set_skill2),
            (self.set_skill2_lvl_value, Column.set_skill2_lvl),
            (self.skill1_value, Column.skill1),
            (self.skill1_lvl_value, Column.skill1_lvl),
            (self.skill2_value, Column.skill2),
            (self.skill2_lvl_value, Column.skill2_lvl),
            (self.skill3_value, Column.skill3),
            (self.skill3_lvl_value, Column.skill3_lvl),
            (self.num_gem_slots, Column.num_gem_slots),
            (self.gem_slot1_lvl_value, Column.gem_slot1_lvl),
            (self.gem_slot2_lvl_value, Column.gem_slot2_lvl),
            (self.gem_slot3_lvl_value, Column.gem_slot3_lvl),
        ]
        for mapping in mappings:
            self.armor_item_mapper.addMapping(*mapping)

    def handle_parts_tree_activated(self, qindex: QModelIndex):
        if isinstance(qindex.internalPointer(), ArmorSetNode):
            return
        self.armor_item_mapper.setRootIndex(qindex.parent())
        self.armor_item_mapper.setCurrentModelIndex(qindex)
        entry = qindex.internalPointer().ref
        self.crafting_requirements_editor.set_current(entry.id)

    def set_model(self, model):
        self.model = model
        if self.model is None:
            self.parts_tree_model = None
            self.parts_tree_view.setModel(None)
            return

        self.skill_model.update(model.get_relation_data("t9n_skill_pt"))
        self.crafting_requirements_editor.set_model(model, None)
        self.parts_tree_model.update(model)
        self.configure_tree_view()

    def configure_tree_view(self):
        header = self.parts_tree_view.header()
        header.setSectionResizeMode(0, QHeaderView.Stretch)
        header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        header.setStretchLastSection(False)
        for i in range(2, self.parts_tree_model.columnCount(None)):
            header.hideSection(i)
spin_box.setMinimum(-10000)
spin_box.setMaximum(10000)
line_edit = QLineEdit()

vbox = QVBoxLayout()

vbox.addWidget(table_view)
vbox.addWidget(spin_box)
vbox.addWidget(line_edit)

window.setLayout(vbox)

###

mapper = QDataWidgetMapper()        # <--
mapper.setModel(my_model)           # <--
mapper.addMapping(spin_box, 0)      # <--
mapper.addMapping(line_edit, 1)     # <--
mapper.toFirst()                    # <--

def update_selection(selected, deselected):                 # <--
    index = table_view.selectionModel().currentIndex()      # <--
    mapper.setCurrentIndex(index.row())                     # <--
    print("Index: ", index.row())

table_view.selectionModel().selectionChanged.connect(update_selection)   # <--

###

window.show()
Exemple #28
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)
Exemple #29
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)
class MainWindow(QMainWindow):

    def __init__(self, data):
        super().__init__()

        self.resize(400, 600)
        self.setWindowTitle('Logger Skeleton')
        self.statusBar().showMessage("Ready", 2000)

        # Make widgets ####################################

        self.tabs = QTabWidget(self)
        self.setCentralWidget(self.tabs)

        # Add tabs
        self.table_tab = QWidget(self)
        self.stats_tab = QWidget(self)

        self.tabs.addTab(self.table_tab, "Table")
        self.tabs.addTab(self.stats_tab, "Stats")

        # Table tab ###########################################################

        self.table_view = QTableView(self.table_tab)
        self.text_edit = QPlainTextEdit()
        self.btn_add_row = QPushButton("Add a row")
        #self.btn_remove_row = QPushButton("Remove selected rows")

        table_tab_vbox = QVBoxLayout()

        table_tab_vbox.addWidget(self.table_view)
        table_tab_vbox.addWidget(self.text_edit)
        table_tab_vbox.addWidget(self.btn_add_row)
        #table_tab_vbox.addWidget(self.btn_remove_row)

        self.table_tab.setLayout(table_tab_vbox)

        # Set model #######################################

        my_model = DataQtModel(data, parent=self)  # TODO: right use of "parent" ?

        # Proxy model #####################################

        proxy_model = QSortFilterProxyModel(parent=self)  # TODO: right use of "parent" ?
        proxy_model.setSourceModel(my_model)

        self.table_view.setModel(proxy_model)
        #self.table_view.setModel(my_model)

        # Set the view ####################################

        self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows)    # Select the full row when a cell is selected (See http://doc.qt.io/qt-5/qabstractitemview.html#selectionBehavior-prop )
        #self.table_view.setSelectionMode(QAbstractItemView.SingleSelection)  # Set selection mode. See http://doc.qt.io/qt-5/qabstractitemview.html#selectionMode-prop

        self.table_view.setAlternatingRowColors(True)
        self.table_view.setSortingEnabled(True)
        self.table_view.setColumnWidth(0, 200)                       # TODO: automatically get the best width

        self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)    # https://stackoverflow.com/q/17535563

        self.table_view.setColumnHidden(COMMENT_COLUMN_INDEX, True)

        delegate = Delegate()
        self.table_view.setItemDelegate(delegate)

        # Set key shortcut ################################

        # see https://stackoverflow.com/a/17631703  and  http://doc.qt.io/qt-5/qaction.html#details

        # Add row action

        add_action = QAction(self.table_view)
        add_action.setShortcut(Qt.CTRL | Qt.Key_N)

        add_action.triggered.connect(self.add_row_btn_callback)
        self.table_view.addAction(add_action)

        # Delete action

        del_action = QAction(self.table_view)
        del_action.setShortcut(Qt.Key_Delete)

        del_action.triggered.connect(self.remove_row_callback)
        self.table_view.addAction(del_action)

        # Set QDataWidgetMapper ###########################

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(proxy_model)          # WARNING: do not use `my_model` here otherwise the index mapping will be wrong!
        self.mapper.addMapping(self.text_edit, COMMENT_COLUMN_INDEX)
        self.mapper.toFirst()                      # TODO: is it a good idea ?

        self.table_view.selectionModel().selectionChanged.connect(self.update_selection)

        # Set slots #######################################

        self.btn_add_row.clicked.connect(self.add_row_btn_callback)
        #self.btn_remove_row.clicked.connect(self.remove_row_callback)

        #self.table_view.setColumnHidden(1, True)

        # Stats tab ###########################################################

        # See https://matplotlib.org/examples/user_interfaces/embedding_in_qt5.html

        stats_tab_layout = QVBoxLayout(self.stats_tab)
        self.plot_canvas = PlotCanvas(data, self.stats_tab, width=5, height=4, dpi=100)
        stats_tab_layout.addWidget(self.plot_canvas)

        ###################################################

        #proxy_model.dataChanged.connect(plot_canvas.update_figure)
        #proxy_model.rowsInserted.connect(plot_canvas.update_figure)  # TODO
        #proxy_model.rowsRemoved.connect(plot_canvas.update_figure)   # TODO

        self.tabs.currentChanged.connect(self.updatePlot)  # Update the stats plot when the tabs switch to the stats tab

        # Show ############################################

        self.show()


    def update_selection(self, selected, deselected):
        index = self.table_view.selectionModel().currentIndex()
        self.mapper.setCurrentIndex(index.row())
        print("Index: ", index.row())


    def updatePlot(self, index):
        """

        Parameters
        ----------
        index

        Returns
        -------

        """
        if index == self.tabs.indexOf(self.stats_tab):
            self.plot_canvas.update_figure()


    def add_row_btn_callback(self):
        parent = QModelIndex()                                   # More useful with e.g. tree structures

        #row_index = 0                                           # Insert new rows to the begining
        row_index = self.table_view.model().rowCount(parent)     # Insert new rows to the end

        self.table_view.model().insertRows(row_index, 1, parent)

    def remove_row_callback(self):
        parent = QModelIndex()                                   # More useful with e.g. tree structures

        # See http://doc.qt.io/qt-5/model-view-programming.html#handling-selections-in-item-views
        #current_index = self.table_view.selectionModel().currentIndex()
        #print("Current index:", current_index.row(), current_index.column())

        selection_index_list = self.table_view.selectionModel().selectedRows()
        selected_row_list = [selection_index.row() for selection_index in selection_index_list]

        print("Current selection:", selected_row_list)

        #row_index = 0                                           # Remove the first row
        #row_index = self.table_view.model().rowCount(parent) - 1 # Remove the last row

        # WARNING: the list of rows to remove MUST be sorted in reverse order
        # otherwise the index of rows to remove may change at each iteration of the for loop!

        # TODO: there should be a lock mechanism to avoid model modifications from external sources while iterating this loop...
        #       Or as a much simpler alternative, modify the ItemSelectionMode to forbid the non contiguous selection of rows and remove the following for loop
        for row_index in sorted(selected_row_list, reverse=True):
            # Remove rows one by one to allow the removql of non-contiguously selected rows (e.g. "rows 0, 2 and 3")
            success = self.table_view.model().removeRows(row_index, 1, parent)
            if not success:
                raise Exception("Unknown error...")   # TODO
class WpDatGEditor(WeaponGunEditorWidgetBase, WeaponGunEditorWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        self.model = None
        self.item_model = WpDatGTableModel(self)
        self.weapon_tree_view.setModel(self.item_model)
        self.shell_table_model = ShellTableModel()
        self.shell_table_view.setModel(self.shell_table_model)
        self.bottle_table_model = BottleTableModel(self)
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setItemDelegate(ItemDelegate())
        self.mapper.setModel(self.item_model)
        self.bottle_mapper = QDataWidgetMapper(self)
        self.bottle_mapper.setItemDelegate(ItemDelegate())
        self.bottle_mapper.setModel(self.bottle_table_model)
        self.weapon_tree_view.activated.connect(
            self.handle_weapon_tree_view_activated)
        self.skill_model = SkillTranslationModel()
        self.skill_id_value.setModel(self.skill_model)
        self.import_export_manager = ImportExportManager(
            self.weapon_tree_view,
            WpDatGPlugin.import_export.get("safe_attrs"))
        self.import_export_manager.connect_custom_context_menu()
        mappings = [
            (self.id_value, WpDatGEntry.id.index, b"text"),
            (self.name_value, WpDatGEntry.gmd_name_index.index, b"text"),
            (self.description_value, WpDatGEntry.gmd_description_index.index,
             b"text"),
            (self.order_value, WpDatGEntry.order.index),
            (self.tree_id_value, WpDatGEntry.tree_id.index),
            (self.tree_position_value, WpDatGEntry.tree_position.index),
            (self.is_fixed_upgrade_value, WpDatGEntry.is_fixed_upgrade.index,
             b"checked"),
            (self.base_model_id_value, WpDatGEntry.base_model_id.index),
            (self.part1_id_value, WpDatGEntry.part1_id.index),
            (self.part2_id_value, WpDatGEntry.part2_id.index),
            (self.color_value, WpDatGEntry.color.index),
            (self.muzzle_type_value, WpDatGEntry.muzzle_type.index,
             b"currentIndex"),
            (self.barrel_type_value, WpDatGEntry.barrel_type.index,
             b"currentIndex"),
            (self.magazine_type_value, WpDatGEntry.magazine_type.index,
             b"currentIndex"),
            (self.scope_type_value, WpDatGEntry.scope_type.index,
             b"currentIndex"),
            (self.rarity_value, WpDatGEntry.rarity.index),
            (self.cost_value, WpDatGEntry.crafting_cost.index),
            (self.raw_damage_value, WpDatGEntry.raw_damage.index),
            (self.affinity_value, WpDatGEntry.affinity.index),
            (self.defense_value, WpDatGEntry.defense.index),
            (self.deviation_value, WpDatGEntry.deviation.index,
             b"currentIndex"),
            (self.special_ammo_type_value, WpDatGEntry.special_ammo_type.index,
             b"currentIndex"),
            (self.element_id_value, WpDatGEntry.element_id.index,
             b"currentIndex"),
            (self.element_damage_value, WpDatGEntry.element_damage.index),
            (self.hidden_element_id_value, WpDatGEntry.hidden_element_id.index,
             b"currentIndex"),
            (self.hidden_element_damage_value,
             WpDatGEntry.hidden_element_damage.index),
            (self.elderseal_value, WpDatGEntry.elderseal.index,
             b"currentIndex"),
            (self.num_gem_slots, WpDatGEntry.num_gem_slots.index),
            (self.gem_slot1_lvl_value, WpDatGEntry.gem_slot1_lvl.index),
            (self.gem_slot2_lvl_value, WpDatGEntry.gem_slot2_lvl.index),
            (self.gem_slot3_lvl_value, WpDatGEntry.gem_slot3_lvl.index),
            (self.skill_id_value, WpDatGEntry.skill_id.index),
        ]
        for mapping in mappings:
            self.mapper.addMapping(*mapping)
        mappings = [
            (self.close_range_value, BbtblEntry.close_range.index,
             b"currentIndex"),
            (self.power_value, BbtblEntry.power.index, b"currentIndex"),
            (self.paralysis_value, BbtblEntry.paralysis.index,
             b"currentIndex"),
            (self.poison_value, BbtblEntry.poison.index, b"currentIndex"),
            (self.sleep_value, BbtblEntry.sleep.index, b"currentIndex"),
            (self.blast_value, BbtblEntry.blast.index, b"currentIndex"),
        ]
        for mapping in mappings:
            self.bottle_mapper.addMapping(*mapping)

    @property
    def is_bow_type(self):
        return self.model.attrs.get("equip_type") == WeaponType.Bow

    def handle_weapon_tree_view_activated(self, qindex: QModelIndex):
        self.mapper.setCurrentModelIndex(qindex)
        entry = self.item_model.entries[qindex.row()]
        self.tabs_weapon_details.setTabText(
            0, self.item_model.data(qindex, Qt.DisplayRole))
        self.crafting_requirements_editor.set_current(entry.id)
        if self.is_bow_type:
            index = self.bottle_table_model.index(entry.special_ammo_type, 0)
            self.bottle_mapper.setCurrentModelIndex(index)
        else:
            index = self.shell_table_model.index(entry.shell_table_id, 0,
                                                 QModelIndex())
            self.shell_table_view.setRootIndex(index)
            self.shell_table_view.expandAll()

    def set_model(self, model):
        self.model = model
        self.item_model.update(model)
        self.skill_model.update(model.get_relation_data("t9n_skill_pt"))
        self.crafting_requirements_editor\
            .set_model(model, model.attrs.get("equip_type"))
        if self.is_bow_type:
            self.bottle_table_model.update(model)
            self.hide_tab(self.tab_shell_table)
            self.special_ammo_type_value.deleteLater()
            self.special_ammo_type_label.deleteLater()
        else:
            self.shell_table_model.update(model)
            self.hide_tab(self.tab_bottle_table)
        self.configure_tree_view()

    def configure_tree_view(self):
        for index, col in enumerate(self.item_model.fields):
            self.weapon_tree_view.hideColumn(index)
        self.weapon_tree_view.showColumn(WpDatGEntry.id.index)
        self.weapon_tree_view.showColumn(WpDatGEntry.gmd_name_index.index)
        header = self.weapon_tree_view.header()
        header.setSectionResizeMode(WpDatGEntry.gmd_name_index.index,
                                    QHeaderView.Stretch)
        header.setSectionResizeMode(WpDatGEntry.id.index,
                                    QHeaderView.ResizeToContents)

    def hide_tab(self, widget):
        index = self.tabs_weapon_details.indexOf(widget)
        self.tabs_weapon_details.removeTab(index)
Exemple #32
0
class SettingsController(QObject, LogMixin):

    settingsClosed = pyqtSignal()    # send after model or backend data has been updated

    def __init__(self, parent):
        """
        Initiate settings editing

        Signals
        * settingsClosed

        :param parent: parent window of settings dialog
        :return:
        """
        super().__init__(parent)
        self._parent = parent
        print("controller/SettingsController parent: ", self._parent, " -> self: ", self) if oPB.PRINTHIER else None

        self.logger.debug("Initialize settings dialog")

        self.model = None              # data models
        self.datamapper = None             # QDataWidgetMapper object for field mapping
        self._modelDataChanged = False  # is connect via model_data_changed function to itemChanged Signal of QStandardItemModel, will be reset in close_project()

        # create main window and logic
        self.ui = SettingsDialog(self._parent)

        # build special button groups for False/True choice
        self.optionGroupSrvVersion = SpecialOptionButtonGroup(self.ui.rdOpsiSrvNew, self.ui.rdOpsiSrvOld,
                                                              [self.ui.rdSUDOWithPass, self.ui.rdSUDOWithoutPass],
                                                              [self.ui.inpRootPass])

        self.optionGroupSUDO = SpecialOptionButtonGroup(self.ui.rdSUDOWithPass, self.ui.rdSUDOWithoutPass)

        self.optionGroupEditorTyp = SpecialOptionButtonGroup(self.ui.rdEditorInternal, self.ui.rdEditorExternal,
                                                             [self.ui.chkSyntaxHighlight, self.ui.chkCodeFolding],
                                                             [self.ui.btnExternalEditor, self.ui.inpExternalEditor])

        self.optionGroupDepotFuncs = SpecialOptionButtonGroup(self.ui.chkUseDepotFunctions, None, [],
                                                              [self.ui.inpInstallCommand, self.ui.inpInstSetupCommand,
                                                               self.ui.inpUninstallCommand, self.ui.inpUploadCommand])

        self.optionGroupProxy = SpecialOptionButtonGroup(self.ui.chkUseProxy, None,
                                                         [self.ui.inpProxyServer, self.ui.inpProxyPort,
                                                          self.ui.inpProxyUser, self.ui.inpProxyPass], [])

        self.optionGroupSSHKeyFile = SpecialOptionButtonGroup(self.ui.chkUseKeyFile, None,
                                                              [self.ui.btnSetKeyFile, self.ui.inpKeyFile], [])

        self.optionGroupLogFile = SpecialOptionButtonGroup(self.ui.chkWriteLog, None,
                                                              [self.ui.btnLogFile, self.ui.inpLogFile, self.ui.cmbLogLevel], [])

        self.generate_model()
        self.connect_signals()

        # open modal dialog
        self.ui.tabWidget.setCurrentIndex(0)

    def generate_model(self):
        """Create data models and assign field mappings"""
        self.logger.debug("Generate configuration model")
        self.model = QtGui.QStandardItemModel(self.ui)
        self.model.setItem(0, 0, QtGui.QStandardItem(ConfigHandler.cfg.opsi_server))
        self.model.setItem(0, 1, QtGui.QStandardItem(ConfigHandler.cfg.opsi_user))
        self.model.setItem(0, 2, QtGui.QStandardItem(ConfigHandler.cfg.opsi_pass))
        self.model.setItem(0, 3, QtGui.QStandardItem(ConfigHandler.cfg.root_pass))
        self.model.setItem(0, 4, QtGui.QStandardItem(ConfigHandler.cfg.usenetdrive))
        self.model.setItem(0, 5, QtGui.QStandardItem(ConfigHandler.cfg.age))
        self.model.setItem(0, 6, QtGui.QStandardItem(ConfigHandler.cfg.sudo))
        self.model.setItem(0, 7, QtGui.QStandardItem(ConfigHandler.cfg.sshport))
        self.model.setItem(0, 8, QtGui.QStandardItem(ConfigHandler.cfg.usekeyfile))
        self.model.setItem(0, 9, QtGui.QStandardItem(ConfigHandler.cfg.keyfilename))
        self.model.setItem(0, 10, QtGui.QStandardItem(ConfigHandler.cfg.packagemaintainer))
        self.model.setItem(0, 11, QtGui.QStandardItem(ConfigHandler.cfg.mailaddress))
        self.model.setItem(0, 12, QtGui.QStandardItem(ConfigHandler.cfg.dev_dir))
        self.model.setItem(0, 13, QtGui.QStandardItem(ConfigHandler.cfg.buildcommand))
        self.model.setItem(0, 14, QtGui.QStandardItem(ConfigHandler.cfg.installcommand))
        self.model.setItem(0, 15, QtGui.QStandardItem(ConfigHandler.cfg.uninstallcommand))
        self.model.setItem(0, 16, QtGui.QStandardItem(ConfigHandler.cfg.showoutput))
        self.model.setItem(0, 17, QtGui.QStandardItem(ConfigHandler.cfg.reload_for_at))
        self.model.setItem(0, 18, QtGui.QStandardItem(ConfigHandler.cfg.wol_lead_time))
        self.model.setItem(0, 19, QtGui.QStandardItem(ConfigHandler.cfg.uploadcommand))
        self.model.setItem(0, 20, QtGui.QStandardItem(ConfigHandler.cfg.instsetupcommand))
        self.model.setItem(0, 21, QtGui.QStandardItem(ConfigHandler.cfg.use_depot_funcs))
        self.model.setItem(0, 22, QtGui.QStandardItem(ConfigHandler.cfg.use_extended_changelog))
        self.model.setItem(0, 23, QtGui.QStandardItem(ConfigHandler.cfg.scripteditor))
        self.model.setItem(0, 24, QtGui.QStandardItem(ConfigHandler.cfg.chlog_block_marker))
        self.model.setItem(0, 25, QtGui.QStandardItem(ConfigHandler.cfg.editor_intern))
        self.model.setItem(0, 26, QtGui.QStandardItem(ConfigHandler.cfg.editor_use_styling))
        self.model.setItem(0, 27, QtGui.QStandardItem(ConfigHandler.cfg.editor_use_folding))
        self.model.setItem(0, 28, QtGui.QStandardItem(ConfigHandler.cfg.chlog_on_build))
        self.model.setItem(0, 29, QtGui.QStandardItem(ConfigHandler.cfg.chlog_on_save))
        self.model.setItem(0, 30, QtGui.QStandardItem(ConfigHandler.cfg.no_error_msg))
        self.model.setItem(0, 31, QtGui.QStandardItem(ConfigHandler.cfg.no_warning_msg))
        self.model.setItem(0, 32, QtGui.QStandardItem(ConfigHandler.cfg.no_info_msg))
        self.model.setItem(0, 33, QtGui.QStandardItem(ConfigHandler.cfg.no_at_warning_msg))
        self.model.setItem(0, 34, QtGui.QStandardItem(ConfigHandler.cfg.language))
        self.model.setItem(0, 35, QtGui.QStandardItem(ConfigHandler.cfg.useproxy))
        self.model.setItem(0, 36, QtGui.QStandardItem(ConfigHandler.cfg.updatecheck))
        self.model.setItem(0, 37, QtGui.QStandardItem(ConfigHandler.cfg.proxy_server))
        self.model.setItem(0, 38, QtGui.QStandardItem(ConfigHandler.cfg.proxy_port))
        self.model.setItem(0, 39, QtGui.QStandardItem(ConfigHandler.cfg.proxy_user))
        self.model.setItem(0, 40, QtGui.QStandardItem(ConfigHandler.cfg.proxy_pass))
        self.model.setItem(0, 41, QtGui.QStandardItem(ConfigHandler.cfg.log_always))
        self.model.setItem(0, 42, QtGui.QStandardItem(ConfigHandler.cfg.log_file))
        self.model.setItem(0, 43, QtGui.QStandardItem(ConfigHandler.cfg.log_level))

        self.logger.debug("Create data widget mapper")
        self.datamapper = QDataWidgetMapper(self.ui)
        self.datamapper.setModel(self.model)
        self.datamapper.addMapping(self.ui.inpConfigServer, 0)
        self.datamapper.addMapping(self.ui.inpOpsiUser, 1)
        self.datamapper.addMapping(self.ui.inpOpsiPass, 2)
        self.datamapper.addMapping(self.ui.inpRootPass, 3)
        self.datamapper.addMapping(self.ui.chkUseNetworkDrive, 4, "checked")
        self.datamapper.addMapping(self.optionGroupSrvVersion, 5, "checked")
        self.datamapper.addMapping(self.optionGroupSUDO, 6, "checked")
        self.datamapper.addMapping(self.ui.inpSSHPort, 7)
        self.datamapper.addMapping(self.optionGroupSSHKeyFile, 8, "checked")
        self.datamapper.addMapping(self.ui.inpKeyFile, 9)
        self.datamapper.addMapping(self.ui.inpMaintainer, 10)
        self.datamapper.addMapping(self.ui.inpMailAddress, 11)
        self.datamapper.addMapping(self.ui.inpDevFolder, 12)
        self.datamapper.addMapping(self.ui.inpBuildCommand, 13)
        self.datamapper.addMapping(self.ui.inpInstallCommand, 14)
        self.datamapper.addMapping(self.ui.inpUninstallCommand, 15)
        self.datamapper.addMapping(self.ui.chkShowOutput, 16, "checked")
        self.datamapper.addMapping(self.ui.chkAlwaysReload, 17, "checked")
        self.datamapper.addMapping(self.ui.inpWOLLeadTime, 18)
        self.datamapper.addMapping(self.ui.inpUploadCommand, 19)
        self.datamapper.addMapping(self.ui.inpInstSetupCommand, 20)
        #self.datamapper.addMapping(self.settings.chkUseDepotFunctions, 21, "checked")
        self.datamapper.addMapping(self.optionGroupDepotFuncs, 21, "checked")
        self.datamapper.addMapping(self.ui.chkExtendedEditor, 22, "checked")
        self.datamapper.addMapping(self.ui.inpExternalEditor, 23)
        self.datamapper.addMapping(self.ui.inpBlockMarker, 24)
        self.datamapper.addMapping(self.optionGroupEditorTyp, 25, "checked")
        self.datamapper.addMapping(self.ui.chkSyntaxHighlight, 26, "checked")
        self.datamapper.addMapping(self.ui.chkCodeFolding, 27, "checked")
        self.datamapper.addMapping(self.ui.chkForceEntryBuild, 28, "checked")
        self.datamapper.addMapping(self.ui.chkForceEntrySave, 29, "checked")
        self.datamapper.addMapping(self.ui.chkMsgError, 30, "checked")
        self.datamapper.addMapping(self.ui.chkMsgWarning, 31, "checked")
        self.datamapper.addMapping(self.ui.chkMsgInfo, 32, "checked")
        self.datamapper.addMapping(self.ui.chkMsgAT, 33, "checked")
        self.datamapper.addMapping(self.ui.cmbLanguage, 34, "currentText")
        self.datamapper.addMapping(self.optionGroupProxy, 35, "checked")
        self.datamapper.addMapping(self.ui.chkUpdates, 36, "checked")
        self.datamapper.addMapping(self.ui.inpProxyServer, 37)
        self.datamapper.addMapping(self.ui.inpProxyPort, 38)
        self.datamapper.addMapping(self.ui.inpProxyUser, 39)
        self.datamapper.addMapping(self.ui.inpProxyPass, 40)
        self.datamapper.addMapping(self.optionGroupLogFile, 41, "checked")
        self.datamapper.addMapping(self.ui.inpLogFile, 42)
        self.datamapper.addMapping(self.ui.cmbLogLevel, 43)
        self.datamapper.toFirst()

    def connect_signals(self):
        """Connect signals"""

        self.logger.debug("Connect signals")
        self.model.itemChanged.connect(self.model_data_changed)

        self.ui.btnSave.clicked.connect(self.save_config)
        self.ui.dataChanged.connect(self.datamapper.submit)
        self.ui.settingsAboutToBeClosed.connect(self.close_dialog)

        self.ui.rdOpsiSrvNew.clicked.connect(self.set_model_data)
        self.ui.rdOpsiSrvOld.clicked.connect(self.set_model_data)
        self.ui.rdSUDOWithPass.clicked.connect(self.set_model_data)
        self.ui.rdSUDOWithoutPass.clicked.connect(self.set_model_data)
        self.ui.rdEditorInternal.clicked.connect(self.set_model_data)
        self.ui.rdEditorExternal.clicked.connect(self.set_model_data)
        self.ui.chkUseDepotFunctions.clicked.connect(self.set_model_data)
        self.ui.chkUseProxy.clicked.connect(self.set_model_data)
        self.ui.chkUseKeyFile.clicked.connect(self.set_model_data)
        self.ui.chkWriteLog.clicked.connect(self.set_model_data)

    @pyqtSlot()
    def model_data_changed(self):
        """Update model changed marker"""
        self.logger.debug("Model data changed")
        self._modelDataChanged = True

    @pyqtSlot()
    def set_model_data(self):
        """Whenever a special radio button or checkbox is clicked,
        the corresponding model data element will be set accordingly.

        This has to be done like so, because radio buttons and checkboxes are not directly linked
        to the model, but via a SpecialOptionButtonGroup object.
        """
        self.logger.debug("Set model data values from button: " + self.sender().objectName())

        # radio buttons
        if self.sender().objectName() == "rdOpsiSrvNew":
            if self.ui.rdOpsiSrvNew.isChecked():
                self.model.item(0, 5).setText("True")

        if self.sender().objectName() == "rdOpsiSrvOld":
            if self.ui.rdOpsiSrvOld.isChecked():
                self.model.item(0, 5).setText("False")

        if self.sender().objectName() == "rdSUDOWithPass":
            if self.ui.rdSUDOWithPass.isChecked():
                self.model.item(0, 6).setText("True")

        if self.sender().objectName() == "rdSUDOWithoutPass":
            if self.ui.rdSUDOWithoutPass.isChecked():
                self.model.item(0, 6).setText("False")

        if self.sender().objectName() == "rdEditorInternal":
            if self.ui.rdEditorInternal.isChecked():
                self.model.item(0, 25).setText("True")

        if self.sender().objectName() == "rdEditorExternal":
            if self.ui.rdEditorExternal.isChecked():
                self.model.item(0, 25).setText("False")

        # check boxes
        if self.sender().objectName() == "chkUseKeyFile":
            if self.ui.chkUseKeyFile.isChecked():
                self.model.item(0, 8).setText("True")
            else:
                self.model.item(0, 8).setText("False")

        if self.sender().objectName() == "chkUseDepotFunctions":
            if self.ui.chkUseDepotFunctions.isChecked():
                self.model.item(0, 21).setText("True")
            else:
                self.model.item(0, 21).setText("False")

        if self.sender().objectName() == "chkUseProxy":
            if self.ui.chkUseProxy.isChecked():
                self.model.item(0, 35).setText("True")
            else:
                self.model.item(0, 35).setText("False")

        if self.sender().objectName() == "chkWriteLog":
            if self.ui.chkWriteLog.isChecked():
                self.model.item(0, 41).setText("True")
            else:
                self.model.item(0, 41).setText("False")

    def update_backend_data(self):
        self.logger.debug("Update config backend")
        ConfigHandler.cfg.opsi_server = self.model.item(0, 0).text()
        ConfigHandler.cfg.opsi_user = self.model.item(0, 1).text()
        ConfigHandler.cfg.opsi_pass =  self.model.item(0, 2).text()
        ConfigHandler.cfg.root_pass = self.model.item(0, 3).text()
        ConfigHandler.cfg.usenetdrive = self.model.item(0, 4).text().title()
        ConfigHandler.cfg.age = self.model.item(0, 5).text().title()
        ConfigHandler.cfg.sudo = self.model.item(0, 6).text().title()
        ConfigHandler.cfg.cfg.sshport = self.model.item(0, 7).text()
        ConfigHandler.cfg.usekeyfile = self.model.item(0, 8).text().title()
        ConfigHandler.cfg.keyfilename = self.model.item(0, 9).text()
        ConfigHandler.cfg.packagemaintainer = self.model.item(0, 10).text()
        ConfigHandler.cfg.mailaddress = self.model.item(0, 11).text()
        ConfigHandler.cfg.dev_dir = self.model.item(0, 12).text()
        ConfigHandler.cfg.buildcommand = self.model.item(0, 13).text()
        ConfigHandler.cfg.installcommand = self.model.item(0, 14).text()
        ConfigHandler.cfg.uninstallcommand = self.model.item(0, 15).text()
        ConfigHandler.cfg.showoutput = self.model.item(0, 16).text().title()
        ConfigHandler.cfg.reload_for_at = self.model.item(0, 17).text().title()
        ConfigHandler.cfg.wol_lead_time = self.model.item(0, 18).text()
        ConfigHandler.cfg.uploadcommand = self.model.item(0, 19).text()
        ConfigHandler.cfg.instsetupcommand = self.model.item(0, 20).text()
        ConfigHandler.cfg.use_depot_funcs = self.model.item(0, 21).text().title()
        ConfigHandler.cfg.use_extended_changelog = self.model.item(0, 22).text().title()
        ConfigHandler.cfg.scripteditor = self.model.item(0, 23).text()
        ConfigHandler.cfg.chlog_block_marker = self.model.item(0, 24).text()
        ConfigHandler.cfg.editor_intern = self.model.item(0, 25).text().title()
        ConfigHandler.cfg.editor_use_styling = self.model.item(0, 26).text().title()
        ConfigHandler.cfg.editor_use_folding = self.model.item(0, 27).text().title()
        ConfigHandler.cfg.chlog_on_build = self.model.item(0, 28).text().title()
        ConfigHandler.cfg.chlog_on_save = self.model.item(0, 29).text().title()
        ConfigHandler.cfg.no_error_msg = self.model.item(0, 30).text().title()
        ConfigHandler.cfg.no_warning_msg = self.model.item(0, 31).text().title()
        ConfigHandler.cfg.no_info_msg = self.model.item(0, 32).text().title()
        ConfigHandler.cfg.no_at_warning_msg = self.model.item(0, 33).text().title()
        ConfigHandler.cfg.language = self.model.item(0, 34).text()
        ConfigHandler.cfg.useproxy = self.model.item(0, 35).text().title()
        ConfigHandler.cfg.updatecheck = self.model.item(0, 36).text().title()
        ConfigHandler.cfg.proxy_server = self.model.item(0, 37).text()
        ConfigHandler.cfg.proxy_port = self.model.item(0, 38).text()
        ConfigHandler.cfg.proxy_user = self.model.item(0, 39).text()
        ConfigHandler.cfg.proxy_pass = self.model.item(0, 40).text()
        ConfigHandler.cfg.log_always = self.model.item(0, 41).text().title()
        ConfigHandler.cfg.log_file = self.model.item(0, 42).text()
        ConfigHandler.cfg.log_level = self.model.item(0, 43).text()

    def close_dialog(self):
        """Close settings dialog"""
        ignoreChanges = True
        if self._modelDataChanged == True:
            retval = QMessageBox.question(None, translate("settingsController", "Question"), translate("settingsController", "There are unsaved changes! Do you really want to continue?"), QMessageBox.Yes, QMessageBox.No)
            if retval == QMessageBox.No:
                self.logger.debug("Unsaved changes have been ignored.")
                ignoreChanges = False

        if ignoreChanges:
            self.logger.debug("Close settings dialog")
            self.ui.close()
            self.logger.debug("Emit signal settingsClosed")
            self.settingsClosed.emit()

    @pyqtSlot()
    def save_config(self):
        """Get field values and initiate saving of configuration"""
        if self._modelDataChanged:
            self.update_backend_data()
            ConfigHandler.cfg.save()
            self._modelDataChanged = None

        self.close_dialog()
Exemple #33
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)
Exemple #34
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()))
Exemple #35
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)