class OntoOnlineSearch(QWidget):

    tagSelected = pyqtSignal(str, str)

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

        self.termListTblWdg = QTableView()
        self.termTableModel = OntoTermsListModel(parent=self)
        self.termListTblWdg.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.termListTblWdg.setSelectionMode(QAbstractItemView.SingleSelection)
        self.termListTblWdg.setModel(self.termTableModel)

        self.termListTblWdg.setColumnWidth(0, 300)
        self.termListTblWdg.setColumnWidth(1, 200)

        # Signals
        self.termSelectionModel = self.termListTblWdg.selectionModel()
        self.termSelectionModel.selectionChanged.connect(self.termSelected)
        #self.termTableModel.layoutChanged.connect(self.termTableLayoutChanged)

        self.autoCompleteTxt = OntoAutoComplete(self)
        self.autoCompleteTxt.completionTerminated.connect(
            self.completionUpdate)

        grid = QGridLayout(self)
        grid.addWidget(self.termListTblWdg, 0, 0)
        grid.addWidget(self.autoCompleteTxt, 1, 0)

    def termSelected(self, selection, deselected=None):
        #id = [tagId for tagId, tagName in self.dicData.items() if name == tagName]
        #assert(len(id)==1)
        #id = id[0]
        #self.addTagToAnnotation(id)
        #self.tagEdit.erase = True
        #self.tagEdit.clearEditText()
        if len(selection.indexes()):
            term = self.termTableModel.getTerm(selection.indexes()[0])
            self.tagSelected.emit(term[0], term[1])

            # Unselect selected item in the table view.
            #self.termListTblWdg.setCurrentCell(-1,-1)
            self.termListTblWdg.clearSelection()
            self.termTableModel.refresh()

    @pyqtSlot(dict)
    def completionUpdate(self, termDic):
        #print(termDic)
        self.termTableModel.setTerms(termDic)
Exemple #2
0
class AddTableDetailsView(QSplitter):
    """ This is a splitter widget that contains a table and
    a details widget. Used in the Add Show dialog. """

    changed = QtCore.pyqtSignal(dict)

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

        self.table = QTableView()
        m = AddTableModel()
        proxy = QtCore.QSortFilterProxyModel()
        proxy.setSourceModel(m)

        self.table.setGridStyle(QtCore.Qt.NoPen)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setModel(proxy)

        # Allow sorting but don't sort by default
        self.table.horizontalHeader().setSortIndicator(
            -1, QtCore.Qt.AscendingOrder)
        self.table.setSortingEnabled(True)

        if pyqt_version == 5:
            self.table.horizontalHeader().setSectionResizeMode(
                0, QHeaderView.Stretch)
        else:
            self.table.horizontalHeader().setResizeMode(0, QHeaderView.Stretch)

        self.table.selectionModel().currentRowChanged.connect(
            self.s_show_selected)
        self.addWidget(self.table)

        self.details = DetailsWidget(parent, worker)
        self.addWidget(self.details)

        self.setSizes([1, 1])

    def s_show_selected(self, new, old=None):
        if not new:
            return

        index = self.table.model().mapToSource(new).row()
        selected_show = self.getModel().results[index]
        self.details.load(selected_show)

        self.changed.emit(selected_show)

    def setResults(self, results):
        self.getModel().setResults(results)

    def getModel(self):
        return self.table.model().sourceModel()

    def clearSelection(self):
        return self.table.clearSelection()
