def activeAppStateChange(self, newState): """ Called when the active application changes its state. :param newState: the new application's state (see FilterState) :return: """ assertMainThread() if newState == FilterState.CONSTRUCTED: self.actActivate.setEnabled(True) else: self.actActivate.setEnabled(False) if newState == FilterState.ACTIVE: if self._waitForOpenState is not None: app, pbfile, startPlay = self._waitForOpenState self._waitForOpenState = None if app == Application.activeApplication.getApplication( ).getName(): pbsrv = Services.getService("PlaybackControl") if startPlay: pbsrv.playbackPaused.connect(self._singleShotPlay) QTimer.singleShot(2000, self._disconnectSingleShotPlay) MethodInvoker(pbsrv.browser.setActive, Qt.QueuedConnection, pbfile) self.actDeactivate.setEnabled(True) self.actSaveWithGuiState.setEnabled(False) else: self.actDeactivate.setEnabled(False) self.actSaveWithGuiState.setEnabled(True)
def _onItemDoubleClicked(self, index): assertMainThread() if self.model.isApplication(index): app = self.model.data(index, Qt.DisplayRole) self.changeActiveApp(app) else: self.treeView.edit(index)
def renameNode(self, oldName, newName): """ Rename a node in the graph (connections will be adapted as well) :param oldName: the original name of the node :param newName: the new name of the node :return: None """ assertMainThread() if not oldName in self._nodes: raise NodeNotFoundError(oldName) if newName in self._nodes: raise NodeExistsError(newName) if oldName in self._protected: raise NodeProtectedError(oldName) of = self._nodes[oldName] del self._nodes[oldName] self._nodes[newName] = of for i in range(len(self._connections)): c = self._connections[i] if c[0] == oldName: c = (newName, c[1], c[2], c[3]) if c[2] == oldName: c = (c[0], c[1], newName, c[3]) self._connections[i] = c self.nodeRenamed.emit(oldName, newName) self.dirtyChanged.emit()
def _operationFinished(self): """ slot called once from each thread which has been finished with an operation """ logger.internal("operation finished callback") assertMainThread() self._numThreadsSynced += 1 if self._numThreadsSynced == len(self._threads): # received the finished signal from all threads # perform state transition self._numThreadsSynced = 0 if self._state == FilterState.CONSTRUCTING: self._state = FilterState.CONSTRUCTED elif self._state == FilterState.INITIALIZING: self._state = FilterState.INITIALIZED elif self._state == FilterState.OPENING: self._state = FilterState.OPENED elif self._state == FilterState.STARTING: self._state = FilterState.ACTIVE elif self._state == FilterState.STOPPING: self._state = FilterState.OPENED elif self._state == FilterState.CLOSING: self._state = FilterState.INITIALIZED elif self._state == FilterState.DEINITIALIZING: self._state = FilterState.CONSTRUCTED elif self._state == FilterState.DESTRUCTING: self._state = FilterState.DESTRUCTED self.stopThreads() self.stateChanged.emit(self._state)
def allNodes(self): """ Return all node names. :return: list of nodes """ assertMainThread() return list(self._nodes.keys())
def allConnections(self): """ Return all connections :return: list of 4 tuples of strings (nodeFrom, portFrom, nodeTo, portTo) """ assertMainThread() return self._connections
def stop(self): """ Perform stop operation :return: None """ logger.internal("entering stop operation, old state %s", FilterState.state2str(self._state)) assertMainThread() while self._operationInProgress and self._state != FilterState.ACTIVE: QCoreApplication.processEvents() if self._state != FilterState.ACTIVE: logger.warning("Unexpected state %s", FilterState.state2str(self._state)) raise FilterStateMachineError(self._state, FilterState.STOPPING) self._operationInProgress = True self._state = FilterState.STOPPING for itc in self._interThreadConns: # set connections in active mode. itc.setStopped(True) self.performOperation.emit("stop", Barrier(len(self._threads))) while self._state == FilterState.STOPPING: logger.internal("stopping ... %s", FilterState.state2str(self._state)) QCoreApplication.processEvents() self._operationInProgress = False logger.internal("leaving stop operation, new state %s", FilterState.state2str(self._state))
def renameOutputPort(self, node, oldPortName, newPortName): """ Rename an output port of a node (connections will be renamed as needed) :param node: the node name :param oldPortName: the original port name :param newPortName: the new port name :return: None """ assertMainThread() if not node in self._nodes: raise NodeNotFoundError(node) if not oldPortName in self._nodes[node]["outports"]: if newPortName in self._nodes[node]["outports"]: # already renamed. return raise PortNotFoundError(node, oldPortName) if newPortName in self._nodes[node]["outports"]: raise PortExistsError(node, newPortName) idx = self._nodes[node]["outports"].index(oldPortName) self._nodes[node]["outports"][idx] = newPortName for i in range(len(self._connections)): fromNode, fromPort, toNode, toPort = self._connections[i] if (fromNode == node and fromPort == oldPortName): fromPort = newPortName self._connections[i] = (fromNode, fromPort, toNode, toPort) self.outPortRenamed.emit(node, oldPortName, newPortName)
def _supportedFeaturesChanged(self, featureset, nameFilters): """ overwritten from MVCPlaybackControlBase. This function is called from multiple threads, but not at the same time. :param featureset: the current featureset :return: """ assertMainThread() self.featureset = featureset self.actStepFwd.setEnabled("stepForward" in featureset) self.actStepBwd.setEnabled("stepBackward" in featureset) self.actSeekBegin.setEnabled("seekBeginning" in featureset) self.actSeekEnd.setEnabled("seekEnd" in featureset) self.positionSlider.setEnabled("seekTime" in featureset) self.browser.setEnabled("setSequence" in featureset) self.timeRatioLabel.setEnabled("setTimeFactor" in featureset) for f in self.actSetTimeFactor: self.actSetTimeFactor[f].setEnabled("setTimeFactor" in featureset) self.timeRatioLabel.setEnabled("setTimeFactor" in featureset) self.timeRatioLabel.setEnabled("setTimeFactor" in featureset) self.timeRatioLabel.setEnabled("setTimeFactor" in featureset) self.timeRatioLabel.setEnabled("setTimeFactor" in featureset) if "startPlayback" not in featureset: self.actStart.setEnabled(False) if "pausePlayback" not in featureset: self.actPause.setEnabled(False) logger.debug("current feature set: %s", featureset) logger.debug("Setting name filters of browser: %s", list(nameFilters)) self.nameFiltersChanged.emit(list(nameFilters)) super()._supportedFeaturesChanged(featureset, nameFilters)
def restoreState(self): """ Restores the state of the playback control from the given property collection :param propertyCollection: a PropertyCollection instance :return: """ assertMainThread() propertyCollection = self.config.guiState() propertyCollection.defineProperty("PlaybackControl_showAllFiles", 0, "show all files setting") showAllFiles = propertyCollection.getProperty("PlaybackControl_showAllFiles") self.actShowAllFiles.setChecked(bool(showAllFiles)) propertyCollection.defineProperty("PlaybackControl_folder", "", "current folder name") folder = propertyCollection.getProperty("PlaybackControl_folder") if Path(folder).is_dir(): logger.debug("Setting current file: %s", folder) self.browser.setFolder(folder) propertyCollection.defineProperty("PlaybackControl_recent", "", "recent opened sequences") recentFiles = propertyCollection.getProperty("PlaybackControl_recent") idx = 0 for f in recentFiles.split("|"): if f != "" and Path(f).is_file(): self.recentSeqs[idx].setData(f) self.recentSeqs[idx].setText(self.compressFileName(f)) self.recentSeqs[idx].setVisible(True) idx += 1 if idx >= len(self.recentSeqs): break for a in self.recentSeqs[idx:]: a.setData(None) a.setText("") a.setVisible(False)
def browserActivated(self, filename): """ Called when the user activated a file. :param filename: the new filename :return: """ assertMainThread() if filename is not None and Path(filename).is_file(): foundIdx = None for i, a in enumerate(self.recentSeqs): if a.data() == filename: foundIdx = i if foundIdx is None: foundIdx = len(self.recentSeqs) - 1 for i in range(foundIdx, 0, -1): self.recentSeqs[i].setText(self.recentSeqs[i - 1].text()) self.recentSeqs[i].setData(self.recentSeqs[i - 1].data()) logger.debug("%d data: %s", i, self.recentSeqs[i - 1].data()) self.recentSeqs[i].setVisible( self.recentSeqs[i - 1].data() is not None) self.recentSeqs[0].setText(self.compressFileName(filename)) self.recentSeqs[0].setData(filename) self.recentSeqs[0].setVisible(True) self.setSequence(filename)
def __init__(self, subConfig): super().__init__() assertMainThread() self._parent = subConfig self._filters = {} self._properties = subConfig.getPropertyCollection() self.nodeDeleted.connect(self.onNodeDeleted) self.nodeRenamed.connect(self.onNodeRename)
def _disconnectSingleShotPlay(self): assertMainThread() pbsrv = Services.getService("PlaybackControl") try: pbsrv.playbackPaused.disconnect(self._singleShotPlay) except RuntimeError: # we are already disconnected. pass
def getMockup(self, name): """ Get the mockup related to the given filter. :param name: the node name :return: FilterMockup instance """ assertMainThread() return self._filters[name]
def _updateFeatureSet(self): assertMainThread() featureset = set() nameFilters = set() for devid in self._registeredDevices: featureset = featureset.union(self._registeredDevices[devid]["featureset"]) nameFilters = nameFilters.union(self._registeredDevices[devid]["nameFilters"]) self._supportedFeaturesChanged(featureset, nameFilters)
def __init__(self, configuration): super().__init__() assertMainThread() self._configuration = configuration self.cfgfile = None self.model = ConfigurationModel(configuration, self) configuration.appActivated.connect(self.appActivated)
def openRecent(self): """ Called when the user clicks on a recent sequence. :return: """ assertMainThread() action = self.sender() self.browser.setActive(action.data())
def scrollToCurrent(self): """ Scrolls to the current item in the browser :return: """ assertMainThread() c = self.browser.current() if c is not None: self.browser.scrollTo(c)
def stopThreads(self): """ stop all threads (except main) :return: None """ logger.internal("stopping threads...") assertMainThread() for tname in self._threads: self._threads[tname].cleanup() self._threads.clear()
def onNodeDeleted(self, name): """ Delete corresponding FilterMockup and PropertyCollection instances. :param name: the node name :return: None """ assertMainThread() logger.debug("onNodeDeleted: Deleted filter %s", name) self._properties.deleteChild(name) del self._filters[name]
def deleteDynamicPort(self, portname, factory): """ Remove a dynamic port of the filter. :param portname: name of the dynamic port :param factory: either InputPort or OutputPort :return: """ assertMainThread() p = self.getPort(portname, factory) self.removePort(p) self.createFilterAndUpdate(False)
def _playbackStarted(self): """ Notifies about starting playback :return: None """ assertMainThread() self.actStart.setEnabled(False) if "pausePlayback" in self.featureset: self.actPause.setEnabled(True) super()._playbackStarted()
def addDynamicOutputPort(self, node, port): """ Add a dynamic output port to the referenced node. :param node: the name of the affected node :param port: the name of the new port :return: None """ assertMainThread() self._filters[node].addDynamicPort(port, OutputPortInterface) self.dynOutputPortAdded.emit(node, port) self.dirtyChanged.emit()
def __init__(self, name, parentPropColl, loadedFromConfig=None): PropertyCollection.__init__(self) assertMainThread() self._properties = {} self._accessed = False # if no access to properties has been made, we stick with configs from config file. self._loadedFromConfig = loadedFromConfig if loadedFromConfig is not None else {} self._propertyMutex = QMutex(QMutex.Recursive) if parentPropColl is not None: if not isinstance(parentPropColl, PropertyCollectionImpl): raise NexTInternalError("parentPropColl should always be a property collection instance but it isn't") parentPropColl.addChild(name, self)
def deleteDynamicOutputPort(self, node, port): """ Remove a dynamic output port of a node. :param node: the affected node name :param port: the name of the port to be deleted :return: None """ assertMainThread() self._filters[node].deleteDynamicPort(port, OutputPortInterface) self.dynOutputPortDeleted.emit(node, port) self.dirtyChanged.emit()
def _execNew(self): assertMainThread() if self._checkDirty(): return fn, _ = QFileDialog.getSaveFileName(self.mainWidget, "New configuration", ".", filter="*.json") if fn is not None and fn != "": logger.debug("Creating config file %s", fn) self.newConfig(fn)
def onNodeRename(self, oldName, newName): """ Renames the corresponding filter of the node. :param oldName: the old node name :param newName: the new node name :return: None """ assertMainThread() f = self._filters[oldName] del self._filters[oldName] self._filters[newName] = f self._properties.renameChild(oldName, newName)
def _playbackPaused(self): """ Notifies about pause playback :return: None """ assertMainThread() logger.debug("playbackPaused received") if "startPlayback" in self.featureset: self.actStart.setEnabled(True) self.actPause.setEnabled(False) super()._playbackPaused()
def deInitialize(): """ Deinitialize the active application such that the filters are in CONSTRUCTED state :return: """ assertMainThread() if Application.activeApplication is None: raise NexTRuntimeError("No active application to initialize") MethodInvoker(Application.activeApplication.stop, Qt.DirectConnection) MethodInvoker(Application.activeApplication.close, Qt.DirectConnection) MethodInvoker(Application.activeApplication.deinit, Qt.DirectConnection)
def _execSaveConfigAs(self): """ Opens a file dialog to get the save file name and calls saveConfig. :return: """ assertMainThread() fn, _ = QFileDialog.getSaveFileName(self.mainWidget, "Save configuration as", ".", "*.json") if fn is not None and fn != "": self.saveConfigAs(fn)