def __init__(self, addmode=True):
        super(CredentialDialog, self).__init__()

        # Set size and position
        # self.setGeometry(0, 0, 800, 500)
        frameGm = self.frameGeometry()
        screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos())
        centerPoint = QApplication.desktop().screenGeometry(screen).center()
        frameGm.moveCenter(centerPoint)
        self.move(frameGm.topLeft())

        # Setup fields
        self.host = QLineEdit()
        self.profiles = QComboBox()
        self.profiles.addItem("New...")
        self.profilename = QLineEdit()
        self.username = QLineEdit()
        self.password = QLineEdit()
        self.password.setEchoMode(QLineEdit.Password)
        self.savepassword = QCheckBox("Save Password")
        self.rememberprofile = QCheckBox("Remember Profile")

        # Setup dialog buttons
        self.addButton = QPushButton("&Add")
        self.connectButton = QPushButton("C&onnect")
        self.cancelButton = QPushButton("&Cancel")
        self.addButton.clicked.connect(self.add)
        self.connectButton.clicked.connect(self.connect)
        self.cancelButton.clicked.connect(self.close)
        self.profiles.currentTextChanged.connect(self.loadProfile)
        self.buttonboxWidget = QDialogButtonBox()
        if addmode:
            self.buttonboxWidget.addButton(self.addButton, QDialogButtonBox.AcceptRole)
        else:
            self.buttonboxWidget.addButton(self.connectButton, QDialogButtonBox.AcceptRole)

        self.buttonboxWidget.addButton(self.cancelButton, QDialogButtonBox.RejectRole)

        # Compose main layout
        mainLayout = QFormLayout()
        if not addmode:
            mainLayout.addRow("Profile", self.profiles)
        mainLayout.addRow("Profile", self.profilename)
        mainLayout.addRow("Host", self.host)
        mainLayout.addRow("Username", self.username)
        mainLayout.addRow("Password", self.password)
        mainLayout.addRow(self.savepassword)
        if not addmode:
            mainLayout.addRow(self.rememberprofile)
        mainLayout.addRow(self.buttonboxWidget)

        # Populate profiles
        for name, credential in manager.get_plugin_by_name("Connections", "SettingsPlugin").credentials.items():
            self.profiles.addItem(name)

        self.setLayout(mainLayout)
        self.setWindowTitle("Add Connection...")

        # Set modality
        self.setModal(True)
    def __init__(self):
        super(DeviceView, self).__init__()

        happi_settings_plugin = pluginmanager.get_plugin_by_name('happi_devices',
                                                                 'SettingsPlugin')
        self.view = happi_settings_plugin.devices_view
        self.model = happi_settings_plugin.devices_model
Exemple #3
0
 def fieldChanged(self, field):
     self.setCatalog(self.catalog, self.stream, field)
     # TODO -- figure out where to put the geometry update
     if QSpace in inspect.getmro(type(self)):
         self.setGeometry(
             pluginmanager.get_plugin_by_name('xicam.SAXS.calibration',
                                              'SettingsPlugin').AI(field))
 def setField(self, field):
     self.clear()
     self.field = field
     self._updateCatalog()
     # TODO -- figure out where to put the geometry update
     if QSpace in inspect.getmro(type(self)):
         self.setGeometry(pluginmanager.get_plugin_by_name("xicam.SAXS.calibration", "SettingsPlugin").AI(field))
     self.sigFieldChanged.emit(field)
Exemple #5
0
    def __init__(self):
        super(ipythonconsole, self).__init__()
        plugin = pluginmanager.get_plugin_by_name('IPython', 'GUIPlugin')

        self.kernel_manager = plugin.kernel_manager
        self.kernel_client = plugin.kernel_client

        # self.style_sheet = (qdarkstyle.load_stylesheet())
        self.syntax_style = u'monokai'
        self.set_default_style(colors='Linux')
 def widget(self):
     if not self._widget:
         controllername = self.device.controller
         controllerclass = pluginmanager.get_plugin_by_name(
             controllername, 'ControllerPlugin')
         if not controllerclass:
             raise ImportError(
                 f"The '{controllername}' controller could not be loaded.")
         self._widget = controllerclass(self.device)
     return self._widget