class MasternodesWidget(QWidget):
    """Widget that displays masternodes."""
    def __init__(self, manager, parent=None):
        super(MasternodesWidget, self).__init__(parent)
        self.manager = manager
        self.model = MasternodesModel(self.manager)
        self.proxy_model = QSortFilterProxyModel()
        self.proxy_model.setSourceModel(self.model)
        self.view = QTableView()
        self.view.setModel(self.proxy_model)
        for header in [self.view.horizontalHeader(), self.view.verticalHeader()]:
            header.setHighlightSections(False)

        header = self.view.horizontalHeader()
        header.setSectionResizeMode(MasternodesModel.ALIAS, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(MasternodesModel.VIN, QHeaderView.Stretch)
        header.setSectionResizeMode(MasternodesModel.COLLATERAL, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(MasternodesModel.DELEGATE, QHeaderView.ResizeToContents)
        self.view.verticalHeader().setVisible(False)

        self.view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.view.setSortingEnabled(True)
        self.view.sortByColumn(self.model.ALIAS, Qt.AscendingOrder)

        vbox = QVBoxLayout()
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.addWidget(self.view)
        self.setLayout(vbox)

    def select_masternode(self, alias):
        """Select the row that represents alias."""
        self.view.clearSelection()
        for i in range(self.proxy_model.rowCount()):
            idx = self.proxy_model.index(i, 0)
            mn_alias = str(self.proxy_model.data(idx))
            if mn_alias == alias:
                self.view.selectRow(i)
                break

    def populate_collateral_key(self, row):
        """Fill in the collateral key for a masternode based on its collateral output.

        row refers to the desired row in the proxy model, not the actual model.
        """
        mn = self.masternode_for_row(row)
        self.manager.populate_masternode_output(mn.alias)
        # Emit dataChanged for the collateral key.
        index = self.model.index(row, self.model.COLLATERAL)
        self.model.dataChanged.emit(index, index)

    def refresh_items(self):
        self.model.dataChanged.emit(QModelIndex(), QModelIndex())

    def add_masternode(self, masternode, save = True):
        self.model.add_masternode(masternode, save=save)

    def remove_masternode(self, alias, save = True):
        self.model.remove_masternode(alias, save=save)

    def masternode_for_row(self, row):
        idx = self.proxy_model.mapToSource(self.proxy_model.index(row, 0))
        return self.model.masternode_for_row(idx.row())

    def import_masternode_conf_lines(self, conf_lines, pw):
        return self.model.import_masternode_conf_lines(conf_lines, pw)
class ParamModWgt(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.main_window = parent

        self.buildRequiredTagsGB()

        # Widgets
        self.newParamBtn = QPushButton("New")
        self.deleteParamBtn = QPushButton("Delete")
        self.paramSaveAnnotBtn = QPushButton("Save")
        buttonWidget = QWidget(self)

        self.existingParamsGB = QGroupBox("Existing parameters", self)

        self.paramListTblWdg = QTableView()
        self.paramListModel = ParameterListModel(parent=self)
        self.paramListTblWdg.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.paramListTblWdg.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.paramListTblWdg.setModel(self.paramListModel)

        self.paramListTblWdg.setColumnWidth(0, 150)
        self.paramListTblWdg.setColumnWidth(1, 350)

        self.relationWgt = ParamRelationWgt(parent)
        self.newParamsGB = QGroupBox("Parameter details", self)
        self.resultTypeCbo = QComboBox(self)
        self.isExpProp = QCheckBox("is an experimental property", self)

        self.resultTypeCbo.addItems(
            ["point value", "function", "numerical trace"])

        self.singleValueParamWgt = ParamValueWgt(parent)
        self.functionParamWgt = ParamFunctionWgt(parent)
        self.traceParamWgt = ParamTraceWgt(parent)

        self.functionParamWgt.mainWgt = self

        self.paramModStack = QStackedWidget(self)
        self.paramModStack.addWidget(self.singleValueParamWgt)
        self.paramModStack.addWidget(self.functionParamWgt)
        self.paramModStack.addWidget(self.traceParamWgt)

        # Signals
        selectionModel = self.paramListTblWdg.selectionModel()
        selectionModel.selectionChanged.connect(self.selectedParameterChanged)

        self.newParamBtn.clicked.connect(self.newParameter)
        self.deleteParamBtn.clicked.connect(self.deleteParameter)
        self.paramSaveAnnotBtn.clicked.connect(self.saveParameter)
        self.resultTypeCbo.currentIndexChanged.connect(
            self.paramModStack.setCurrentIndex)
        self.singleValueParamWgt.paramTypeSelected.connect(
            self.newParamTypeSelected)
        self.functionParamWgt.paramTypeSelected.connect(
            self.newParamTypeSelected)
        self.traceParamWgt.paramTypeSelected.connect(self.newParamTypeSelected)

        # Layout
        buttonLayout = QVBoxLayout(buttonWidget)
        buttonLayout.addWidget(self.paramSaveAnnotBtn)
        buttonLayout.addWidget(self.deleteParamBtn)
        buttonLayout.addWidget(self.newParamBtn)

        existGrid = QHBoxLayout(self.existingParamsGB)
        existGrid.addWidget(buttonWidget)
        existGrid.addWidget(self.paramListTblWdg)

        newGrid = QGridLayout(self.newParamsGB)
        newGrid.addWidget(QLabel("Result type"), 0, 0)
        newGrid.addWidget(self.resultTypeCbo, 0, 1)
        newGrid.addWidget(self.isExpProp, 0, 2)

        newGrid.addWidget(self.paramModStack, 1, 0, 1, 3)
        newGrid.addWidget(self.relationWgt, 1, 3)

        layout = QVBoxLayout(self)
        self.rootLayout = QSplitter(Qt.Vertical, self)
        self.rootLayout.setOrientation(Qt.Vertical)
        self.rootLayout.addWidget(self.existingParamsGB)
        self.rootLayout.addWidget(self.newParamsGB)
        self.rootLayout.addWidget(self.requireTagGB)
        layout.addWidget(self.rootLayout)

        # Initial behavior
        self.newParamBtn.setEnabled(True)
        self.deleteParamBtn.setEnabled(False)
        self.paramSaveAnnotBtn.setEnabled(False)
        self.additionMode = False
        self.newParamsGB.setEnabled(False)

    def setRootLayoutSizes(self, sizes):
        self.rootLayout.setSizes(sizes)

    def viewParameter(self, parameter):
        row = -1
        for row, param in enumerate(self.paramListModel.parameterList):
            if param.id == parameter.id:
                break
        assert (row > -1)
        self.paramListTblWdg.selectRow(row)

    @pyqtSlot(str)
    def newParamTypeSelected(self, paramName):
        self.requiredTagsListModel.clear()
        self.requiredTagsListModel.refresh()

        paramType = getParameterTypeFromName(paramName)
        if paramType is None:
            raise ValueError("Parameter type with name '" + paramName +
                             "' was not found.")

        for reqTag in paramType.requiredTags:
            self.requiredTagsListModel.addTag(reqTag.id, reqTag.name,
                                              reqTag.id, reqTag.name)

        self.requiredTagsListModel.refresh()

    def buildRequiredTagsGB(self):

        # Widgets
        self.requireTagGB = QGroupBox("Required tag categories", self)

        self.requiredTagsListTblWdg = RequiredTagsTableView()
        self.requiredTagsListModel = RequiredTagsListModel(parent=self)
        self.requiredTagsListTblWdg.setSelectionBehavior(
            QAbstractItemView.SelectRows)
        self.requiredTagsListTblWdg.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.requiredTagsListTblWdg.setModel(self.requiredTagsListModel)
        self.requiredTagsListTblWdg.setColumnWidth(0, 200)
        self.requiredTagsListTblWdg.setColumnWidth(1, 200)

        # Layout
        requiredTagLayout = QGridLayout(self.requireTagGB)
        requiredTagLayout.addWidget(self.requiredTagsListTblWdg, 0, 0, 4, 1)

    def newParameter(self):
        self.resultTypeCbo.setCurrentIndex(0)
        self.paramModStack.currentWidget().newParameter()

        self.singleValueParamWgt.newParameter()
        self.functionParamWgt.newParameter()
        self.traceParamWgt.newParameter()

        self.newParamsGB.setEnabled(True)
        self.paramListTblWdg.clearSelection()

        self.newParamBtn.setEnabled(False)
        self.deleteParamBtn.setEnabled(False)
        self.paramSaveAnnotBtn.setEnabled(True)

        self.isExpProp.setChecked(False)

    def saveParameter(self):

        relationship = self.relationWgt.getRelationship()

        # Get the ID of the modified parameter if we are modifying an existing
        # parameters
        if len(self.paramListTblWdg.selectionModel().selectedRows()) != 0:
            selectedRow = self.paramListTblWdg.selectionModel().currentIndex(
            ).row()
            paramId = self.main_window.currentAnnotation.parameters[
                selectedRow].id
        else:
            paramId = None

        param = self.paramModStack.currentWidget().saveParameter(
            relationship, paramId)

        if not param is None:
            param.requiredTags = self.requiredTagsListModel.getRequiredTags()
            param.isExperimentProperty = self.isExpProp.isChecked()

            selectedRow = self.paramListTblWdg.selectionModel().currentIndex(
            ).row()
            # Even when there is no selection, selectedRow can take a zero value. This "if"
            # controls for that.
            if len(self.paramListTblWdg.selectionModel().selectedRows()) == 0:
                selectedRow = -1

            if selectedRow >= 0:
                self.main_window.currentAnnotation.parameters[
                    selectedRow] = param
            else:
                self.main_window.currentAnnotation.parameters.append(param)

            self.additionMode = False
            nbParams = len(self.main_window.currentAnnotation.parameters)
            self.main_window.saveAnnotation()

            if selectedRow < 0:
                selectedRow = nbParams - 1
            self.paramListTblWdg.selectRow(selectedRow)
            self.loadRow(selectedRow)

    def deleteParameter(self):
        selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row(
        )
        del self.main_window.currentAnnotation.parameters[selectedRow]
        self.main_window.saveAnnotation()
        self.refreshModelingParameters()

    def refreshModelingParameters(self):
        selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row(
        )
        self.loadModelingParameter(selectedRow)

    def loadModelingParameter(self, row=None):
        """
         Call when a new annotation has been selected so that all the modeling parameters
         associated with this annotation are loaded in the parameter list. 
        """

        self.requiredTagsListModel.clear()
        self.requiredTagsListModel.refresh()

        if self.main_window.currentAnnotation is None:
            self.paramListModel.parameterList = []
        else:
            self.paramListModel.parameterList = self.main_window.currentAnnotation.parameters

            aRowIsSelected = not row is None
            if aRowIsSelected:
                if row < 0:
                    noRowToLoad = self.paramListTblWdg.model().rowCount() - row
                else:
                    noRowToLoad = row
            else:
                ## No rows are selected
                noRowToLoad = -1

            self.loadRow(noRowToLoad)
            self.newParamBtn.setEnabled(True)
            self.deleteParamBtn.setEnabled(aRowIsSelected)
            self.paramSaveAnnotBtn.setEnabled(aRowIsSelected)
            self.paramModStack.currentWidget().loadModelingParameter(row)
            self.relationWgt.loadModelingParameter(row)

            self.newParamsGB.setEnabled(aRowIsSelected)

        self.paramListModel.refresh()

    def loadRow(self, selectedRow=None):
        """
         Called when a row has been selected in the table listing all the modeling parameters.
         It update the interface with the values associated with this specific parameter.
        """
        def nlxCheck(id):
            if id in nlx2ks:
                return nlx2ks[id]
            return id

        def clear():
            self.requiredTagsListModel.clear()
            self.paramModStack.currentWidget().loadRow(None)
            self.relationWgt.clear()
            self.paramListTblWdg.clearSelection()

        if selectedRow is None:
            selectedRow = self.paramListTblWdg.selectionModel().currentIndex(
            ).row()

        if self.main_window.currentAnnotation is None:
            clear()
            return

        if selectedRow < 0 or selectedRow >= len(
                self.main_window.currentAnnotation.parameters):
            clear()
            return

        currentParameter = self.main_window.currentAnnotation.parameters[
            selectedRow]

        self.newParamBtn.setEnabled(True)
        self.deleteParamBtn.setEnabled(True)
        self.paramSaveAnnotBtn.setEnabled(True)

        if currentParameter.description.type == "pointValue":
            self.resultTypeCbo.setCurrentIndex(0)
            self.paramModStack.setCurrentIndex(0)
        elif currentParameter.description.type == "function":
            self.resultTypeCbo.setCurrentIndex(1)
            self.paramModStack.setCurrentIndex(1)
        elif currentParameter.description.type == "numericalTrace":
            self.resultTypeCbo.setCurrentIndex(2)
            self.paramModStack.setCurrentIndex(2)
        else:
            raise ValueError("Type of parameter description " +
                             currentParameter.description.type +
                             " is invalid.")

        self.paramModStack.currentWidget().loadRow(currentParameter)
        self.relationWgt.loadRow(currentParameter)
        self.isExpProp.setChecked(currentParameter.isExperimentProperty)

        ## UPDATING REQUIRED TAGS
        self.requiredTagsListModel.clear()
        for tag in currentParameter.requiredTags:
            self.requiredTagsListModel.addTag(
                tag.rootId, self.main_window.dicData[tag.rootId], tag.id,
                tag.name)

        ## Adding new required tags that may have been specified since the
        ## creation of this parameter instance.
        parameterType = getParameterTypeFromID(currentParameter.typeId)
        reqTags = {
            reqTag.rootId: reqTag
            for reqTag in parameterType.requiredTags
        }
        for reqTagRootId, reqTag in reqTags.items():
            #print(nlxCheck(reqTagRootId), [nlxCheck(tag.rootId) for tag in currentParameter.requiredTags])
            if not nlxCheck(reqTagRootId) in [
                    nlxCheck(tag.rootId)
                    for tag in currentParameter.requiredTags
            ]:
                self.requiredTagsListModel.addTag(
                    reqTag.rootId, self.main_window.dicData[reqTag.rootId],
                    reqTag.id, reqTag.name)

        self.requiredTagsListModel.refresh()

        self.newParamsGB.setEnabled(True)

    def selectedParameterChanged(self, selected, deselected):
        if len(selected.indexes()) == 0:
            return
        if self.additionMode:
            msgBox = QMessageBox(self)
            msgBox.setWindowTitle("Cancellation")
            msgBox.setText(
                "Are you sure you want to cancel the addition of the new parameter being edited? If not, say no and then hit 'Save' to save this new parameter."
            )
            msgBox.setStandardButtons(QMessageBox.No | QMessageBox.Yes)
            msgBox.setDefaultButton(QMessageBox.No)
            if msgBox.exec_() == QMessageBox.Yes:
                self.additionMode = False
                self.loadRow()
            else:
                #self.paramListTblWdg.selectRow(-1)
                self.paramListTblWdg.clearSelection()
        else:
            self.loadRow()
Exemple #5
0
class QtComparePanel(QWidget):

    filterChanged = pyqtSignal(str)

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

        self.visibility_flags = []
        self.visibility_buttons = []
        self.labels_projects = []

        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)
        self.setMinimumWidth(400)
        self.setMinimumHeight(100)

        self.data_table = QTableView()
        self.data_table.setSizePolicy(QSizePolicy.MinimumExpanding,
                                      QSizePolicy.MinimumExpanding)
        self.data_table.setSelectionMode(QAbstractItemView.MultiSelection)
        self.data_table.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.data_table.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.model = None
        self.data = None

        self.combodelegate1 = ComboBoxItemDelegate(self.data_table)
        self.combodelegate2 = ComboBoxItemDelegate(self.data_table)

        lblFilter = QLabel("Filter: ")
        self.comboboxFilter = QComboBox()
        self.comboboxFilter.setMinimumWidth(80)
        self.comboboxFilter.addItem("All")
        self.comboboxFilter.addItem("Same")
        self.comboboxFilter.addItem("Born")
        self.comboboxFilter.addItem("Dead")
        self.comboboxFilter.addItem("Grow")
        self.comboboxFilter.addItem("Shrink")

        filter_layout = QHBoxLayout()
        filter_layout.addWidget(lblFilter)
        filter_layout.addWidget(self.comboboxFilter)
        filter_layout.addStretch()

        layout = QVBoxLayout()
        layout.addLayout(filter_layout)
        layout.addWidget(self.data_table)
        self.setLayout(layout)

        self.correspondences = None
        self.data = None

        self.comboboxFilter.currentTextChanged.connect(self.changeFilter)

    def setTable(self, project, img1idx, img2idx):

        self.correspondences = project.getImagePairCorrespondences(
            img1idx, img2idx)
        self.data = self.correspondences.data

        self.model = TableModel(self.data)
        self.sortfilter = QSortFilterProxyModel(self)
        self.sortfilter.setSourceModel(self.model)
        self.data_table.setModel(self.sortfilter)

        self.data_table.setVisible(False)
        self.data_table.verticalHeader().hide()
        self.data_table.resizeColumnsToContents()
        self.data_table.setVisible(True)

        self.data_table.setItemDelegateForColumn(5, self.combodelegate1)
        self.data_table.setItemDelegateForColumn(6, self.combodelegate2)
        self.data_table.setEditTriggers(QAbstractItemView.DoubleClicked)

        self.data_table.update()

        self.data_table.setStyleSheet(
            "QHeaderView::section { background-color: rgb(40,40,40) }")

    def updateData(self, corr):

        if corr is None:
            return

        self.correspondences = corr
        self.sortfilter.beginResetModel()
        self.model.beginResetModel()
        self.model._data = corr.data
        self.sortfilter.endResetModel()
        self.model.endResetModel()

        self.data_table.update()

    def selectRows(self, rows):
        self.data_table.clearSelection()

        indexes = [self.model.index(r, 0) for r in rows]
        mode = QItemSelectionModel.Select | QItemSelectionModel.Rows
        [
            self.data_table.selectionModel().select(index, mode)
            for index in indexes
        ]

        if len(rows) > 0:
            value = self.data_table.horizontalScrollBar().value()
            column = self.data_table.columnAt(value)
            self.data_table.scrollTo(self.data_table.model().index(
                rows[0], column))

    @pyqtSlot(QModelIndex)
    def getData(self, index):

        pass
        #column = index.column()
        #row = index.row()
        #self.data_table.model().index(row, column).data()

    @pyqtSlot(str)
    def changeFilter(self, txt):

        if self.data is None:
            return

        if txt == 'All':
            self.sortfilter.setFilterRegExp(QRegExp())
        else:
            self.sortfilter.setFilterKeyColumn(5)
            self.sortfilter.setFilterRegExp(txt.lower())
            self.sortfilter.setFilterRole(Qt.DisplayRole)

        self.filterChanged.emit(txt.lower())
Exemple #6
0
class SubtitleEditor(SubTab):
    def __init__(self, filePath, subtitleData, parent = None):
        name = os.path.split(filePath)[1]
        super(SubtitleEditor, self).__init__(name, parent)
        self.__initWidgets()
        self.__initContextMenu()

        self._settings = SubSettings()

        self._filePath = filePath
        self._movieFilePath = None
        self._subtitleData = subtitleData

        self.refreshSubtitles()

        # Some signals
        self._subtitleData.fileChanged.connect(self.fileChanged)
        self._subtitleData.subtitlesAdded.connect(self._subtitlesAdded)
        self._subtitleData.subtitlesRemoved.connect(self._subtitlesRemoved)
        self._subtitleData.subtitlesChanged.connect(self._subtitlesChanged)
        self._model.itemChanged.connect(self._subtitleEdited)
        self.customContextMenuRequested.connect(self.showContextMenu)

    def __initWidgets(self):
        minimalSizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        # List of subtitles
        subListDelegate = SubListItemDelegate()
        self._model = QStandardItemModel(0, 3, self)
        self._model.setHorizontalHeaderLabels([_("Begin"), _("End"), _("Subtitle")])
        self._subList = QTableView(self)
        self._subList.setModel(self._model)
        self._subList.setItemDelegateForColumn(0, subListDelegate)
        self._subList.setItemDelegateForColumn(1, subListDelegate)
        self._subList.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)

        self._searchBar = SearchBar(self)
        self._searchBar.hide()

        # Top toolbar
        toolbar = QHBoxLayout()
        toolbar.setAlignment(Qt.AlignLeft)
        #toolbar.addWidget(someWidget....)
        toolbar.addStretch(1)

        # Main layout
        grid = QGridLayout()
        grid.setSpacing(10)
        grid.setContentsMargins(0, 3, 0, 0)
        grid.addLayout(toolbar, 0, 0, 1, 1) # stretch to the right
        grid.addWidget(self._subList, 1, 0)
        grid.addWidget(self._searchBar, 2, 0)
        self.setLayout(grid)

    def __initContextMenu(self):
        self._contextMenu = QMenu(self)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        af = ActionFactory(self)

        insertSub = af.create(title = _("&Insert subtitle"), icon = "list-add",
            connection = self.insertNewSubtitle)
        self._contextMenu.addAction(insertSub)

        insertSub = af.create(title = _("&Add subtitle"), icon = "list-add",
            connection = self.addNewSubtitle)
        self._contextMenu.addAction(insertSub)

        removeSub = af.create(title = _("&Remove subtitles"), icon = "list-remove",
            connection = self.removeSelectedSubtitles)
        self._contextMenu.addAction(removeSub)

    def _changeRowBackground(self, rowNo, bg):
        with DisableSignalling(self._model.itemChanged, self._subtitleEdited):
            for columnNo in range(self._model.columnCount()):
                item = self._model.item(rowNo, columnNo)
                item.setBackground(bg)

    def _changeItemData(self, item, val, role):
        with DisableSignalling(self._model.itemChanged, self._subtitleEdited):
            item.setData(val, role)

    def _handleIncorrectItem(self, item):
        with DisableSignalling(self._model.itemChanged, self._subtitleEdited):
            item.setData(False, CustomDataRoles.ErrorFlagRole)

        bg = item.background()
        rowNo = item.row()
        self._changeRowBackground(rowNo, Qt.red)
        QTimer.singleShot(600, lambda rowNo=rowNo, bg=bg: self._changeRowBackground(rowNo, bg))

    def _subtitleEdited(self, item):
        modelIndex = item.index()
        column = modelIndex.column()
        subNo = modelIndex.row()

        errorFlag = item.data(CustomDataRoles.ErrorFlagRole)
        if errorFlag is True:
            self._handleIncorrectItem(item)
        else:
            # TODO: timeStart and timeEnd might be displayed in a frame format in a bright future.
            # Check it and create FrameTime properly in that case.
            # TODO: Maybe add column numbers to some kind of enum to avoid magic numbers?
            oldSubtitle = self.subtitles[subNo]
            newSubtitle = oldSubtitle.clone()
            if 0 == column:
                timeStart = item.data(CustomDataRoles.FrameTimeRole)
                newSubtitle.change(start = timeStart)
            elif 1 == column:
                timeEnd = item.data(CustomDataRoles.FrameTimeRole)
                newSubtitle.change(end = timeEnd)
            elif 2 == column:
                newSubtitle.change(text = item.text())
            command = ChangeSubtitle(self.filePath, oldSubtitle, newSubtitle, subNo)
            self._subtitleData.execute(command)

    def _subtitlesAdded(self, path, subNos):
        if path != self.filePath:
            return

        subtitles = self.subtitles
        for subNo in subNos:
            row = createRow(subtitles[subNo])
            self._model.insertRow(subNo, row)

    def _subtitlesRemoved(self, path, subNos):
        if path != self.filePath:
            return

        for subNo in subNos:
            self._model.removeRow(subNo)

    def _subtitlesChanged(self, path, subNos):
        if path != self.filePath:
            return

        for subNo in subNos:
            self.refreshSubtitle(subNo)

    def _createNewSubtitle(self, data, subNo):
        fps = data.fps # data is passed to avoid unnecessary copies
        minFrameTime = FrameTime(fps, frames = 1)

        # calculate correct minimum subtitle start time
        if subNo > 0:
            timeStart = data.subtitles[subNo - 1].end + minFrameTime
        else:
            timeStart = FrameTime(fps, frames = 0)

        # calculate correct maximum subtitle end time
        if subNo < data.subtitles.size():
            try:
                timeEnd = data.subtitles[subNo].start - minFrameTime
            except SubException:
                timeEnd = FrameTime(fps, frames = 0)
        else:
            timeEnd = timeStart + FrameTime(fps, frames = 50)

        # add subtitle to DataModel
        sub = Subtitle(timeStart, timeEnd, "")
        command = AddSubtitle(self.filePath, subNo, sub)
        with DisableSignalling(self._subtitleData.subtitlesAdded, self._subtitlesAdded):
            self._subtitleData.execute(command)

        # create subtitle graphical representation in editor sub list
        row = createRow(sub)
        self._model.insertRow(subNo, row)
        index = self._model.index(subNo, 2)
        self._subList.clearSelection()
        self._subList.setCurrentIndex(index)
        self._subList.edit(index)

    def addNewSubtitle(self):
        data = self.data
        subNo = data.subtitles.size()
        indices = self._subList.selectedIndexes()
        if len(indices) > 0:
            rows = [index.row() for index in indices]
            subNo = max(rows) + 1
        self._createNewSubtitle(data, subNo)

    def insertNewSubtitle(self):
        data = self.data
        subNo = 0
        indices = self._subList.selectedIndexes()
        if len(indices) > 0:
            rows = [index.row() for index in indices]
            subNo = max(rows)
        self._createNewSubtitle(data, subNo)

    def removeSelectedSubtitles(self):
        indices = self._subList.selectedIndexes()
        if len(indices) > 0:
            rows = list(set([index.row() for index in indices]))
            command = RemoveSubtitles(self.filePath, rows)
            self._subtitleData.execute(command)
            if self._model.rowCount() > rows[-1]:
                self._subList.selectRow(rows[-1])
            else:
                self._subList.selectRow(self._model.rowCount() - 1)

    def highlight(self):
        self._searchBar.show()
        self._searchBar.highlight()

    def showContextMenu(self):
        self._contextMenu.exec(QCursor.pos())

    def changeInputEncoding(self, encoding):
        data = self._subtitleData.data(self.filePath)
        if encoding != data.inputEncoding:
            try:
                data.encode(encoding)
            except UnicodeDecodeError:
                message = QMessageBox(
                    QMessageBox.Warning,
                    _("Decoding error"),
                    _("Cannot decode subtitles to '%s' encoding.\nPlease try different encoding.") % encoding,
                    QMessageBox.Ok, self
                )
                message.exec()
            except LookupError:
                message = QMessageBox(QMessageBox.Warning,
                    _("Unknown encoding"), _("Unknown encoding: '%s'") % encoding,
                    QMessageBox.Ok, self
                )
                message.exec()
            else:
                # TODO: outputEncoding
                command = ChangeData(self.filePath, data, _("Input encoding: %s") % encoding)
                self._subtitleData.execute(command)

    def changeOutputEncoding(self, encoding):
        data = self._subtitleData.data(self.filePath)
        if encoding != data.outputEncoding:
            data.outputEncoding = encoding
            command = ChangeData(self.filePath, data, _("Output encoding: %s") % encoding)
            self._subtitleData.execute(command)

    def changeSubFormat(self, fmt):
        data = self._subtitleData.data(self.filePath)
        if data.outputFormat != fmt:
            data.outputFormat = fmt
            command = ChangeData(self.filePath, data)
            self._subtitleData.execute(command)

    def changeFps(self, fps):
        data = self.data
        if data.fps != fps:
            data.subtitles.changeFps(fps)
            data.fps = fps
            command = ChangeData(self.filePath, data, _("FPS: %s") % fps)
            self._subtitleData.execute(command)

    def changeVideoPath(self, path):
        data = self.data
        if data.videoPath != path:
            data.videoPath = path
            command = ChangeData(self.filePath, data, _("Video path: %s") % path)
            self._subtitleData.execute(command)

    def offset(self, seconds):
        data = self.data
        fps = data.subtitles.fps
        if fps is None:
            log.error(_("No FPS for '%s' (empty subtitles)." % self.filePath))
            return
        ft = FrameTime(data.subtitles.fps, seconds=seconds)
        data.subtitles.offset(ft)
        command = ChangeData(self.filePath, data,
                             _("Offset by: %s") % ft.toStr())
        self._subtitleData.execute(command)

    def detectFps(self):
        data = self.data
        if data.videoPath is not None:
            fpsInfo = File.detectFpsFromMovie(data.videoPath)
            if data.videoPath != fpsInfo.videoPath or data.fps != fpsInfo.fps:
                data.videoPath = fpsInfo.videoPath
                data.subtitles.changeFps(fpsInfo.fps)
                data.fps = fpsInfo.fps
                command = ChangeData(self.filePath, data, _("Detected FPS: %s") % data.fps)
                self._subtitleData.execute(command)

    def fileChanged(self, filePath):
        if filePath == self._filePath:
            self.refreshSubtitles()

    def refreshSubtitle(self, subNo):
        sub = self.subtitles[subNo]
        self._model.removeRow(subNo)
        self._model.insertRow(subNo, createRow(sub))

    def refreshSubtitles(self):
        self._model.removeRows(0, self._model.rowCount())
        for sub in self.subtitles:
            self._model.appendRow(createRow(sub))

    def updateTab(self):
        self.refreshSubtitles()

    def selectedSubtitles(self):
        rows = self.selectedRows()
        subtitleList = [self.subtitles[row] for row in rows]
        return subtitleList

    def selectedRows(self):
        indices = self._subList.selectedIndexes()
        # unique list
        rows = list(set([index.row() for index in indices]))
        rows.sort()
        return rows

    def selectRow(self, row):
        self._subList.selectRow(row)

    @property
    def filePath(self):
        return self._filePath

    @property
    def movieFilePath(self):
        return self._movieFilePath

    @property
    def data(self):
        return self._subtitleData.data(self.filePath)

    @property
    def subtitles(self):
        return self.data.subtitles

    @property
    def history(self):
        return self._subtitleData.history(self.filePath)

    @property
    def inputEncoding(self):
        return self.data.inputEncoding

    @property
    def outputEncoding(self):
        return self.data.outputEncoding

    @property
    def outputFormat(self):
        return self.data.outputFormat
Exemple #7
0
class ReqTableWidget(QWidget):
    requestsChanged = pyqtSignal(list)
    requestsSelected = pyqtSignal(list)

    def __init__(self,
                 client,
                 repeater_widget=None,
                 macro_widget=None,
                 *args,
                 **kwargs):
        QWidget.__init__(self, *args, **kwargs)
        self.allow_save = False

        self.client = client
        self.repeater_widget = repeater_widget
        self.macro_widget = macro_widget
        self.query = []
        self.req_view_widget = None

        self.setLayout(QStackedLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.tableModel = ReqListModel(self.client)
        self.tableView = QTableView()
        self.tableView.setModel(self.tableModel)

        self.tableView.verticalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        self.tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        self.tableView.verticalHeader().hide()
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        #self.tableView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.tableView.horizontalHeader().setStretchLastSection(True)

        self.tableView.selectionModel().selectionChanged.connect(
            self.on_select_change)
        self.tableModel.dataChanged.connect(self._paint_view)
        self.tableModel.rowsInserted.connect(self._on_rows_inserted)
        self.requestsChanged.connect(self.set_requests)
        self.requestsSelected.connect(self._updated_selected_request)

        self.selected_reqs = []

        self.layout().addWidget(self.tableView)
        self.layout().addWidget(
            QLabel("<b>Loading requests from data file...</b>"))

    @pyqtSlot(HTTPRequest)
    def add_request(self, req):
        with DisableUpdates(self.tableView):
            if req.db_id != "":
                reqid = self.client.get_reqid(req)
                if self.client.check_request(self.query, reqid=reqid):
                    self.tableModel.add_request_head(req)
                if req.unmangled and req.unmangled.db_id != "" and self.tableModel.has_request(
                        req.unmangled):
                    self.tableModel.delete_request(req.unmangled)
            else:
                if self.client.check_request(self.query, req=req):
                    self.tableModel.add_request_head(req)

    @pyqtSlot()
    def clear(self):
        self.tableModel.clear()

    def get_requests(self):
        return self.tableModel.get_requests()

    @pyqtSlot(list)
    def set_requests(self, reqs, check_filter=False):
        to_add = []
        if not check_filter:
            to_add = reqs
        else:
            for req in reqs:
                if req.db_id != "":
                    reqid = self.client.get_reqid(req)
                    if self.client.check_request(self.query, reqid=reqid):
                        to_add.append(req)
                else:
                    if self.client.check_request(self.query, req=req):
                        to_add.append(req)
        with DisableUpdates(self.tableView):
            self.clear()
            self.tableModel.disable_sort()
            self.tableModel.add_requests(to_add)
            self.tableModel.enable_sort()
            self.set_is_not_loading()

    @pyqtSlot(HTTPRequest)
    def update_request(self, req):
        with DisableUpdates(self.tableView):
            self.tableModel.update_request(req)
            if req.db_id != "":
                if req.unmangled and req.unmangled.db_id != "":
                    self.tableModel.delete_request(
                        reqid=self.client.get_reqid(req.unmangled))

    @pyqtSlot(str)
    def delete_request(self, reqid):
        with DisableUpdates(self.tableView):
            self.tableModel.delete_request(reqid=reqid)

    @pyqtSlot(list)
    def set_filter(self, query):
        self.query = query
        self.set_is_loading()
        self.client.query_storage_async(self.requestsChanged,
                                        self.query,
                                        headers_only=True)

    @pyqtSlot(list)
    def _updated_selected_request(self, reqs):
        if len(reqs) > 0:
            self.selected_reqs = reqs
        else:
            self.selected_reqs = []

    @pyqtSlot(QModelIndex, int, int)
    def _on_rows_inserted(self, parent, first, last):
        rows = self.tableView.selectionModel().selectedRows()
        if len(rows) > 0:
            row = rows[0].row()
            idx = self.tableModel.index(row, 0, QModelIndex())
            self.tableView.scrollTo(idx)

    @pyqtSlot(QItemSelection, QItemSelection)
    def on_select_change(self, newSelection, oldSelection):
        reqs = []
        added = set()
        for rowidx in self.tableView.selectionModel().selectedRows():
            row = rowidx.row()
            if row not in added:
                reqs.append(self.tableModel.req_by_ind(row))
                added.add(row)
        self.requestsSelected.emit(reqs)

    @pyqtSlot()
    def clear_selection(self):
        self.tableView.clearSelection()

    def get_selected_request(self):
        # load the full request
        if len(self.selected_reqs) > 0:
            return self.client.load_by_reqheaders(self.selected_reqs[0])
        else:
            return None

    def get_selected_requests(self):
        ret = []
        for hreq in self.selected_reqs:
            ret.append(self.client.load_by_reqheaders(hreq))
        return ret

    def get_all_requests(self):
        return [
            self.client.req_by_id(self.client.get_reqid(req))
            for req in self.tableModel.get_requests()
        ]

    def contextMenuEvent(self, event):
        if len(self.selected_reqs) > 1:
            reqs = self.get_selected_requests()
            display_multi_req_context(self,
                                      self.client,
                                      reqs,
                                      event,
                                      macro_widget=self.macro_widget,
                                      save_option=self.allow_save)
        elif len(self.selected_reqs) == 1:
            req = self.get_selected_request()
            display_req_context(self,
                                self.client,
                                req,
                                event,
                                repeater_widget=self.repeater_widget,
                                req_view_widget=self.req_view_widget,
                                macro_widget=self.macro_widget,
                                save_option=self.allow_save)

    def set_is_loading(self):
        self.set_loading(True)

    def set_is_not_loading(self):
        self.set_loading(False)

    def set_loading(self, is_loading):
        with DisableUpdates(self.tableView):
            if is_loading:
                self.layout().setCurrentIndex(1)
            else:
                self.layout().setCurrentIndex(0)

    @pyqtSlot(QModelIndex, QModelIndex)
    def _paint_view(self, indA, indB):
        self.tableView.repaint()

    @pyqtSlot()
    def delete_selected(self):
        with DisableUpdates(self.tableView):
            for req in self.selected_reqs:
                self.tableModel.delete_request(req=req)
class ParamModWgt(QWidget):

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

        self.main_window = parent

        self.buildRequiredTagsGB()

        # Widgets        
        self.newParamBtn        = QPushButton("New")
        self.deleteParamBtn     = QPushButton("Delete")
        self.paramSaveAnnotBtn  = QPushButton("Save")
        buttonWidget             = QWidget(self)

        self.existingParamsGB     = QGroupBox("Existing parameters", self)

        self.paramListTblWdg      = QTableView()
        self.paramListModel     = ParameterListModel(parent=self)
        self.paramListTblWdg.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.paramListTblWdg.setSelectionMode(QAbstractItemView.SingleSelection)
        self.paramListTblWdg.setModel(self.paramListModel)

        self.paramListTblWdg.setColumnWidth(0, 150)
        self.paramListTblWdg.setColumnWidth(1, 350)

        self.relationWgt    = ParamRelationWgt(parent)
        self.newParamsGB    = QGroupBox("Parameter details", self)
        self.resultTypeCbo  = QComboBox(self)
        self.isExpProp      = QCheckBox("is an experimental property", self)

        self.resultTypeCbo.addItems(["point value", "function", "numerical trace"])
        
        self.singleValueParamWgt = ParamValueWgt(parent)
        self.functionParamWgt    = ParamFunctionWgt(parent)
        self.traceParamWgt       = ParamTraceWgt(parent)

        self.functionParamWgt.mainWgt = self

        self.paramModStack       = QStackedWidget(self)
        self.paramModStack.addWidget(self.singleValueParamWgt)
        self.paramModStack.addWidget(self.functionParamWgt)
        self.paramModStack.addWidget(self.traceParamWgt)

        # Signals
        selectionModel = self.paramListTblWdg.selectionModel()
        selectionModel.selectionChanged.connect(self.selectedParameterChanged)

        self.newParamBtn.clicked.connect(self.newParameter)
        self.deleteParamBtn.clicked.connect(self.deleteParameter)
        self.paramSaveAnnotBtn.clicked.connect(self.saveParameter)
        self.resultTypeCbo.currentIndexChanged.connect(self.paramModStack.setCurrentIndex)
        self.singleValueParamWgt.paramTypeSelected.connect(self.newParamTypeSelected)
        self.functionParamWgt.paramTypeSelected.connect(self.newParamTypeSelected)
        self.traceParamWgt.paramTypeSelected.connect(self.newParamTypeSelected)

        # Layout
        buttonLayout = QVBoxLayout(buttonWidget)
        buttonLayout.addWidget(self.paramSaveAnnotBtn)
        buttonLayout.addWidget(self.deleteParamBtn)
        buttonLayout.addWidget(self.newParamBtn)

        existGrid     = QHBoxLayout(self.existingParamsGB)
        existGrid.addWidget(buttonWidget)
        existGrid.addWidget(self.paramListTblWdg)
        
        newGrid     = QGridLayout(self.newParamsGB)
        newGrid.addWidget(QLabel("Result type"), 0, 0)
        newGrid.addWidget(self.resultTypeCbo, 0, 1)
        newGrid.addWidget(self.isExpProp, 0, 2)
        
        newGrid.addWidget(self.paramModStack, 1, 0, 1, 3)
        newGrid.addWidget(self.relationWgt, 1, 3)

        layout = QVBoxLayout(self)
        self.rootLayout = QSplitter(Qt.Vertical, self)
        self.rootLayout.setOrientation(Qt.Vertical)
        self.rootLayout.addWidget(self.existingParamsGB)
        self.rootLayout.addWidget(self.newParamsGB)
        self.rootLayout.addWidget(self.requireTagGB)
        layout.addWidget(self.rootLayout)

        # Initial behavior
        self.newParamBtn.setEnabled(True)
        self.deleteParamBtn.setEnabled(False)
        self.paramSaveAnnotBtn.setEnabled(False)
        self.additionMode = False
        self.newParamsGB.setEnabled(False)

    def setRootLayoutSizes(self, sizes):
        self.rootLayout.setSizes(sizes)


    def viewParameter(self, parameter):
        row = -1
        for row, param in enumerate(self.paramListModel.parameterList):
            if param.id == parameter.id:
                break
        assert(row > -1)
        self.paramListTblWdg.selectRow(row)

        

    @pyqtSlot(str)
    def newParamTypeSelected(self, paramName):
        self.requiredTagsListModel.clear()
        self.requiredTagsListModel.refresh()

        paramType  = getParameterTypeFromName(paramName)
        if paramType is None:
            raise ValueError("Parameter type with name '" + paramName + "' was not found.")

        for reqTag in paramType.requiredTags:
            self.requiredTagsListModel.addTag(reqTag.id, reqTag.name, reqTag.id, reqTag.name)

        self.requiredTagsListModel.refresh()


    def buildRequiredTagsGB(self):

        # Widgets            
        self.requireTagGB = QGroupBox("Required tag categories", self)

        self.requiredTagsListTblWdg      = RequiredTagsTableView() 
        self.requiredTagsListModel       = RequiredTagsListModel(parent=self)
        self.requiredTagsListTblWdg.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.requiredTagsListTblWdg.setSelectionMode(QAbstractItemView.SingleSelection)
        self.requiredTagsListTblWdg.setModel(self.requiredTagsListModel)
        self.requiredTagsListTblWdg.setColumnWidth(0, 200)
        self.requiredTagsListTblWdg.setColumnWidth(1, 200)

        # Layout
        requiredTagLayout = QGridLayout(self.requireTagGB)
        requiredTagLayout.addWidget(self.requiredTagsListTblWdg, 0, 0, 4, 1)


    def newParameter(self):
        self.resultTypeCbo.setCurrentIndex(0)
        self.paramModStack.currentWidget().newParameter()
        
        self.singleValueParamWgt.newParameter()
        self.functionParamWgt.newParameter()
        self.traceParamWgt.newParameter()       
        
        self.newParamsGB.setEnabled(True)
        self.paramListTblWdg.clearSelection()

        self.newParamBtn.setEnabled(False)
        self.deleteParamBtn.setEnabled(False)
        self.paramSaveAnnotBtn.setEnabled(True)

        self.isExpProp.setChecked(False)


    def saveParameter(self):

        relationship = self.relationWgt.getRelationship()
        
        # Get the ID of the modified parameter if we are modifying an existing
        # parameters        
        if len(self.paramListTblWdg.selectionModel().selectedRows()) != 0:
            selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row()
            paramId = self.main_window.currentAnnotation.parameters[selectedRow].id
        else:
            paramId = None
        
        param = self.paramModStack.currentWidget().saveParameter(relationship, paramId)

        if not param is None:
            param.requiredTags             = self.requiredTagsListModel.getRequiredTags()
            param.isExperimentProperty     = self.isExpProp.isChecked()

            selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row()
            # Even when there is no selection, selectedRow can take a zero value. This "if" 
            # controls for that.
            if len(self.paramListTblWdg.selectionModel().selectedRows()) == 0:
                selectedRow = -1

            if selectedRow >= 0:
                self.main_window.currentAnnotation.parameters[selectedRow] = param
            else:
                self.main_window.currentAnnotation.parameters.append(param)

            self.additionMode = False
            nbParams = len(self.main_window.currentAnnotation.parameters)
            self.main_window.saveAnnotation()

            if selectedRow < 0 :
                selectedRow = nbParams-1
            self.paramListTblWdg.selectRow(selectedRow)
            self.loadRow(selectedRow)     



    def deleteParameter(self):
        selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row()
        del self.main_window.currentAnnotation.parameters[selectedRow]
        self.main_window.saveAnnotation()
        self.refreshModelingParameters()


    def refreshModelingParameters(self):
        selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row()
        self.loadModelingParameter(selectedRow)


    def loadModelingParameter(self, row = None):
        """
         Call when a new annotation has been selected so that all the modeling parameters
         associated with this annotation are loaded in the parameter list. 
        """

        self.requiredTagsListModel.clear()
        self.requiredTagsListModel.refresh()

        if self.main_window.currentAnnotation is None:
            self.paramListModel.parameterList = []
        else:
            self.paramListModel.parameterList = self.main_window.currentAnnotation.parameters

            aRowIsSelected = not row is None
            if aRowIsSelected:
                if row < 0:
                    noRowToLoad = self.paramListTblWdg.model().rowCount()-row
                else:
                    noRowToLoad = row
            else:
                ## No rows are selected
                noRowToLoad = -1
            
            self.loadRow(noRowToLoad)
            self.newParamBtn.setEnabled(True)
            self.deleteParamBtn.setEnabled(aRowIsSelected)
            self.paramSaveAnnotBtn.setEnabled(aRowIsSelected)
            self.paramModStack.currentWidget().loadModelingParameter(row)
            self.relationWgt.loadModelingParameter(row)

            self.newParamsGB.setEnabled(aRowIsSelected)
        
        self.paramListModel.refresh()


    def loadRow(self, selectedRow = None):
        """
         Called when a row has been selected in the table listing all the modeling parameters.
         It update the interface with the values associated with this specific parameter.
        """
        
        def nlxCheck(id):
            if id in nlx2ks:
                return nlx2ks[id]
            return id
            
        def clear():
            self.requiredTagsListModel.clear()
            self.paramModStack.currentWidget().loadRow(None)
            self.relationWgt.clear()        
            self.paramListTblWdg.clearSelection()

        if selectedRow is None:
            selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row()
        
        if self.main_window.currentAnnotation is None:
            clear()
            return
        
        if selectedRow < 0 or selectedRow >= len(self.main_window.currentAnnotation.parameters) :
            clear()
            return
            
        currentParameter = self.main_window.currentAnnotation.parameters[selectedRow]
    
        self.newParamBtn.setEnabled(True)
        self.deleteParamBtn.setEnabled(True)
        self.paramSaveAnnotBtn.setEnabled(True)

        if currentParameter.description.type == "pointValue":
            self.resultTypeCbo.setCurrentIndex(0)
            self.paramModStack.setCurrentIndex(0)
        elif currentParameter.description.type == "function": 
            self.resultTypeCbo.setCurrentIndex(1)
            self.paramModStack.setCurrentIndex(1)
        elif currentParameter.description.type == "numericalTrace": 
            self.resultTypeCbo.setCurrentIndex(2)
            self.paramModStack.setCurrentIndex(2)
        else:
            raise ValueError("Type of parameter description " + currentParameter.description.type + " is invalid.")

        self.paramModStack.currentWidget().loadRow(currentParameter)
        self.relationWgt.loadRow(currentParameter)
        self.isExpProp.setChecked(currentParameter.isExperimentProperty)

        ## UPDATING REQUIRED TAGS
        self.requiredTagsListModel.clear()       
        for tag in currentParameter.requiredTags:        
            self.requiredTagsListModel.addTag(tag.rootId, self.main_window.dicData[tag.rootId], tag.id, tag.name)
        
        ## Adding new required tags that may have been specified since the 
        ## creation of this parameter instance.
        parameterType = getParameterTypeFromID(currentParameter.typeId)
        reqTags = {reqTag.rootId:reqTag for reqTag in parameterType.requiredTags}
        for reqTagRootId, reqTag in reqTags.items():
            #print(nlxCheck(reqTagRootId), [nlxCheck(tag.rootId) for tag in currentParameter.requiredTags])
            if not nlxCheck(reqTagRootId) in [nlxCheck(tag.rootId) for tag in currentParameter.requiredTags]:
                self.requiredTagsListModel.addTag(reqTag.rootId, self.main_window.dicData[reqTag.rootId], reqTag.id, reqTag.name)
            
        self.requiredTagsListModel.refresh()

        self.newParamsGB.setEnabled(True)


    def selectedParameterChanged(self, selected, deselected):
        if len(selected.indexes()) == 0:
            return
        if self.additionMode:
            msgBox = QMessageBox(self)
            msgBox.setWindowTitle("Cancellation")
            msgBox.setText("Are you sure you want to cancel the addition of the new parameter being edited? If not, say no and then hit 'Save' to save this new parameter.")
            msgBox.setStandardButtons(QMessageBox.No | QMessageBox.Yes)
            msgBox.setDefaultButton(QMessageBox.No)
            if msgBox.exec_() == QMessageBox.Yes:
                self.additionMode = False
                self.loadRow()
            else:
                #self.paramListTblWdg.selectRow(-1)
                self.paramListTblWdg.clearSelection()
        else:
            self.loadRow()
Exemple #9
0
class DataTab(QScrollArea):
    def __init__(self, parent=None):
        super().__init__(parent)

    def display(self, path: str):
        self.tab = TabsWidget.QUERY_TAB_INDEX
        self.initial_query: Query = None
        self.initial_result_set: DataFrame = None
        self.rfd: RFD = None
        self.extended_query: Query = None
        self.extended_result_set: DataFrame = None
        self.relaxed_query: Query = None
        self.relaxed_result_set: DataFrame = None

        self.setWidgetResizable(True)
        self.setLayout(QVBoxLayout())

        self.csv_parser: CSVParser = CSVParser(path)
        self.data_frame: DataFrame = self.csv_parser.data_frame

        self.table = QTableView()
        pandas_model: QAbstractTableModel = PandasTableModel(
            self.data_frame, self)
        self.table.setModel(pandas_model)
        self.table.setSortingEnabled(False)
        self.table.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)  # full width table
        self.table.setSelectionMode(QAbstractItemView.MultiSelection)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)

        delegate = ItemDelegate(self)
        self.table.setItemDelegate(delegate)
        self.table.horizontalHeader().setSectionsClickable(False)
        self.table.verticalHeader().setSectionsClickable(False)

        for i in reversed(range(self.layout().count())):
            self.layout().itemAt(i).widget().deleteLater()

        self.extent_label: QLabel = QLabel('Extent percentage: 0%')
        self.layout().addWidget(self.extent_label)

        self.layout().addWidget(self.table)

    def set_initial_query_subject(self, query_subject: Subject):
        self.initial_query_subject: Subject = query_subject

        self.initial_query_subject.subscribe(
            on_next=lambda query: (self.__update_initial_query(query)))

    def __update_initial_query(self, query: Query):
        print("Update initial query:")
        self.initial_query: Query = query
        self.initial_result_set: DataFrame = self.data_frame.query(
            self.initial_query.to_expression())

        self.__highlight_initial_query()

    def __highlight_initial_query(self):
        if self.tab == TabsWidget.QUERY_TAB_INDEX:
            if hasattr(self, "table") and self.table:
                self.table.clearSelection()

            if hasattr(self, "initial_result_set"
                       ) and self.initial_result_set is not None:
                df_indexes = self.initial_result_set.index.values.tolist()

                for index in df_indexes:
                    self.table.selectRow(index)

                extent_percentage = self.initial_result_set.shape[
                    0] / self.data_frame.shape[0]
                self.extent_label.setText('Extent percentage: ' +
                                          str(round(extent_percentage *
                                                    100, 2)) + '%')
            elif hasattr(self, 'extent_label'):
                self.extent_label.setText('Extent percentage: 0%')

    def set_rfd_subject(self, rfd_subject: Subject):
        self.rfd_subject: Subject = rfd_subject
        self.rfd_subject.subscribe(
            on_next=lambda rfd: (self.__update_selected_rfd(rfd)))

    def __update_selected_rfd(self, rfd: RFD):
        print("Update selected RFD...")
        self.rfd: RFD = rfd

        self.__highlight_rfd()

    def __highlight_rfd(self):
        if self.tab == TabsWidget.RFDS_TAB_INDEX:
            if hasattr(self, "table") and self.table:
                self.table.clearSelection()

            if hasattr(
                    self,
                    "data_frame") and self.data_frame is not None and self.rfd:
                rfd_df_indexes = RFDExtent.extent_indexes(
                    self.data_frame, self.rfd)
                for index in rfd_df_indexes:
                    self.table.selectRow(index)

                extent_percentage = len(
                    rfd_df_indexes) / self.data_frame.shape[0]
                self.extent_label.setText('Extent percentage: ' +
                                          str(round(extent_percentage *
                                                    100, 2)) + '%')
            elif hasattr(self, "extent_label"):
                self.extent_label.setText('Extent percentage: 0%')

    def set_extended_query_subject(self, query_subject: Subject):
        self.extended_query_subject: Subject = query_subject

        self.extended_query_subject.subscribe(
            on_next=lambda query: (self.__update_extended_query(query)))

    def __update_extended_query(self, query: Query):
        print("Update extended query...")
        self.extended_query: Query = query
        self.extended_result_set: DataFrame = self.data_frame.query(
            self.extended_query.to_expression())

        self.__highlight_extended_query()

    def __highlight_extended_query(self):
        if self.tab == TabsWidget.EXTENSION_TAB_INDEX:
            if hasattr(self, "table") and self.table:
                self.table.clearSelection()

            if hasattr(self, "extended_result_set"
                       ) and self.extended_result_set is not None:
                df_indexes = self.extended_result_set.index.values.tolist()

                for index in df_indexes:
                    self.table.selectRow(index)

                extent_percentage = self.extended_result_set.shape[
                    0] / self.data_frame.shape[0]
                self.extent_label.setText('Extent percentage: ' +
                                          str(round(extent_percentage *
                                                    100, 2)) + '%')
            elif hasattr(self, 'extent_label'):
                self.extent_label.setText('Extent percentage: 0%')

    def set_relaxed_query_subject(self, query_subject: Subject):
        self.relaxed_query_subject: Subject = query_subject

        self.relaxed_query_subject.subscribe(
            on_next=lambda query: (self.__update_relaxed_query(query)))

    def __update_relaxed_query(self, query: Query):
        print("Update relaxed query...")
        self.relaxed_query: Query = query
        self.relaxed_result_set: DataFrame = self.data_frame.query(
            self.relaxed_query.to_expression())

        self.__highlight_relaxed_query()

    def __highlight_relaxed_query(self):
        if self.tab == TabsWidget.RELAX_TAB_INDEX:
            if hasattr(self, "table") and self.table:
                self.table.clearSelection()

            if hasattr(self, "relaxed_result_set"
                       ) and self.relaxed_result_set is not None:
                df_indexes = self.relaxed_result_set.index.values.tolist()

                for index in df_indexes:
                    self.table.selectRow(index)

                extent_percentage = self.relaxed_result_set.shape[
                    0] / self.data_frame.shape[0]
                self.extent_label.setText('Extent percentage: ' +
                                          str(round(extent_percentage *
                                                    100, 2)) + '%')
            elif hasattr(self, 'extent_label'):
                self.extent_label.setText('Extent percentage: 0%')

    def onTabChange(self, index):
        print("DataTab: On Tab Change...")
        if index == TabsWidget.QUERY_TAB_INDEX:
            print("Query TAB")
            self.tab = TabsWidget.QUERY_TAB_INDEX
            self.__highlight_initial_query()
        elif index == TabsWidget.RFDS_TAB_INDEX:
            print("RFD TAB")
            self.tab = TabsWidget.RFDS_TAB_INDEX
            self.__highlight_rfd()
        elif index == TabsWidget.EXTENSION_TAB_INDEX:
            print("Extension TAB")
            self.tab = TabsWidget.EXTENSION_TAB_INDEX
            self.__highlight_extended_query()
        elif index == TabsWidget.RELAX_TAB_INDEX:
            print("Relax TAB")
            self.tab = TabsWidget.RELAX_TAB_INDEX
            self.__highlight_relaxed_query()
