def get_wf_graph(w_list, workflow_info=None, pdf=False): """run_and_get_results(w_list: list of (locator, version), workflow_info:str, pdf:bool) Load all workflows in wf_list and dump their graph to workflow_info. """ result = [] if is_running_gui(): from gui.vistrail_controller import VistrailController as \ GUIVistrailController for locator, workflow in w_list: try: (v, abstractions, thumbnails, mashups) = load_vistrail(locator) controller = GUIVistrailController() if type(workflow) == type("str"): version = v.get_version_number(workflow) elif type(workflow) in [type(1), long]: version = workflow elif workflow is None: version = controller.get_latest_version_in_graph() else: msg = "Invalid version tag or number: %s" % workflow raise VistrailsInternalError(msg) controller.change_selected_version(version) if (workflow_info is not None and controller.current_pipeline is not None): from gui.pipeline_view import QPipelineView pipeline_view = QPipelineView() controller.current_pipeline_view = pipeline_view.scene() controller.set_vistrail(v, locator, abstractions, thumbnails, mashups) pipeline_view.scene().setupScene( controller.current_pipeline) if pdf: base_fname = "%s_%s_pipeline.pdf" % ( locator.short_name, version) filename = os.path.join(workflow_info, base_fname) pipeline_view.scene().saveToPDF(filename) else: base_fname = "%s_%s_pipeline.png" % ( locator.short_name, version) filename = os.path.join(workflow_info, base_fname) pipeline_view.scene().saveToPNG(filename) del pipeline_view result.append((True, "")) except Exception, e: result.append((False, str(e)))
def get_wf_graph(w_list, workflow_info=None, pdf=False): """run_and_get_results(w_list: list of (locator, version), workflow_info:str, pdf:bool) Load all workflows in wf_list and dump their graph to workflow_info. """ result = [] if is_running_gui(): from gui.vistrail_controller import VistrailController as \ GUIVistrailController for locator, workflow in w_list: try: (v, abstractions , thumbnails, mashups) = load_vistrail(locator) controller = GUIVistrailController() if type(workflow) == type("str"): version = v.get_version_number(workflow) elif type(workflow) in [ type(1), long]: version = workflow elif workflow is None: version = controller.get_latest_version_in_graph() else: msg = "Invalid version tag or number: %s" % workflow raise VistrailsInternalError(msg) controller.change_selected_version(version) if (workflow_info is not None and controller.current_pipeline is not None): from gui.pipeline_view import QPipelineView pipeline_view = QPipelineView() controller.current_pipeline_view = pipeline_view.scene() controller.set_vistrail(v, locator, abstractions, thumbnails, mashups) pipeline_view.scene().setupScene(controller.current_pipeline) if pdf: base_fname = "%s_%s_pipeline.pdf" % (locator.short_name, version) filename = os.path.join(workflow_info, base_fname) pipeline_view.scene().saveToPDF(filename) else: base_fname = "%s_%s_pipeline.png" % (locator.short_name, version) filename = os.path.join(workflow_info, base_fname) pipeline_view.scene().saveToPNG(filename) del pipeline_view result.append((True, "")) except Exception, e: result.append((False, str(e)))
class QVistrailView(QDockContainer): """ QVistrailView is a widget containing four stacked widgets: Pipeline View, Version Tree View, Query View and Parameter Exploration view for manipulating vistrails. """ def __init__(self, parent=None): """ QVistrailItem(parent: QWidget) -> QVistrailItem Make it a main window with dockable area """ QDockContainer.__init__(self, parent) # The window title is the name of the vistrail file self.setWindowTitle('untitled%s'%vistrails_default_file_type()) # Create the views self.pipelineTab = QPipelineTab() self.versionTab = QVersionTab() self.connect(self.versionTab.versionProp, QtCore.SIGNAL('textQueryChange(bool)'), self.setQueryMode) self.pipelineTab.pipelineView.setPIPScene( self.versionTab.versionView.scene()) self.versionTab.versionView.setPIPScene( self.pipelineTab.pipelineView.scene()) self.versionTab.versionView.scene()._pipeline_scene = self.pipelineTab.pipelineView.scene() self.queryTab = QQueryTab() self.peTab = QParameterExplorationTab() self.peTab.annotatedPipelineView.setScene( self.pipelineTab.pipelineView.scene()) # Setup a central stacked widget for pipeline view and version # tree view self.stackedWidget = QtGui.QStackedWidget() self.setCentralWidget(self.stackedWidget) self.stackedWidget.addWidget(self.pipelineTab) self.stackedWidget.addWidget(self.versionTab) self.stackedWidget.addWidget(self.queryTab) self.stackedWidget.addWidget(self.peTab) self.stackedWidget.setCurrentIndex(1) # Initialize the vistrail controller self.controller = VistrailController() self.controller.vistrail_view = self self.connect(self.controller, QtCore.SIGNAL('stateChanged'), self.stateChanged) self.connect(self.controller, QtCore.SIGNAL('new_action'), self.new_action) self.connect(self.versionTab.versionView.scene(), QtCore.SIGNAL('versionSelected(int,bool)'), self.versionSelected) self.connect(self.versionTab, QtCore.SIGNAL('twoVersionsSelected(int,int)'), self.twoVersionsSelected) self.connect(self.queryTab, QtCore.SIGNAL('queryPipelineChange'), self.queryPipelineChange) self.connect(self.peTab, QtCore.SIGNAL('exploreChange(bool)'), self.exploreChange) # We also keep track where this vistrail comes from # So we can save in the right place self.locator = None self.closeEventHandler = None # the redo stack stores the undone action ids # (undo is automatic with us, through the version tree) self.redo_stack = [] # Keep the state of the execution button and menu items for the view self.execQueryEnabled = False self.execDiffEnabled = False self.execExploreEnabled = False self.execPipelineEnabled = False self.execDiffId1 = -1 self.execDiffId2 = -1 def updateCursorState(self, mode): """ updateCursorState(mode: Int) -> None Change cursor state in all different modes. """ self.pipelineTab.pipelineView.setDefaultCursorState(mode) self.versionTab.versionView.setDefaultCursorState(mode) self.queryTab.pipelineView.setDefaultCursorState(mode) if self.parent().parent().parent().pipViewAction.isChecked(): self.pipelineTab.pipelineView.pipFrame.graphicsView.setDefaultCursorState(mode) self.versionTab.versionView.pipFrame.graphicsView.setDefaultCursorState(mode) def flush_changes(self): """Flush changes in the vistrail before closing or saving. """ # Quick workaround for notes focus out bug (ticket #182) # There's probably a much better way to fix this. prop = self.versionTab.versionProp prop.versionNotes.commit_changes() def setup_view(self, version=None): """setup_view(version = None:int) -> None Sets up the correct view for a fresh vistrail. Previously, there was a method setInitialView and another setOpenView. They were supposed to do different things but the code was essentially identical. FIXME: this means that the different calls are being handled somewhere else in the code. Figure this out.""" if version is None: self.controller.select_latest_version() version = self.controller.current_version self.versionSelected(version, False) self.setPIPMode(True) self.setQueryMode(False) def setPIPMode(self, on): """ setPIPMode(on: bool) -> None Set the PIP state for the view """ self.pipelineTab.pipelineView.setPIPEnabled(on) self.versionTab.versionView.setPIPEnabled(on) def setQueryMode(self, on): """ setQueryMode(on: bool) -> None Set the Reset Query button mode for the view """ self.pipelineTab.pipelineView.setQueryEnabled(on) self.versionTab.versionView.setQueryEnabled(on) self.queryTab.pipelineView.setQueryEnabled(on) def setMethodsMode(self, on): """ setMethodsMode(on: bool) -> None Set the methods panel state for the view """ if on: self.pipelineTab.methodPalette.toolWindow().show() else: self.pipelineTab.methodPalette.toolWindow().hide() def setSetMethodsMode(self, on): """ setSetMethodsMode(on: bool) -> None Set the set methods panel state for the view """ if on: self.pipelineTab.moduleMethods.toolWindow().show() else: self.pipelineTab.moduleMethods.toolWindow().hide() def setPropertiesMode(self, on): """ setPropertiesMode(on: bool) -> None Set the properties panel state for the view """ if on: self.versionTab.versionProp.toolWindow().show() else: self.versionTab.versionProp.toolWindow().hide() def setPropertiesOverlayMode(self, on): """ setPropertiesMode(on: bool) -> None Set the properties overlay state for the view """ if on: self.versionTab.versionView.versionProp.show() else: self.versionTab.versionView.versionProp.hide() def viewModeChanged(self, index): """ viewModeChanged(index: int) -> None Slot for switching different views when the tab's current widget is changed """ if self.stackedWidget.count()>index: self.stackedWidget.setCurrentIndex(index) def sizeHint(self): """ sizeHint(self) -> QSize Return recommended size of the widget """ return QtCore.QSize(1024, 768) def set_vistrail(self, vistrail, locator=None): """ set_vistrail(vistrail: Vistrail, locator: BaseLocator) -> None Assign a vistrail to this view, and start interacting with it """ self.vistrail = vistrail self.locator = locator self.controller.set_vistrail(vistrail, locator) self.versionTab.setController(self.controller) self.pipelineTab.setController(self.controller) self.peTab.setController(self.controller) def stateChanged(self): """ stateChanged() -> None Handles 'stateChanged' signal from VistrailController Update the window and tab title """ title = self.controller.name if title=='': title = 'untitled%s'%vistrails_default_file_type() if self.controller.changed: title += '*' self.setWindowTitle(title) # propagate the state change to the version prop # maybe in the future we should propagate as a signal versionId = self.controller.current_version self.versionTab.versionProp.updateVersion(versionId) def emitDockBackSignal(self): """ emitDockBackSignal() -> None Emit a signal for the View Manager to take this widget back """ self.emit(QtCore.SIGNAL('dockBack'), self) def closeEvent(self, event): """ closeEvent(event: QCloseEvent) -> None Only close if we save information """ if self.closeEventHandler: if self.closeEventHandler(self): event.accept() else: event.ignore() else: #I think there's a problem with two pipeline views and the same #scene on Macs. After assigning a new scene just before deleting #seems to solve the problem self.peTab.annotatedPipelineView.setScene(QtGui.QGraphicsScene()) return QDockContainer.closeEvent(self, event) # super(QVistrailView, self).closeEvent(event) def queryVistrail(self, on=True): """ queryVistrail(on: bool) -> None Inspecting the query tab to get a pipeline for querying """ if on: queryPipeline = self.queryTab.controller.current_pipeline if queryPipeline: self.controller.query_by_example(queryPipeline) self.setQueryMode(True) else: self.controller.set_search(None) self.setQueryMode(False) def createPopupMenu(self): """ createPopupMenu() -> QMenu Create a pop up menu that has a list of all tool windows of the current tab of the view. Tool windows can be toggled using this menu """ return self.stackedWidget.currentWidget().createPopupMenu() def executeParameterExploration(self): """ executeParameterExploration() -> None Execute the current parameter exploration in the exploration tab """ self.peTab.performParameterExploration() def versionSelected(self, versionId, byClick): """ versionSelected(versionId: int, byClick: bool) -> None A version has been selected/unselected, update the controller and the pipeline view """ if self.controller: self.controller.reset_pipeline_view = byClick self.controller.change_selected_version(versionId) self.controller.invalidate_version_tree(False) if byClick: self.controller.current_pipeline_view.fitToAllViews(True) self.versionTab.versionProp.updateVersion(versionId) self.versionTab.versionView.versionProp.updateVersion(versionId) self.redo_stack = [] self.emit(QtCore.SIGNAL('versionSelectionChange'),versionId) self.execPipelineEnabled = versionId>-1 self.execDiffEnabled = False self.execExploreChange = False self.emit(QtCore.SIGNAL('execStateChange()')) def twoVersionsSelected(self, id1, id2): """ twoVersionsSelected(id1: Int, id2: Int) -> None Just echo the signal from the view """ self.execDiffEnabled = True self.execDiffId1 = id1 self.execDiffId2 = id2 self.emit(QtCore.SIGNAL('execStateChange()')) def queryPipelineChange(self, notEmpty): """ queryPipelineChange(notEmpty: bool) -> None Update the status of tool bar buttons if there are modules on the query canvas """ self.execQueryEnabled = notEmpty self.emit(QtCore.SIGNAL('execStateChange()')) def exploreChange(self, notEmpty): """ exploreChange(notEmpty: bool) -> None Update the status of tool bar buttons if there are parameters in the exploration canvas """ self.execExploreEnabled = notEmpty self.emit(QtCore.SIGNAL('execStateChange()')) ########################################################################## # Undo/redo def set_pipeline_selection(self, old_action, new_action, optype): # Sets up the right selection based on the the old and new # actions coming from undo/redo. pScene = self.pipelineTab.pipelineView.scene() # select things, if appropriate def old_deletion_test(): return (old_action and any(old_action.operations, lambda x: x.vtType == 'delete')) def old_deletion(): # Previous action was a deletion, select what was just # deleted and undone for op in old_action.operations: if op.what == 'module' and op.vtType == 'delete': module = pScene.modules[op.objectId] module.setSelected(True) def old_move_test(): return (old_action and any(old_action.operations, lambda x: x.what == 'location' and x.vtType == 'change')) def old_move(): for op in old_action.operations: if op.what == 'location' and op.vtType == 'change': module = pScene.modules[op.parentObjId] module.setSelected(True) def new_addition_test(): return (new_action and any(new_action.operations, lambda x: x.vtType == 'add')) def new_addition(): # This action was an addition, select the thing that was # added in this version for op in new_action.operations: if op.what == 'module' and op.vtType == 'add': module = pScene.modules[op.objectId] module.setSelected(True) def new_move_test(): return (new_action and any(new_action.operations, lambda x: x.what == 'location' and x.vtType == 'change')) def new_move(): # some action was a move, select the things that were moved for op in new_action.operations: if op.what == 'location' and op.vtType == 'change': module = pScene.modules[op.parentObjId] module.setSelected(True) old_deletion_pair = (old_deletion_test, old_deletion) old_move_pair = (old_move_test, old_move) new_addition_pair = (new_addition_test, new_addition) new_move_pair = (new_move_test, new_move) dispatch = {'undo': [old_deletion_pair, old_move_pair, new_addition_pair, new_move_pair], 'redo': [new_move_pair, new_addition_pair, old_move_pair, old_deletion_pair]} assert optype in dispatch for (test, handler) in dispatch[optype]: if test(): handler() return # If we get here, we couldn't recognize the action # FIXME: Add tests and handlers for change parameter def undo(self): """Performs one undo step, moving up the version tree.""" action_map = self.controller.vistrail.actionMap old_action = action_map.get(self.controller.current_version, None) self.redo_stack.append(self.controller.current_version) self.controller.show_parent_version() new_action = action_map.get(self.controller.current_version, None) self.set_pipeline_selection(old_action, new_action, 'undo') return self.controller.current_version def redo(self): """Performs one redo step if possible, moving down the version tree.""" action_map = self.controller.vistrail.actionMap old_action = action_map.get(self.controller.current_version, None) if not self.can_redo(): critical("Redo on an empty redo stack. Ignoring.") return next_version = self.redo_stack[-1] self.redo_stack = self.redo_stack[:-1] self.controller.show_child_version(next_version) new_action = action_map[self.controller.current_version] self.set_pipeline_selection(old_action, new_action, 'redo') return next_version def can_redo(self): return len(self.redo_stack) <> 0 def new_action(self, action): """new_action Handler for VistrailController.new_action """ self.redo_stack = []
class QQueryView(QtGui.QWidget, BaseView): VISUAL_SEARCH_VIEW = 0 GLOBAL_RESULT_VIEW = 1 VERSION_RESULT_VIEW = 2 WORKFLOW_RESULT_VIEW = 3 RESULT_LEVEL_MAP = \ Bidict([(QueryController.LEVEL_ALL, GLOBAL_RESULT_VIEW), (QueryController.LEVEL_VISTRAIL, VERSION_RESULT_VIEW), (QueryController.LEVEL_WORKFLOW, WORKFLOW_RESULT_VIEW)]) def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) BaseView.__init__(self) self.build_widget() self.set_title("Search") def set_controller(self, controller=None): if self.controller: self.disconnect(self.controller, QtCore.SIGNAL('stateChanged'), self.update_controller) self.controller = controller if controller: self.connect(self.controller, QtCore.SIGNAL('stateChanged'), self.update_controller) self.vt_controller.vistrail_view = self.version_result_view self.vt_controller.current_pipeline_view = \ self.workflow_result_view.scene() # self.vt_controller.vistrail_view.set_controller(self.vt_controller) self.vt_controller.set_vistrail(controller.vistrail, None, set_log_on_vt=False) self.vt_controller.change_selected_version(controller.current_version) self.version_result_view.set_controller(self.vt_controller) self.workflow_result_view.set_controller(self.vt_controller) self.query_controller.set_vistrail_controller(controller) def update_controller(self): self.vt_controller.set_vistrail(self.controller.vistrail, None, set_log_on_vt=False) self.vt_controller.change_selected_version( self.controller.current_version) def build_widget(self): layout = QtGui.QVBoxLayout() layout.setMargin(0) layout.setSpacing(0) self.query_controller = QueryController(self) self.vt_controller = VistrailController(auto_save=False) self.p_controller = VistrailController(Vistrail(), auto_save=False) self.connect(self.p_controller, QtCore.SIGNAL('vistrailChanged()'), self.vistrailChanged) self.query_box = QQueryBox() self.query_box.set_controller(self.query_controller) layout.addWidget(self.query_box) self.stacked_widget = QtGui.QStackedWidget() self.pipeline_view = QQueryPipelineView() self.p_controller.current_pipeline_view = self.pipeline_view.scene() self.pipeline_view.set_controller(self.p_controller) self.pipeline_view.set_query_controller(self.query_controller) QQueryView.VISUAL_SEARCH_VIEW = \ self.stacked_widget.addWidget(self.pipeline_view) self.global_result_view = QQueryResultGlobalView() QQueryView.GLOBAL_RESULT_VIEW = \ self.stacked_widget.addWidget(self.global_result_view) self.version_result_view = QQueryResultVersionView() self.connect(self.version_result_view.scene(), QtCore.SIGNAL('versionSelected(int,bool,bool,bool,bool)'), self.result_version_selected) # self.version_result_view.set_controller(self.vt_controller) QQueryView.VERSION_RESULT_VIEW = \ self.stacked_widget.addWidget(self.version_result_view) self.workflow_result_view = QQueryResultWorkflowView() # self.workflow_result_view.set_controller(self.vt_controller) QQueryView.WORKFLOW_RESULT_VIEW = \ self.stacked_widget.addWidget(self.workflow_result_view) self.stacked_widget.setCurrentWidget(self.pipeline_view) layout.addWidget(self.stacked_widget) self.setLayout(layout) self.current_display = QQueryView.VISUAL_SEARCH_VIEW self.current_result_view = QQueryView.VERSION_RESULT_VIEW def set_default_layout(self): from gui.module_palette import QModulePalette from gui.module_info import QModuleInfo self.set_palette_layout( {QtCore.Qt.LeftDockWidgetArea: QModulePalette, QtCore.Qt.RightDockWidgetArea: QModuleInfo, }) def set_action_links(self): self.action_links = \ { 'execute': ('query_pipeline_changed', self.set_execute_action) } # also add other notification here... from gui.vistrails_window import _app _app.register_notification('query_pipeline_changed', self.set_reset_button) def set_reset_button(self, pipeline): self.query_box.setManualResetEnabled(self.pipeline_non_empty(pipeline)) def set_result_level(self, level): view_idx = QQueryView.RESULT_LEVEL_MAP[level] if self.current_display != QQueryView.VISUAL_SEARCH_VIEW: self.set_display_view(view_idx) self.current_result_view = view_idx self.query_controller.update_results() def set_to_search_mode(self): self.set_display_view(QQueryView.VISUAL_SEARCH_VIEW) self.query_box.backButton.setEnabled(False) self.query_box.editButton.setEnabled(False) self.set_reset_button(self.p_controller.current_pipeline) from gui.vistrails_window import _app _app.notify('query_pipeline_changed', self.p_controller.current_pipeline) def set_to_result_mode(self): self.set_display_view(self.current_result_view) self.query_box.backButton.setEnabled(True) if self.query_controller.level >= QueryController.LEVEL_VISTRAIL: self.query_box.editButton.setEnabled(True) self.query_box.setManualResetEnabled(True) from gui.vistrails_window import _app _app.notify('query_pipeline_changed', self.p_controller.current_pipeline) def set_display_view(self, view_type): self.current_display = view_type self.stacked_widget.setCurrentIndex(view_type) def get_current_view(self): return self.stacked_widget.currentWidget() def set_action_defaults(self): self.action_defaults = \ { 'execute': [('setEnabled', True, self.set_execute_action), ('setIcon', False, CurrentTheme.VISUAL_QUERY_ICON), ('setToolTip', False, 'Execute a visual query')], 'publishWeb': [('setEnabled', False, False)], 'publishPaper': [('setEnabled', False, False)], } def set_execute_action(self, pipeline=None): if not self.vt_controller: return False if pipeline is None: pipeline = self.p_controller.current_pipeline if self.current_display == QQueryView.VISUAL_SEARCH_VIEW: return self.pipeline_non_empty(pipeline) return False def pipeline_non_empty(self, pipeline): return pipeline is not None and len(pipeline.modules) > 0 def vistrailChanged(self): from gui.vistrails_window import _app self.p_controller.current_pipeline.ensure_connection_specs() _app.notify('query_pipeline_changed', self.p_controller.current_pipeline) def query_changed(self, query=None): if query is None: self.query_controller.reset_search() # FIXME add support for changing the query to something specific def version_changed(self, version_id): self.vt_controller.change_selected_version(version_id) def result_version_selected(self, version_id, by_click, do_validate=True, from_root=False, double_click=False): if by_click: self.query_controller.search.setCurrentVistrail( self.vt_controller.vistrail) self.vt_controller.change_selected_version(version_id, by_click, do_validate, from_root) if double_click: self.query_controller.set_level(QueryController.LEVEL_WORKFLOW) self.query_controller.show_workflow_matches()