Exemple #7
0
    def is_matching_canvas_type(self, index: QModelIndex,
                                match_index: QModelIndex):
        match_intent = match_index.data(EnsembleModel.object_role)
        intent = index.data(EnsembleModel.object_role)
        if not isinstance(intent, Intent):
            print(
                f"WARNING: during matching, index {index.data} is not an Intent"
            )
            return False
        if not isinstance(match_intent, Intent):
            print(
                f"WARNING: during matching, match_index {index.data} is not an Intent"
            )
            return False
        # assert isinstance(intent, Intent)
        # assert isinstance(match_intent, Intent)

        # Ignore self matching
        if intent is match_intent:
            return False

        match_canvas_type_string = match_intent.canvas
        intent_canvas_type_string = intent.canvas

        match_intent_canvas_type = pluginmanager.get_plugin_by_name(
            match_canvas_type_string, "IntentCanvasPlugin")
        intent_canvas_type = pluginmanager.get_plugin_by_name(
            intent_canvas_type_string, "IntentCanvasPlugin")

        if not issubclass(intent_canvas_type, match_intent_canvas_type) \
            and not issubclass(match_intent_canvas_type, intent_canvas_type):
            return False

        # By definition, if a match_key is not provided, the intent is un-matchable
        if intent.match_key is None or match_intent.match_key is None:
            return False

        if intent.match_key != match_intent.match_key:
            return False

        return True
Exemple #8
0
def project_intents(run_catalog):
    intents = []

    for projection in run_catalog.metadata['start'].get('projections', []):
        if projection['name'] == 'intent':
            intent_class_name = projection['projection']['intent_type']['value']
            args = projection['projection']['args']['value']
            kwargs = projection['projection']['kwargs']['value']
            output_map = projection['projection']['output_map']['value']
            name = projection['projection']['name']['value']
            operation_id = projection['projection']['operation_id']['value']

            intent_class = plugin_manager.get_plugin_by_name(intent_class_name, 'intents')

            for intent_kwarg_name, output_name in output_map.items():
                kwargs[intent_kwarg_name] = getattr(run_catalog, operation_id).to_dask()[output_name]
            intent = intent_class(name=name, *args, **kwargs)
            intents.append(intent)
    return intents
 def loadProfile(self):
     profilename = self.profiles.currentText()
     if profilename == "New...":
         self.username.setEnabled(True)
         self.password.setEnabled(True)
         self.host.setEnabled(True)
         self.savepassword.setEnabled(True)
         self.rememberprofile.setVisible(True)
     else:
         credential = manager.get_plugin_by_name("Connections", "SettingsPlugin").credentials[profilename]
         self.username.setText(credential["username"])
         self.host.setText(credential["host"])
         self.password.setText(credential["password"])
         self.savepassword.setChecked(credential["savepassword"])
         self.profilename.setText(profilename)
         self.username.setEnabled(False)
         self.password.setEnabled(False)
         self.host.setEnabled(False)
         self.savepassword.setEnabled(False)
         self.rememberprofile.setVisible(False)
Exemple #10
0
    def checkPolygonsSet(self, workflow: Workflow):
        """
        Check for any unset polygonmask processes; start masking mode if found

        Parameters
        ----------
        workflow: Workflow

        Returns
        -------
        bool
            True if unset polygonmask process is found

        """
        pluginmaskclass = pluginmanager.get_plugin_by_name('Polygon Mask', 'ProcessingPlugin')
        for process in workflow.processes:
            if isinstance(process, pluginmaskclass):
                if process.polygon.value is None:
                    self.startPolygonMasking(process)
                    return True
        return False
Exemple #11
0
    def _activate(self, index: QModelIndex):
        display = index.data(
            HappiClientModel.displayRole)  # try to get display from model

        if not display:
            happi_item = index.data(HappiClientModel.happiItemRole)
            device = from_container(happi_item)

            try:
                device.wait_for_connection()
            except TimeoutError as ex:
                msg.logError(ex)

            controller_name = happi_item.extraneous.get(
                "controller_class", "typhos")
            controller = pluginmanager.get_plugin_by_name(
                controller_name, 'ControllerPlugin')
            display = controller(device)

            # Stash display back on the model
            self.model().setData(index, display, HappiClientModel.displayRole)

        self.sigShowControl.emit(display)
 def __new__(cls, datasource):
     model = pluginmanager.get_plugin_by_name('plans',
                                              "SettingsPlugin").plansmodel
     model.dataresource = datasource
     return model
Exemple #13
0
 def SavePlan(self):
     pluginmanager.get_plugin_by_name('plans', 'SettingsPlugin').add_plan(
         self.editor.toPlainText())