class GDriveTableController(QObject):

    did_change_path = pyqtSignal()

    def __init__(self, folder_id="root"):
        super().__init__()
        self._file_thread = None
        self.table_view = QTableView()
        self.files = []
        self._model = gdrive_table_model.GDriveTableModel()
        self.table_view.setModel(self._model)
        self._set_table_view_style()
        self._connect_table_view_signals()
        self._update_files(folder_id)
        self.path = [file_handler.get_gdrive_file(folder_id)]

    def _set_table_view_style(self):
        self.table_view.verticalHeader().hide()
        self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table_view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table_view.setShowGrid(False)
        self.table_view.setUpdatesEnabled(True)
        self.table_view.setColumnWidth(0, 230)
        self.table_view.setColumnWidth(1, 150)
        self.table_view.setColumnWidth(2, 120)

        vertical_header = self.table_view.verticalHeader()
        vertical_header.setSectionResizeMode(QHeaderView.Fixed)
        vertical_header.setDefaultSectionSize(24)

        horizontal_header = self.table_view.horizontalHeader()
        horizontal_header.setHighlightSections(False)
        # horizontal_header.setSectionResizeMode()

    def _connect_table_view_signals(self):
        selectionModel = self.table_view.selectionModel()
        selectionModel.currentRowChanged.connect(self.did_select_row_index)

        self.table_view.doubleClicked.connect(self.did_double_click_row_index)

    def _update_files(self, folder_id):

        def did_get_files(files):
            self.files = files
            self._model.load_files(self.files)
            self._model.refresh()
            # self.table_view.viewport().update()
            self._set_loading_mode(False)

        def error_occurred(error):
            print(error)

        if self._file_thread == None:
            self._file_thread = FileThread()
            self._file_thread.did_get_files.connect(did_get_files)
            self._file_thread.error_occurred.connect(error_occurred)

        self._file_thread.file_id = folder_id
        self._set_loading_mode(True)
        self._file_thread.run()

    def _set_loading_mode(self, is_loading):
        if is_loading:
            self.table_view.setEnabled(False)
        else :
            self.table_view.setEnabled(True)

    def did_double_click_row_index(self, index):
        row = index.row()
        file = self.files[row]
        if file.is_folder:
            self.path.append(file)
            self._update_files(str(file.id))
            self.table_view.clearSelection()
            self.did_change_path.emit()

    def did_select_row_index(self, index):
        row = index.row()
        # print("row changed to " + str(row))

    def go_back(self):
        if len(self.path) > 1:
            self.path.pop()
            self._update_files(str(self.path[-1].id))
            self.table_view.clearSelection()
            self.did_change_path.emit()
