Esempio n. 1
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()
    # --------------------------------
Esempio n. 2
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()
Esempio n. 3
0
class NoteEditDialog(QDialog, Ui_Dialog):
    ready = pyqtSignal(bool, int, name='ready')

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

        self.init_ui()
        self.init_model(model)

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

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

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

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

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

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

    def reject(self): # это стандартный метод
        super().reject()
        self.__mapper.revert()
        self.__model.revertAll()
Esempio n. 4
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()
Esempio n. 5
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()
Esempio n. 6
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()))
Esempio n. 7
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)
Esempio n. 8
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)
Esempio n. 9
0
class APISFilm(QDialog, FORM_CLASS):

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

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

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

        self.parent = parent

        self.setupUi(self)

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

        self.printingOptionsDlg = None

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.setupNavigation()

        self.mapper.toFirst()

        self.initalLoad = False

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

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

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

        self.mapper.setModel(self.model)

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

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

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

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

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

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

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

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

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

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

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

        tv = QTableView()
        editor.setView(tv)

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

        editor.setModel(model)

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

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

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

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

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

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

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

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

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

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

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

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

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

        query.exec_(qryStr)

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

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

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

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

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

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

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

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

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

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

    def onComboBoxChanged(self, editor):
        pass

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

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

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

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

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

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

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

        self.printingOptionsDlg.show()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.model.insertRow(row)

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

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

        self.mapper.setCurrentIndex(row)

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

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

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

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

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

        self.initalLoad = False

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

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

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

        res = self.mapper.submit()

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

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

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

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

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

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

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

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

        self.uiFilmModeCombo.setEnabled(False)

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

        if self.dbm.dbRequiresUpdate:
            self.initalLoad = True
            for editor in [self.uiArchiveCombo, self.uiCameraCombo, self.uiFilmMakeCombo, self.uiCopyrightCombo, self.uiProjectSelectionCombo, self.newFilmDlg.uiProducerCombo]:
                self.updateComboBox(editor)
            currIdx = self.mapper.currentIndex()
            self.model.select()
            while (self.model.canFetchMore()):
                self.model.fetchMore()
            self.mapper.setCurrentIndex(currIdx)
            self.dbm.dbRequiresUpdate = False
            self.initalLoad = False
Esempio n. 10
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)
Esempio n. 11
0
class APISSharding(QDialog, FORM_CLASS):

    shardingEditsSaved = pyqtSignal(bool)

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

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

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

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

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

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

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

        self.initalLoad = False

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

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

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

        self.initalLoad = False

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

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

        self.mapper.setModel(self.model)

        self.mandatoryEditors = [self.uiShardingDate]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.addMode = True
        self.startEditMode()

        # self.mapper.submit()

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

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

        self.setKgNameAndCode()

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

        self.initalLoad = False

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

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

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

        self.mapper.setCurrentIndex(currIdx)

        # emit signal
        self.shardingEditsSaved.emit(True)

        self.endEditMode()
        return True

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

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

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

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

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

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

        self.loadInImageViewer(path)

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

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

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

        self.loadInImageViewer(path)

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.ui.lblFileFPS.setText("")

        self.ui.spinBoxFrameJumpMultiplier.value = 1



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


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

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

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

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

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

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

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

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

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

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

        self.ui.show()


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

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


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

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

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

        self.update_video_file_play_labels()

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

        curr_frame = int(round(curr_percent_complete * totalNumFrames))

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

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






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

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

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

            self.update_video_file_play_labels()

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

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


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

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

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

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

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

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




        totalNumFrames = int(curr_total_duration * curr_total_fps)

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

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

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

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

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


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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

        self.video_filename = filename

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

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

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

    def _show_error(self, message, title="Error"):
        QMessageBox.warning(self, title, message)
Esempio n. 13
0
class DeviceEditDialog(QDialog):
    def __init__(self, model, row, *args, **kwargs):
        super(DeviceEditDialog, self).__init__(*args, **kwargs)
        self.setMinimumWidth(400)
        self.setWindowTitle("Edit device")

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

        vl = VLayout()

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

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

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

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

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

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

        self.mapper.setCurrentIndex(row)

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

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

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

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

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

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

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

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


    def reject(self):
        self.mapper.revert()
        self.done(QDialog.Rejected)
Esempio n. 14
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)
Esempio n. 15
0
class EditForm(QWidget, Ui_EditForm):
    def __init__(self, current_index, model):
        super().__init__()
        # uic.loadUi('editForm.ui', self)
        self.setupUi(self)
        # self.db = database

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

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

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

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

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

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

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

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

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

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