Exemple #14
0
    def __init__(self):
        # Late imports required due to plugin system
        from xicam.SAXS.calibration import CalibrationPanel
        from xicam.SAXS.widgets.SAXSViewerPlugin import SAXSCalibrationViewer, SAXSMaskingViewer, SAXSReductionViewer
        from xicam.SAXS.widgets.SAXSToolbar import SAXSToolbarRaw, SAXSToolbarMask, SAXSToolbarReduce
        from xicam.SAXS.widgets.XPCSToolbar import XPCSToolBar

        self.derivedDataModel = DerivedDataModel()
        self.catalogModel = QStandardItemModel()

        # Data model
        self.catalogModel = QStandardItemModel()
        self.selectionmodel = QItemSelectionModel(self.catalogModel)

        # Initialize workflows
        self.maskingworkflow = MaskingWorkflow()
        self.simulateworkflow = SimulateWorkflow()
        self.displayworkflow = DisplayWorkflow()
        self.reduceworkflow = ReduceWorkflow()
        self.roiworkflow = ROIWorkflow()

        # Grab the calibration plugin
        self.calibrationsettings = pluginmanager.get_plugin_by_name('xicam.SAXS.calibration',
                                                                    'SettingsPlugin')

        # Setup TabViews
        # FIXME -- rework how fields propagate to displays (i.e. each image has its own detector, switching
        # between tabs updates the detector combobbox correctly)
        field = "fccd_image"
        self.calibrationtabview = TabView(self.catalogModel, widgetcls=SAXSCalibrationViewer,
                                          stream='primary', field=field,
                                          selectionmodel=self.selectionmodel,
                                          bindings=[(self.calibrationsettings.sigGeometryChanged, 'setGeometry')],
                                          geometry=self.getAI)
        self.masktabview = TabView(self.catalogModel, widgetcls=SAXSMaskingViewer, selectionmodel=self.selectionmodel,
                                   stream='primary', field=field,
                                   bindings=[('sigTimeChangeFinished', self.indexChanged),
                                             (self.calibrationsettings.sigGeometryChanged, 'setGeometry')],
                                   geometry=self.getAI)
        self.reducetabview = TabView(self.catalogModel, widgetcls=SAXSReductionViewer,
                                     selectionmodel=self.selectionmodel,
                                     stream='primary', field=field,
                                     bindings=[('sigTimeChangeFinished', self.indexChanged),
                                               (self.calibrationsettings.sigGeometryChanged, 'setGeometry')],
                                     geometry=self.getAI)
        self.comparemultiview = QLabel("COMING SOON!")  # SAXSMultiViewerPlugin(self.catalogModel, self.selectionmodel)

        # Setup correlation views
        self.correlationView = TabView(self.catalogModel, widgetcls=SAXSReductionViewer,
                                       selectionmodel=self.selectionmodel,
                                       stream='primary', field=field)
        self.twoTimeProcessor = TwoTimeParameterTree(processor=self.processTwoTime)
        self.twoTimeToolBar = XPCSToolBar(headermodel=self.catalogModel,
                                          selectionmodel=self.selectionmodel,
                                          view=self.correlationView.currentWidget,
                                          workflow=self.roiworkflow,
                                          index=0)
        self.oneTimeProcessor = OneTimeParameterTree(processor=self.processOneTime)
        self.oneTimeToolBar = XPCSToolBar(view=self.correlationView.currentWidget,
                                          workflow=self.roiworkflow,
                                          index=0)

        # Setup toolbars
        self.rawtoolbar = SAXSToolbarRaw(self.catalogModel, self.selectionmodel)
        self.masktoolbar = SAXSToolbarMask(self.catalogModel, self.selectionmodel)
        self.reducetoolbar = SAXSToolbarReduce(self.catalogModel, self.selectionmodel,
                                               view=self.reducetabview.currentWidget, workflow=self.reduceworkflow)
        self.reducetabview.kwargs['toolbar'] = self.reducetoolbar
        self.reducetoolbar.sigDeviceChanged.connect(self.deviceChanged)

        # Setup calibration widgets
        self.calibrationsettings.setModels(self.catalogModel, self.calibrationtabview.selectionmodel)
        self.calibrationpanel = CalibrationPanel(self.catalogModel, self.calibrationtabview.selectionmodel)
        self.calibrationpanel.sigDoCalibrateWorkflow.connect(self.doCalibrateWorkflow)
        self.calibrationsettings.sigGeometryChanged.connect(self.doSimulateWorkflow)

        # Setup masking widgets
        self.maskeditor = WorkflowEditor(self.maskingworkflow)
        self.maskeditor.sigWorkflowChanged.connect(self.doMaskingWorkflow)

        # Setup reduction widgets
        self.displayeditor = WorkflowEditor(self.displayworkflow)
        self.reduceeditor = WorkflowEditor(self.reduceworkflow)
        self.reduceplot = DerivedDataWidget(self.derivedDataModel)
        self.reducetoolbar.sigDoWorkflow.connect(self.doReduceWorkflow)
        self.reduceeditor.sigWorkflowChanged.connect(self.doReduceWorkflow)
        self.displayeditor.sigWorkflowChanged.connect(self.doDisplayWorkflow)
        self.reducetabview.currentChanged.connect(self.catalogChanged)

        # Setup correlation widgets
        self.correlationResults = DerivedDataWidget(self.derivedDataModel)

        self.stages = {
            'Calibrate': GUILayout(self.calibrationtabview,
                                   right=self.calibrationsettings.widget,
                                   rightbottom=self.calibrationpanel,
                                   top=self.rawtoolbar),
            'Mask': GUILayout(self.masktabview,
                              right=self.maskeditor,
                              top=self.masktoolbar),
            'Reduce': GUILayout(self.reducetabview,
                                bottom=self.reduceplot, right=self.reduceeditor, righttop=self.displayeditor,
                                top=self.reducetoolbar),
            'Compare': GUILayout(self.comparemultiview, top=self.reducetoolbar, bottom=self.reduceplot,
                                 right=self.reduceeditor),
            'Correlate': {
                '2-Time Correlation': GUILayout(self.correlationView,
                                                top=self.twoTimeToolBar,
                                                rightbottom=self.twoTimeProcessor,
                                                bottom=self.correlationResults),
                '1-Time Correlation': GUILayout(self.correlationView,
                                                top=self.oneTimeToolBar,
                                                rightbottom=self.oneTimeProcessor,
                                                bottom=self.correlationResults)
            }
        }

        super(SAXSPlugin, self).__init__()

        # Start visualizations
        self.displayworkflow.visualize(self.reduceplot, imageview=lambda: self.reducetabview.currentWidget(),
                                       toolbar=self.reducetoolbar)
    def __init__(self, device: Device):
        super(DiodeController, self).__init__(device)

        self.RE = get_run_engine()

        full_layout = QVBoxLayout()
        self.setLayout(full_layout)

        # create upper layout/widget
        top_layout = QHBoxLayout()
        top_widget = QWidget()
        top_widget.setLayout(top_layout)
        # add actual widgets to the top part
        typhos_panel = TyphosCompositeSignalPanel.from_device(device)
        typhos_panel.setMaximumHeight(50)
        time_plot = PyDMTimePlot()
        time_plot.setTimeSpan(120)
        time_plot.addYChannel(y_channel=f'ca://{device.prefix}',
                              name="Diode",
                              color="red",
                              lineWidth=3)
        top_layout.addWidget(time_plot)
        top_layout.addWidget(typhos_panel)

        # create lower layout/widget
        bottom_layout = QHBoxLayout()
        bottom_widget = QWidget()
        bottom_widget.setLayout(bottom_layout)
        bottom_widget.setMinimumHeight(350)
        # add actual widgets to the bottom part
        self.plot_panel = CatalogImagePlotView(field_filter=None)
        config_layout = QVBoxLayout()
        scan_panel = QGroupBox('Diode Scan')
        scan_panel.setMaximumSize(200, 250)
        scan_panel.setLayout(config_layout)
        bottom_layout.addWidget(self.plot_panel)
        bottom_layout.addWidget(scan_panel)

        # add a splitter
        splitter = QSplitter(Qt.Vertical)
        splitter.addWidget(top_widget)
        splitter.addWidget(bottom_widget)

        full_layout.addWidget(splitter)

        # get devices from happi database
        happi_settings = plugin_manager.get_plugin_by_name(
            "happi_devices", "SettingsPlugin")

        def from_device_container(container) -> Device:
            try:
                return from_container(container.device)
            except Exception as e:
                logError(e)
                return None

        self.async_poll_devices = list(
            map(
                from_device_container,
                happi_settings.search(source='labview',
                                      device_class='ophyd.EpicsMotor')))
        self.async_poll_devices += map(
            from_device_container, happi_settings.search(prefix=device.prefix))
        # Remove errored from_container devices (Nones)
        self.async_poll_devices = list(
            filter(lambda device: device, self.async_poll_devices))
        self.async_poll_devices.remove(device)
        self.device_dict = {
            device.name: device
            for device in self.async_poll_devices
        }
        # get the diode as detector
        diode = device.diode

        self.device_selector = QComboBox()
        self.device_selector.addItems(list(self.device_dict.keys()))

        input_layout = QFormLayout()
        self.start_range = QLineEdit()
        self.stop_range = QLineEdit()
        self.n_steps = QLineEdit()
        self.step_size = QLineEdit()
        input_layout.addRow('Start Range', self.start_range)
        input_layout.addRow('Stop Range', self.stop_range)
        input_layout.addRow('N Steps', self.n_steps)
        input_layout.addRow('Step Size', self.step_size)

        config_layout.addWidget(self.device_selector)
        config_layout.addLayout(input_layout)

        button_layout = QHBoxLayout()
        start_button = QPushButton("Start")
        button_layout.addWidget(start_button)
        start_button.clicked.connect(self.push_start)
        config_layout.addLayout(button_layout)

        # TODO get data from bluesky run in callback
        # runs = []
        # self.RE.subscribe(stream_documents_into_runs(self.plot_panel.setCatalog))
        # self.plot_panel.setData(runs)

        # Wireup display to receive completed runs
        self.run_dispatcher = RunDispatcher(self.plot_panel.setCatalog)
    def __init__(self, device: Device):
        super(FastCCDController, self).__init__(device)

        camera_layout = QVBoxLayout()
        camera_panel = QGroupBox('Camera State')
        camera_panel.setLayout(camera_layout)

        camera_layout.addWidget(
            PyDMLabel(init_channel=f'ca://{device.cam.state.pvname}'))

        camera_layout.addWidget(
            PyDMPushButton(
                pressValue=1,
                init_channel=f'ca://{device.cam.initialize.setpoint_pvname}',
                label='Initialize'))
        camera_layout.addWidget(
            PyDMPushButton(
                pressValue=1,
                init_channel=f'ca://{device.cam.shutdown.setpoint_pvname}',
                label='Shutdown'))

        dg_layout = QHBoxLayout()
        dg_panel = QGroupBox('Delay Gen State')
        dg_panel.setLayout(dg_layout)

        dg_state_layout = QVBoxLayout()
        dg_layout.addLayout(dg_state_layout)
        dg_state_layout.addWidget(
            PyDMLabel(init_channel=f'ca://{device.dg1.state.pvname}'))

        dg_state_layout.addWidget(
            PyDMPushButton(
                pressValue=1,
                init_channel=f'ca://{device.dg1.initialize.setpoint_pvname}',
                label='Initialize'))
        dg_state_layout.addWidget(
            PyDMPushButton(
                pressValue=1,
                init_channel=f'ca://{device.dg1.reset.setpoint_pvname}',
                label='Reset'))

        dg_shutter_layout = QVBoxLayout()
        dg_layout.addLayout(dg_shutter_layout)
        dg_shutter_layout.addWidget(
            PyDMLabel(
                init_channel=f'ca://{device.dg1.shutter_enabled.pvname}'))
        dg_shutter_layout.addWidget(
            PyDMPushButton(
                pressValue=0,
                init_channel=
                f'ca://{device.dg1.shutter_enabled.setpoint_pvname}',
                label='Enable Trigger'))
        dg_shutter_layout.addWidget(
            PyDMPushButton(
                pressValue=2,
                init_channel=
                f'ca://{device.dg1.shutter_enabled.setpoint_pvname}',
                label='Keep Closed'))
        dg_shutter_layout.addWidget(
            PyDMPushButton(
                pressValue=1,
                init_channel=
                f'ca://{device.dg1.shutter_enabled.setpoint_pvname}',
                label='Keep Open'))

        self.hlayout.addWidget(camera_panel)
        self.hlayout.addWidget(dg_panel)
        self.passive.setVisible(
            False)  # active mode is useless for fastccd at COSMIC-Scattering

        # Subscribe to the error status PV so we can create notifications
        # (only relevant for cam init errors for now)
        self.device.cam.error_status.subscribe(self.report_error, 'value')

        # TODO: pull from settingsplugin
        self.db = Broker.named('local').v2

        happi_settings = plugin_manager.get_plugin_by_name(
            "happi_devices", "SettingsPlugin")

        # Find coupled devices and add them so they'll be used with RE
        def from_device_container(container) -> Device:
            try:
                return from_container(container.device)
            except Exception as e:
                logError(e)
                return None

        self.async_poll_devices = list(
            map(from_device_container,
                happi_settings.search(source='labview')))
        self.async_poll_devices += map(
            from_device_container, happi_settings.search(prefix=device.prefix))

        # Remove errored from_container devices (Nones)
        self.async_poll_devices = list(
            filter(lambda device: device, self.async_poll_devices))

        self.async_poll_devices.remove(device)

        self.metadata["projections"] = [{
            'name': 'NXsas',
            'version': '0.1.0',
            'projection': {
                NXsas.DATA_PROJECTION_KEY: {
                    'type': 'linked',
                    'stream': 'primary',
                    'location': 'event',
                    'field': f"{device.name}_image"
                },
                NXsas.AZIMUTHAL_ANGLE_PROJECTION_KEY: {
                    'type': 'linked',
                    'stream': 'labview',
                    'location': 'event',
                    'field': 'detector_rotate'
                },
                # TODO: source this from somewhere
                NXsas.ENERGY_PROJECTION_KEY: {
                    'type': 'linked',
                    'stream': 'labview',
                    'location': 'event',
                    'field': 'mono_energy'
                },
                NXsas.INCIDENCE_ANGLE_PROJECTION_KEY: {
                    'type': 'linked',
                    'stream': 'labview',
                    'location': 'event',
                    'field': 'sample_rotate_steppertheta'
                },
                # TODO: CHECK IF THIS EXISTS
                # FIXME: Is this the right motor???
                NXsas.DETECTOR_TRANSLATION_X_PROJECTION_KEY: {
                    'type': 'linked',
                    'stream': 'labview',
                    'location': 'event',
                    'field': 'det_translate'
                },
            },
            'configuration': {
                'detector_name': 'fastccd',
                'sdd': 0.5,
                'geometry_mode': 'transmission',
                'poni1': 480,
                'poni2': 1025
            }
        }]
 def __new__(cls, datasource):
     model = pluginmanager.get_plugin_by_name('xicam.Acquire.devices',
                                              "SettingsPlugin").devicesmodel
     model.dataresource = datasource
     return model