Exemple #11
0
class StickyLoad(QDialog):
    def __init__(self):
        super().__init__()
        self.resize(600, 400)
        # Получение id стикера для загрузки
        self.setLayout(self.myLayout())
        # Словарь горячих клавиш
        self.hotkeys = {
            (Qt.Key_W, int(Qt.ControlModifier)): self.close,
            (Qt.Key_Q, int(Qt.ControlModifier)): qApp.myQuit,
            (Qt.Key_Enter - 1, int(Qt.NoModifier)): self.getSIDandClose,
            (Qt.Key_Delete, int(Qt.NoModifier)): self.deleteRow
        }
        self.view.doubleClicked.connect(self.getSIDandClose)
        self.exec_()

    def myLayout(self):
        qmodel = QtSql.QSqlQueryModel()
        qmodel.setQuery("select id, text from sticky order by id desc")
        self.view = QTableView(self)
        self.view.setModel(qmodel)
        self.view.verticalHeader().hide()
        self.view.resizeColumnToContents(0)
        self.view.horizontalHeader().setStretchLastSection(True)
        self.view.setSelectionBehavior(QTableView.SelectRows)
        self.view.setSelectionMode(QTableView.SingleSelection)
        self.view.selectRow(0)
        layout = QVBoxLayout()
        layout.addWidget(self.view)
        layout.setContentsMargins(0, 0, 0, 0)
        return layout

    def getSID(self):
        index = self.view.selectedIndexes()[0]
        self.sid = self.view.model().data(index)

    def getSIDandClose(self):
        self.getSID()
        self.close()

    def keyPressEvent(self, event):
        self.hotkeys.get((event.key(), int(event.modifiers())), lambda: None)()

    def deleteRow(self):
        self.getSID()
        qmodel = QtSql.QSqlQueryModel()
        qmodel.setQuery("delete from sticky where id = {}".format(self.sid))
        deletedRow = self.view.selectedIndexes()[0].row()
        for x in (i for j in (range(deletedRow + 1,
                                    self.view.model().rowCount()),
                              range(deletedRow - 1, -1, -1)) for i in j):
            if self.view.isRowHidden(x):
                continue
            rowToSelecet = x
            break
        try:
            self.view.selectRow(rowToSelecet)
        except:
            self.view.clearSelection()
        self.view.hideRow(deletedRow)
        del self.sid

    def __repr__(self):
        return repr(self.sid)
