''' Created on 23 Oct 2012 @author: francis ''' from PyQt4 import QtGui, Qt, QtCore from PyRQ.Ui.qt4.RRQDebugger.ExecutionState import ExecutionState from PyRQ.Ui.qt4.RRQDebugger.GlobalExecutioner import GlobalExecutioner from PyRQ.Ui.qt4.RRQDebugger.NoResult import NoResult from PyRQ.Ui.qt4.RRQDebugger.ScriptTreeBuilder import TreeBuilder from PyRQ.Ui.qt4.RRQDebugger.ScriptTreeNodes import TreeCommand, \ TreeCommandDelayPost, TreeCommandDelayPre, TreeCommandAuthor, TreeCommands, \ TreeCommandRoot, TreeScriptDelayPre, TreeScriptDelayPost, TreeScriptAuthor, TreeRoot, \ TreeCommandResult, _baseTreeCommandConfig import itertools import os import pickle import threading class Scripter(QtGui.QWidget): RESOURCE_NAME = "Scripter.ui" DEFAULT_LOOP_INDEX = 2 DEFAULT_TREE_EXPANDED_STATE = 2 # 0=collapsed, 1=expanded, 2=whatever uId = itertools.count(0) dataCount = itertools.count(0) def __init__(self, parent): super(Scripter, self).__init__(parent=parent) self._parent = parent self._scripts = [] self._executing = None self._resourcePath = self._parent.resourcesPath self._paused = False self._readOnly = False self._enableTreeChangeEvents = False self._timeouts = self._getDefaultsTimeouts() self._treeIsExpanded = Scripter.DEFAULT_TREE_EXPANDED_STATE self._icons = {"exec":{"running":None, "paused":None, "finished":None}, "result":{"none":None, "exc":None, "ok":None}, "author":None, "time":{"sleep":None, "delay":None}, "enabled":{True:None, False:None}, "node":None, "command":{"generic":None, "create":None, "close":None, "put":None, "get":None, "qsize":None, "maxQSize":None}, "state":{ExecutionState.FINISHED:None, ExecutionState.NOT_RUN:None, ExecutionState.RUNNING:None, ExecutionState.PAUSED:None}} def show(self): super(Scripter, self).show() self.connect(self, Qt.SIGNAL("readOnly()"), self._onReadOnly) self.connect(self._parent, Qt.SIGNAL("injectScript(PyQt_PyObject)"), self._onInjectScript, QtCore.Qt.QueuedConnection) self.connect(self._parent, Qt.SIGNAL("executeStarted(int, PyQt_PyObject)"), self._onExecutionStarted, QtCore.Qt.QueuedConnection) self.connect(self._parent, Qt.SIGNAL("executeFinished(int, PyQt_PyObject)"), self._onExecutionFinished, QtCore.Qt.QueuedConnection) self.connect(self._parent, Qt.SIGNAL("executeStepped(int, int, PyQt_PyObject)"), self._onExecutionStepped, QtCore.Qt.QueuedConnection) self.connect(self._parent, Qt.SIGNAL("executeStepping(int, int, PyQt_PyObject)"), self._onExecutionStepping, QtCore.Qt.QueuedConnection) self.connect(self._parent, Qt.SIGNAL("executeStepResult(int, PyQt_PyObject, PyQt_PyObject)"), self._onExecutionStepResult, QtCore.Qt.QueuedConnection) self.connect(self._parent, Qt.SIGNAL("executeDelay(int, int, int, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)"), self._onExecutionDelay, QtCore.Qt.QueuedConnection) self.connect(self._parent, Qt.SIGNAL("stepExecution(int, PyQt_PyObject)"), self._onStepExecution, QtCore.Qt.QueuedConnection) self.connect(self.pushButton_Run, Qt.SIGNAL("pressed()"), self._onExecute, QtCore.Qt.QueuedConnection) self.connect(self.pushButton_Pause, Qt.SIGNAL("pressed()"), self._onPause, QtCore.Qt.QueuedConnection) self.connect(self.pushButton_Clear, Qt.SIGNAL("pressed()"), self._onClear, QtCore.Qt.QueuedConnection) self.connect(self.pushButton_Save, Qt.SIGNAL("pressed()"), self._onSave, QtCore.Qt.QueuedConnection) self.connect(self.pushButton_Reload, Qt.SIGNAL("pressed()"), self._onReload, QtCore.Qt.QueuedConnection) self.connect(self.treeWidget_ScriptActions, Qt.SIGNAL("customContextMenuRequested(QPoint)"), self._onTreePopup, QtCore.Qt.QueuedConnection) self.connect(self.treeWidget_ScriptActions, Qt.SIGNAL("itemPressed(QTreeWidgetItem*, int)"), self._onTreeItemClicked) self.connect(self.treeWidget_ScriptActions, Qt.SIGNAL("itemClicked(QTreeWidgetItem*, int)"), self._onTreeClicked) self.connect(self.treeWidget_ScriptActions, Qt.SIGNAL("itemChanged(QTreeWidgetItem*, int)"), self._onTreeChanged) self._configureMenuActions() self._configureIcons() self.label_executing.setText("") self.label_executing.setPixmap(self._icons["exec"]["paused"]) self.tb = TreeBuilder(self.treeWidget_ScriptActions, self._icons) self._enableTreeChangeEvents = True def _configureMenuActions(self): self._actions = { # Tree: "tree_scrollTop":QtGui.QAction("Go to top", self.treeWidget_ScriptActions), "tree_scrollBottom":QtGui.QAction("Go to bottom", self.treeWidget_ScriptActions), "tree_collapseAll":QtGui.QAction("Collapse all", self.treeWidget_ScriptActions), "tree_expandAll":QtGui.QAction("Expand all", self.treeWidget_ScriptActions), # Script: DONE. "script_run":QtGui.QAction("Run script", self.treeWidget_ScriptActions), "script_pause":QtGui.QAction("Pause script", self.treeWidget_ScriptActions), "script_enable":QtGui.QAction("Enable script", self.treeWidget_ScriptActions), "script_disable":QtGui.QAction("Disable script", self.treeWidget_ScriptActions), "script_delayPre":QtGui.QAction("Configure script delay pre", self.treeWidget_ScriptActions), "script_delayPost":QtGui.QAction("Configure script delay post", self.treeWidget_ScriptActions), "script_author":QtGui.QAction("Configure script author", self.treeWidget_ScriptActions), "script_remove":QtGui.QAction("Remove script", self.treeWidget_ScriptActions), # All script: "all_script_enable":QtGui.QAction("Enable all scripts", self.treeWidget_ScriptActions), "all_script_disable":QtGui.QAction("Disable all scripts", self.treeWidget_ScriptActions), "all_script_delayPre":QtGui.QAction("Configure all scripts' delay pre", self.treeWidget_ScriptActions), "all_script_delayPost":QtGui.QAction("Configure all scripts' delay post", self.treeWidget_ScriptActions), "all_script_author":QtGui.QAction("Configure all scripts' author", self.treeWidget_ScriptActions), # Commands: "command_enable":QtGui.QAction("Enable this command", self.treeWidget_ScriptActions), "command_disable":QtGui.QAction("Disable this command", self.treeWidget_ScriptActions), "command_delayPre":QtGui.QAction("Configure command delay pre", self.treeWidget_ScriptActions), "command_delayPost":QtGui.QAction("Configure command delay post", self.treeWidget_ScriptActions), "command_author":QtGui.QAction("Edit command's author", self.treeWidget_ScriptActions), # All command "all_command_enable":QtGui.QAction("Enable all commands", self.treeWidget_ScriptActions), "all_command_disable":QtGui.QAction("Disable all commands", self.treeWidget_ScriptActions), "all_command_delayPre":QtGui.QAction("Configure all commands' delay pre", self.treeWidget_ScriptActions), "all_command_delayPost":QtGui.QAction("Configure all commands' delay post", self.treeWidget_ScriptActions), "all_command_author":QtGui.QAction("Edit all command's author", self.treeWidget_ScriptActions), "all_command_collapseAll":QtGui.QAction("Collapse all script's commands", self.treeWidget_ScriptActions), "all_command_expandAll":QtGui.QAction("Expand all script's commands", self.treeWidget_ScriptActions), } def _configureIcons(self): resourcesPath = self._resourcePath self._icons["enabled"][True] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "tree_tick.png")) self._icons["enabled"][False] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "tree_cross.png")) self._icons["state"][ExecutionState.RUNNING] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "state_running.png")) self._icons["state"][ExecutionState.PAUSED] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "state_paused.png")) self._icons["state"][ExecutionState.FINISHED] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "state_finished.png")) self._icons["state"][ExecutionState.NOT_RUN] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "state_notrun.png")) self._icons["time"]["delay"] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "time_delay.png")) self._icons["time"]["sleep"] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "time_sleep.png")) self._icons["author"] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "author.png")) self._icons["result"]["exc"] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "tree_cross.png")) self._icons["result"]["ok"] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "tree_tick.png")) self._icons["result"]["none"] = QtGui.QIcon(os.path.join(resourcesPath, "icons", "result_none.png")) self._icons["exec"]["running"] = QtGui.QPixmap(os.path.join(self._resourcePath, "icons", "icon_running.png")) self._icons["exec"]["paused"] = QtGui.QPixmap(os.path.join(self._resourcePath, "icons", "icon_sleep.png")) self._icons["exec"]["finished"] = QtGui.QPixmap(os.path.join(self._resourcePath, "icons", "icon_finished.png")) cmdPath = os.path.join(self._resourcePath, "icons", "actions") self._icons["command"]["generic"] = QtGui.QIcon(os.path.join(cmdPath, "action_command_generic.png")) for iconName, action in [("action_create.png", "create"), ("action_close.png", "close"), ("action_get.png", "get"), ("action_put.png", "put"), ("action_qsize.png", "qsize"), ("action_maxQSize.png", "maxQSize"), ]: self._loadIcon(cmdPath, iconName, action, self._icons["command"]["generic"]) self._icons["node"] = QtGui.QIcon(os.path.join(self._resourcePath, "icons", "icon_node.png")) def _loadIcon(self, path, iconName, action, defaultIcon): p = os.path.join(path, iconName) if os.path.exists(p): icon = QtGui.QIcon(p) else: icon = defaultIcon self._icons["command"][action] = icon return icon def _onTreeItemClicked(self, item, index): if self._enableTreeChangeEvents==True: pass # print "itemPressed(QTreeWidgetItem*, int): ", item, index def _onTreeClicked(self, item, index): if self._enableTreeChangeEvents==True: pass # print "itemClicked(QTreeWidgetItem*, int): ", item, index def _onTreeChanged(self, item, index): if self._enableTreeChangeEvents==True: print "itemChanged(QTreeWidgetItem*, int): ", item, index # Search the tree for the item and change the model's data: executioner = item.getScript() if executioner in self._scripts: self._changeExecutionerData(executioner, item, index) def _changeExecutionerData(self, executioner, item, index=1): newValue = item.text(index) if isinstance(item, TreeScriptDelayPre): executioner.delays["pre"] = int(newValue) elif isinstance(item, TreeScriptDelayPost): executioner.delays["post"] = int(newValue) elif isinstance(item, TreeScriptAuthor): executioner.author = str(newValue) elif isinstance(item, _baseTreeCommandConfig): config = item.getConfig() if isinstance(item, TreeCommandDelayPre): config["_delay_pre_"] = int(newValue) elif isinstance(item, TreeCommandDelayPost): config["_delay_post_"] = int(newValue) elif isinstance(item, TreeCommandAuthor): config["_author_"] = str(newValue) else: # No idea how to edit this one!!! pass # print "No idea what I'm editing at index: %(I)s for: %(W)s"%{"I":index, "W":item} def _getAllRootScripts(self): scripts = [] for index in xrange(self.treeWidget_ScriptActions.topLevelItemCount()): scripts.append(self.treeWidget_ScriptActions.topLevelItem(index).getScript()) return scripts def _onTreePopup(self, pos): result = self._showTreePopup(pos) if result!=None: (action, item) = result self._handleActions(action, item) def _getAuthor(self, text, value): (value, ok) = QtGui.QInputDialog.getText(self, text, "Author:", QtGui.QLineEdit.Normal, value) if ok is False: return value = str(value) return value def _getDelay(self, value): value, ok = QtGui.QInputDialog.getInt(self, "Edit script: _delay_pre_", "Delay (seconds):", value=0, min=-1, step=1) if ok is False: return return value def _scrollToTop(self): try: self.treeWidget_ScriptActions.scrollToItem(self.treeWidget_ScriptActions.topLevelItem(0), Qt.QAbstractItemView.PositionAtTop) except Exception, _e: pass def _scrollToBottom(self): index = (self.treeWidget_ScriptActions.topLevelItemCount()-1) if index>=0: item = self.treeWidget_ScriptActions.topLevelItem(index) self.treeWidget_ScriptActions.scrollToItem(item, Qt.QAbstractItemView.PositionAtTop) def _handleActions(self, action, item): self._enableTreeChangeEvents = False try: script = item.getScript() config = None if isinstance(item, _baseTreeCommandConfig): config = item.getConfig() # Script: if action==self._actions["tree_collapseAll"]: self._treeIsExpanded = 0 self._expandTree() elif action==self._actions["tree_expandAll"]: self._treeIsExpanded = 1 self._expandTree() elif action==self._actions["tree_scrollTop"]: self._scrollToTop() elif action==self._actions["tree_scrollBottom"]: self._scrollToBottom() elif action==self._actions["script_run"]: self._onExecute(script) elif action==self._actions["script_pause"]: self._onPause() elif action==self._actions["script_enable"]: script.enabled = True self._updateScriptEnabled(script) elif action==self._actions["script_disable"]: script.enabled = False self._updateScriptEnabled(script) elif action==self._actions["script_remove"]: self._scripts.remove(script) self._updateScriptRemoved(script) elif action==self._actions["script_author"]: value = self._getAuthor("Edit: Author", script.author) if value==None: return script.author = value self._updateScriptAuthor(script) elif action==self._actions["script_delayPre"]: value = self._getDelay(script.delays["pre"]) if value==None: return if value==-1: value = None script.delays["pre"] = str(value) self._updateScriptDelayPre(script) elif action==self._actions["script_delayPost"]: value = self._getDelay(script.delays["post"]) if value==None: return if value==-1: value = None script.delays["post"] = str(value) self._updateScriptDelayPost(script) # All script: elif action==self._actions["all_script_enable"]: for script in self._getAllRootScripts(): script.enabled = True self._updateScriptEnabled(script) elif action==self._actions["all_script_disable"]: for script in self._getAllRootScripts(): script.enabled = False self._updateScriptEnabled(script) elif action==self._actions["all_script_author"]: value = self._getAuthor("Edit: Author", script.author) if value==None: return for script in self._getAllRootScripts(): script.author = value self._updateScriptAuthor(script) elif action==self._actions["all_script_delayPre"]: value = self._getDelay(script.delays["pre"]) if value==None: return if value==-1: value = None for script in self._getAllRootScripts(): script.delays["pre"] = value self._updateScriptDelayPre(script) elif action==self._actions["all_script_delayPost"]: value = self._getDelay(script.delays["post"]) if value==None: return if value==-1: value = None for script in self._getAllRootScripts(): script.delays["post"] = value self._updateScriptDelayPost(script) # Commands: elif action==self._actions["command_enable"]: config["_enabled_"] = True self._updateCommandEnable(script, config) elif action==self._actions["command_disable"]: config["_enabled_"] = False self._updateCommandEnable(script, config) elif action==self._actions["command_delayPre"]: value = self._getDelay(config["_delay_pre_"] ) if value==None: return if value==-1: value = None config["_delay_pre_"] = value self._updateDelayPre(script, config) elif action==self._actions["command_delayPost"]: value = self._getDelay(config["_delay_post_"] ) if value==None: return if value==-1: value = None config["_delay_post_"] = value self._updateDelayPost(script, config) elif action==self._actions["command_author"]: if "_author_" in config: author = config["_author_"] else: author = self._parent.author value = self._getAuthor("Edit: Author", author) if value==None: return config["_author_"] = value self._updateCommandAuthor(script, config) # All commands elif action==self._actions["all_command_collapseAll"]: # Collapse all tree nodes for this script: item = self._findScript(script) self._collapseCommands(item) elif action==self._actions["all_command_expandAll"]: item = self._findScript(script) self._expandCommands(item) elif action==self._actions["all_command_enable"]: for config_ in script.configs: config_["_enabled_"] = True self._updateCommandEnable(script, config_) elif action==self._actions["all_command_disable"]: for config_ in script.configs: config_["_enabled_"] = False self._updateCommandEnable(script, config_) elif action==self._actions["all_command_delayPre"]: value = self._getDelay(0) if value==None: return if value==-1: value = None for config_ in script.configs: config_["_delay_pre_"] = value self._updateDelayPre(script, config_) elif action==self._actions["all_command_delayPost"]: value = self._getDelay(0) if value==None: return if value==-1: value = None for config_ in script.configs: config_["_delay_post_"] = value self._updateDelayPost(script, config_) elif action==self._actions["all_command_author"]: author = self._parent.author value = self._getAuthor("Edit: Author", author) if value==None: return for config_ in script.configs: config_["_author_"] = value self._updateCommandAuthor(script, config_) finally: self._enableTreeChangeEvents = True def _expandCommands(self, item): # Expand all tree command nodes for this item: for index in xrange(0, item.childCount()): child = item.child(index) if isinstance(child, TreeCommandRoot): for index in xrange(0, child.childCount()): child1 = child.child(index) print "expanding item: ", child1 self.treeWidget_ScriptActions.expandItem(child1) return def _collapseCommands(self, item): # Collapse all tree command nodes for this item: for index in xrange(0, item.childCount()): child = item.child(index) if isinstance(child, TreeCommandRoot): for index in xrange(0, child.childCount()): child1 = child.child(index) print "collapsing item: ", child1 self.treeWidget_ScriptActions.collapseItem(child1) return def _updateScriptEnabled(self, script): # The current script 'enabled' has changed, alter the tree to reflect this. root = self._findScript(script) self.tb.setScriptEnabled(script, root) def _updateScriptRemoved(self, script): item = self._findScript(script) t = self.treeWidget_ScriptActions t.takeTopLevelItem(t.indexOfTopLevelItem(item)) def _updateCommandEnable(self, script, config): # The current config 'enabled' has changed, alter the tree to reflect this. child = self._findConfig(script, config["uId"]) commandState = config["_executing_"] enabledState = config["_enabled_"] self.tb.setConfigEnabled(child, commandState, enabledState) return def _findConfig(self, script, uId): for index in xrange(self.treeWidget_ScriptActions.topLevelItemCount()): item = self.treeWidget_ScriptActions.topLevelItem(index) itemScript = item.getScript() if itemScript==script: for childIndex in xrange(0, item.childCount()): child = item.child(childIndex) if isinstance(child, TreeCommandRoot): for childIndex1 in xrange(0, child.childCount()): child1 = child.child(childIndex1) if isinstance(child1, TreeCommands): if child1.getConfig()["uId"]==uId: return child1 def _findConfigAuthor(self, script, uId): child1 = self._findConfig(script, uId) # Now find the author from the child1's children, # if no author, return child1. for index in xrange(0, child1.childCount()): child2 = child1.child(index) if isinstance(child2, TreeCommandAuthor): return (child1, child2) else: return (child1, None) def _updateDelayPre(self, script, config): # The current config 'delay-pre' has changed, alter the tree to reflect this. delay = config["_delay_pre_"] item, parent = self._findConfigDelayPre(script, config["uId"]) if delay!=None: if item: item.setText(1, str(delay)) else: # Add a new node: item = self.tb.addConfigDelayPre(script, script.configs.index(config), config, parent) parent.insertChild(0, item) else: # Remove an existing delay: if item: parent.removeChild(item) def _updateDelayPost(self, script, config): # The current config 'delay-post' has changed, alter the tree to reflect this. delay = config["_delay_post_"] item, parent = self._findConfigDelayPost(script, config["uId"]) if delay!=None: if item: item.setText(1, str(delay)) else: # Add a new node: item = self.tb.addConfigDelayPost(script, script.configs.index(config), config, parent) parent.insertChild(0, item) else: # Remove an existing delay: if item: parent.removeChild(item) def _findConfigDelayPost(self, script, uId): return self._findConfigDelay(script, uId, TreeCommandDelayPost) def _findConfigDelayPre(self, script, uId): return self._findConfigDelay(script, uId, TreeCommandDelayPre) def _findConfigDelay(self, script, uId, type_): item = self._findConfig(script, uId) for childIndex2 in xrange(0, item.childCount()): child2 = item.child(childIndex2) if isinstance(child2, type_): return child2, item return (None, item) def _updateScriptDelayPre(self, script): # The current script 'delay-pre' has changed, alter the tree to reflect this. child = self._findScriptDelayPre(script) delay = script.delays["pre"] child.setText(1, str(delay)) def _updateScriptDelayPost(self, script): # The current script 'delay-post' has changed, alter the tree to reflect this. child = self._findScriptDelayPost(script) delay = script.delays["post"] child.setText(1, str(delay)) def _findScriptDelayPost(self, script): # The current script 'delay-post' has changed, alter the tree to reflect this. return self._findScriptDelay(script, TreeScriptDelayPost) def _findScriptDelayPre(self, script): # The current script 'delay-pre' has changed, alter the tree to reflect this. return self._findScriptDelay(script, TreeScriptDelayPre) def _findScriptDelay(self, script, type_): item = self._findScript(script) for childIndex in xrange(0, item.childCount()): child = item.child(childIndex) if isinstance(child, type_): return child def _findScript(self, script): for index in xrange(self.treeWidget_ScriptActions.topLevelItemCount()): item = self.treeWidget_ScriptActions.topLevelItem(index) itemScript = item.getScript() if itemScript==script: return item def _updateScriptFinished(self, script): # The current script has finished, alter the tree to reflect this. item = self._findScript(script) if item!=None: self.tb.setResultIcon(item) item.setText(1, "Status: Finished") self.tb.setStateIcon(item, ExecutionState.FINISHED) def _updateScriptStarted(self, script): # The current script has started, alter the tree to reflect this. item = self._findScript(script) if item!=None: self.tb.setResultIcon(item) item.setText(1, "Status: Testing") self.tb.setStateIcon(item, ExecutionState.RUNNING) def _updateScriptPaused(self, script=None): # The current script has paused, alter the tree to reflect this. if script==None: try: script = self._scripts[self._executing] except Exception, _e: return item = self._findScript(script) if item!=None: self.tb.setResultIcon(item) item.setText(1, "Status: Paused") self.tb.setStateIcon(item, ExecutionState.PAUSED) def _updateScriptAuthor(self, script): # The current script 'author' has changed, alter the tree to reflect this. child = self._findScriptAuthor(script) author = str(script.author) child.setText(1, author) def _updateCommandAuthor(self, script, config): # The current command 'enabled' has changed, alter the tree to reflect this. author = str(config["_author_"]) (parent, child) = self._findConfigAuthor(script, config) if child==None: # Need to add an author element. item = self.tb.addConfigAuthor(script, self._scripts.index(script), config, parent) parent.insertChild(0, item) else: # Need to change the existing element: child.setText(1, str(author)) def _updateCommandResult(self, script, config, result): state = config["_executing_"] (child, parent) = self._findCommandResult(script, config["uId"]) if child==None: if isinstance(result, NoResult): # Alter the parent's icon! self.tb.setStateIcon(parent, state) else: # Need to add an author element. item = self.tb.addConfigResult(script, self._scripts.index(script), config, parent) parent.insertChild(0, item) else: # Need to change the existing element: if result==None: result = "" child.setText(1, str(result)) self.tb.setResultIcon(child, result) def _updateCommandFinished(self, script, uId): (child, parent) = self._findCommandResult(script, uId) if child!=None: # Set the parent's icon too: self.tb.setStateIcon(parent, ExecutionState.FINISHED) def _findCommandResult(self, script, uId): node = self._findConfig(script, uId) for index in xrange(node.childCount()): child = node.child(index) if isinstance(child, TreeCommandResult): return (child, node) return (None, node) def _findScriptAuthor(self, script): for index in xrange(self.treeWidget_ScriptActions.topLevelItemCount()): item = self.treeWidget_ScriptActions.topLevelItem(index) itemScript = item.getScript() if itemScript==script: for childIndex in xrange(0, item.childCount()): child = item.child(childIndex) if isinstance(child, TreeScriptAuthor): return child def _showTreePopup(self, pos): item = self.treeWidget_ScriptActions.itemAt(pos) if item!=None: pos = self.treeWidget_ScriptActions.mapToGlobal(pos) return item.showTreePopup(self, item, self._actions, QtGui.QMenu(self.treeWidget_ScriptActions), pos) def _onReload(self): self._onClear() self.doLoadUi() def _renderScript(self, scriptIndex): tb =self.tb script = self._scripts[scriptIndex] tv = self.treeWidget_ScriptActions # Now create it from scratch: root = tb.addScriptRoot(script) tb.addScriptAuthor(script, root) delay = script.delays["pre"] if delay==None: delay = 0 tb.addScriptDelayPre(script, str(delay), root) delay = script.delays["post"] if delay==None: delay = 0 tb.addScriptDelayPost(script, str(delay), root) commands = tb.addConfigRoot(script, root) for index, config in enumerate(script.configs): command = tb.addConfigs(script, index, config, commands) if "_author_" in config and config["_author_"]!=None: tb.addConfigAuthor(script, index, config, command) if config["_delay_pre_"]!=None: tb.addConfigDelayPre(script, index, config, command) tb.addCommand(script, index, config, command) if config["_delay_post_"]!=None: tb.addConfigDelayPost(script, index, config, command) tv.insertTopLevelItem(0, root) return root def _render(self): self._enableTreeChangeEvents = False try: # Clear the existing model: tv = self.treeWidget_ScriptActions model = tv.model() try: model.removeRows(0, model.rowCount()) except: pass tv.setColumnCount(2) for index in xrange(0, len(self._scripts)): self._renderScript(index) if len(self._scripts)>0: self.pushButton_Run.setEnabled(True) self.pushButton_Pause.setEnabled(False) else: self.pushButton_Run.setEnabled(False) self.pushButton_Pause.setEnabled(False) self._expandTree() finally: self._enableTreeChangeEvents = True def _getUniqueName(self, script): eName = script.getName() names = [] for script_ in self._scripts: names.append(script_.getName()) while eName in names: eName = script.uId.next() script.name = eName def _onInjectScript(self, script): self._enableTreeChangeEvents = False self._getUniqueName(script) self._scripts.append(script) item = self._renderScript(len(self._scripts)-1) # Now scroll to show the newly inserted script: self.treeWidget_ScriptActions.scrollToItem(item, Qt.QAbstractItemView.EnsureVisible) self.pushButton_Run.setEnabled(True) self._enableTreeChangeEvents = True if (self._executing==None) and (script.enabled==True): self._onExecute(script=script) def _onPause(self): self._paused = True self.label_executing.setPixmap(self._icons["exec"]["paused"]) if self._executing!=None: for script in self._scripts: script.pause() self.pushButton_Run.setEnabled(True) self.pushButton_Pause.setEnabled(False) self._updateScriptPaused() else: self.pushButton_Run.setEnabled(True) self.pushButton_Pause.setEnabled(False) def _onExecute(self, script=None, workId=None): # Execute the next available script (primary) or 'script' if provided (secondary). self._paused = False if len(self._scripts)==0: self.pushButton_Run.setEnabled(False) self.pushButton_Pause.setEnabled(False) return if self._executing==None: # Get the next available script: if script==None: for index, script in enumerate(self._scripts): if script.enabled==True: break else: index = self._scripts.index(script) if index==-1: script = None if script!=None: # Mark the first script as executing. self._executing = index else: # Is the current script disabled, if so move onto the next script # unless 'script' is disabled. if self._executing>=len(self._scripts): self._executing = 0 startIndex = self._executing while self._scripts[self._executing].enabled==False: # Find the next script: self._executing += 1 if self._executing>=len(self._scripts): self._executing = 0 if self._executing==startIndex: break # Execute the current script (un-pause it) if self._executing!=None: self.label_executing.setPixmap(self._icons["exec"]["running"]) self.pushButton_Run.setEnabled(False) self.pushButton_Pause.setEnabled(True) self._readOnly = True self.emit(Qt.SIGNAL("readOnly()")) self._scripts[self._executing].execute(workId=workId) def _getLoop(self): for what, index in [(self.radioButton_LoopOne, 0), (self.radioButton_LoopAll, 1), (self.radioButton_LoopNone, 2)]: if what.isChecked(): return index self.radioButton_LoopOne.isChecked() def _setLoop(self, index): if index==0: self.radioButton_LoopOne.setChecked(True) elif index==1: self.radioButton_LoopAll.setChecked(True) else: self.radioButton_LoopNone.setChecked(True) def _getDefaultsTimeouts(self): return {"loop": 1} def doLoadUi(self): settings = self._parent.settings settings.beginGroup("ui") try: settings.beginGroup("scripter") try: self.loadUi(settings) finally: settings.endGroup() finally: settings.endGroup() def loadUi(self, settings=None): if settings==None: settings = self._parent.settings (value, isValid) = settings.value("executing").toInt() if isValid: self._executing = int(value) else: self._executing = None (value, isValid) = settings.value("loop", Scripter.DEFAULT_LOOP_INDEX).toInt() if isValid: self._setLoop(int(value)) (value, isValid) = settings.value("treeExpanded", Scripter.DEFAULT_TREE_EXPANDED_STATE).toInt() if isValid: self._treeIsExpanded = value self._paused = settings.value("paused").toBool() try: value = settings.value("timeouts", type=bytearray) value = str(value) self._timeouts = pickle.loads(value) except Exception, _e: pass settings.beginGroup("scripts") try: for group in settings.childGroups(): settings.beginGroup(group) try: script = GlobalExecutioner.loadUi(self, settings) if script!=None: self._scripts.append(script) finally: settings.endGroup() finally: settings.endGroup() # All scripts are loaded and paused. self._render() def saveUi(self, settings=None): if settings==None: settings = self._parent.settings settings.setValue("executing", self._executing) settings.setValue("loop", self._getLoop()) settings.setValue("treeExpanded", self._treeIsExpanded) settings.setValue("paused", self._paused) settings.setValue("timeouts", bytearray(pickle.dumps(self._timeouts))) settings.beginGroup("scripts") try: settings.remove("") for script in self._scripts: group = script.getName() settings.beginGroup(group) try: script.saveUi(settings) finally: settings.endGroup() finally: settings.endGroup() def _onClear(self): # Teardown the tree and rebuild it. for script in self._scripts: script.pause() self._scripts = [] self._executing = None self._render() def _onSave(self): settings = self._parent.settings settings.beginGroup("ui") try: settings.beginGroup("scripter") try: self.saveUi(settings) finally: settings.endGroup() finally: settings.endGroup() def _onStepExecution(self, workId, script): if script in self._scripts: script.step(workId) def _onExecutionFinished(self, workId, script): # A script has completed, mark it as completed in the tree. print "Script finished...workId: %(W)s, for script: %(S)s"%{"S":script, "W":workId} if len(self._scripts)==0: return loop = self._getLoop() def startTimeout(timeout, script, workId=None): def doExecute(script, workId=None): if self._paused==False: self._resetScript(script, workId) self._onExecute(script=script, workId=workId) if timeout==None: doExecute(script, workId) else: t = threading.Timer(timeout, doExecute, args=[script]) t.setName("LoopOne_%(T)s"%{"T":timeout}) t.setDaemon(True) t.start() timeout = self._timeouts["loop"] if loop==0: # Re-run the script: print "Re-running script: %(S)s"%{"S":script} startTimeout(timeout, script, workId) elif loop==1: print "Loop onto next script: %(S)s"%{"S":script} # Onto the next script: if (len(self._scripts)-1)==self._executing: # Loop self._executing = 0 else: self._executing += 1 startTimeout(timeout, script) else: # Stop script execution: self.label_executing.setPixmap(self._icons["exec"]["finished"]) self.pushButton_Run.setEnabled(True) self.pushButton_Pause.setEnabled(False) self._updateScriptFinished(script) self._readOnly = False self.emit(Qt.SIGNAL("readOnly()")) def _resetScript(self, script, workId): # Reset the script: script.reset(workId) # TODO: reset the script in the tree. def _expandTree(self): value = self._treeIsExpanded if value==0: self.treeWidget_ScriptActions.collapseAll() self.treeWidget_ScriptActions.resizeColumnToContents(0) elif value==1: self.treeWidget_ScriptActions.expandAll() self.treeWidget_ScriptActions.resizeColumnToContents(0) def _onExecutionStepped(self, workId, uId, script): # A script config uId is completed, mark it as completed in the tree. print "Command stepped...workId: %(W)s, uId: %(U)s, for script: %(S)s"%{"S":script, "W":workId, "U":uId} self._updateCommandFinished(script, uId) if self._paused==True: self._readOnly = False self.emit(Qt.SIGNAL("readOnly()")) def _onReadOnly(self): enabler = not self._readOnly for what in [ self.pushButton_Reload, self.pushButton_Clear, self.pushButton_Reload, self.pushButton_Save, ]: what.setEnabled(enabler) def _onExecutionStepping(self, workId, uId, script): # A script config uId is starting to execute, mark it as started in the tree. print "Command stepping...workId: %(W)s, uId: %(U)s, for script: %(S)s"%{"S":script, "W":workId, "U":uId} for config in script.configs: if config["uId"]==uId: item = self._findConfig(script, config["uId"]) self.tb.setStateIcon(item, ExecutionState.RUNNING) def _onExecutionStepResult(self, uId, kwargs, script): # Script command result in... if script in self._scripts: if "result" in kwargs: result = kwargs["result"] print "Command result...uId: %(U)s, for script: %(S)s:\r\n<%(R)s>"%{"S":script, "U":uId, "R":result} for config in script.configs: if config["uId"]==uId: config["_result_"] = result self._updateCommandResult(script, config, result) break def _onExecutionStarted(self, workId, script): # Script has begun execution, mark it as started in the tree. print "script started: %(S)s"%{"S":script} self._updateScriptStarted(script) def _onExecutionDelay(self, state, workId, delay, what, uId, script): # Script/Command has begun delay action, mark it as delayed in the tree. print "Delay...workId: %(W)s, uId: %(U)s, delay: %(D)s, state: %(ST)s for script: %(S)s"%{"S":script, "W":workId, "U":uId, "D":delay, "ST":state} if "script" in what: if "pre" in what["script"]: item = self._findScriptDelayPre(script) else: item = self._findScriptDelayPost(script) if state==1: self.tb.setScriptSleepIcon(item) else: self.tb.setScriptDelayIcon(item) elif "config" in what: if "pre" in what["config"]: (item, _) = self._findConfigDelayPre(script, uId) else: (item, _) = self._findConfigDelayPost(script, uId) if item!=None: if state==1: self.tb.setConfigSleepIcon(item) else: self.tb.setConfigDelayIcon(item)