Exemple #18
0
    def __init__(self, *args, **kwargs):
        super(RunEngineWidget, self).__init__(*args, **kwargs)

        self.planview = QListView()
        self.plansmodel = pluginmanager.get_plugin_by_name('plans',
                                                           'SettingsPlugin').plansmodel  # type: QStandardItemModel
        self.planview.setModel(self.plansmodel)
        self.selectionmodel = QItemSelectionModel(self.plansmodel)
        self.planview.setSelectionModel(self.selectionmodel)

        self.parameterview = ParameterTree()

        self.metadata = MetadataWidget()

        self.runbutton = QPushButton('Run')
        self.pausebutton = QPushButton('Pause')
        self.resumebutton = QPushButton('Resume')
        self.abortbutton = QPushButton('Abort')
        self.abortbutton.setStyleSheet('background-color:red;color:white;font-weight:bold;')

        # Layout
        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.layout)
        self.splitter = QSplitter()
        self.layout.addWidget(self.splitter)

        self.splitter.addWidget(self.planview)
        self.runwidget = QWidget()
        self.runlayout = QVBoxLayout()
        self.runlayout.setContentsMargins(0, 0, 0, 0)
        self.runlayout.addWidget(self.parameterview)
        self.runlayout.addWidget(self.runbutton)
        self.runlayout.addWidget(self.pausebutton)
        self.runlayout.addWidget(self.resumebutton)
        self.runlayout.addWidget(self.abortbutton)
        self.runwidget.setLayout(self.runlayout)
        self.splitter.addWidget(self.runwidget)
        self.splitter.addWidget(self.metadata)

        # Set initial states
        self._resumed()
        self._finished()

        # Wireup signals
        self.selectionmodel.currentChanged.connect(self.showPlan)
        self.runbutton.clicked.connect(self.run)
        self.abortbutton.clicked.connect(self.abort)
        self.pausebutton.clicked.connect(self.pause)
        self.resumebutton.clicked.connect(self.resume)

        self.RE = get_run_engine()
        self.RE.sigPause.connect(self._paused)
        self.RE.sigResume.connect(self._resumed)
        self.RE.sigFinish.connect(self._finished)
        self.RE.sigStart.connect(self._started)
        self.RE.sigAbort.connect(self._aborted)

        # Run model
        self.runmodel = QStandardItemModel()
        self.runselectionmodel = QItemSelectionModel(self.runmodel)
        self._current_planitem = None