Exemple #12
0
class Viewer(QMainWindow):
    def __init__(self, parent=None):
        super(Viewer, self).__init__(parent)
        self.MaxRecentFiles = 5
        self.windowList = []
        self.recentFiles = []
        self.settings = QSettings('Axel Schneider', 'QTableViewPandas')
        self.filename = ""
        self.setGeometry(0, 0, 800, 600)
        self.lb = QTableView()
        self.lb.verticalHeader().setVisible(True)
        self.lb.setGridStyle(1)
        self.model = PandasModel()
        self.lb.setModel(self.model)
        self.lb.setEditTriggers(QAbstractItemView.DoubleClicked)
        self.lb.setSelectionBehavior(self.lb.SelectRows)
        self.lb.setSelectionMode(self.lb.SingleSelection)
        self.setStyleSheet(stylesheet(self))
        self.lb.setAcceptDrops(True)
        self.setCentralWidget(self.lb)
        self.setContentsMargins(10, 10, 10, 10)
        self.createToolBar()
        self.readSettings()
        self.lb.setFocus()
        self.statusBar().showMessage("Ready", 0)

    def readSettings(self):
        print("reading settings")
        if self.settings.contains("geometry"):
            self.setGeometry(self.settings.value('geometry'))
        if self.settings.contains("recentFiles"):
            self.recentFiles = self.settings.value('recentFiles')
            self.lastFiles.addItem("last Files")
            self.lastFiles.addItems(self.recentFiles[:15])

    def saveSettings(self):
        print("saving settings")
        self.settings.setValue('geometry', self.geometry())
        self.settings.setValue('recentFiles', self.recentFiles)

    def closeEvent(self, event):
        print(self.model.setChanged)
        if self.model.setChanged == True:
            print("is changed, saving?")
            quit_msg = "<b>The document was changed.<br>Do you want to save the changes?</ b>"
            reply = QMessageBox.question(self, 'Save Confirmation', quit_msg,
                                         QMessageBox.Yes | QMessageBox.No,
                                         QMessageBox.Yes)
            if reply == QMessageBox.Yes:
                self.writeCSV_update()
            else:
                print("not saved, goodbye ...")
                return
        else:
            print("nothing changed. goodbye")
        self.saveSettings()

    def createToolBar(self):
        openAction = QAction(QIcon.fromTheme("document-open"),
                             "Open",
                             self,
                             triggered=self.loadCSV,
                             shortcut=QKeySequence.Open)
        saveAction = QAction(QIcon.fromTheme("document-save"),
                             "Save",
                             self,
                             triggered=self.writeCSV_update,
                             shortcut=QKeySequence.Save)
        saveAsAction = QAction(QIcon.fromTheme("document-save-as"),
                               "Save as ...",
                               self,
                               triggered=self.writeCSV,
                               shortcut=QKeySequence.SaveAs)
        self.tbar = self.addToolBar("File")
        self.tbar.setContextMenuPolicy(Qt.PreventContextMenu)
        self.tbar.setIconSize(QSize(16, 16))
        self.tbar.setMovable(False)
        self.tbar.addAction(openAction)
        self.tbar.addAction(saveAction)
        self.tbar.addAction(saveAsAction)

        empty = QWidget()
        empty.setFixedWidth(10)
        self.tbar.addWidget(empty)

        self.lastFiles = QComboBox()
        self.lastFiles.setFixedWidth(300)
        self.lastFiles.currentIndexChanged.connect(self.loadRecent)
        self.tbar.addWidget(self.lastFiles)

        empty = QWidget()
        empty.setFixedWidth(10)
        self.tbar.addWidget(empty)

        findbyText = QAction(QIcon.fromTheme("edit-find-symbolic"),
                             "find",
                             self,
                             triggered=self.findInTable)
        self.lineFind = QLineEdit()
        self.lineFind.addAction(findbyText, 0)
        self.lineFind.setPlaceholderText("find")
        self.lineFind.setClearButtonEnabled(True)
        self.lineFind.setFixedWidth(250)
        self.lineFind.returnPressed.connect(self.findInTable)
        self.tbar.addWidget(self.lineFind)
        self.tbar.addAction(findbyText)

        empty = QWidget()
        empty.setFixedWidth(10)
        self.tbar.addWidget(empty)

        self.previewAction = QAction(QIcon.fromTheme("document-print-preview"),
                                     "print",
                                     self,
                                     triggered=self.handlePreview)
        self.tbar.addAction(self.previewAction)
        self.printAction = QAction(QIcon.fromTheme("document-print"),
                                   "print",
                                   self,
                                   triggered=self.handlePrint)
        self.tbar.addAction(self.printAction)

    def loadRecent(self):
        if self.lastFiles.currentIndex() > 0:
            print(self.lastFiles.currentText())
            print(self.model.setChanged)
            if self.model.setChanged == True:
                print("is changed, saving?")
                quit_msg = "<b>The document was changed.<br>Do you want to save the changes?</ b>"
                reply = QMessageBox.question(self, 'Save Confirmation',
                                             quit_msg,
                                             QMessageBox.Yes | QMessageBox.No,
                                             QMessageBox.Yes)
                if reply == QMessageBox.Yes:
                    self.openCSV(self.lastFiles.currentText())
                else:
                    self.openCSV(self.lastFiles.currentText())
            else:
                self.openCSV(self.lastFiles.currentText())

    def openCSV(self, path):
        f = open(path, 'r+b')
        with f:
            df = pd.read_csv(f,
                             delimiter='\t',
                             keep_default_na=False,
                             low_memory=False,
                             header=None)
            f.close()
            self.model = PandasModel(df)
            self.lb.setModel(main.model)
            self.lb.resizeColumnsToContents()
            self.lb.selectRow(0)
            self.statusBar().showMessage("%s %s" % (path, "loaded"), 0)

    def findInTable(self):
        self.lb.clearSelection()
        text = self.lineFind.text()
        model = self.lb.model()
        for column in range(self.model.columnCount()):
            start = model.index(0, column)
            matches = model.match(start, Qt.DisplayRole, text, -1,
                                  Qt.MatchContains)
            if matches:
                for index in matches:
                    print(index.row(), index.column())
                    self.lb.selectionModel().select(index,
                                                    QItemSelectionModel.Select)

    def openFile(self, path=None):
        print(self.model.setChanged)
        if self.model.setChanged == True:
            print("is changed, saving?")
            quit_msg = "<b>The document was changed.<br>Do you want to save the changes?</ b>"
            reply = QMessageBox.question(self, 'Save Confirmation', quit_msg,
                                         QMessageBox.Yes | QMessageBox.No,
                                         QMessageBox.Yes)
            if reply == QMessageBox.Yes:
                self.writeCSV_update()
            else:
                print("not saved, loading ...")
                return
        path, _ = QFileDialog.getOpenFileName(
            self, "Open File",
            QDir.homePath() + "/Dokumente/CSV/", "CSV Files (*.csv)")
        if path:
            return path

    def loadCSV(self):
        fileName = self.openFile()
        if fileName:
            print(fileName + " loaded")
            f = open(fileName, 'r+b')
            with f:
                df = pd.read_csv(f,
                                 delimiter='\t',
                                 keep_default_na=False,
                                 low_memory=False,
                                 header=None)
                f.close()
                self.model = PandasModel(df)
                self.lb.setModel(self.model)
                self.lb.resizeColumnsToContents()
                self.lb.selectRow(0)
        self.statusBar().showMessage("%s %s" % (fileName, "loaded"), 0)
        self.recentFiles.insert(0, fileName)
        self.lastFiles.insertItem(1, fileName)

    def writeCSV(self):
        fileName, _ = QFileDialog.getSaveFileName(self, "Open File",
                                                  self.filename,
                                                  "CSV Files (*.csv)")
        if fileName:
            print(fileName + " saved")
            f = open(fileName, 'w')
            newModel = self.model
            dataFrame = newModel._df.copy()
            dataFrame.to_csv(f, sep='\t', index=False, header=False)

    def writeCSV_update(self):
        if self.filename:
            f = open(self.filename, 'w')
            newModel = self.model
            dataFrame = newModel._df.copy()
            dataFrame.to_csv(f, sep='\t', index=False, header=False)
            self.model.setChanged = False
            print("%s %s" % (self.filename, "saved"))
            self.statusBar().showMessage("%s %s" % (self.filename, "saved"), 0)

    def handlePrint(self):
        if self.model.rowCount() == 0:
            self.msg("no rows")
        else:
            dialog = QtPrintSupport.QPrintDialog()
            if dialog.exec_() == QDialog.Accepted:
                self.handlePaintRequest(dialog.printer())
                print("Document printed")

    def handlePreview(self):
        if self.model.rowCount() == 0:
            self.msg("no rows")
        else:
            dialog = QtPrintSupport.QPrintPreviewDialog()
            dialog.setFixedSize(1000, 700)
            dialog.paintRequested.connect(self.handlePaintRequest)
            dialog.exec_()
            print("Print Preview closed")

    def handlePaintRequest(self, printer):
        printer.setDocName(self.filename)
        document = QTextDocument()
        cursor = QTextCursor(document)
        model = self.lb.model()
        tableFormat = QTextTableFormat()
        tableFormat.setBorder(0.2)
        tableFormat.setBorderStyle(3)
        tableFormat.setCellSpacing(0)
        tableFormat.setTopMargin(0)
        tableFormat.setCellPadding(4)
        table = cursor.insertTable(model.rowCount() + 1, model.columnCount(),
                                   tableFormat)
        model = self.lb.model()
        ### get headers
        myheaders = []
        for i in range(0, model.columnCount()):
            myheader = model.headerData(i, Qt.Horizontal)
            cursor.insertText(str(myheader))
            cursor.movePosition(QTextCursor.NextCell)
        ### get cells
        for row in range(0, model.rowCount()):
            for col in range(0, model.columnCount()):
                index = model.index(row, col)
                cursor.insertText(str(index.data()))
                cursor.movePosition(QTextCursor.NextCell)
        document.print_(printer)
class Viewer(QMainWindow):
    def __init__(self, parent=None):
      super(Viewer, self).__init__(parent)
      self.filename = ""
      self.fname = ""
      self.csv_file = ''
      self.isChanged = False
      self.mychannels_file = 'myradio.txt'
      self.mychannels_file_backup = 'myradio.txt_backup'
      self.setGeometry(0, 0, 1000, 600)
      self.lb = QTableView()
      self.lb.horizontalHeader().hide()
      self.model = QStandardItemModel()
      self.lb.setModel(self.model)
      self.model.itemChanged.connect(self.finishedEdit)
      self.lb.setEditTriggers(QAbstractItemView.DoubleClicked)
      self.lb.setSelectionBehavior(self.lb.SelectRows)
      self.lb.setSelectionMode(self.lb.SingleSelection)
      self.lb.setDragDropMode(self.lb.InternalMove)
      self.setStyleSheet(stylesheet(self))
      self.lb.setAcceptDrops(True)
      self.setCentralWidget(self.lb)
      self.setContentsMargins(10, 10, 10, 10)
      self.statusBar().showMessage("Willkommen", 0)
      self.setWindowTitle("myRadio Listeneditor")
      self.setWindowIcon(QIcon.fromTheme("multimedia-playlist"))
      #self.createMenuBar()
      self.createToolBar()
      self.create_backup()
      self.show()
      print("Hello")
      self.open_channels(self.mychannels_file)
      self.lb.setFocus()
      
    def finishedEdit(self):
        self.isChanged = True
      
    def setChanged(self):
        self.isChanged = True
      
    def msgbox(self, message):
        msg = QMessageBox(2, "Information", message, QMessageBox.Ok)
        msg.exec()

      
    def create_backup(self):
        if shutil.copyfile(self.mychannels_file, self.mychannels_file_backup):
            self.msgbox('myradio.txt_backup wurde erstellt')

    def closeEvent(self, event):
        print(self.isChanged)
        if  self.isChanged == True:
            quit_msg = "<b>Das Dokument wurde geändert.<br>Wollen Sie die Änderungen speichern?</ b>"
            reply = QMessageBox.question(self, 'Speichern', 
                     quit_msg, QMessageBox.Yes, QMessageBox.No)
            if reply == QMessageBox.Yes:
                event.accept()
                self.save_file(self.filename)
        else:
            print("keine Änderungen.")

    def createMenuBar(self):
        bar=self.menuBar()
        self.filemenu=bar.addMenu("Datei")
        self.separatorAct = self.filemenu.addSeparator()
        self.filemenu.addAction(QIcon.fromTheme("document-open"), "Datei öffnen",  self.openFile, QKeySequence.Open) 
        self.filemenu.addAction(QIcon.fromTheme("document-save-as"), "Speichern als ...",  self.writeCSV, QKeySequence.SaveAs) 

    def createToolBar(self):
        tb = self.addToolBar("Werkzeuge")
        tb.setIconSize(QSize(16, 16))
        
        self.findfield = QLineEdit(placeholderText = "finden ...")
        self.findfield.setClearButtonEnabled(True)
        self.findfield.setFixedWidth(200)
        tb.addWidget(self.findfield)
        
        tb.addSeparator()
        
        self.replacefield = QLineEdit(placeholderText = "ersetzen mit ...")
        self.replacefield.setClearButtonEnabled(True)
        self.replacefield.setFixedWidth(200)
        tb.addWidget(self.replacefield)
        
        tb.addSeparator()
        
        btn = QToolButton()
        btn.setText("alles ersetzen")
        btn.setToolTip("alles ersetzen")
        btn.clicked.connect(self.replace_in_table)
        tb.addWidget(btn)
        
        tb.addSeparator()

        del_btn = QToolButton()
        del_btn.setIcon(QIcon.fromTheme("edit-delete"))
        del_btn.setToolTip("Zeile löschen")
        del_btn.clicked.connect(self.del_row)
        tb.addWidget(del_btn)
        
        tb.addSeparator()
        
        add_btn = QToolButton()
        add_btn.setIcon(QIcon.fromTheme("add"))
        add_btn.setToolTip("Zeile hinzufügen")
        add_btn.clicked.connect(self.add_row)
        tb.addWidget(add_btn)

        move_down_btn = QToolButton()
        move_down_btn.setIcon(QIcon.fromTheme("down"))
        move_down_btn.setToolTip("nach unten bewegen")
        move_down_btn.clicked.connect(self.move_down)
        tb.addWidget(move_down_btn)
        
        move_up_up = QToolButton()
        move_up_up.setIcon(QIcon.fromTheme("up"))
        move_up_up.setToolTip("nach oben bewegen")
        move_up_up.clicked.connect(self.move_up)
        tb.addWidget(move_up_up)
        
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, 0)
        tb.addWidget(spacer)
        
        self.filter_field = QLineEdit(placeholderText = "Filtern (Enter drücken)")
        self.filter_field.setClearButtonEnabled(True)
        self.filter_field.setToolTip("Suchbegriff einfügen und Enter drücken")
        self.filter_field.setFixedWidth(200)
        self.filter_field.returnPressed.connect(self.filter_table)
        self.filter_field.textChanged.connect(self.update_filter)
        tb.addWidget(self.filter_field)
        
        
    def move_down(self):
        if self.model.rowCount() < 1:
            return
        row = self.lb.selectionModel().selection().indexes()[0].row()
        if row > self.model.rowCount() - 2:
            return
        nextrow = row + 1
        itemList = self.model.takeRow(row)
        self.model.insertRow(nextrow,itemList)
        self.isChanged = True
        self.lb.selectRow(nextrow)
        
    def move_up(self):
        if self.model.rowCount() < 1:
            return
        row = self.lb.selectionModel().selection().indexes()[0].row()
        if row < 1:
            return
        nextrow = row - 1
        itemList = self.model.takeRow(row)
        self.model.insertRow(nextrow,itemList)
        self.isChanged = True
        self.lb.selectRow(nextrow)
        
    def del_row(self): 
        if self.model.rowCount() < 1:
            return
        row = self.lb.selectionModel().selection().indexes()[0].row()
        self.model.takeRow(row)
        self.isChanged = True
        self.lb.selectRow(row)
            
    def add_row(self): 
        if self.model.rowCount() < 1:
            return
        print("Zeile hinzufügen")
        newrow = ['name', 'group', 'url']       
        items = [QStandardItem(field) for field in newrow]
        self.model.appendRow(items)
        self.isChanged = True
        self.lb.selectRow(self.model.rowCount() - 1)
                

    def load_channels_file(self):
        if self.isChanged == True:
            save_msg = "<b>Das Dokument wurde geändert.<br>Wollen Sie die Änderungen speichern?</ b>"
            reply = QMessageBox.question(self, 'Speichern', 
                     save_msg, QMessageBox.Yes, QMessageBox.No)
            if reply == QMessageBox.Yes:
                self.writeCSV()
                self.open_channels()
            else:
                self.isChanged = False
                self.open_channels()
        else:
            self.isChanged = False
            self.open_channels()
        
    def open_channels(self, fileName):
        if fileName:
            self.convert_to_csv(fileName)
            print(fileName + " geladen")
            with open(self.csv_file, 'r') as f:
                i = 0
                reader = csv.reader(f, delimiter = '\t')
                self.model.clear()
                for row in reader:  
                    items = [QStandardItem(field) for field in row]
                    self.model.appendRow(items)
                    self.model.setHeaderData(i - 1, Qt.Horizontal, str(i))
                    i = i + 1     
                self.lb.resizeColumnsToContents()           
                self.lb.selectRow(0)
                self.statusBar().showMessage(f"{fileName} loaded", 0)
                self.isChanged = False
                self.lb.verticalHeader().setMinimumWidth(24)
                self.filename = fileName
             
    def convert_to_csv(self, fileName):
        #mychannels_file = 'myradio.txt'
        channels_list = open(fileName, 'r').read().splitlines()
        csv_content = ""
        group = ""
        name = ""
        url = ""

        for x in reversed(range(len(channels_list))):
            line = channels_list[x]
            if line == "":
                print(f"empty line {x} removed")
                del(channels_list[x])
               
        i = 0
        for x in range(0, len(channels_list)):
            line = channels_list[x]
            while True:
                if line.startswith("--"):
                    group = line.replace("-- ", "").replace(" --", "")
                    break
                    continue

                elif not line.startswith("--"):
                    ch_line = line.split(",")
                    name = ch_line[0]
                    url = ch_line[1]
                    i += 1
                    break
                    
            if not name == "" and not name == channels_list[x-1].partition(",")[0]:        
                csv_content += (f'{name}\t{group}\t{url}\n')

        self.csv_file = '/tmp/mychannels.csv'
        with open(self.csv_file, 'w') as f:        
            f.write(csv_content)
            
    def writeCSV(self):
        fileName, _ = QFileDialog.getSaveFileName(self, "Datei speichern", self.mychannels_file,"TVPlayer2 List (*.txt)")
        if fileName:
            self.save_file(fileName)
            
    def save_file(self, fileName):
        # save temporary csv
        f = open(self.csv_file, 'w')

        content = ""
        
        for row in range(self.lb.model().rowCount()):
            itemlist = []
            for column in range(self.lb.model().columnCount()):
                itemlist.append(self.model.item(row, column).text())
            
            content += '\t'.join(itemlist)
            content += '\n'
        with open(self.csv_file, 'w') as f:
            f.write(content)
            
                
            
            # convert to txt
            channels_list = open(self.csv_file, 'r').read().splitlines()

            group = ""
            name = ""
            url = ""
            out_list = []

            for x in range(len(channels_list)):
                line = channels_list[x].split('\t')
                name = line[0]
                group = line[1]
                url = line[2]
                
                out_list.append(f"-- {group} --")
                out_list.append(f'{name},{url}')
                

            tlist = self.ordered_set(out_list)
            m3u_content = '\n'.join(tlist)
            m3u_content += '\n'

            with open(fileName, 'w') as f:        
                f.write(m3u_content)

            print(fileName + " gespeichert")
            self.isChanged = False
            
    def ordered_set(self, in_list):
        out_list = []
        added = set()
        for val in in_list:
            if not val in added:
                out_list.append(val)
                added.add(val)
        return out_list


    def replace_in_table(self):
        if self.model.rowCount() < 1:
            return
        searchterm = self.findfield.text()
        replaceterm = self.replacefield.text()
        if searchterm == "":
            return
        else:
            for i in range(self.lb.model().columnCount() - 1):
                indexes = self.lb.model().match(
                                    self.lb.model().index(0, i),
                                    Qt.DisplayRole,
                                    searchterm,
                                    -1,
                                    Qt.MatchContains
                                )
                for ix in indexes:
                    old_item = self.model.item(ix.row(), i)
                    new_item = old_item.text().replace(searchterm, replaceterm)
                    self.model.setItem(ix.row(), i, QStandardItem(new_item))
                self.lb.resizeColumnsToContents()
                self.isChanged = True
                
    def filter_table(self):
        if self.model.rowCount() < 1:
            return
        searchterm = self.filter_field.text()  
    
        row_list = []
        self.lb.clearSelection()

        for i in range(self.lb.model().columnCount()-1):
            indexes = self.lb.model().match(
                                self.lb.model().index(0, i),
                                Qt.DisplayRole,
                                searchterm,
                                -1,
                                Qt.MatchContains
                            )
            for ix in indexes:
                self.lb.selectRow(ix.row())    
                row_list.append(ix.row()) 
                
        for x in range(self.lb.model().rowCount()):
            if not x in row_list:
                self.lb.hideRow(x)    
       
    def update_filter(self):
        if self.filter_field.text() == "":
            for x in range(self.lb.model().rowCount()):
                self.lb.showRow(x)
Exemple #14
0
class Ui_MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.select_checkbox_num = 0
        self.all_widgets = []
        self.game_sub_menus = []
        self.face_sub_menus = []
        self.setupUi(self)
        self.updateMenu(self)
        self.retranslateUi(self)

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(775, 532)

        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 775, 23))
        self.menubar.setObjectName("menubar")

        self.menu = QtWidgets.QMenu(self.menubar)
        self.menu.setObjectName("menu")

        self.menu_team = QtWidgets.QMenu(self.menubar)  #参赛队组建菜单
        self.menu_team.setObjectName("menu_team")

        self.menu_face = QtWidgets.QMenu(self.menubar)  #对阵组建
        self.menu_face.setObjectName("menu_face")

        MainWindow.setMenuBar(self.menubar)

        mgr_player = QAction(QIcon(), '运动员管理', self)
        mgr_player.triggered.connect(
            functools.partial(self.edit_player, *self.get_player_parmas()))

        mgr_playground = QAction(QIcon(), '场地管理', self)
        mgr_playground.triggered.connect(
            functools.partial(self.edit_player, *self.get_playground_parmas()))

        mgr_game = QAction(QIcon(), '竞赛项目', self)
        mgr_game.triggered.connect(
            functools.partial(self.edit_player, *self.get_game_parmas()))

        mgr_team = QAction(QIcon(), '参赛团队', self)
        mgr_team.triggered.connect(self.edit_team)

        mgr_group = QAction(QIcon(), '分组管理', self)
        mgr_group.triggered.connect(self.edit_group)

        mgr_test = QAction(QIcon(), '我的测试', self)
        mgr_test.triggered.connect(self.test)

        # mgr_face = QAction(QIcon(),'对阵设定',self)
        # mgr_face.triggered.connect(self.edit_face)

        self.toolbar = self.addToolBar('Mytool')
        self.toolbar.addAction(mgr_player)
        self.toolbar.addAction(mgr_playground)
        self.toolbar.addAction(mgr_game)
        self.toolbar.addAction(mgr_team)
        self.toolbar.addAction(mgr_group)
        self.toolbar.addAction(mgr_test)
        # self.toolbar.addAction(mgr_face)

        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.action_init = QtWidgets.QAction(MainWindow)
        self.action_init.setObjectName("action_init")

        self.action_import_data = QtWidgets.QAction(MainWindow)
        self.action_import_data.setObjectName("action_import_data")

        self.action_gamemgr = QtWidgets.QAction(MainWindow)
        self.action_gamemgr.setObjectName("action_gamemgr")

        self.menu.addAction(self.action_init)
        self.menu.addAction(self.action_import_data)
        self.menu.addSeparator()

        self.menubar.addAction(self.menu.menuAction())
        self.menubar.addAction(self.menu_team.menuAction())
        self.menubar.addAction(self.menu_face.menuAction())

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.action_init.triggered.connect(self.clear_data_firm)
        self.action_import_data.triggered.connect(self.get_data_file)

        self.add_first_ui()

        # if has_data():
        #     self.add_team_ui()
        # time.sleep(2)
        # self.centralwidget.hide()

    # def pr(self):
    #     print('prrrrr')

    def updateMenu(self, MainWindow):
        """添加或更新为每个竞赛项目组队的‘参赛队组建’菜单"""
        self.games = get_games()
        # 清除‘参赛队组建’原子菜单
        for game_sub_menu in self.game_sub_menus:
            self.menu_team.removeAction(game_sub_menu)

        for game in self.games:
            self.game_sub_menus.append(QtWidgets.QAction(MainWindow))

        for game_sub_menu, game in zip(self.game_sub_menus, self.games):
            game_sub_menu.setObjectName(game.name)
            game_sub_menu.triggered.connect(
                functools.partial(self.select_player, game.id, game.name,
                                  game.team_num, game.sex))
            game_sub_menu.setText(
                QtCore.QCoreApplication.translate("MainWindow",
                                                  "&{}".format(game.name)))

        for game_sub_menu in self.game_sub_menus:
            self.menu_team.addAction(game_sub_menu)
        """添加或更新为每个竞赛项目组队的‘对阵组建’菜单"""
        for face_sub_menu in self.face_sub_menus:
            self.menu_face.removeAction(face_sub_menu)

        for game in self.games:
            self.face_sub_menus.append(QtWidgets.QAction(MainWindow))

        for game_sub_menu, game in zip(self.face_sub_menus, self.games):
            game_sub_menu.setObjectName(game.name + '_')
            game_sub_menu.triggered.connect(
                functools.partial(self.new_face, game.id))
            game_sub_menu.setText(
                QtCore.QCoreApplication.translate("MainWindow",
                                                  "&{}".format(game.name)))

        for game_sub_menu in self.face_sub_menus:
            self.menu_face.addAction(game_sub_menu)

    def add_first_ui(self, info="Welcome!"):
        self.takeCentralWidget()
        self.main_frame = QScrollArea(self)
        self.main_frame.setStyleSheet(
            'QWidget{background-color:rgb(255,255,255)}')
        self.wel = QLabel(info)

        boxlayout = QHBoxLayout()
        boxlayout.addStretch()
        boxlayout.addWidget(self.wel)
        boxlayout.addStretch()

        self.main_frame.setLayout(boxlayout)
        self.setCentralWidget(self.main_frame)

    # def add_team_ui(self):
    #     self.centralwidget = QWidget()
    #     self.form_layout = QHBoxLayout(self.centralwidget)

    #     self.left_layout = MyQVBoxLayout()
    #     self.right_layout = QVBoxLayout()

    #     # qbtn = QPushButton('1')
    #     # qbtn.resize(qbtn.minimumSize())
    #     self.left_widgts = self.get_left_widgts()
    #     # self.left_layout.addWidget(qbtn)
    #     # self.left_layout.addWidget(QLabel('def'))
    #     for widgt in self.left_widgts:
    #         self.left_layout.addWidget(widgt)
    #     self.left_layout.addStretch()
    #     # self.right_layout.addWidget(QLabel('aaaa'),0,0)
    #     # self.right_layout.addWidget(QLabel('bbbb'),1,0)
    #     self.right_widgts = self.get_right_widgets()
    #     for widgt in self.right_widgts:
    #         self.right_layout.addWidget(widgt)
    #     self.right_layout.addStretch()
    #     self.form_layout.addLayout(self.left_layout)
    #     self.form_layout.addLayout(self.right_layout)

    #     self.setCentralWidget(self.centralwidget)

    #     qbtn.clicked.connect(self.test)

    # def test(self):
    #     centralwidget = QWidget()
    #     test_layout = QHBoxLayout(centralwidget)
    #     test_layout.addWidget(QLabel('kkkkkkkkkkkkkkkkkkk'))
    #     # self.removeWidget(self.centralwidget)
    #     self.takeCentralWidget()
    #     self.setCentralWidget(centralwidget)
    #     # self.show()
    #     # self.update()
    #     # self.repaint()

    # def test_tool(self):
    #     print('abccc')
    #     self.wel.setText('akkkkkkkkkkkk!')
    #     self.takeCentralWidget()
    #     self.setCentralWidget(QLabel('kkkdkddaaaaaaaaaaaaaa'))

#         main_form = QFormLayout()
#         left_widgt = QWidget(None)
#         left_widgt_layout = QVBoxLayout()
#         left_widgt.setLayout(left_widgt_layout)
#         for i in range(5):
#             left_widgt_layout.addWidget(QLabel('标签%i' % i))

#         for w in self.get_left_widgts():
#             left_widgt_layout.addWidget(w)

#         scroll_area = QScrollArea()
#         right_widgt = QWidget(None)
#         self.right_widgt_layout = QVBoxLayout()
#         right_widgt.setLayout(self.right_widgt_layout)
#         self.right_widgt_layout.addWidget(QLabel('标签%i' % 5))
#         self.right_widgt_layout.addWidget(QLabel('标签%i' % 7))
#         scroll_area.setWidget(right_widgt)

#         main_form.addRow(left_widgt,scroll_area)

#         main_widgt = QWidget(None)
#         main_widgt.setLayout(main_form)
#         self.setCentralWidget(main_widgt)

# def get_left_widgts(self):
#     widgts = []
#     self.game_data = get_games()
#     mylbl = QLabel('运动项目:')
#     mylbl.setMaximumHeight(20)
#     widgts.append(mylbl)
#     self.game_combo = QComboBox(None)
#     self.game_combo.setMaximumWidth(80)
#     self.game_combo.setMaximumHeight(20)
#     for item in self.game_data.keys():
#         self.game_combo.addItem(item)
#     widgts.append(self.game_combo)
#     self.game_combo.setCurrentIndex(-1)
#     self.game_combo.activated[str].connect(self.set_cur_game)
#     return widgts

# def set_cur_game(self,game):
#     self.game = game
#     print(game,self.game_data[game])
#     if self.game_data[game] == 1:
#         self.show_players(game)

# def get_right_widgets(self):
#     players = get_players()
#     widgts = []

#     for p in players:
#         data = [p.name,p.idcode,p.sex,p.age,p.work_place,p.tel]
#         data = ['' if d is None else d for d in data]
#         info = '{: <8} {: <8} {: <2} {: <2} {: <10} {: <12}'.format(*data)
#         widgts.append(QLabel(info))
#     return widgts

# def show_players(self,game):
#     self.test()

#     game_sex = get_games_sex()
#     sex = game_sex[game]
#     self.players = get_players(sex)
#     self.p_checkboxes = [QCheckBox(' '.join((p.name,p.idcode))) for p in self.players]
#     for w in self.right_widgts:
#         w.hide()
#     for cb in self.p_checkboxes:
#         cb.toggle()
#         print('abc')
#         self.right_layout.addWidget(cb)
#     self.right_layout.addStretch()

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "易用竞赛管理系统"))
        self.menu.setTitle(_translate("MainWindow", "&管理数据"))
        self.action_init.setText(_translate("MainWindow", "&清理数据"))
        self.action_import_data.setText(_translate("MainWindow", "&导入数据"))

        self.menu_team.setTitle(_translate("MainWindow", "&参赛队组建"))

        self.menu_face.setTitle(_translate("MainWindow", "&对阵组建"))

    def get_data_file(self):
        fname = QFileDialog.getOpenFileName(self, '打开文件', '.\\')
        if fname[0]:
            info = load_data(fname[0])
            if info:
                QMessageBox.information(self, "数据错误,请修改后重新导入!", info)
            else:
                QMessageBox.information(self, "提示:", '数据导入成功!')
                self.add_first_ui('数据已导入!')
                # self.add_team_ui()
                self.updateMenu(self)

    def clear_data_firm(self):
        reply = QMessageBox.question(self, '确认', '确定删除数据?',
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        self.takeCentralWidget()
        if reply == QMessageBox.Yes:
            clear_data()
            self.add_first_ui('数据已全部清空!')

    def get_player_parmas(self):
        head_lst = ['索引号', '姓名', '身份证号', '性别', '年龄', '工作单位', '电话']
        keys = ['id', 'name', 'idcode', 'sex', 'age', 'work_place', 'tel']
        return get_players, keys, head_lst, Player

    def get_playground_parmas(self):
        head_lst = ['索引号', '场地名', '使用状态', '备注']
        keys = ['id', 'name', 'using', 'memo']
        return get_playgrounds, keys, head_lst, PlayGround

    def get_game_parmas(self):
        head_lst = ['索引号', '竞赛项目', '队员人数', '队员性别', '备注']
        keys = ['id', 'name', 'team_num', 'sex', 'memo']
        return get_games, keys, head_lst, Games

    def edit_player(self, getfunc, keys, head_lst, obj):
        model_objs = getfunc()
        datas = []
        for model_obj in model_objs:
            # data = [p.id,p.name,p.idcode,p.sex,p.age,p.work_place,p.tel]
            data = [getattr(model_obj, key) for key in keys]
            data = ['' if d is None else d for d in data]
            datas.append(data)
        # head_lst = ['索引号','姓名','身份证号','性别','年龄','工作单位','电话']
        if datas:
            self.takeCentralWidget()
            main_frame = QScrollArea(self)
            main_frame.setStyleSheet(
                'QWidget{background-color:rgb(255,255,255)}')

            self.player_tabview = QTableView()
            r, c = len(datas), len(datas[0])
            self.player_model = QStandardItemModel(r, c)
            self.player_model.setHorizontalHeaderLabels(head_lst)
            for r, rdata in enumerate(datas):
                for c, cell in enumerate(rdata):
                    it = QStandardItem(str(cell))
                    if c == 0:
                        it.setEditable(False)
                    self.player_model.setItem(r, c, it)
            # keys = ['id','name','idcode','sex','age','work_place','tel']
            edit_cell = functools.partial(self.edit_cell, obj, keys)
            self.player_model.itemChanged.connect(edit_cell)

            self.player_tabview.setModel(self.player_model)

            boxlayout = QVBoxLayout()
            # boxlayout.addStretch(1)
            boxlayout.addWidget(self.player_tabview, 18)
            # boxlayout.addStretch(1)

            del_btn = QPushButton('删除')
            del_btn.clicked.connect(functools.partial(self.del_row, obj))
            boxlayout.addWidget(del_btn)

            main_frame.setLayout(boxlayout)
            self.setCentralWidget(main_frame)

    def edit_cell(self, obj, keys):
        r = self.player_tabview.currentIndex().row()
        c = self.player_tabview.currentIndex().column()
        curr_data = self.player_tabview.currentIndex().data()
        item = self.player_model.index(r, 0)
        param = dict()
        param[keys[c]] = curr_data
        save_cell(obj, int(item.data()), param)
        if obj == Games and 'name' in param:
            self.updateMenu(self)

    def del_row(self, obj):
        reply = QMessageBox.question(self, '确认', '确定删除数据?',
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        if reply == QMessageBox.Yes:
            r = self.player_tabview.currentIndex().row()
            item = self.player_model.index(r, 0)
            # print(int(item.data()))
            del_rowdb(obj, int(item.data()))
            self.player_model.removeRow(r)
            if obj == Games:
                self.updateMenu(self)

    def edit_team(self):
        datas = get_team_datas()
        head_lst = ['索引号', '队名', '项目', '分组']
        if datas:
            self.takeCentralWidget()
            main_frame = QScrollArea(self)
            main_frame.setStyleSheet(
                'QWidget{background-color:rgb(255,255,255)}')

            self.player_tabview = QTableView()
            r, c = len(datas), len(datas[0])
            self.player_model = QStandardItemModel(r, c)
            self.player_model.setHorizontalHeaderLabels(head_lst)
            for r, rdata in enumerate(datas):
                for c, cell in enumerate(rdata):
                    it = QStandardItem(str(cell))
                    if c == 0:
                        it.setEditable(False)
                    self.player_model.setItem(r, c, it)
            # keys = ['id','name','idcode','sex','age','work_place','tel']
            # edit_cell = functools.partial(self.edit_cell,obj,keys)
            # self.player_model.itemChanged.connect(edit_cell)

            self.player_tabview.setModel(self.player_model)

            boxlayout = QVBoxLayout()
            # boxlayout.addStretch(1)
            boxlayout.addWidget(self.player_tabview, 18)
            # boxlayout.addStretch(1)

            del_btn = QPushButton('删除')
            del_btn.clicked.connect(self.del_team)
            boxlayout.addWidget(del_btn)

            main_frame.setLayout(boxlayout)
            self.setCentralWidget(main_frame)

    def del_team(self):
        # v = MyDialog()
        # if v.exec_():
        #     name,game = v.get_data()
        #     print(name,game)
        reply = QMessageBox.question(self, '确认', '确定删除数据?',
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        if reply == QMessageBox.Yes:
            r = self.player_tabview.currentIndex().row()
            item = self.player_model.index(r, 0)
            # print(int(item.data()))
            del_rowdb(Team, int(item.data()))
            self.player_model.removeRow(r)

    def select_player(self, gid, gname, gteam_num, gsex):
        # 新建团队UI
        players = get_players(gsex)
        head_lst = ['索引号', '姓名', '身份证号', '性别', '年龄', '工作单位', '电话']
        keys = ['id', 'name', 'idcode', 'sex', 'age', 'work_place', 'tel']
        datas = []
        for player in players:
            data = [getattr(player, key) for key in keys]
            data = ['' if d is None else d for d in data]
            datas.append(data)
        if datas:
            self.takeCentralWidget()
            main_frame = QScrollArea(self)
            main_frame.setStyleSheet(
                'QWidget{background-color:rgb(255,255,255)}')

            self.player_tabview = QTableView()
            r, c = len(datas), len(datas[0])
            self.player_model = QStandardItemModel(r, c)

            print(self.player_tabview.itemDelegate())

            self.player_model.setHorizontalHeaderLabels(head_lst)
            for r, rdata in enumerate(datas):
                for c, cell in enumerate(rdata):
                    it = QStandardItem(str(cell))
                    if c == 0:
                        it.setEditable(False)
                    self.player_model.setItem(r, c, it)
            self.player_tabview.setModel(self.player_model)

            boxlayout = QVBoxLayout()
            # boxlayout.addStretch(1)
            boxlayout.addWidget(self.player_tabview, 18)
            # boxlayout.addStretch(1)

            new_btn = QPushButton('新建团队({})'.format(gname))
            new_btn.clicked.connect(
                functools.partial(self.add_team, gid, gteam_num, gsex))
            boxlayout.addWidget(new_btn)

            main_frame.setLayout(boxlayout)
            self.setCentralWidget(main_frame)

    def add_team(self, gid, gteam_num, gsex):
        # 新建团队方法
        rows = set()
        pids = []
        for selected_model_index in self.player_tabview.selectedIndexes():
            rows.add(selected_model_index.row())
        for r in rows:
            item = self.player_model.index(r, 0)
            pids.append(item.data())
        if gteam_num == 1:
            info = new_team(gid, pids, flag=1)
            if info:
                QMessageBox.warning(self, '完成', info, QMessageBox.Ok)
            else:
                QMessageBox.information(self, '完成', '成功建立!', QMessageBox.Ok)
        if gteam_num > 1:
            if len(rows) == gteam_num:
                info = new_team(gid, pids)
                if info:
                    QMessageBox.warning(self, '完成', info, QMessageBox.Ok)
                else:
                    QMessageBox.information(self, '完成', '成功建立!',
                                            QMessageBox.Ok)
            else:
                QMessageBox.warning(self, '错误',
                                    '请选中指定的运动员数:{}'.format(gteam_num),
                                    QMessageBox.Ok)
        self.player_tabview.clearSelection()

    def test(self):
        from .modeltt import TObjModel, MyDelegate
        md = MyDelegate()
        self.takeCentralWidget()
        main_frame = QScrollArea(self)
        main_frame.setStyleSheet('QWidget{background-color:rgb(255,255,255)}')

        self.player_tabview = QTableView()
        self.player_model = TObjModel()
        self.player_tabview.setModel(self.player_model)

        boxlayout = QVBoxLayout()
        # boxlayout.addStretch(1)
        boxlayout.addWidget(self.player_tabview, 18)
        self.player_tabview.setItemDelegateForColumn(2, md)
        self.player_tabview.hideColumn(0)
        main_frame.setLayout(boxlayout)
        self.setCentralWidget(main_frame)

    def edit_group(self):
        datas = get_group_datas()
        head_lst = ['索引号', '组名', '项目', '所含队名', 'gameid']
        self.takeCentralWidget()
        main_frame = QScrollArea(self)
        main_frame.setStyleSheet('QWidget{background-color:rgb(255,255,255)}')

        self.player_tabview = QTableView()
        self.player_model = QStandardItemModel()
        self.player_model.setHorizontalHeaderLabels(head_lst)
        if datas:
            r, c = len(datas), len(datas[0])
            # self.player_model = QStandardItemModel(r,c)
            self.player_model.setHorizontalHeaderLabels(head_lst)
            for r, rdata in enumerate(datas):
                for c, cell in enumerate(rdata):
                    it = QStandardItem(str(cell))
                    # if c == 0:
                    it.setEditable(False)
                    self.player_model.setItem(r, c, it)
        # keys = ['id','name','idcode','sex','age','work_place','tel']
        # edit_cell = functools.partial(self.edit_cell,obj,keys)
        # self.player_model.itemChanged.connect(edit_cell)

        self.player_tabview.setModel(self.player_model)

        boxlayout = QVBoxLayout()
        # boxlayout.addStretch(1)
        boxlayout.addWidget(self.player_tabview, 18)
        # boxlayout.addStretch(1)
        self.player_tabview.hideColumn(4)

        add_btn = QPushButton('添加分组')
        add_btn.clicked.connect(self.add_group)
        boxlayout.addWidget(add_btn)

        del_btn = QPushButton('删除分组')
        del_btn.clicked.connect(functools.partial(self.del_row, Group))
        boxlayout.addWidget(del_btn)

        add_team_btn = QPushButton('分配参赛团队')
        add_team_btn.clicked.connect(self.add_team2group)
        boxlayout.addWidget(add_team_btn)

        main_frame.setLayout(boxlayout)
        self.setCentralWidget(main_frame)

    def add_group(self):
        v = MyDialog()
        if v.exec_():
            name, game = v.get_data()
            if name and game:
                info = add_groupdb(name, int(game))
                if info:
                    QMessageBox.warning(self, '错误', info, QMessageBox.Ok)
                else:
                    QMessageBox.information(self, '完成', '成功建立!',
                                            QMessageBox.Ok)
                    self.edit_group()

    def add_team2group(self):
        rows = set()

        for selected_model_index in self.player_tabview.selectedIndexes():
            rows.add(selected_model_index.row())
        if len(rows) != 1:
            QMessageBox.warning(self, '错误', '请仅选择其中一个小组', QMessageBox.Ok)
            return
        row = rows.pop()
        groupid = self.player_model.index(row, 0).data()
        gameid = self.player_model.index(row, 4).data()

        print(groupid, gameid)
        if get_team_datas(gameid):
            v = GroupDialog(gameid, "添加团队到小组", get_team_datas)
            if v.exec_():
                tids = v.get_data()
                print(tids)
                if tids:
                    add_team2group_db(groupid, tids)
                    QMessageBox.information(self, '提示', '操作完成!',
                                            QMessageBox.Ok)
        else:
            QMessageBox.information(self, '提示', '无参赛团队可以分组!', QMessageBox.Ok)

    def get_grp_combo(self, gid):
        groups = get_group_for_game(gid)
        cur_index = -1
        grp_combo = QComboBox()
        for index, (ggid, gname, ggname) in enumerate(groups):
            grp_combo.addItem('-'.join((ggname, gname)), ggid)

        grp_combo.setCurrentIndex(cur_index)

        grp_combo.currentIndexChanged.connect(
            functools.partial(self.disp_face, gid))
        grp_combo.setToolTip('请选择一个分组,并为其建立对阵。')

        return grp_combo

    def new_face(self, gid):
        # print(gid)
        self.takeCentralWidget()
        main_frame = QScrollArea(self)
        main_frame.setStyleSheet('QWidget{background-color:rgb(255,255,255)}')

        boxlayout = QVBoxLayout()

        self.grp_combo = self.get_grp_combo(gid)

        boxlayout.addWidget(self.grp_combo)
        # boxlayout.addStretch(1)

        self.face_view = QTableView()
        self.face_model = QStandardItemModel()
        self.face_model.setHorizontalHeaderLabels(['id', '队A', '队B'])
        self.face_view.setModel(self.face_model)

        boxlayout.addWidget(self.face_view)

        add_btn = QPushButton('添加对阵')
        add_btn.clicked.connect(functools.partial(self.add_face, gid))
        boxlayout.addWidget(add_btn)

        main_frame.setLayout(boxlayout)
        self.setCentralWidget(main_frame)

    def disp_face(self, gid):
        # print(self.grp_combo.currentIndex(),self.grp_combo.currentText())
        self.ggid = int(self.grp_combo.itemData(self.grp_combo.currentIndex()))
        if self.ggid >= 1:

            self.face_model.beginResetModel()
            self.face_model.clear()
            self.face_model.setHorizontalHeaderLabels(['id', '队A', '队B'])
            faces = get_faces(gid, self.ggid)
            for r, rd in enumerate(faces):
                for c, cd in enumerate(rd):
                    item = QStandardItem(str(cd))
                    item.setEditable(False)
                    self.face_model.setItem(r, c, item)
            self.face_model.endResetModel()

    def add_face(self, gid):

        v = GroupDialog(self.ggid, "添加对阵团队", get_teams_for_group)
        if v.exec_():
            tids = v.get_data()
            print(tids)
            tids = [int(tid) for tid in tids]
            if len(tids) != 2:
                QMessageBox.warning(self, '错误', '请仅选择对阵的双方小组', QMessageBox.Ok)
            else:
                tids.sort()
                if add_face2db(*tids):
                    self.disp_face(gid)
                    QMessageBox.information(self, '提示', '操作完成!',
                                            QMessageBox.Ok)
                else:
                    QMessageBox.warning(self, '错误', '对阵不能重复!', QMessageBox.Ok)