Пример #1
0
class LogScaleIntensity(ComposableItemImageView):
    def __init__(self, *args, **kwargs):
        # Composes a new type consisting of any ImageItem types in imageItem_bases with this classes's helper ImageItem
        # class (LogScaleImageItem)
        self.imageItem_bases += (LogScaleImageItem,)
        imageItem = type("DynamicImageItem", tuple(self.imageItem_bases), {})()
        if "imageItem" in kwargs:
            del kwargs["imageItem"]
        super(LogScaleIntensity, self).__init__(imageItem=imageItem, *args, **kwargs)

        self.logScale = True

        # Setup log scale button
        self.logIntensityButton = QPushButton("Log Intensity")
        sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.logIntensityButton.sizePolicy().hasHeightForWidth())
        self.logIntensityButton.setSizePolicy(sizePolicy)
        self.logIntensityButton.setObjectName("logIntensity")
        self.ui.gridLayout.addWidget(self.logIntensityButton, 3, 2, 1, 1)
        self.logIntensityButton.setCheckable(True)
        self.setLogScale(True)
        self.logIntensityButton.clicked.connect(self._setLogScale)

    def _setLogScale(self, value):
        self.imageItem.logScale = value
        self.imageItem.qimage = None
        self.imageItem.update()
        self.getHistogramWidget().region.setBounds([0 if value else None, None])

    def setLogScale(self, value):
        self._setLogScale(value)
        self.logIntensityButton.setChecked(value)
Пример #2
0
    def setup_btn_grid(self, n_lights_1axis):
        """Set up grid of buttons."""
        table = self.btn_grid_table
        if n_lights_1axis != table.rowCount():
            table.clear()
            table.setSelectionMode(QAbstractItemView.NoSelection)
            table.setColumnCount(n_lights_1axis)
            table.setRowCount(n_lights_1axis)
            table.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
            table.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)

            table.horizontalHeader().setDefaultSectionSize(CELL_SIZE)
            table.verticalHeader().setDefaultSectionSize(CELL_SIZE)

            table.horizontalHeader().hide()
            table.verticalHeader().hide()

            for idx_row in range(n_lights_1axis):
                for idx_col in range(n_lights_1axis):
                    btn = QPushButton(self)
                    btn.setStyleSheet(BTN_STYLE)
                    btn.setCheckable(True)
                    btn.setChecked(True)
                    btn.clicked.connect(
                        self.clicked_btn_of_grid_factory(idx_row, idx_col))
                    table.setCellWidget(idx_row, idx_col, btn)
        self.show_solution()
Пример #3
0
class LogButtons(BetterLayout):
    """Button mixin that can toggle x/y log modes."""
    def __init__(self, *args, **kwargs):
        super(LogButtons, self).__init__(*args, **kwargs)
        # Define single-source of text state
        self.X_ON_TEXT = "X Log Mode On"
        self.X_OFF_TEXT = "X Log Mode Off"
        self.Y_ON_TEXT = "Y Log Mode On"
        self.Y_OFF_TEXT = "Y Log Mode Off"

        # Create checkable buttons
        self.x_log_button = QPushButton(self.X_OFF_TEXT)
        self.x_log_button.setCheckable(True)
        self.x_log_button.toggled.connect(self.set_x_log_mode)
        self.y_log_button = QPushButton(self.Y_OFF_TEXT)
        self.y_log_button.setCheckable(True)
        self.y_log_button.toggled.connect(self.set_y_log_mode)

        # Update button check state when pyqtgraph log x checkbox is toggled by user
        self.getPlotItem().ctrl.logXCheck.toggled.connect(
            self._update_x_button)
        # Update button check state when pyqtgraph log y checkbox is toggled by user
        self.getPlotItem().ctrl.logYCheck.toggled.connect(
            self._update_y_button)

        # Create a layout to have these buttons side-by-side
        layout = QHBoxLayout()
        layout.addWidget(self.x_log_button)
        layout.addWidget(self.y_log_button)
        # TODO: BetterLayout
        #  RightLayout   BottomLayout
        #  add_widget    add_widget
        self.add_widget_to_bottom(layout)

    def _update_y_button(self, state: bool):
        self.y_log_button.setChecked(state)
        if state:
            self.y_log_button.setText(self.Y_ON_TEXT)
        else:
            self.y_log_button.setText(self.Y_OFF_TEXT)

    def _update_x_button(self, state: bool):
        self.x_log_button.setChecked(state)
        if state:
            self.x_log_button.setText(self.X_ON_TEXT)
        else:
            self.x_log_button.setText(self.X_OFF_TEXT)

    def set_x_log_mode(self, state: bool):
        self._update_x_button(state)
        # Grab existing x log state from pyqtgraph
        y_log_mode = self.getPlotItem().ctrl.logYCheck.isChecked()
        self.setLogMode(x=state, y=y_log_mode)

    def set_y_log_mode(self, state: bool):
        self._update_y_button(state)
        # Grab existing y log state from pyqtgraph
        x_log_mode = self.getPlotItem().ctrl.logXCheck.isChecked()
        self.setLogMode(x=x_log_mode, y=state)
Пример #4
0
 def add_canvas_display_widgets():
     for i in range(len(self.canvas_display_widgets)):
         # Add the view to the stacked widget
         self.stackedwidget.addWidget(self.canvas_display_widgets[i])
         # Create a button, using the view's recommended display icon
         button = QPushButton(self)
         button.setCheckable(True)
         button.setIcon(self.canvas_display_widgets[i].icon)
         # Add the button to the logical button group
         self.buttongroup.addButton(button, i)
         # Add the button to the visual layout section
         self.buttonpanel.addWidget(button)
Пример #5
0
class DataSelector(QWidget):
    """
    Simple button to create and hold information about a selection area
    in a pyqtgraph.PlotItem object
    """
    new_selection = Signal(float, float)
    abort_selection = Signal()

    def __init__(self, plotitem, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.plot = plotitem
        self.sele = None

        self.setLayout(QHBoxLayout())
        # remove annoying padding
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.toggle = QPushButton(self)
        self.toggle.setText('Select Area')
        self.toggle.setCheckable(True)
        self.toggle.setChecked(False)

        self.layout().addWidget(self.toggle)

        self.toggle.toggled.connect(self.toggle_selection)

    def toggle_selection(self, activated):
        if activated:
            self.toggle.setText('Stop Selecting')
            sele = pg.LinearRegionItem()
            sele.sigRegionChangeFinished.connect(self.on_selection_changed)
            self.sele = sele
            self.plot.addItem(sele)
        else:
            self.toggle.setText('Select Area')
            if self.sele is not None:
                self.sele.sigRegionChangeFinished.disconnect()
                self.plot.removeItem(self.sele)
                self.sele = None
            self.on_selection_changed(None)

    def on_selection_changed(self, region_changed):
        if region_changed is None:
            self.abort_selection.emit()
        else:
            left, right = region_changed.getRegion()
            self.new_selection.emit(left, right)

    def toggle_enabled(self, enabled):
        self.toggle.setVisible(enabled)
        if not enabled:
            self.toggle_selection(False)
Пример #6
0
 def create_autofit_group(self):
     auto_button = QPushButton(get_icon("apply.png"), _("Run"), self)
     auto_button.clicked.connect(self.autofit)
     autoprm_button = QPushButton(get_icon("settings.png"), _("Settings"),
                                  self)
     autoprm_button.clicked.connect(self.edit_parameters)
     xrange_button = QPushButton(get_icon("xrange.png"), _("Bounds"), self)
     xrange_button.setCheckable(True)
     xrange_button.toggled.connect(self.toggle_xrange)
     auto_layout = QVBoxLayout()
     auto_layout.addWidget(auto_button)
     auto_layout.addWidget(autoprm_button)
     auto_layout.addWidget(xrange_button)
     self.button_list += [auto_button, autoprm_button, xrange_button]
     return create_groupbox(self, _("Automatic fit"), layout=auto_layout)
Пример #7
0
    def __init__(self, layer: Image, parent=None) -> None:
        super().__init__(parent=parent)

        self.setLayout(QHBoxLayout())
        self.layout().setSpacing(2)
        self.layout().setContentsMargins(0, 0, 0, 0)
        once_btn = QPushButton(trans._('once'))
        once_btn.setFocusPolicy(Qt.NoFocus)

        auto_btn = QPushButton(trans._('continuous'))
        auto_btn.setCheckable(True)
        auto_btn.setFocusPolicy(Qt.NoFocus)
        once_btn.clicked.connect(lambda: auto_btn.setChecked(False))
        connect_no_arg(once_btn.clicked, layer, "reset_contrast_limits")
        connect_setattr(auto_btn.toggled, layer, "_keep_autoscale")
        connect_no_arg(auto_btn.clicked, layer, "reset_contrast_limits")

        self.layout().addWidget(once_btn)
        self.layout().addWidget(auto_btn)
Пример #8
0
    def createTopRightGroupBox(self):
        self.topRightGroupBox = QGroupBox("Group 2")

        defaultPushButton = QPushButton("Default Push Button")
        defaultPushButton.setDefault(True)

        togglePushButton = QPushButton("Toggle Push Button")
        togglePushButton.setCheckable(True)
        togglePushButton.setChecked(True)

        flatPushButton = QPushButton("Flat Push Button")
        flatPushButton.setFlat(True)

        layout = QVBoxLayout()
        layout.addWidget(defaultPushButton)
        layout.addWidget(togglePushButton)
        layout.addWidget(flatPushButton)
        layout.addStretch(1)
        self.topRightGroupBox.setLayout(layout)
Пример #9
0
class ToggleSymbols(BetterLayout):
    """Simple mixin that adds a button to toggle 'o' symbols on plot data curves in the plot widget."""
    def __init__(self, *args, **kwargs):
        super(ToggleSymbols, self).__init__(*args, **kwargs)

        self.toggle_symbols_button = QPushButton("Toggle Symbols")
        self.toggle_symbols_button.setCheckable(True)
        self.add_widget_to_right(self.toggle_symbols_button)

        self.toggle_symbols_button.toggled.connect(self._toggle_symbol)

        self._symbol_cache = []

    def _toggle_symbol(self, checked: bool):
        for item in self.scene().items():
            if isinstance(item, pg.PlotDataItem):
                if checked:
                    item.setData(symbol=None)
                else:
                    item.setData(symbol='o')
Пример #10
0
class DimSwitch(QWidget):
    dimChanged = Signal(bool)

    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QHBoxLayout()
        layout.addStretch(1)
        self.button_2d = QPushButton("2D")
        self.button_2d.setCheckable(True)
        self.button_2d.setChecked(True)
        self.button_2d.clicked.connect(functools.partial(self.set_2D, True))
        self.button_3d = QPushButton("3D")
        self.button_3d.setCheckable(True)
        self.button_3d.clicked.connect(functools.partial(self.set_2D, False))
        layout.addWidget(self.button_2d)
        layout.addWidget(self.button_3d)
        layout.addStretch(1)
        self.setLayout(layout)

    def set_2D(self, bool2d):
        self.button_2d.setChecked(bool2d)
        self.button_3d.setChecked(not bool2d)
        self.dimChanged.emit(bool2d)
Пример #11
0
class FixableWidgetParameterItem(parameterTypes.WidgetParameterItem):
    def __init__(self, param, depth):
        super(FixableWidgetParameterItem, self).__init__(param, depth)
        if param.opts.get("fixable"):
            self.fixbutton = QPushButton()
            self.fixbutton.setFixedWidth(20)
            self.fixbutton.setFixedHeight(20)
            self.fixbutton.setCheckable(True)
            self.fixbutton.setChecked(param.opts["fixed"])
            self.fixbutton.toggled.connect(param.sigFixToggled)
            self.fixbutton.toggled.connect(
                lambda fixed: param.setOpts(fixed=fixed))
            # self.fixbutton.toggled.connect(lambda fixed: self.widgetValueChanged())

            self.fixbutton.setIcon(QIcon(path("icons/anchor.png")))
            self.layoutWidget.layout().addWidget(self.fixbutton)

    def optsChanged(self, param, opts):
        """Called when any options are changed that are not
        name, value, default, or limits"""
        # print "opts changed:", opts
        ParameterItem.optsChanged(self, param, opts)

        if "readonly" in opts:
            self.updateDefaultBtn()
            if isinstance(self.widget, (QCheckBox, ColorButton)):
                self.widget.setEnabled(not opts["readonly"])

        ## If widget is a SpinBox, pass options straight through
        if isinstance(self.widget, SpinBox):
            if "units" in opts and "suffix" not in opts:
                opts["suffix"] = opts["units"]
            try:  # patch passes silently for 'fixed'
                self.widget.setOpts(**opts)
            except TypeError:
                pass
            self.updateDisplayLabel()
Пример #12
0
class LogScaleIntensity(ImageView):
    def __init__(self, *args, **kwargs):
        if kwargs.get("imageItem") and not isinstance(kwargs.get("imageItem"),
                                                      LogScaleImageItem):
            raise RuntimeError(
                "The imageItem set to a LogScaleIntensity ImageView must be a LogScaleImageItem."
            )

        kwargs["imageItem"] = LogScaleImageItem()
        super(LogScaleIntensity, self).__init__(*args, **kwargs)

        self.logScale = True

        # Setup log scale button
        self.logIntensityButton = QPushButton("Log Intensity")
        sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(
            self.logIntensityButton.sizePolicy().hasHeightForWidth())
        self.logIntensityButton.setSizePolicy(sizePolicy)
        self.logIntensityButton.setObjectName("logIntensity")
        self.ui.gridLayout.addWidget(self.logIntensityButton, 3, 2, 1, 1)
        self.logIntensityButton.setCheckable(True)
        self.setLogScale(True)
        self.logIntensityButton.clicked.connect(self._setLogScale)

    def _setLogScale(self, value):
        self.imageItem.logScale = value
        self.imageItem.qimage = None
        self.imageItem.update()
        self.getHistogramWidget().region.setBounds(
            [0 if value else None, None])

    def setLogScale(self, value):
        self._setLogScale(value)
        self.logIntensityButton.setChecked(value)
Пример #13
0
class OffsetPlots(BetterLayout):
    """Create a visual offset in the plots"""

    # TODO: implement the offset code
    def __init__(self, *args, **kwargs):
        super(OffsetPlots, self).__init__(*args, **kwargs)
        self.offset_box = QDoubleSpinBox()
        self.offset_box.setMinimum(0.0)
        self.offset_box.setDecimals(1)
        self.offset_box.setSingleStep(0.1)
        self.offset_button = QPushButton("Enable Offset")
        self.offset_button.setCheckable(True)
        self.offset_button.toggled.connect(self._offset_toggled)

        layout = QHBoxLayout()
        layout.addWidget(self.offset_box)
        layout.addWidget(self.offset_button)
        self.add_widget_to_bottom(layout)

    def _offset_toggled(self, enabled):
        if enabled:
            self.offset_button.setText("Disable Offset")
        else:
            self.offset_button.setText("Enable Offset")
Пример #14
0
class RunDialog(QDialog):
    simulation_done = Signal(bool, str)

    def __init__(self, config_file, run_model, arguments, parent=None):
        QDialog.__init__(self, parent)
        self.setWindowFlags(Qt.Window)
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)
        self.setModal(True)
        self.setWindowModality(Qt.WindowModal)
        self.setWindowTitle("Simulations - {}".format(config_file))

        assert isinstance(run_model, BaseRunModel)
        self._run_model = run_model

        ert = None
        if isinstance(run_model, BaseRunModel):
            ert = run_model.ert()

        self._simulations_argments = arguments

        self.simulations_tracker = create_tracker(
            run_model,
            qtimer_cls=QTimer,
            event_handler=self._on_tracker_event,
            num_realizations=arguments["active_realizations"].count())

        states = self.simulations_tracker.get_states()
        self.state_colors = {state.name: state.color for state in states}
        self.state_colors['Success'] = self.state_colors["Finished"]
        self.state_colors['Failure'] = self.state_colors["Failed"]

        self.total_progress = SimpleProgress()

        status_layout = QHBoxLayout()
        status_layout.addStretch()
        self.__status_label = QLabel()
        status_layout.addWidget(self.__status_label)
        status_layout.addStretch()
        status_widget_container = QWidget()
        status_widget_container.setLayout(status_layout)

        self.progress = Progress()
        self.progress.setIndeterminateColor(self.total_progress.color)
        for state in states:
            self.progress.addState(state.state, QColor(*state.color),
                                   100.0 * state.count / state.total_count)

        legend_layout = QHBoxLayout()
        self.legends = {}
        for state in states:
            self.legends[state] = Legend("%s (%d/%d)", QColor(*state.color))
            self.legends[state].updateLegend(state.name, 0, 0)
            legend_layout.addWidget(self.legends[state])

        legend_widget_container = QWidget()
        legend_widget_container.setLayout(legend_layout)

        self.running_time = QLabel("")

        self.plot_tool = PlotTool(config_file)
        self.plot_tool.setParent(self)
        self.plot_button = QPushButton(self.plot_tool.getName())
        self.plot_button.clicked.connect(self.plot_tool.trigger)
        self.plot_button.setEnabled(ert is not None)

        self.kill_button = QPushButton("Kill simulations")
        self.done_button = QPushButton("Done")
        self.done_button.setHidden(True)
        self.restart_button = QPushButton("Restart")
        self.restart_button.setHidden(True)
        self.show_details_button = QPushButton("Details")
        self.show_details_button.setCheckable(True)

        size = 20
        spin_movie = resourceMovie("ide/loading.gif")
        spin_movie.setSpeed(60)
        spin_movie.setScaledSize(QSize(size, size))
        spin_movie.start()

        self.processing_animation = QLabel()
        self.processing_animation.setMaximumSize(QSize(size, size))
        self.processing_animation.setMinimumSize(QSize(size, size))
        self.processing_animation.setMovie(spin_movie)

        button_layout = QHBoxLayout()
        button_layout.addWidget(self.processing_animation)
        button_layout.addWidget(self.running_time)
        button_layout.addStretch()
        button_layout.addWidget(self.show_details_button)
        button_layout.addWidget(self.plot_button)
        button_layout.addWidget(self.kill_button)
        button_layout.addWidget(self.done_button)
        button_layout.addWidget(self.restart_button)
        button_widget_container = QWidget()
        button_widget_container.setLayout(button_layout)

        self.detailed_progress = DetailedProgressWidget(
            self, self.state_colors)
        self.detailed_progress.setVisible(False)
        self.dummy_widget_container = QWidget(
        )  #Used to keep the other widgets from stretching

        layout = QVBoxLayout()
        layout.addWidget(self.total_progress)
        layout.addWidget(status_widget_container)
        layout.addWidget(self.progress)
        layout.addWidget(legend_widget_container)
        layout.addWidget(self.detailed_progress)
        layout.addWidget(self.dummy_widget_container)
        layout.addWidget(button_widget_container)

        layout.setStretch(0, 0)
        layout.setStretch(1, 0)
        layout.setStretch(2, 0)
        layout.setStretch(3, 0)
        layout.setStretch(4, 1)
        layout.setStretch(5, 1)
        layout.setStretch(6, 0)

        self.setLayout(layout)

        self.kill_button.clicked.connect(self.killJobs)
        self.done_button.clicked.connect(self.accept)
        self.restart_button.clicked.connect(self.restart_failed_realizations)
        self.show_details_button.clicked.connect(self.toggle_detailed_progress)
        self.simulation_done.connect(self._on_simulation_done)

    def reject(self):
        return

    def closeEvent(self, QCloseEvent):
        self.simulations_tracker.stop()
        if self._run_model.isFinished():
            self.simulation_done.emit(self._run_model.hasRunFailed(),
                                      self._run_model.getFailMessage())
        else:
            # Kill jobs if dialog is closed
            if self.killJobs() != QMessageBox.Yes:
                QCloseEvent.ignore()

    def startSimulation(self):
        self._run_model.reset()
        self.simulations_tracker.reset()

        def run():
            self._run_model.startSimulations(self._simulations_argments)

        simulation_thread = Thread(name="ert_gui_simulation_thread")
        simulation_thread.setDaemon(True)
        simulation_thread.run = run
        simulation_thread.start()

        self.simulations_tracker.track()

    def killJobs(self):

        msg = "Are you sure you want to kill the currently running simulations?"
        if self._run_model.getQueueStatus().get(
                JobStatusType.JOB_QUEUE_UNKNOWN, 0) > 0:
            msg += "\n\nKilling a simulation with unknown status will not kill the realizations already submitted!"
        kill_job = QMessageBox.question(self, "Kill simulations?", msg,
                                        QMessageBox.Yes | QMessageBox.No)

        if kill_job == QMessageBox.Yes:
            if self._run_model.killAllSimulations():
                self.reject()
        return kill_job

    @Slot(bool, str)
    def _on_simulation_done(self, failed, failed_msg):
        self.simulations_tracker.stop()
        self.processing_animation.hide()
        self.kill_button.setHidden(True)
        self.done_button.setHidden(False)
        self.restart_button.setVisible(self.has_failed_realizations())
        self.restart_button.setEnabled(self._run_model.support_restart)

        if failed:
            QMessageBox.critical(
                self, "Simulations failed!",
                "The simulation failed with the following " +
                "error:\n\n{}".format(failed_msg))

    @Slot(object)
    def _on_tracker_event(self, event):
        if isinstance(event, TickEvent):
            self.running_time.setText(format_running_time(event.runtime))

        if isinstance(event, GeneralEvent):
            self.total_progress.setProgress(event.progress)
            self.progress.setIndeterminate(event.indeterminate)

            if event.indeterminate:
                for state in event.sim_states:
                    self.legends[state].updateLegend(state.name, 0, 0)
            else:
                for state in event.sim_states:
                    self.progress.updateState(
                        state.state, 100.0 * state.count / state.total_count)
                    self.legends[state].updateLegend(state.name, state.count,
                                                     state.total_count)

        if isinstance(event, DetailedEvent):
            if not self.progress.get_indeterminate():
                self.detailed_progress.set_progress(event.details,
                                                    event.iteration)

        if isinstance(event, EndEvent):
            self.simulation_done.emit(event.failed, event.failed_msg)

    def has_failed_realizations(self):
        completed = self._run_model.completed_realizations_mask
        initial = self._run_model.initial_realizations_mask
        for (index, successful) in enumerate(completed):
            if initial[index] and not successful:
                return True
        return False

    def count_successful_realizations(self):
        """
        Counts the realizations completed in the prevoius ensemble run
        :return:
        """
        completed = self._run_model.completed_realizations_mask
        return completed.count(True)

    def create_mask_from_failed_realizations(self):
        """
        Creates a BoolVector mask representing the failed realizations
        :return: Type BoolVector
        """
        completed = self._run_model.completed_realizations_mask
        initial = self._run_model.initial_realizations_mask
        inverted_mask = BoolVector(default_value=False)
        for (index, successful) in enumerate(completed):
            inverted_mask[index] = initial[index] and not successful
        return inverted_mask

    def restart_failed_realizations(self):

        msg = QMessageBox(self)
        msg.setIcon(QMessageBox.Information)
        msg.setText(
            "Note that workflows will only be executed on the restarted realizations and that this might have unexpected consequences."
        )
        msg.setWindowTitle("Restart Failed Realizations")
        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        result = msg.exec_()

        if result == QMessageBox.Ok:
            self.restart_button.setVisible(False)
            self.kill_button.setVisible(True)
            self.done_button.setVisible(False)
            active_realizations = self.create_mask_from_failed_realizations()
            self._simulations_argments[
                'active_realizations'] = active_realizations
            self._simulations_argments[
                'prev_successful_realizations'] = self._simulations_argments.get(
                    'prev_successful_realizations', 0)
            self._simulations_argments[
                'prev_successful_realizations'] += self.count_successful_realizations(
                )
            self.startSimulation()

    def toggle_detailed_progress(self):

        self.detailed_progress.setVisible(not (
            self.detailed_progress.isVisible()))
        self.dummy_widget_container.setVisible(not (
            self.detailed_progress.isVisible()))
        self.adjustSize()
Пример #15
0
class QtPluginDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.installer = Installer()
        self.setup_ui()
        self.installer.set_output_widget(self.stdout_text)
        self.installer.process.started.connect(self._on_installer_start)
        self.installer.process.finished.connect(self._on_installer_done)
        self.refresh()

    def _on_installer_start(self):
        self.show_status_btn.setChecked(True)
        self.working_indicator.show()
        self.process_error_indicator.hide()

    def _on_installer_done(self, exit_code, exit_status):
        self.working_indicator.hide()
        if exit_code:
            self.process_error_indicator.show()
        else:
            self.show_status_btn.setChecked(False)
        self.refresh()
        self.plugin_sorter.refresh()

    def refresh(self):
        self.installed_list.clear()
        self.available_list.clear()

        # fetch installed
        from ...plugins import plugin_manager

        plugin_manager.discover()  # since they might not be loaded yet

        already_installed = set()

        for plugin_name, mod_name, distname in plugin_manager.iter_available():
            # not showing these in the plugin dialog
            if plugin_name in ('napari_plugin_engine', ):
                continue
            if distname:
                already_installed.add(distname)
                meta = standard_metadata(distname)
            else:
                meta = {}
            self.installed_list.addItem(
                ProjectInfo(
                    normalized_name(distname or ''),
                    meta.get('version', ''),
                    meta.get('url', ''),
                    meta.get('summary', ''),
                    meta.get('author', ''),
                    meta.get('license', ''),
                ),
                plugin_name=plugin_name,
                enabled=plugin_name in plugin_manager.plugins,
            )
        # self.v_splitter.setSizes([70 * self.installed_list.count(), 10, 10])

        # fetch available plugins
        self.worker = create_worker(iter_napari_plugin_info)

        def _handle_yield(project_info):
            if project_info.name in already_installed:
                self.installed_list.tag_outdated(project_info)
            else:
                self.available_list.addItem(project_info)

        self.worker.yielded.connect(_handle_yield)
        self.worker.finished.connect(self.working_indicator.hide)
        self.worker.finished.connect(self._update_count_in_label)
        self.worker.start()

    def setup_ui(self):
        self.resize(1080, 640)
        vlay_1 = QVBoxLayout(self)
        self.h_splitter = QSplitter(self)
        vlay_1.addWidget(self.h_splitter)
        self.h_splitter.setOrientation(Qt.Horizontal)
        self.v_splitter = QSplitter(self.h_splitter)
        self.v_splitter.setOrientation(Qt.Vertical)
        self.v_splitter.setMinimumWidth(500)
        self.plugin_sorter = QtPluginSorter(parent=self.h_splitter)
        self.plugin_sorter.layout().setContentsMargins(2, 0, 0, 0)
        self.plugin_sorter.hide()

        installed = QWidget(self.v_splitter)
        lay = QVBoxLayout(installed)
        lay.setContentsMargins(0, 2, 0, 2)
        lay.addWidget(QLabel(trans._("Installed Plugins")))
        self.installed_list = QPluginList(installed, self.installer)
        lay.addWidget(self.installed_list)

        uninstalled = QWidget(self.v_splitter)
        lay = QVBoxLayout(uninstalled)
        lay.setContentsMargins(0, 2, 0, 2)
        self.avail_label = QLabel(trans._("Available Plugins"))
        lay.addWidget(self.avail_label)
        self.available_list = QPluginList(uninstalled, self.installer)
        lay.addWidget(self.available_list)

        self.stdout_text = QTextEdit(self.v_splitter)
        self.stdout_text.setReadOnly(True)
        self.stdout_text.setObjectName("pip_install_status")
        self.stdout_text.hide()

        buttonBox = QHBoxLayout()
        self.working_indicator = QLabel(trans._("loading ..."), self)
        sp = self.working_indicator.sizePolicy()
        sp.setRetainSizeWhenHidden(True)
        self.working_indicator.setSizePolicy(sp)
        self.process_error_indicator = QLabel(self)
        self.process_error_indicator.setObjectName("error_label")
        self.process_error_indicator.hide()
        load_gif = str(Path(napari.resources.__file__).parent / "loading.gif")
        mov = QMovie(load_gif)
        mov.setScaledSize(QSize(18, 18))
        self.working_indicator.setMovie(mov)
        mov.start()

        self.direct_entry_edit = QLineEdit(self)
        self.direct_entry_edit.installEventFilter(self)
        self.direct_entry_edit.setPlaceholderText(
            trans._('install by name/url, or drop file...'))
        self.direct_entry_btn = QPushButton(trans._("Install"), self)
        self.direct_entry_btn.clicked.connect(self._install_packages)

        self.show_status_btn = QPushButton(trans._("Show Status"), self)
        self.show_status_btn.setFixedWidth(100)
        self.show_sorter_btn = QPushButton(trans._("<< Show Sorter"), self)
        self.close_btn = QPushButton(trans._("Close"), self)
        self.close_btn.clicked.connect(self.reject)
        buttonBox.addWidget(self.show_status_btn)
        buttonBox.addWidget(self.working_indicator)
        buttonBox.addWidget(self.direct_entry_edit)
        buttonBox.addWidget(self.direct_entry_btn)
        buttonBox.addWidget(self.process_error_indicator)
        buttonBox.addSpacing(60)
        buttonBox.addWidget(self.show_sorter_btn)
        buttonBox.addWidget(self.close_btn)
        buttonBox.setContentsMargins(0, 0, 4, 0)
        vlay_1.addLayout(buttonBox)

        self.show_status_btn.setCheckable(True)
        self.show_status_btn.setChecked(False)
        self.show_status_btn.toggled.connect(self._toggle_status)

        self.show_sorter_btn.setCheckable(True)
        self.show_sorter_btn.setChecked(False)
        self.show_sorter_btn.toggled.connect(self._toggle_sorter)

        self.v_splitter.setStretchFactor(1, 2)
        self.h_splitter.setStretchFactor(0, 2)

    def _update_count_in_label(self):
        count = self.available_list.count()
        self.avail_label.setText(
            trans._("Available Plugins ({count})".format(count=count)))

    def eventFilter(self, watched, event):
        if event.type() == QEvent.DragEnter:
            # we need to accept this event explicitly to be able
            # to receive QDropEvents!
            event.accept()
        if event.type() == QEvent.Drop:
            md = event.mimeData()
            if md.hasUrls():
                files = [url.toLocalFile() for url in md.urls()]
                self.direct_entry_edit.setText(files[0])
                return True
        return super().eventFilter(watched, event)

    def _toggle_sorter(self, show):
        if show:
            self.show_sorter_btn.setText(trans._(">> Hide Sorter"))
            self.plugin_sorter.show()
        else:
            self.show_sorter_btn.setText(trans._("<< Show Sorter"))
            self.plugin_sorter.hide()

    def _toggle_status(self, show):
        if show:
            self.show_status_btn.setText(trans._("Hide Status"))
            self.stdout_text.show()
        else:
            self.show_status_btn.setText(trans._("Show Status"))
            self.stdout_text.hide()

    def _install_packages(self, packages: Sequence[str] = ()):
        if not packages:
            _packages = self.direct_entry_edit.text()
            if os.path.exists(_packages):
                packages = [_packages]
            else:
                packages = _packages.split()
            self.direct_entry_edit.clear()
        if packages:
            self.installer.install(packages)
Пример #16
0
    def get_auto_correction_widget(self, parent):
        """."""
        auto_wid = QWidget(parent)
        vbl2 = QVBoxLayout(auto_wid)

        tabw = QTabWidget(auto_wid)
        vbl2.addWidget(tabw)

        # Add Main Tab
        gpbx = QWidget(tabw)
        gpbx_lay = QVBoxLayout(gpbx)
        tabw.addTab(gpbx, 'Main')

        fbl = QFormLayout()
        fbl.setHorizontalSpacing(9)
        gpbx_lay.addLayout(fbl)

        lbl = QLabel('Freq. [Hz]', gpbx)
        wid = self.create_pair(gpbx, 'LoopFreq')
        fbl.addRow(lbl, wid)

        lbl = QLabel('Max. Orb. Distortion [um]', gpbx)
        wid = self.create_pair(gpbx, 'LoopMaxOrbDistortion')
        fbl.addRow(lbl, wid)

        wid = QWidget(gpbx)
        wid.setLayout(QHBoxLayout())
        pbtn = QPushButton('Loop Performance', wid)
        pbtn.setIcon(qta.icon('mdi.poll'))
        wid.layout().addStretch()
        wid.layout().addWidget(pbtn)
        icon = qta.icon(
            'fa5s.hammer', color=_util.get_appropriate_color(self.acc))
        wind = create_window_from_widget(
            PerformanceWidget, title='Loop Performance', icon=icon)
        _util.connect_window(
            pbtn, wind, self, device=self.device, prefix=self.prefix)
        fbl.addRow(wid)

        # Add PID Tab
        gpbx = QWidget(tabw)
        gpbx_lay = QGridLayout(gpbx)
        gpbx_lay.setSpacing(1)
        tabw.addTab(gpbx, 'PID')

        gpbx_lay.addWidget(QLabel('CH', gpbx), 1, 0)
        gpbx_lay.addWidget(QLabel('CV', gpbx), 2, 0)
        tmpl = 'LoopPID{:s}{:s}'
        pairs = []
        for i, k in enumerate(('Kp', 'Ki', 'Kd'), 1):
            gpbx_lay.addWidget(
                QLabel(k, gpbx), 0, i, alignment=Qt.AlignCenter)
            pair = self.create_pair(wid, tmpl.format(k, 'CH'), is_vert=True)
            pairs.append(pair)
            gpbx_lay.addWidget(pair, 1, i)
            pair = self.create_pair(wid, tmpl.format(k, 'CV'), is_vert=True)
            pairs.append(pair)
            gpbx_lay.addWidget(pair, 2, i)
            if self.acc in {'SI', 'BO'}:
                pair = self.create_pair(
                    wid, tmpl.format(k, 'RF'), is_vert=True)
                pairs.append(pair)
                gpbx_lay.addWidget(pair, 3, i)
        if self.acc in {'SI', 'BO'}:
            gpbx_lay.addWidget(QLabel('RF', gpbx), 3, 0)

        pbc = QPushButton('SP')
        pbc.setStyleSheet('max-width:2.2em;')
        gpbx_lay.addWidget(pbc, 0, 0)
        pbc.setCheckable(True)
        pbc.setChecked(False)
        pbc.toggled.connect(
            lambda x: pbc.setText('RB' if x else 'SP'))
        for pair in pairs:
            pair.rb_wid.setVisible(False)
            pbc.toggled.connect(pair.rb_wid.setVisible)
            pbc.toggled.connect(pair.sp_wid.setHidden)
        gpbx_lay.setRowStretch(4, 2)
        return auto_wid
Пример #17
0
class PlotNameWidget(QWidget):
    """A widget to display the plot name, and edit and close buttons

    This widget is added to the table widget to support the renaming
    and close buttons, as well as the direct renaming functionality.
    """
    def __init__(self, presenter, plot_number, parent=None):
        super(PlotNameWidget, self).__init__(parent)

        self.presenter = presenter
        self.plot_number = plot_number

        self.mutex = QMutex()

        self.line_edit = QLineEdit(
            self.presenter.get_plot_name_from_number(plot_number))
        self.line_edit.setReadOnly(True)
        self.line_edit.setFrame(False)
        # changes the line edit to look like normal even when
        self.line_edit.setStyleSheet(
            """* { background-color: rgba(0, 0, 0, 0); }
        QLineEdit:disabled { color: black; }""")
        self.line_edit.setAttribute(Qt.WA_TransparentForMouseEvents, True)
        self.line_edit.editingFinished.connect(self.rename_plot)
        # Disabling the line edit prevents it from temporarily
        # grabbing focus when changing code editors - this triggered
        # the editingFinished signal, which was causing #26305
        self.line_edit.setDisabled(True)

        shown_icon = get_icon('mdi.eye')
        self.hide_button = QPushButton(shown_icon, "")
        self.hide_button.setToolTip('Hide')
        self.hide_button.setFlat(True)
        self.hide_button.setMaximumWidth(self.hide_button.iconSize().width() *
                                         5 / 3)
        self.hide_button.clicked.connect(self.toggle_visibility)

        rename_icon = get_icon('mdi.square-edit-outline')
        self.rename_button = QPushButton(rename_icon, "")
        self.rename_button.setToolTip('Rename')
        self.rename_button.setFlat(True)
        self.rename_button.setMaximumWidth(
            self.rename_button.iconSize().width() * 5 / 3)
        self.rename_button.setCheckable(True)
        self.rename_button.toggled.connect(self.rename_button_toggled)

        close_icon = get_icon('mdi.close')
        self.close_button = QPushButton(close_icon, "")
        self.close_button.setToolTip('Delete')
        self.close_button.setFlat(True)
        self.close_button.setMaximumWidth(
            self.close_button.iconSize().width() * 5 / 3)
        self.close_button.clicked.connect(
            lambda: self.close_pressed(self.plot_number))

        self.layout = QHBoxLayout()

        # Get rid of the top and bottom margins - the button provides
        # some natural margin anyway. Get rid of right margin and
        # reduce spacing to get buttons closer together.
        self.layout.setContentsMargins(5, 0, 0, 0)
        self.layout.setSpacing(0)

        self.layout.addWidget(self.line_edit)
        self.layout.addWidget(self.hide_button)
        self.layout.addWidget(self.rename_button)
        self.layout.addWidget(self.close_button)

        self.layout.sizeHint()
        self.setLayout(self.layout)

    def set_plot_name(self, new_name):
        """
        Sets the internally stored and displayed plot name
        :param new_name: The name to set
        """
        self.line_edit.setText(new_name)

    def close_pressed(self, plot_number):
        """
        Close the plot with the given name
        :param plot_number: The unique number in GlobalFigureManager
        """
        self.presenter.close_single_plot(plot_number)

    def rename_button_toggled(self, checked):
        """
        If the rename button is pressed from being unchecked then
        make the line edit item editable
        :param checked: True if the rename toggle is now pressed
        """
        if checked:
            self.toggle_plot_name_editable(True, toggle_rename_button=False)

    def toggle_plot_name_editable(self, editable, toggle_rename_button=True):
        """
        Set the line edit item to be editable or not editable. If
        editable move the cursor focus to the editable name and
        highlight it all.
        :param editable: If true make the plot name editable, else
                         make it read only
        :param toggle_rename_button: If true also toggle the rename
                                     button state
        """
        self.line_edit.setReadOnly(not editable)
        self.line_edit.setDisabled(not editable)
        self.line_edit.setAttribute(Qt.WA_TransparentForMouseEvents,
                                    not editable)

        # This is a sneaky way to avoid the issue of two calls to
        # this toggle method, by effectively disabling the button
        # press in edit mode.
        self.rename_button.setAttribute(Qt.WA_TransparentForMouseEvents,
                                        editable)

        if toggle_rename_button:
            self.rename_button.setChecked(editable)

        if editable:
            self.line_edit.setFocus()
            self.line_edit.selectAll()
        else:
            self.line_edit.setSelection(0, 0)

    def toggle_visibility(self):
        """
        Calls the presenter to hide the selected plot
        """
        self.presenter.toggle_plot_visibility(self.plot_number)

    def set_visibility_icon(self, is_shown):
        """
        Change the widget icon between shown and hidden
        :param is_shown: True if plot is shown, false if hidden
        """
        if is_shown:
            self.hide_button.setIcon(get_icon('mdi.eye'))
            self.hide_button.setToolTip('Hide')
        else:
            self.hide_button.setIcon(get_icon('mdi.eye', 'lightgrey'))
            self.hide_button.setToolTip('Show')

    def rename_plot(self):
        """
        Called when the editing is finished, gets the presenter to
        do the real renaming of the plot
        """
        self.presenter.rename_figure(self.plot_number, self.line_edit.text())

        self.toggle_plot_name_editable(False)
Пример #18
0
class QtPluginDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.refresh_state = RefreshState.DONE
        self.already_installed = set()

        installer_type = "mamba" if running_as_constructor_app() else "pip"

        self.installer = Installer(installer=installer_type)
        self.setup_ui()
        self.installer.set_output_widget(self.stdout_text)
        self.installer.started.connect(self._on_installer_start)
        self.installer.finished.connect(self._on_installer_done)
        self.refresh()

    def _on_installer_start(self):
        self.cancel_all_btn.setVisible(True)
        self.working_indicator.show()
        self.process_error_indicator.hide()
        self.close_btn.setDisabled(True)

    def _on_installer_done(self, exit_code):
        self.working_indicator.hide()
        if exit_code:
            self.process_error_indicator.show()

        self.cancel_all_btn.setVisible(False)
        self.close_btn.setDisabled(False)
        self.refresh()

    def closeEvent(self, event):
        if self.close_btn.isEnabled():
            super().closeEvent(event)

        event.ignore()

    def refresh(self):
        if self.refresh_state != RefreshState.DONE:
            self.refresh_state = RefreshState.OUTDATED
            return
        self.refresh_state = RefreshState.REFRESHING
        self.installed_list.clear()
        self.available_list.clear()

        # fetch installed
        from npe2 import PluginManager

        from ...plugins import plugin_manager

        plugin_manager.discover()  # since they might not be loaded yet

        self.already_installed = set()

        def _add_to_installed(distname, enabled, npe_version=1):
            norm_name = normalized_name(distname or '')
            if distname:
                try:
                    meta = metadata(distname)
                except PackageNotFoundError:
                    self.refresh_state = RefreshState.OUTDATED
                    return  # a race condition has occurred and the package is uninstalled by another thread
                if len(meta) == 0:
                    # will not add builtins.
                    return
                self.already_installed.add(norm_name)
            else:
                meta = {}

            self.installed_list.addItem(
                PackageMetadata(
                    metadata_version="1.0",
                    name=norm_name,
                    version=meta.get('version', ''),
                    summary=meta.get('summary', ''),
                    home_page=meta.get('url', ''),
                    author=meta.get('author', ''),
                    license=meta.get('license', ''),
                ),
                installed=True,
                enabled=enabled,
                npe_version=npe_version,
            )

        pm2 = PluginManager.instance()
        for manifest in pm2.iter_manifests():
            distname = normalized_name(manifest.name or '')
            if distname in self.already_installed or distname == 'napari':
                continue
            enabled = not pm2.is_disabled(manifest.name)
            _add_to_installed(distname, enabled, npe_version=2)

        for (
                plugin_name,
                _mod_name,
                distname,
        ) in plugin_manager.iter_available():
            # not showing these in the plugin dialog
            if plugin_name in ('napari_plugin_engine', ):
                continue
            if distname in self.already_installed:
                continue
            _add_to_installed(distname,
                              not plugin_manager.is_blocked(plugin_name))

        self.installed_label.setText(
            trans._(
                "Installed Plugins ({amount})",
                amount=len(self.already_installed),
            ))

        # fetch available plugins
        settings = get_settings()
        use_hub = (running_as_bundled_app() or running_as_constructor_app()
                   or settings.plugins.plugin_api.name == "napari_hub")
        if use_hub:
            conda_forge = running_as_constructor_app()
            self.worker = create_worker(iter_hub_plugin_info,
                                        conda_forge=conda_forge)
        else:
            self.worker = create_worker(iter_napari_plugin_info)

        self.worker.yielded.connect(self._handle_yield)
        self.worker.finished.connect(self.working_indicator.hide)
        self.worker.finished.connect(self._update_count_in_label)
        self.worker.finished.connect(self._end_refresh)
        self.worker.start()

    def setup_ui(self):
        self.resize(1080, 640)
        vlay_1 = QVBoxLayout(self)
        self.h_splitter = QSplitter(self)
        vlay_1.addWidget(self.h_splitter)
        self.h_splitter.setOrientation(Qt.Horizontal)
        self.v_splitter = QSplitter(self.h_splitter)
        self.v_splitter.setOrientation(Qt.Vertical)
        self.v_splitter.setMinimumWidth(500)

        installed = QWidget(self.v_splitter)
        lay = QVBoxLayout(installed)
        lay.setContentsMargins(0, 2, 0, 2)
        self.installed_label = QLabel(trans._("Installed Plugins"))
        self.packages_filter = QLineEdit()
        self.packages_filter.setPlaceholderText(trans._("filter..."))
        self.packages_filter.setMaximumWidth(350)
        self.packages_filter.setClearButtonEnabled(True)
        mid_layout = QVBoxLayout()
        mid_layout.addWidget(self.packages_filter)
        mid_layout.addWidget(self.installed_label)
        lay.addLayout(mid_layout)

        self.installed_list = QPluginList(installed, self.installer)
        self.packages_filter.textChanged.connect(self.installed_list.filter)
        lay.addWidget(self.installed_list)

        uninstalled = QWidget(self.v_splitter)
        lay = QVBoxLayout(uninstalled)
        lay.setContentsMargins(0, 2, 0, 2)
        self.avail_label = QLabel(trans._("Available Plugins"))
        mid_layout = QHBoxLayout()
        mid_layout.addWidget(self.avail_label)
        mid_layout.addStretch()
        lay.addLayout(mid_layout)
        self.available_list = QPluginList(uninstalled, self.installer)
        self.packages_filter.textChanged.connect(self.available_list.filter)
        lay.addWidget(self.available_list)

        self.stdout_text = QTextEdit(self.v_splitter)
        self.stdout_text.setReadOnly(True)
        self.stdout_text.setObjectName("pip_install_status")
        self.stdout_text.hide()

        buttonBox = QHBoxLayout()
        self.working_indicator = QLabel(trans._("loading ..."), self)
        sp = self.working_indicator.sizePolicy()
        sp.setRetainSizeWhenHidden(True)
        self.working_indicator.setSizePolicy(sp)
        self.process_error_indicator = QLabel(self)
        self.process_error_indicator.setObjectName("error_label")
        self.process_error_indicator.hide()
        load_gif = str(Path(napari.resources.__file__).parent / "loading.gif")
        mov = QMovie(load_gif)
        mov.setScaledSize(QSize(18, 18))
        self.working_indicator.setMovie(mov)
        mov.start()

        visibility_direct_entry = not running_as_constructor_app()
        self.direct_entry_edit = QLineEdit(self)
        self.direct_entry_edit.installEventFilter(self)
        self.direct_entry_edit.setPlaceholderText(
            trans._('install by name/url, or drop file...'))
        self.direct_entry_edit.setVisible(visibility_direct_entry)
        self.direct_entry_btn = QPushButton(trans._("Install"), self)
        self.direct_entry_btn.setVisible(visibility_direct_entry)
        self.direct_entry_btn.clicked.connect(self._install_packages)

        self.show_status_btn = QPushButton(trans._("Show Status"), self)
        self.show_status_btn.setFixedWidth(100)

        self.cancel_all_btn = QPushButton(trans._("cancel all actions"), self)
        self.cancel_all_btn.setObjectName("remove_button")
        self.cancel_all_btn.setVisible(False)
        self.cancel_all_btn.clicked.connect(lambda: self.installer.cancel())

        self.close_btn = QPushButton(trans._("Close"), self)
        self.close_btn.clicked.connect(self.accept)
        self.close_btn.setObjectName("close_button")
        buttonBox.addWidget(self.show_status_btn)
        buttonBox.addWidget(self.working_indicator)
        buttonBox.addWidget(self.direct_entry_edit)
        buttonBox.addWidget(self.direct_entry_btn)
        if not visibility_direct_entry:
            buttonBox.addStretch()
        buttonBox.addWidget(self.process_error_indicator)
        buttonBox.addSpacing(20)
        buttonBox.addWidget(self.cancel_all_btn)
        buttonBox.addSpacing(20)
        buttonBox.addWidget(self.close_btn)
        buttonBox.setContentsMargins(0, 0, 4, 0)
        vlay_1.addLayout(buttonBox)

        self.show_status_btn.setCheckable(True)
        self.show_status_btn.setChecked(False)
        self.show_status_btn.toggled.connect(self._toggle_status)

        self.v_splitter.setStretchFactor(1, 2)
        self.h_splitter.setStretchFactor(0, 2)

        self.packages_filter.setFocus()

    def _update_count_in_label(self):
        count = self.available_list.count()
        self.avail_label.setText(
            trans._("Available Plugins ({count})", count=count))

    def _end_refresh(self):
        refresh_state = self.refresh_state
        self.refresh_state = RefreshState.DONE
        if refresh_state == RefreshState.OUTDATED:
            self.refresh()

    def eventFilter(self, watched, event):
        if event.type() == QEvent.DragEnter:
            # we need to accept this event explicitly to be able
            # to receive QDropEvents!
            event.accept()
        if event.type() == QEvent.Drop:
            md = event.mimeData()
            if md.hasUrls():
                files = [url.toLocalFile() for url in md.urls()]
                self.direct_entry_edit.setText(files[0])
                return True
        return super().eventFilter(watched, event)

    def _toggle_status(self, show):
        if show:
            self.show_status_btn.setText(trans._("Hide Status"))
            self.stdout_text.show()
        else:
            self.show_status_btn.setText(trans._("Show Status"))
            self.stdout_text.hide()

    def _install_packages(self, packages: Sequence[str] = ()):
        if not packages:
            _packages = self.direct_entry_edit.text()
            if os.path.exists(_packages):
                packages = [_packages]
            else:
                packages = _packages.split()
            self.direct_entry_edit.clear()

        if packages:
            self.installer.install(packages)

    def _handle_yield(self, data: Tuple[PackageMetadata, bool]):
        project_info, is_available = data
        if project_info.name in self.already_installed:
            self.installed_list.tag_outdated(project_info, is_available)
        else:
            self.available_list.addItem(project_info)
            if not is_available:
                self.available_list.tag_unavailable(project_info)

        self.filter()

    def filter(self, text: str = None) -> None:
        """Filter by text or set current text as filter."""
        if text is None:
            text = self.packages_filter.text()
        else:
            self.packages_filter.setText(text)

        self.installed_list.filter(text)
        self.available_list.filter(text)
Пример #19
0
class Dimension(QWidget):
    stateChanged = Signal(int)
    valueChanged = Signal()
    """
    pass in dimension

    state: one of (State.X, State.Y, State.NONE, State.DISBALE)

    Can be run independently by:

    from mantidqt.widgets.sliceviewer.dimensionwidget import Dimension
    from qtpy.QtWidgets import QApplication
    app = QApplication([])
    window = Dimension({'minimum':-1.1, 'number_of_bins':11, 'width':0.2, 'name':'Dim0', 'units':'A'})
    window.show()
    app.exec_()
    """
    def __init__(self, dim_info, number=0, state=State.NONE, parent=None):
        super(Dimension, self).__init__(parent)

        self.minimum = dim_info['minimum']
        self.nbins = dim_info['number_of_bins']
        self.width = dim_info['width']
        self.number = number

        self.layout = QHBoxLayout(self)

        self.name = QLabel(dim_info['name'])
        self.units = QLabel(dim_info['units'])

        self.x = QPushButton('X')
        self.x.setFixedSize(32,32)
        self.x.setCheckable(True)
        self.x.clicked.connect(self.x_clicked)

        self.y = QPushButton('Y')
        self.y.setFixedSize(32,32)
        self.y.setCheckable(True)
        self.y.clicked.connect(self.y_clicked)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, self.nbins-1)
        self.slider.valueChanged.connect(self.slider_changed)

        self.spinbox = QDoubleSpinBox()
        self.spinbox.setDecimals(3)
        self.spinbox.setRange(self.get_bin_center(0), self.get_bin_center(self.nbins-1))
        self.spinbox.setSingleStep(self.width)
        self.spinbox.valueChanged.connect(self.spinbox_changed)

        self.layout.addWidget(self.name)
        self.layout.addWidget(self.x)
        self.layout.addWidget(self.y)
        self.layout.addWidget(self.slider, stretch=1)
        self.layout.addStretch(0)
        self.layout.addWidget(self.spinbox)
        self.layout.addWidget(self.units)

        self.set_value(0)

        if self.nbins < 2:
            state = State.DISABLE

        self.set_state(state)

    def set_state(self, state):
        self.state = state
        if self.state == State.X:
            self.x.setChecked(True)
            self.y.setChecked(False)
            self.slider.hide()
            self.spinbox.hide()
            self.units.hide()
        elif self.state == State.Y:
            self.x.setChecked(False)
            self.y.setChecked(True)
            self.slider.hide()
            self.spinbox.hide()
            self.units.hide()
        elif self.state == State.NONE:
            self.x.setChecked(False)
            self.y.setChecked(False)
            self.slider.show()
            self.spinbox.show()
            self.units.show()
        else:
            self.x.setChecked(False)
            self.x.setDisabled(True)
            self.y.setChecked(False)
            self.y.setDisabled(True)
            self.slider.hide()
            self.spinbox.show()
            self.spinbox.setDisabled(True)
            self.units.show()

    def get_state(self):
        return self.state

    def x_clicked(self):
        old_state = self.state
        self.set_state(State.X)
        if self.state != old_state:
            self.stateChanged.emit(self.number)

    def y_clicked(self):
        old_state = self.state
        self.set_state(State.Y)
        if self.state != old_state:
            self.stateChanged.emit(self.number)

    def spinbox_changed(self):
        self.value = self.spinbox.value()
        self.update_slider()
        self.valueChanged.emit()

    def slider_changed(self):
        self.value = self.get_bin_center(self.slider.value())
        self.update_spinbox()
        self.valueChanged.emit()

    def get_bin_center(self, n):
        return (n+0.5)*self.width+self.minimum

    def update_slider(self):
        i = (self.value-self.minimum)/self.width
        self.slider.setValue(int(min(max(i, 0), self.nbins-1)))

    def update_spinbox(self):
        self.spinbox.setValue(self.value)

    def set_value(self, value):
        self.value = value
        self.update_slider()
        self.update_spinbox()

    def get_value(self):
        return self.value
Пример #20
0
class LibraryWidget(QWidget):
    sigImageChanged = Signal()

    def __init__(self):
        super(LibraryWidget, self).__init__()
        self.image_items = []
        self.views = []
        self.current_image_item = None

        self.setLayout(QHBoxLayout())
        self.right_layout = QVBoxLayout()

        self.scroll_widget = QScrollArea()
        self.scroll_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.scroll_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scroll_widget.setWidgetResizable(True)
        self.flow_widget = QWidget()
        self.flow_layout = FlowLayout()
        self.flow_widget.setLayout(self.flow_layout)
        self.scroll_widget.setWidget(self.flow_widget)
        self.layout().addWidget(self.scroll_widget)

        self.hist_widget = HistogramLUTWidget()
        self.hist_widget.setSizePolicy(QSizePolicy.Minimum,
                                       QSizePolicy.Minimum)
        self.hist_widget.item.sigLevelChangeFinished.connect(self.set_levels)
        self.hist_widget.item.sigLookupTableChanged.connect(
            self.set_lookup_table)
        self.layout().addLayout(self.right_layout)
        self.right_layout.addWidget(self.hist_widget)

        self.link_button = QPushButton("Link Axes")
        self.link_button.setCheckable(True)
        self.right_layout.addWidget(self.link_button)

        # TODO: use Qt styling pallet for theming
        # self.setStyleSheet("background-color:#000;")

        self.current_view = None
        self.axes_linked = False

    def set_slice(self, *args, **kwargs):
        # TODO: support generic orthogonal slicing
        print('slice:', args, kwargs)

    def set_levels(self, *args, **kwargs):
        levels = self.hist_widget.item.getLevels()
        for image_item in self.image_items:
            image_item.setLevels(levels)

    def set_lookup_table(self, *args, **kwargs):
        if self.current_image_item and self.current_image_item.image is not None:
            lut = self.hist_widget.item.getLookupTable(
                self.current_image_item.image)
            for image_item in self.image_items:
                image_item.setLookupTable(lut)

    def set_current_imageitem(self, imageitem: ImageItem):
        if self.current_image_item:
            self.current_image_item.deactivate()
        self.current_image_item = imageitem
        self.current_view = imageitem.getViewBox()
        self.current_image_item.activate()
        self.hist_widget.item.setImageItem(self.current_image_item)

    def propagate_axes(self):
        if self.link_button.isChecked():
            view = self.sender()
            view_rect = view.viewRect()

            for other_view in self.views:
                if other_view is not view:
                    with QSignalBlocker(other_view):
                        other_view.setRange(rect=view_rect, padding=0)

    def add_image(self, image, label):
        w = QFrame()
        w.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        w.setLineWidth(2)
        w.setFixedSize(QSize(500, 500))
        w.setLayout(QVBoxLayout())
        gv = ScrollableGraphicsLayoutWidget()
        vb = ViewBox(lockAspect=True)
        ii = ActivatableImageItem(image=image)
        ii.sigActivated.connect(self.set_current_imageitem)
        self.hist_widget.item.setImageItem(ii)
        self.current_image_item = ii
        self.image_items.append(ii)
        self.views.append(vb)
        vb.sigRangeChangedManually.connect(self.propagate_axes)
        vb.addItem(ii)
        gv.addItem(vb)
        self.set_current_imageitem(ii)

        w.layout().addWidget(gv)
        l = QLabel(label)
        # l.setStyleSheet("color: white;")
        w.layout().addWidget(l)

        self.flow_layout.addWidget(w)
        self.last_vb = vb

    def update_image(self, index, image, label):
        if index < len(self.image_items):
            self.image_items[index].setImage(image)
        else:
            self.add_image(image, label)
Пример #21
0
class RunDialog(QDialog):
    simulation_done = Signal(bool, str)
    simulation_termination_request = Signal()

    def __init__(self, config_file, run_model, parent=None):
        QDialog.__init__(self, parent)
        self.setWindowFlags(Qt.Window)
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)
        self.setModal(True)
        self.setWindowModality(Qt.WindowModal)
        self.setWindowTitle(f"Simulations - {config_file}")

        self._snapshot_model = SnapshotModel(self)
        self._run_model = run_model

        self._isDetailedDialog = False
        self._minimum_width = 1200

        ert = None
        if isinstance(run_model, BaseRunModel):
            ert = run_model.ert()

        self._ticker = QTimer(self)
        self._ticker.timeout.connect(self._on_ticker)

        progress_proxy_model = ProgressProxyModel(self._snapshot_model,
                                                  parent=self)

        self._total_progress_label = QLabel(
            _TOTAL_PROGRESS_TEMPLATE.format(
                total_progress=0, phase_name=run_model.getPhaseName()),
            self,
        )

        self._total_progress_bar = QProgressBar(self)
        self._total_progress_bar.setRange(0, 100)
        self._total_progress_bar.setTextVisible(False)

        self._iteration_progress_label = QLabel(self)

        self._progress_view = ProgressView(self)
        self._progress_view.setModel(progress_proxy_model)
        self._progress_view.setIndeterminate(True)

        legend_view = LegendView(self)
        legend_view.setModel(progress_proxy_model)

        self._tab_widget = QTabWidget(self)
        self._tab_widget.currentChanged.connect(self._current_tab_changed)
        self._snapshot_model.rowsInserted.connect(self.on_new_iteration)

        self._job_label = QLabel(self)

        self._job_model = JobListProxyModel(self, 0, 0, 0, 0)
        self._job_model.setSourceModel(self._snapshot_model)

        self._job_view = QTableView(self)
        self._job_view.setVerticalScrollMode(QAbstractItemView.ScrollPerItem)
        self._job_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self._job_view.setSelectionMode(QAbstractItemView.SingleSelection)
        self._job_view.clicked.connect(self._job_clicked)
        self._open_files = {}
        self._job_view.setModel(self._job_model)

        self.running_time = QLabel("")

        self.plot_tool = PlotTool(ert, config_file)
        self.plot_tool.setParent(self)
        self.plot_button = QPushButton(self.plot_tool.getName())
        self.plot_button.clicked.connect(self.plot_tool.trigger)
        self.plot_button.setEnabled(ert is not None)

        self.kill_button = QPushButton("Kill simulations")
        self.done_button = QPushButton("Done")
        self.done_button.setHidden(True)
        self.restart_button = QPushButton("Restart")
        self.restart_button.setHidden(True)
        self.show_details_button = QPushButton("Show details")
        self.show_details_button.setCheckable(True)

        size = 20
        spin_movie = resourceMovie("loading.gif")
        spin_movie.setSpeed(60)
        spin_movie.setScaledSize(QSize(size, size))
        spin_movie.start()

        self.processing_animation = QLabel()
        self.processing_animation.setMaximumSize(QSize(size, size))
        self.processing_animation.setMinimumSize(QSize(size, size))
        self.processing_animation.setMovie(spin_movie)

        button_layout = QHBoxLayout()
        button_layout.addWidget(self.processing_animation)
        button_layout.addWidget(self.running_time)
        button_layout.addStretch()
        button_layout.addWidget(self.show_details_button)
        button_layout.addWidget(self.plot_button)
        button_layout.addWidget(self.kill_button)
        button_layout.addWidget(self.done_button)
        button_layout.addWidget(self.restart_button)

        button_widget_container = QWidget()
        button_widget_container.setLayout(button_layout)

        layout = QVBoxLayout()
        layout.addWidget(self._total_progress_label)
        layout.addWidget(self._total_progress_bar)
        layout.addWidget(self._iteration_progress_label)
        layout.addWidget(self._progress_view)
        layout.addWidget(legend_view)
        layout.addWidget(self._tab_widget)
        layout.addWidget(self._job_label)
        layout.addWidget(self._job_view)
        layout.addWidget(button_widget_container)

        self.setLayout(layout)

        self.kill_button.clicked.connect(self.killJobs)
        self.done_button.clicked.connect(self.accept)
        self.restart_button.clicked.connect(self.restart_failed_realizations)
        self.show_details_button.clicked.connect(self.toggle_detailed_progress)
        self.simulation_done.connect(self._on_simulation_done)

        self.setMinimumWidth(self._minimum_width)
        self._setSimpleDialog()

    def _current_tab_changed(self, index: int):
        # Clear the selection in the other tabs
        for i in range(0, self._tab_widget.count()):
            if i != index:
                self._tab_widget.widget(i).clearSelection()

    def _setSimpleDialog(self) -> None:
        self._isDetailedDialog = False
        self._tab_widget.setVisible(False)
        self._job_label.setVisible(False)
        self._job_view.setVisible(False)
        self.show_details_button.setText("Show details")

    def _setDetailedDialog(self) -> None:
        self._isDetailedDialog = True
        self._tab_widget.setVisible(True)
        self._job_label.setVisible(True)
        self._job_view.setVisible(True)
        self.show_details_button.setText("Hide details")

    @Slot(QModelIndex, int, int)
    def on_new_iteration(self, parent: QModelIndex, start: int,
                         end: int) -> None:
        if not parent.isValid():
            index = self._snapshot_model.index(start, 0, parent)
            iter_row = start
            self._iteration_progress_label.setText(
                f"Progress for iteration {index.internalPointer().id}")

            widget = RealizationWidget(iter_row)
            widget.setSnapshotModel(self._snapshot_model)
            widget.currentChanged.connect(self._select_real)

            self._tab_widget.addTab(
                widget,
                f"Realizations for iteration {index.internalPointer().id}")

    @Slot(QModelIndex)
    def _job_clicked(self, index):
        if not index.isValid():
            return
        selected_file = index.data(FileRole)

        if selected_file and selected_file not in self._open_files:
            job_name = index.siblingAtColumn(0).data()
            viewer = FileDialog(
                selected_file,
                job_name,
                index.row(),
                index.model().get_real(),
                index.model().get_iter(),
                self,
            )
            self._open_files[selected_file] = viewer

            def remove_file():
                """
                We have sometimes seen this fail because the selected file is not
                in open file, without being able to reproduce the exception.
                """
                try:
                    self._open_files.pop(selected_file)
                except KeyError:
                    logger = logging.getLogger(__name__)
                    logger.exception(
                        f"Failed to pop: {selected_file} from {self._open_files}"
                    )

            viewer.finished.connect(remove_file)

        elif selected_file in self._open_files:
            self._open_files[selected_file].raise_()

    @Slot(QModelIndex)
    def _select_real(self, index):
        step = 0
        stage = 0
        real = index.row()
        iter_ = index.model().get_iter()
        self._job_model.set_step(iter_, real, stage, step)
        self._job_label.setText(
            f"Realization id {index.data(RealIens)} in iteration {iter_}")

        self._job_view.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)

    def reject(self):
        return

    def closeEvent(self, QCloseEvent):
        if self._run_model.isFinished():
            self.simulation_done.emit(self._run_model.hasRunFailed(),
                                      self._run_model.getFailMessage())
        else:
            # Kill jobs if dialog is closed
            if self.killJobs() != QMessageBox.Yes:
                QCloseEvent.ignore()

    def startSimulation(self):
        self._run_model.reset()
        self._snapshot_model.reset()
        self._tab_widget.clear()

        evaluator_server_config = EvaluatorServerConfig()

        def run():
            asyncio.set_event_loop(asyncio.new_event_loop())
            self._run_model.startSimulations(
                evaluator_server_config=evaluator_server_config, )

        simulation_thread = Thread(name="ert_gui_simulation_thread")
        simulation_thread.setDaemon(True)
        simulation_thread.run = run
        simulation_thread.start()

        self._ticker.start(1000)

        tracker = EvaluatorTracker(
            self._run_model,
            ee_con_info=evaluator_server_config.get_connection_info(),
        )

        worker = TrackerWorker(tracker)
        worker_thread = QThread()
        worker.done.connect(worker_thread.quit)
        worker.consumed_event.connect(self._on_tracker_event)
        worker.moveToThread(worker_thread)
        self.simulation_done.connect(worker.stop)
        self._worker = worker
        self._worker_thread = worker_thread
        worker_thread.started.connect(worker.consume_and_emit)
        self._worker_thread.start()

    def killJobs(self):

        msg = "Are you sure you want to kill the currently running simulations?"
        kill_job = QMessageBox.question(self, "Kill simulations?", msg,
                                        QMessageBox.Yes | QMessageBox.No)

        if kill_job == QMessageBox.Yes:
            # Normally this slot would be invoked by the signal/slot system,
            # but the worker is busy tracking the evaluation.
            self._worker.request_termination()
            self.reject()
        return kill_job

    @Slot(bool, str)
    def _on_simulation_done(self, failed, failed_msg):
        self.processing_animation.hide()
        self.kill_button.setHidden(True)
        self.done_button.setHidden(False)
        self.restart_button.setVisible(
            self._run_model.has_failed_realizations())
        self.restart_button.setEnabled(self._run_model.support_restart)
        self._total_progress_bar.setValue(100)
        self._total_progress_label.setText(
            _TOTAL_PROGRESS_TEMPLATE.format(
                total_progress=100, phase_name=self._run_model.getPhaseName()))

        if failed:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Simulations failed!".center(100))
            msg.setDetailedText(failed_msg)
            msg.exec_()

    @Slot()
    def _on_ticker(self):
        runtime = self._run_model.get_runtime()
        self.running_time.setText(format_running_time(runtime))

    @Slot(object)
    def _on_tracker_event(self, event):
        if isinstance(event, EndEvent):
            self.simulation_done.emit(event.failed, event.failed_msg)
            self._worker.stop()
            self._ticker.stop()

        elif isinstance(event, FullSnapshotEvent):
            if event.snapshot is not None:
                self._snapshot_model._add_snapshot(event.snapshot,
                                                   event.iteration)
            self._progress_view.setIndeterminate(event.indeterminate)
            progress = int(event.progress * 100)
            self._total_progress_bar.setValue(progress)
            self._total_progress_label.setText(
                _TOTAL_PROGRESS_TEMPLATE.format(total_progress=progress,
                                                phase_name=event.phase_name))

        elif isinstance(event, SnapshotUpdateEvent):
            if event.partial_snapshot is not None:
                self._snapshot_model._add_partial_snapshot(
                    event.partial_snapshot, event.iteration)
            self._progress_view.setIndeterminate(event.indeterminate)
            progress = int(event.progress * 100)
            self._total_progress_bar.setValue(progress)
            self._total_progress_label.setText(
                _TOTAL_PROGRESS_TEMPLATE.format(total_progress=progress,
                                                phase_name=event.phase_name))

    def restart_failed_realizations(self):

        msg = QMessageBox(self)
        msg.setIcon(QMessageBox.Information)
        msg.setText(
            "Note that workflows will only be executed on the restarted "
            "realizations and that this might have unexpected consequences.")
        msg.setWindowTitle("Restart failed realizations")
        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        result = msg.exec_()

        if result == QMessageBox.Ok:
            self.restart_button.setVisible(False)
            self.kill_button.setVisible(True)
            self.done_button.setVisible(False)
            self._run_model.restart()
            self.startSimulation()

    @Slot()
    def toggle_detailed_progress(self):
        if self._isDetailedDialog:
            self._setSimpleDialog()
        else:
            self._setDetailedDialog()

        self.adjustSize()
Пример #22
0
class PlotNameWidget(QWidget):
    """A widget to display the plot name, and edit and close buttons

    This widget is added to the table widget to support the renaming
    and close buttons, as well as the direct renaming functionality.
    """

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

        self.presenter = presenter
        self.plot_number = plot_number

        self.mutex = QMutex()

        self.line_edit = QLineEdit(self.presenter.get_plot_name_from_number(plot_number))
        self.line_edit.setReadOnly(True)
        self.line_edit.setFrame(False)
        self.line_edit.setStyleSheet("* { background-color: rgba(0, 0, 0, 0); }")
        self.line_edit.setAttribute(Qt.WA_TransparentForMouseEvents, True)
        self.line_edit.editingFinished.connect(self.rename_plot)

        shown_icon = get_icon('mdi.eye')
        self.hide_button = QPushButton(shown_icon, "")
        self.hide_button.setToolTip('Hide')
        self.hide_button.setFlat(True)
        self.hide_button.setMaximumWidth(self.hide_button.iconSize().width() * 5 / 3)
        self.hide_button.clicked.connect(self.toggle_visibility)

        rename_icon = get_icon('mdi.square-edit-outline')
        self.rename_button = QPushButton(rename_icon, "")
        self.rename_button.setToolTip('Rename')
        self.rename_button.setFlat(True)
        self.rename_button.setMaximumWidth(self.rename_button.iconSize().width() * 5 / 3)
        self.rename_button.setCheckable(True)
        self.rename_button.toggled.connect(self.rename_button_toggled)

        close_icon = get_icon('mdi.close')
        self.close_button = QPushButton(close_icon, "")
        self.close_button.setToolTip('Delete')
        self.close_button.setFlat(True)
        self.close_button.setMaximumWidth(self.close_button.iconSize().width() * 5 / 3)
        self.close_button.clicked.connect(lambda: self.close_pressed(self.plot_number))

        self.layout = QHBoxLayout()

        # Get rid of the top and bottom margins - the button provides
        # some natural margin anyway. Get rid of right margin and
        # reduce spacing to get buttons closer together.
        self.layout.setContentsMargins(5, 0, 0, 0)
        self.layout.setSpacing(0)

        self.layout.addWidget(self.line_edit)
        self.layout.addWidget(self.hide_button)
        self.layout.addWidget(self.rename_button)
        self.layout.addWidget(self.close_button)

        self.layout.sizeHint()
        self.setLayout(self.layout)

    def set_plot_name(self, new_name):
        """
        Sets the internally stored and displayed plot name
        :param new_name: The name to set
        """
        self.line_edit.setText(new_name)

    def close_pressed(self, plot_number):
        """
        Close the plot with the given name
        :param plot_number: The unique number in GlobalFigureManager
        """
        self.presenter.close_single_plot(plot_number)

    def rename_button_toggled(self, checked):
        """
        If the rename button is pressed from being unchecked then
        make the line edit item editable
        :param checked: True if the rename toggle is now pressed
        """
        if checked:
            self.toggle_plot_name_editable(True, toggle_rename_button=False)

    def toggle_plot_name_editable(self, editable, toggle_rename_button=True):
        """
        Set the line edit item to be editable or not editable. If
        editable move the cursor focus to the editable name and
        highlight it all.
        :param editable: If true make the plot name editable, else
                         make it read only
        :param toggle_rename_button: If true also toggle the rename
                                     button state
        """
        self.line_edit.setReadOnly(not editable)
        self.line_edit.setAttribute(Qt.WA_TransparentForMouseEvents, not editable)

        # This is a sneaky way to avoid the issue of two calls to
        # this toggle method, by effectively disabling the button
        # press in edit mode.
        self.rename_button.setAttribute(Qt.WA_TransparentForMouseEvents, editable)

        if toggle_rename_button:
            self.rename_button.setChecked(editable)

        if editable:
            self.line_edit.setFocus()
            self.line_edit.selectAll()
        else:
            self.line_edit.setSelection(0, 0)

    def toggle_visibility(self):
        """
        Calls the presenter to hide the selected plot
        """
        self.presenter.toggle_plot_visibility(self.plot_number)

    def set_visibility_icon(self, is_shown):
        """
        Change the widget icon between shown and hidden
        :param is_shown: True if plot is shown, false if hidden
        """
        if is_shown:
            self.hide_button.setIcon(get_icon('mdi.eye'))
            self.hide_button.setToolTip('Hide')
        else:
            self.hide_button.setIcon(get_icon('mdi.eye', 'lightgrey'))
            self.hide_button.setToolTip('Show')

    def rename_plot(self):
        """
        Called when the editing is finished, gets the presenter to
        do the real renaming of the plot
        """
        self.presenter.rename_figure(self.plot_number, self.line_edit.text())
        self.toggle_plot_name_editable(False)
Пример #23
0
class NotificationWidget(QWidget, VCPWidget):
    def __init__(self, parent=None):
        super(NotificationWidget, self).__init__(parent)
        self.notification_channel = getPlugin("notifications")

        self.main_layout = QVBoxLayout()
        self.button_layout = QHBoxLayout()

        self.all_button = QPushButton()
        self.info_button = QPushButton()
        self.warn_button = QPushButton()
        self.error_button = QPushButton()
        self.debug_button = QPushButton()
        self.clear_button = QPushButton()

        self.all_button.setText("all")
        self.info_button.setText("info")
        self.warn_button.setText("warn")
        self.error_button.setText("error")
        self.debug_button.setText("debug")
        self.clear_button.setText("clear")

        self.all_button.setCheckable(True)
        self.info_button.setCheckable(True)
        self.warn_button.setCheckable(True)
        self.error_button.setCheckable(True)
        self.debug_button.setCheckable(True)

        self.all_button.setChecked(True)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.clear_button.clicked.connect(self.clear_all_notifications)

        self.button_layout.addWidget(self.all_button)
        self.button_layout.addWidget(self.info_button)
        self.button_layout.addWidget(self.warn_button)
        self.button_layout.addWidget(self.error_button)
        self.button_layout.addWidget(self.debug_button)
        self.button_layout.addWidget(self.clear_button)

        self.notification_name = QLabel()
        self.notification_name.setAlignment(Qt.AlignCenter)
        self.notification_name.setText("All Notifications")

        self.all_notification_view = QListView()

        self.all_notification_model = QStandardItemModel(
            self.all_notification_view)
        self.all_notification_model_proxy = QSortFilterProxyModel(
            self.all_notification_view)

        self.all_notification_model_proxy.setSourceModel(
            self.all_notification_model)

        # self.all_notification_view.setModel(self.all_notification_model)
        self.all_notification_view.setModel(self.all_notification_model_proxy)

        self.all_notifications = list()

        self.main_layout.addWidget(self.notification_name)
        self.main_layout.addWidget(self.all_notification_view)
        self.main_layout.addLayout(self.button_layout)

        self.setLayout(self.main_layout)

        self.notification_channel.info_message.notify(self.on_info_message)
        self.notification_channel.warn_message.notify(self.on_warn_message)
        self.notification_channel.error_message.notify(self.on_error_message)
        self.notification_channel.debug_message.notify(self.on_debug_message)

        self.all_button.clicked.connect(self.show_all_notifications)
        self.info_button.clicked.connect(self.show_info_notifications)
        self.warn_button.clicked.connect(self.show_warn_notifications)
        self.error_button.clicked.connect(self.show_error_notifications)
        self.debug_button.clicked.connect(self.show_debug_notifications)

    def on_info_message(self, message):
        timestamp = time()
        dt_object = datetime.fromtimestamp(timestamp)

        current_time = str(dt_object)

        msg = 'INFO:\nTIME {}\n  {}'.format(current_time, message)
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-information'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_warn_message(self, message):
        timestamp = time()
        dt_object = datetime.fromtimestamp(timestamp)

        current_time = str(dt_object)

        msg = 'WARNING:\nTIME {}\n  {}'.format(current_time, message)
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-warning'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_error_message(self, message):
        timestamp = time()
        dt_object = datetime.fromtimestamp(timestamp)

        current_time = str(dt_object)

        msg = 'ERROR:\nTIME {}\n  {}'.format(current_time, message)
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-error'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_debug_message(self, message):
        timestamp = time()
        dt_object = datetime.fromtimestamp(timestamp)

        current_time = str(dt_object)

        msg = 'DEBUG\nTIME {}\n  {}'.format(current_time, message)
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-question'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def show_all_notifications(self):
        self.all_button.setChecked(True)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("All Notifications")
        self.all_notification_model_proxy.setFilterRegExp(None)

    def show_info_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(True)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Information Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("INFO", Qt.CaseSensitive, QRegExp.FixedString))

    def show_warn_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(True)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Warning Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("WANRNING", Qt.CaseSensitive, QRegExp.FixedString))

    def show_error_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(True)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Error Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("ERROR", Qt.CaseInsensitive, QRegExp.FixedString))

    def show_debug_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(True)

        self.notification_name.setText("Debug Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("DEBUG", Qt.CaseSensitive, QRegExp.FixedString))

    def clear_all_notifications(self):
        self.all_notification_model.clear()
Пример #24
0
class AnimateDialog(QDialog):
    def __init__(self, vpoints: Sequence[VPoint], vlinks: Sequence[VLink],
                 path: _Paths, slider_path: _SliderPaths, monochrome: bool,
                 parent: QWidget):
        super(AnimateDialog, self).__init__(parent)
        self.setWindowTitle("Vector Animation")
        self.setWindowFlags(self.windowFlags() | Qt.WindowMaximizeButtonHint
                            & ~Qt.WindowContextHelpButtonHint)
        self.setMinimumSize(800, 600)
        self.setModal(True)
        main_layout = QVBoxLayout(self)
        self.canvas = _DynamicCanvas(vpoints, vlinks, path, slider_path, self)
        self.canvas.set_monochrome_mode(monochrome)
        self.canvas.update_pos.connect(self.__set_pos)
        layout = QHBoxLayout(self)
        pt_option = QComboBox(self)
        pt_option.addItems([f"P{p}" for p in range(len(vpoints))])
        layout.addWidget(pt_option)
        value_label = QLabel(self)

        @Slot(int)
        def show_values(ind: int):
            vel, vel_deg = self.canvas.get_vel(ind)
            acc, acc_deg = self.canvas.get_acc(ind)
            value_label.setText(
                f"Velocity: {vel:.04f} ({vel_deg:.04f}deg) | "
                f"Acceleration: {acc:.04f} ({acc_deg:.04f}deg)")

        pt_option.currentIndexChanged.connect(show_values)
        layout.addWidget(value_label)
        self.pos_label = QLabel(self)
        layout.addItem(
            QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))
        layout.addWidget(self.pos_label)
        main_layout.addLayout(layout)
        main_layout.addWidget(self.canvas)
        layout = QHBoxLayout(self)
        self.play = QPushButton(QIcon(QPixmap(":/icons/play.png")), "", self)
        self.play.setCheckable(True)
        self.play.clicked.connect(self.__play)
        layout.addWidget(self.play)
        self.slider = QSlider(Qt.Horizontal, self)
        self.slider.setMaximum(max(len(p) for p in path) - 1)
        self.slider.valueChanged.connect(self.canvas.set_index)
        layout.addWidget(self.slider)
        layout.addWidget(QLabel("Total times:", self))
        factor = QDoubleSpinBox(self)
        factor.valueChanged.connect(self.canvas.set_factor)
        factor.setSuffix('s')
        factor.setRange(0.01, 999999)
        factor.setValue(10)
        layout.addWidget(factor)
        main_layout.addLayout(layout)
        self.timer = QTimer()
        self.timer.setInterval(10)
        self.timer.timeout.connect(self.__move_ind)

    @Slot()
    def __move_ind(self):
        """Move indicator."""
        value = self.slider.value() + 1
        self.slider.setValue(value)
        if value > self.slider.maximum():
            self.slider.setValue(0)

    @Slot(float, float)
    def __set_pos(self, x: float, y: float) -> None:
        """Set mouse position."""
        self.pos_label.setText(f"({x:.04f}, {y:.04f})")

    @Slot()
    def __play(self):
        """Start playing."""
        if self.play.isChecked():
            self.timer.start()
        else:
            self.timer.stop()
Пример #25
0
class NotificationsWidget(QWidget, VCPWidget):
    notificationsCleared = Signal(object)

    def __init__(self, parent=None):
        super(NotificationsWidget, self).__init__(parent)
        self.notification_channel = getPlugin("notifications")

        self.main_layout = QVBoxLayout()
        self.button_layout = QHBoxLayout()

        self.all_button = QPushButton()
        self.info_button = QPushButton()
        self.warn_button = QPushButton()
        self.error_button = QPushButton()
        self.debug_button = QPushButton()
        self.clear_button = QPushButton()

        self.all_button.setText("all")
        self.info_button.setText("info")
        self.warn_button.setText("warn")
        self.error_button.setText("error")
        self.debug_button.setText("debug")
        self.clear_button.setText("clear")

        self.all_button.setCheckable(True)
        self.info_button.setCheckable(True)
        self.warn_button.setCheckable(True)
        self.error_button.setCheckable(True)
        self.debug_button.setCheckable(True)

        self.all_button.setChecked(True)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.clear_button.clicked.connect(self.clear_all_notifications)

        self.button_layout.addWidget(self.all_button)
        self.button_layout.addWidget(self.info_button)
        self.button_layout.addWidget(self.warn_button)
        self.button_layout.addWidget(self.error_button)
        self.button_layout.addWidget(self.debug_button)
        self.button_layout.addWidget(self.clear_button)

        self.notification_name = QLabel()
        self.notification_name.setAlignment(Qt.AlignCenter)
        self.notification_name.setText("All Notifications")

        self.all_notification_view = QListView()

        self.all_notification_model = QStandardItemModel(
            self.all_notification_view)
        self.all_notification_model_proxy = QSortFilterProxyModel(
            self.all_notification_view)

        self.all_notification_model_proxy.setSourceModel(
            self.all_notification_model)

        # self.all_notification_view.setModel(self.all_notification_model)
        self.all_notification_view.setModel(self.all_notification_model_proxy)

        self.all_notifications = list()

        self.main_layout.addWidget(self.notification_name)
        self.main_layout.addWidget(self.all_notification_view)
        self.main_layout.addLayout(self.button_layout)

        self.setLayout(self.main_layout)

        self.notification_channel.info_message.notify(self.on_info_message)
        self.notification_channel.warn_message.notify(self.on_warn_message)
        self.notification_channel.error_message.notify(self.on_error_message)
        self.notification_channel.debug_message.notify(self.on_debug_message)

        self.all_button.clicked.connect(self.show_all_notifications)
        self.info_button.clicked.connect(self.show_info_notifications)
        self.warn_button.clicked.connect(self.show_warn_notifications)
        self.error_button.clicked.connect(self.show_error_notifications)
        self.debug_button.clicked.connect(self.show_debug_notifications)

    @staticmethod
    def _get_time():
        timestamp = time()
        dt_object = datetime.fromtimestamp(timestamp)
        return dt_object.strftime("%d / %b / %Y  -  %H:%M:%S")

    @staticmethod
    def _strip_new_line(message):
        return message.replace('\n', ' ').replace('\r', '').replace(
            '    ', ' ').replace('   ', ' ').replace('  ', ' ')

    def on_info_message(self, message):
        msg = 'INFO - occurred at: [ {} ]\n{}'.format(
            NotificationsWidget._get_time(),
            NotificationsWidget._strip_new_line(message))
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-information'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_warn_message(self, message):
        msg = 'WARNING - occurred at: [ {} ]\n{}'.format(
            NotificationsWidget._get_time(),
            NotificationsWidget._strip_new_line(message))
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-warning'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_error_message(self, message):
        msg = 'ERROR - occurred at: [ {} ]\n{}'.format(
            NotificationsWidget._get_time(),
            NotificationsWidget._strip_new_line(message))
        LOG.debug('-----on_error_message called: {}'.format(message))
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-error'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def on_debug_message(self, message):
        msg = 'DEBUG - occurred at: [ {} ]\n{}'.format(
            NotificationsWidget._get_time(),
            NotificationsWidget._strip_new_line(message))
        notification_item = QStandardItem()
        notification_item.setText(msg)
        notification_item.setIcon(QIcon.fromTheme('dialog-question'))
        notification_item.setEditable(False)
        self.all_notification_model.appendRow(notification_item)

    def show_all_notifications(self):
        self.all_button.setChecked(True)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("All Notifications")
        self.all_notification_model_proxy.setFilterRegExp(None)

    def show_info_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(True)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Information Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("INFO", Qt.CaseSensitive, QRegExp.FixedString))

    def show_warn_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(True)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Warning Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("WANRNING", Qt.CaseSensitive, QRegExp.FixedString))

    def show_error_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(True)
        self.debug_button.setChecked(False)

        self.notification_name.setText("Error Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("ERROR", Qt.CaseInsensitive, QRegExp.FixedString))

    def show_debug_notifications(self):
        self.all_button.setChecked(False)
        self.info_button.setChecked(False)
        self.warn_button.setChecked(False)
        self.error_button.setChecked(False)
        self.debug_button.setChecked(True)

        self.notification_name.setText("Debug Notifications")
        self.all_notification_model_proxy.setFilterRegExp(
            QRegExp("DEBUG", Qt.CaseSensitive, QRegExp.FixedString))

    def clear_all_notifications(self):
        self.all_notification_model.clear()
        self.notificationsCleared.emit(self)
Пример #26
0
class QtReQueueControls(QWidget):
    def __init__(self, model, parent=None):
        super().__init__(parent)
        self.model = model

        self._lb_queue_state = QLabel("STOPPED")

        self._pb_queue_start = QPushButton("Start")
        self._pb_queue_start.setEnabled(False)
        self._pb_queue_start.clicked.connect(self._pb_queue_start_clicked)

        self._pb_queue_stop = QPushButton("Stop")
        self._pb_queue_stop.setEnabled(False)
        self._pb_queue_stop.setCheckable(True)
        self._pb_queue_stop.clicked.connect(self._pb_queue_stop_clicked)

        self._group_box = QGroupBox("Queue")

        vbox = QVBoxLayout()
        vbox.addWidget(self._lb_queue_state, alignment=Qt.AlignHCenter)
        vbox.addWidget(self._pb_queue_start)
        vbox.addWidget(self._pb_queue_stop)

        self._group_box.setLayout(vbox)

        vbox = QVBoxLayout()
        vbox.addWidget(self._group_box)
        self.setLayout(vbox)

        self.model.events.status_changed.connect(self.on_update_widgets)

    def on_update_widgets(self, event):
        # None should be converted to False:
        is_connected = bool(event.is_connected)
        status = event.status
        worker_exists = status.get("worker_environment_exists", False)
        running_item_uid = status.get("running_item_uid", None)
        queue_stop_pending = status.get("queue_stop_pending", False)

        s = "RUNNING" if running_item_uid else "STOPPED"
        self._lb_queue_state.setText(s)

        self._pb_queue_start.setEnabled(is_connected and worker_exists
                                        and not bool(running_item_uid))
        self._pb_queue_stop.setEnabled(is_connected and worker_exists
                                       and bool(running_item_uid))
        self._pb_queue_stop.setChecked(queue_stop_pending)

    def _pb_queue_start_clicked(self):
        try:
            self.model.queue_start()
        except Exception as ex:
            print(f"Exception: {ex}")

    def _pb_queue_stop_clicked(self):
        try:
            if self._pb_queue_stop.isChecked():
                print("Stopping the queue")
                self.model.queue_stop()
            else:
                print("Cancelling stop")
                self.model.queue_stop_cancel()
        except Exception as ex:
            print(f"Exception: {ex}")
Пример #27
0
class QtPluginDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.installer = Installer()
        self.setup_ui()
        self.installer.set_output_widget(self.stdout_text)
        self.installer.process.started.connect(self._on_installer_start)
        self.installer.process.finished.connect(self._on_installer_done)
        self.refresh()

    def _on_installer_start(self):
        self.show_status_btn.setChecked(True)
        self.working_indicator.show()
        self.process_error_indicator.hide()

    def _on_installer_done(self, exit_code, exit_status):
        self.working_indicator.hide()
        if exit_code:
            self.process_error_indicator.show()
        else:
            self.show_status_btn.setChecked(False)
        self.refresh()
        self.plugin_sorter.refresh()

    def refresh(self):
        self.installed_list.clear()
        self.available_list.clear()

        # fetch installed
        from ...plugins import plugin_manager

        plugin_manager.discover()  # since they might not be loaded yet

        already_installed = set()

        for plugin_name, mod_name, distname in plugin_manager.iter_available():
            # not showing these in the plugin dialog
            if plugin_name in ('napari_plugin_engine', ):
                continue
            if distname:
                already_installed.add(distname)
                meta = standard_metadata(distname)
            else:
                meta = {}
            self.installed_list.addItem(
                ProjectInfo(
                    normalized_name(distname or ''),
                    meta.get('version', ''),
                    meta.get('url', ''),
                    meta.get('summary', ''),
                    meta.get('author', ''),
                    meta.get('license', ''),
                ),
                plugin_name=plugin_name,
                enabled=plugin_name in plugin_manager.plugins,
            )
        # self.v_splitter.setSizes([70 * self.installed_list.count(), 10, 10])

        # fetch available plugins
        self.worker = create_worker(iter_napari_plugin_info)

        def _handle_yield(project_info):
            if project_info.name in already_installed:
                self.installed_list.tag_outdated(project_info)
            else:
                self.available_list.addItem(project_info)

        self.worker.yielded.connect(_handle_yield)
        self.worker.finished.connect(self.working_indicator.hide)
        self.worker.start()

    def setup_ui(self):
        self.resize(1080, 640)
        vlay_1 = QVBoxLayout(self)
        self.h_splitter = QSplitter(self)
        vlay_1.addWidget(self.h_splitter)
        self.h_splitter.setOrientation(Qt.Horizontal)
        self.v_splitter = QSplitter(self.h_splitter)
        self.v_splitter.setOrientation(Qt.Vertical)
        self.v_splitter.setMinimumWidth(500)
        self.plugin_sorter = QtPluginSorter(parent=self.h_splitter)
        self.plugin_sorter.layout().setContentsMargins(2, 0, 0, 0)
        self.plugin_sorter.hide()

        installed = QWidget(self.v_splitter)
        lay = QVBoxLayout(installed)
        lay.setContentsMargins(0, 2, 0, 2)
        lay.addWidget(QLabel("Installed Plugins"))
        self.installed_list = QPluginList(installed, self.installer)
        lay.addWidget(self.installed_list)

        uninstalled = QWidget(self.v_splitter)
        lay = QVBoxLayout(uninstalled)
        lay.setContentsMargins(0, 2, 0, 2)
        lay.addWidget(QLabel("Available Plugin Packages"))
        self.available_list = QPluginList(uninstalled, self.installer)
        lay.addWidget(self.available_list)

        self.stdout_text = QTextEdit(self.v_splitter)
        self.stdout_text.setReadOnly(True)
        self.stdout_text.setObjectName("pip_install_status")
        self.stdout_text.hide()

        buttonBox = QHBoxLayout()
        self.working_indicator = QLabel("loading ...", self)
        self.process_error_indicator = QLabel(self)
        self.process_error_indicator.setObjectName("error_label")
        self.process_error_indicator.hide()
        load_gif = str(Path(napari.resources.__file__).parent / "loading.gif")
        mov = QMovie(load_gif)
        mov.setScaledSize(QSize(18, 18))
        self.working_indicator.setMovie(mov)
        mov.start()
        self.show_status_btn = QPushButton("Show Status", self)
        self.show_status_btn.setFixedWidth(100)
        self.show_sorter_btn = QPushButton("<< Show Sorter", self)
        self.close_btn = QPushButton("Close", self)
        self.close_btn.clicked.connect(self.reject)
        buttonBox.addWidget(self.show_status_btn)
        buttonBox.addWidget(self.working_indicator)
        buttonBox.addWidget(self.process_error_indicator)
        buttonBox.addStretch()
        buttonBox.addWidget(self.show_sorter_btn)
        buttonBox.addWidget(self.close_btn)
        buttonBox.setContentsMargins(0, 0, 4, 0)
        vlay_1.addLayout(buttonBox)

        self.show_status_btn.setCheckable(True)
        self.show_status_btn.setChecked(False)
        self.show_status_btn.toggled.connect(self._toggle_status)

        self.show_sorter_btn.setCheckable(True)
        self.show_sorter_btn.setChecked(False)
        self.show_sorter_btn.toggled.connect(self._toggle_sorter)

        self.v_splitter.setStretchFactor(1, 2)
        self.h_splitter.setStretchFactor(0, 2)

    def _toggle_sorter(self, show):
        if show:
            self.show_sorter_btn.setText(">> Hide Sorter")
            self.plugin_sorter.show()
        else:
            self.show_sorter_btn.setText("<< Show Sorter")
            self.plugin_sorter.hide()

    def _toggle_status(self, show):
        if show:
            self.show_status_btn.setText("Hide Status")
            self.stdout_text.show()
        else:
            self.show_status_btn.setText("Show Status")
            self.stdout_text.hide()
Пример #28
0
class PlotPreferences(QWidget):
    def __init__(self, mainWindow):
        super().__init__()
        self.mainWindow = mainWindow

        plotStyleGroup = GroupWidget("Plot style")
        styles = self.mainWindow.plot.getValidStyles()
        self.customStyle = StyleDesigner(
            styleKeys=self.mainWindow.plot.getStyleKeys(),
            symbolKeys=self.mainWindow.plot.getStyleSymbolKeys(),
            invalidNames=styles)
        self.customStyle.setEnabled(False)
        self.customStyle.saveStyle.connect(self._saveStyle)

        self.plotStyleList = QComboBox()
        styles = [s.capitalize() for s in styles]
        styles += ["Add custom theme..."]
        self.plotStyleList.addItems(styles)
        self.plotStyleList.currentTextChanged.connect(
            self._updateCustomStyleWidget)

        foregroundColour = self.palette().windowText().color()
        icon = makeForegroundIcon("edit", foregroundColour)
        self.editPlotStyleButton = QPushButton(icon, "")
        self.editPlotStyleButton.setCheckable(True)
        self.editPlotStyleButton.setToolTip("Edit theme")
        self.editPlotStyleButton.toggled.connect(self._editStyle)

        icon = makeForegroundIcon("trash", foregroundColour)
        self.deletePlotStyleButton = QPushButton(icon, "")
        self.deletePlotStyleButton.setToolTip("Delete theme")
        self.deletePlotStyleButton.clicked.connect(self._deleteTheme)

        self.plotStyleList.setSizePolicy(QSizePolicy.Expanding,
                                         QSizePolicy.Preferred)
        self.editPlotStyleButton.setSizePolicy(QSizePolicy.Minimum,
                                               QSizePolicy.Minimum)
        self.deletePlotStyleButton.setSizePolicy(QSizePolicy.Minimum,
                                                 QSizePolicy.Minimum)

        plotStyleBox = QHBoxLayout()
        plotStyleBox.addWidget(self.plotStyleList)
        plotStyleBox.addWidget(self.editPlotStyleButton)
        plotStyleBox.addWidget(self.deletePlotStyleButton)

        plotStyleGroup.addLayout(plotStyleBox)
        plotStyleGroup.addWidget(self.customStyle)

        plotConfigGroup = GroupWidget("Default plot range", layout="vbox")

        self.plotRangeCombo = QComboBox()
        ranges = [
            "1 month", "3 months", "6 months", "1 year", "Current year", "All"
        ]
        self.plotRangeCombo.addItems(ranges)

        self.customRangeCheckBox = QCheckBox("Custom range")
        self.customRangeSpinBox = QSpinBox()
        self.customRangeSpinBox.setSuffix(" months")
        maxMonths = len(mainWindow.data.splitMonths())
        self.customRangeSpinBox.setRange(1, maxMonths)
        self.customRangeCheckBox.clicked.connect(self.setCustomRange)

        plotRangeLayout = QHBoxLayout()
        plotRangeLayout.addWidget(self.plotRangeCombo)

        customRangeLayout = QHBoxLayout()
        customRangeLayout.addWidget(self.customRangeCheckBox)
        customRangeLayout.addWidget(self.customRangeSpinBox)

        plotConfigGroup.addLayout(plotRangeLayout)
        plotConfigGroup.addLayout(customRangeLayout)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(plotStyleGroup)
        mainLayout.addWidget(plotConfigGroup)
        mainLayout.addStretch(1)

        self.setLayout(mainLayout)

        self.setCurrentValues()
        # apply initial state
        self.apply()

    def setCurrentValues(self):
        self.settings = Settings()
        self.settings.beginGroup("plot")

        plotStyle = self.settings.value("style", "dark")
        self.plotStyleList.setCurrentText(plotStyle.capitalize())
        # does setCurrentText not emit currentTextChanged signal?
        self._enableDisableDeleteButton(plotStyle)

        self.customStyle.setName(plotStyle)
        self.customStyle.setStyle(self.mainWindow.plot.getStyle(plotStyle))

        customRange = self.settings.value("customRange", False)
        rng = self.settings.value("range", "All")

        self.setCustomRange(customRange)
        if customRange:
            rng = int(rng)
            self.customRangeSpinBox.setValue(rng)
        else:
            items = [
                self.plotRangeCombo.itemText(idx)
                for idx in range(self.plotRangeCombo.count())
            ]
            idx = items.index(rng)
            self.plotRangeCombo.setCurrentIndex(idx)

        self.settings.endGroup()

    def _saveStyle(self, name, style, setStyle=False):
        self.mainWindow.plot.addCustomStyle(name, style, setStyle=setStyle)
        idx = self.plotStyleList.count() - 1
        self.plotStyleList.insertItem(idx, name.capitalize())
        self.plotStyleList.setCurrentIndex(idx)

    def _editStyle(self, edit):
        self.customStyle.setEditMode(edit)
        self._updateCustomStyleWidget()

    def apply(self):

        styleName = self.plotStyleList.currentText().lower()
        if styleName == "add custom theme...":
            styleName, styleDct = self.customStyle.getStyle()
            self._saveStyle(styleName, styleDct, setStyle=True)
        else:
            self.mainWindow.plot.setStyle(styleName)

        customRange = self.customRangeCheckBox.isChecked()
        if customRange:
            months = self.customRangeSpinBox.value()
        else:
            text = self.plotRangeCombo.currentText()
            if text == "1 year":
                text = "12 months"
            elif text == "Current year":
                text = f"{date.today().month} months"
            months = None if text == 'All' else int(text.strip(' months'))
        self.mainWindow.plot.setXAxisRange(months)

        self.settings.beginGroup("plot")
        self.settings.setValue("style", styleName)

        self.settings.setValue("customRange", customRange)
        if customRange:
            self.settings.setValue("range", self.customRangeSpinBox.value())
        else:
            self.settings.setValue("range", self.plotRangeCombo.currentText())
        self.settings.endGroup()

    @Slot(bool)
    def setCustomRange(self, custom):
        self.customRangeCheckBox.setChecked(custom)
        if custom:
            self.customRangeSpinBox.setEnabled(True)
            self.plotRangeCombo.setEnabled(False)
        else:
            self.customRangeSpinBox.setEnabled(False)
            self.plotRangeCombo.setEnabled(True)

    def _updateCustomStyleWidget(self, name=None):
        if name is None or name == "Add custom theme...":
            self.customStyle.setEnabled(True)
            if name is None:
                name = self.customStyle.name
            else:
                name = f"custom-{self.customStyle.name}"
            self.customStyle.setName(name)
        else:
            name = name.lower()
            style = self.mainWindow.plot.getStyle(name)
            self.customStyle.setStyle(style, name=name)
            self.customStyle.setEnabled(False)
            self._enableDisableDeleteButton(name)

    def _enableDisableDeleteButton(self, plotStyle):
        if plotStyle in self.mainWindow.plot.getDefaultStyles():
            self.deletePlotStyleButton.setEnabled(False)
            self.deletePlotStyleButton.setToolTip(
                "Cannot delete default theme")
        else:
            self.deletePlotStyleButton.setEnabled(True)
            self.deletePlotStyleButton.setToolTip("Delete theme")

    def _deleteTheme(self):
        styleName = self.plotStyleList.currentText()
        items = [
            self.plotStyleList.itemText(idx)
            for idx in range(self.plotStyleList.count())
        ]
        idx = items.index(styleName)
        self.plotStyleList.removeItem(idx)
        self.mainWindow.plot.removeCustomStyle(styleName.lower())
Пример #29
0
class TogglePanel(QWidget):
    """
    Generic Panel Widget

    Displays a widget below QPushButton that hides and shows the contents. It
    is up to subclasses to re-point the attribute :attr:`.contents` to the
    widget whose visibility you would like to toggle.

    By default, it is assumed that the Panel is initialized with the
    :attr:`.contents` widget as visible, however the contents will be hidden
    and the button synced to the proper position if :meth:`.show_contents` is
    called after instance creation

    Parameters
    ----------
    title : str
        Title of Panel. This will be the text on the QPushButton

    parent : QWidget

    Attributes
    ----------
    contents : QWidget
        Widget whose visibility is controlled via the QPushButton
    """
    def __init__(self, title, parent=None):
        super().__init__(parent=parent)
        # Create Widget Infrastructure
        self.title = title
        self.setLayout(QVBoxLayout())
        self.layout().setContentsMargins(2, 2, 2, 2)
        self.layout().setSpacing(5)
        # Create button control
        # Assuming widget is visible, set the button as checked
        self.contents = None
        self.hide_button = QPushButton(self.title)
        self.hide_button.setCheckable(True)
        self.hide_button.setChecked(True)
        self.layout().addWidget(self.hide_button)
        self.hide_button.clicked.connect(self.show_contents)

    @Slot(bool)
    def show_contents(self, show):
        """
        Show the contents of the Widget

        Hides the :attr:`.contents` QWidget and sets the :attr:`.hide_button`
        to the proper status to indicate whether the widget is hidden or not

        Parameters
        ----------
        show : bool
        """
        # Configure our button in case this slot was called elsewhere
        self.hide_button.setChecked(show)
        # Show or hide the widget if the contents exist
        if self.contents:
            if show:
                self.show()
                self.contents.show()
            else:
                self.contents.hide()
Пример #30
0
class Dimension(QWidget):
    stateChanged = Signal(int)
    valueChanged = Signal()
    """
    pass in dimension

    state: one of (State.X, State.Y, State.NONE, State.DISABLE)

    Can be run independently by:

    from mantidqt.widgets.sliceviewer.dimensionwidget import Dimension
    from qtpy.QtWidgets import QApplication
    app = QApplication([])
    window = Dimension({'minimum':-1.1, 'number_of_bins':11, 'width':0.2, 'name':'Dim0', 'units':'A'})
    window.show()
    app.exec_()
    """
    def __init__(self, dim_info, number=0, state=State.NONE, parent=None):
        super().__init__(parent)

        self.minimum = dim_info['minimum']
        self.nbins = dim_info['number_of_bins']
        self.width = dim_info['width']
        self.number = number

        self.layout = QHBoxLayout(self)

        self.name = QLabel(dim_info['name'])
        self.units = QLabel(dim_info['units'])

        self.x = QPushButton('X')
        self.x.setFixedSize(32, 32)
        self.x.setCheckable(True)
        self.x.clicked.connect(self.x_clicked)

        self.y = QPushButton('Y')
        self.y.setFixedSize(32, 32)
        self.y.setCheckable(True)
        self.y.clicked.connect(self.y_clicked)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, self.nbins - 1)
        self.slider.valueChanged.connect(self.slider_changed)

        self.spinbox = QDoubleSpinBox()
        self.spinbox.setDecimals(3)
        self.spinbox.setRange(self.get_bin_center(0),
                              self.get_bin_center(self.nbins - 1))
        self.spinbox.setSingleStep(self.width)
        self.spinbox.editingFinished.connect(self.spinbox_changed)

        self.layout.addWidget(self.name)
        self.layout.addWidget(self.x)
        self.layout.addWidget(self.y)
        self.layout.addWidget(self.slider, stretch=1)
        self.layout.addStretch(0)
        self.layout.addWidget(self.spinbox)
        self.layout.addWidget(self.units)

        self.set_value(0)

        if self.nbins < 2:
            state = State.DISABLE

        self.set_state(state)

    def set_state(self, state):
        self.state = state
        if self.state == State.X:
            self.x.setChecked(True)
            self.y.setChecked(False)
            self.slider.hide()
            self.spinbox.hide()
            self.units.hide()
        elif self.state == State.Y:
            self.x.setChecked(False)
            self.y.setChecked(True)
            self.slider.hide()
            self.spinbox.hide()
            self.units.hide()
        elif self.state == State.NONE:
            self.x.setChecked(False)
            self.y.setChecked(False)
            self.slider.show()
            self.spinbox.show()
            self.units.show()
        else:
            self.x.setChecked(False)
            self.x.setDisabled(True)
            self.y.setChecked(False)
            self.y.setDisabled(True)
            self.slider.hide()
            self.spinbox.show()
            self.spinbox.setDisabled(True)
            self.units.show()

    def get_state(self):
        return self.state

    def x_clicked(self):
        old_state = self.state
        self.set_state(State.X)
        if self.state != old_state:
            self.stateChanged.emit(self.number)

    def y_clicked(self):
        old_state = self.state
        self.set_state(State.Y)
        if self.state != old_state:
            self.stateChanged.emit(self.number)

    def spinbox_changed(self):
        self.value = self.spinbox.value()
        self.update_slider()

    def slider_changed(self):
        self.value = self.get_bin_center(self.slider.value())
        self.update_spinbox()
        self.valueChanged.emit()

    def get_bin_center(self, n):
        return (n + 0.5) * self.width + self.minimum

    def update_slider(self):
        i = (self.value - self.minimum) / self.width
        self.slider.setValue(int(min(max(i, 0), self.nbins - 1)))

    def update_spinbox(self):
        self.spinbox.setValue(self.value)

    def set_value(self, value):
        self.value = value
        self.update_slider()
        self.update_spinbox()

    def get_value(self):
        return self.value
Пример #31
0
class RunDialog(QDialog):
    simulation_done = Signal(bool, str)
    simulation_termination_request = Signal()

    def __init__(self,
                 config_file,
                 run_model,
                 simulation_arguments,
                 parent=None):
        QDialog.__init__(self, parent)
        self.setWindowFlags(Qt.Window)
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)
        self.setModal(True)
        self.setWindowModality(Qt.WindowModal)
        self.setWindowTitle("Simulations - {}".format(config_file))

        self._snapshot_model = SnapshotModel(self)
        self._run_model = run_model

        self._isDetailedDialog = False
        self._minimum_width = 1200

        ert = None
        if isinstance(run_model, BaseRunModel):
            ert = run_model.ert()

        self._simulations_argments = simulation_arguments

        self._ticker = QTimer(self)
        self._ticker.timeout.connect(self._on_ticker)

        progress_proxy_model = ProgressProxyModel(self._snapshot_model,
                                                  parent=self)

        self._total_progress_label = QLabel(_TOTAL_PROGRESS_TEMPLATE.format(0),
                                            self)

        self._total_progress_bar = QProgressBar(self)
        self._total_progress_bar.setRange(0, 100)
        self._total_progress_bar.setTextVisible(False)

        self._iteration_progress_label = QLabel(self)

        self._progress_view = ProgressView(self)
        self._progress_view.setModel(progress_proxy_model)
        self._progress_view.setIndeterminate(True)

        legend_view = LegendView(self)
        legend_view.setModel(progress_proxy_model)

        self._tab_widget = QTabWidget(self)
        self._snapshot_model.rowsInserted.connect(self.on_new_iteration)

        self._job_label = QLabel(self)

        self._job_model = JobListProxyModel(self, 0, 0, 0, 0)
        self._job_model.setSourceModel(self._snapshot_model)

        self._job_view = QTableView(self)
        self._job_view.clicked.connect(self._job_clicked)
        self._open_files = {}
        self._job_view.setModel(self._job_model)

        self.running_time = QLabel("")

        self.plot_tool = PlotTool(config_file)
        self.plot_tool.setParent(self)
        self.plot_button = QPushButton(self.plot_tool.getName())
        self.plot_button.clicked.connect(self.plot_tool.trigger)
        self.plot_button.setEnabled(ert is not None)

        self.kill_button = QPushButton("Kill Simulations")
        self.done_button = QPushButton("Done")
        self.done_button.setHidden(True)
        self.restart_button = QPushButton("Restart")
        self.restart_button.setHidden(True)
        self.show_details_button = QPushButton("Show Details")
        self.show_details_button.setCheckable(True)

        size = 20
        spin_movie = resourceMovie("ide/loading.gif")
        spin_movie.setSpeed(60)
        spin_movie.setScaledSize(QSize(size, size))
        spin_movie.start()

        self.processing_animation = QLabel()
        self.processing_animation.setMaximumSize(QSize(size, size))
        self.processing_animation.setMinimumSize(QSize(size, size))
        self.processing_animation.setMovie(spin_movie)

        button_layout = QHBoxLayout()
        button_layout.addWidget(self.processing_animation)
        button_layout.addWidget(self.running_time)
        button_layout.addStretch()
        button_layout.addWidget(self.show_details_button)
        button_layout.addWidget(self.plot_button)
        button_layout.addWidget(self.kill_button)
        button_layout.addWidget(self.done_button)
        button_layout.addWidget(self.restart_button)

        button_widget_container = QWidget()
        button_widget_container.setLayout(button_layout)

        layout = QVBoxLayout()
        layout.addWidget(self._total_progress_label)
        layout.addWidget(self._total_progress_bar)
        layout.addWidget(self._iteration_progress_label)
        layout.addWidget(self._progress_view)
        layout.addWidget(legend_view)
        layout.addWidget(self._tab_widget)
        layout.addWidget(self._job_label)
        layout.addWidget(self._job_view)
        layout.addWidget(button_widget_container)

        self.setLayout(layout)

        self.kill_button.clicked.connect(self.killJobs)
        self.done_button.clicked.connect(self.accept)
        self.restart_button.clicked.connect(self.restart_failed_realizations)
        self.show_details_button.clicked.connect(self.toggle_detailed_progress)
        self.simulation_done.connect(self._on_simulation_done)

        self.setMinimumWidth(self._minimum_width)
        self._setSimpleDialog()

    def _setSimpleDialog(self) -> None:
        self._isDetailedDialog = False
        self._tab_widget.setVisible(False)
        self._job_label.setVisible(False)
        self._job_view.setVisible(False)
        self.show_details_button.setText("Show Details")

    def _setDetailedDialog(self) -> None:
        self._isDetailedDialog = True
        self._tab_widget.setVisible(True)
        self._job_label.setVisible(True)
        self._job_view.setVisible(True)
        self.show_details_button.setText("Hide Details")

    @Slot(QModelIndex, int, int)
    def on_new_iteration(self, parent: QModelIndex, start: int,
                         end: int) -> None:
        if not parent.isValid():
            iter = start
            self._iteration_progress_label.setText(
                f"Progress for iteration {iter}")

            widget = RealizationWidget(iter)
            widget.setSnapshotModel(self._snapshot_model)
            widget.currentChanged.connect(self._select_real)

            self._tab_widget.addTab(widget,
                                    f"Realizations for iteration {iter}")

    @Slot(QModelIndex)
    def _job_clicked(self, index):
        if not index.isValid():
            return
        selected_file = index.data(FileRole)

        if selected_file and selected_file not in self._open_files:
            job_name = index.siblingAtColumn(0).data()
            viewer = FileDialog(
                selected_file,
                job_name,
                index.row(),
                index.model().get_real(),
                index.model().get_iter(),
                self,
            )
            self._open_files[selected_file] = viewer
            viewer.finished.connect(
                lambda _, f=selected_file: self._open_files.pop(f))

        elif selected_file in self._open_files:
            self._open_files[selected_file].raise_()

    @Slot(QModelIndex)
    def _select_real(self, index):
        step = 0
        stage = 0
        real = index.row()
        iter_ = index.model().get_iter()
        self._job_model.set_step(iter_, real, stage, step)
        self._job_label.setText(
            f"Realization id {index.data(RealIens)} in iteration {iter_}")

        self._job_view.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)

        # Clear the selection in the other tabs
        for i in range(0, self._tab_widget.count()):
            if i != self._tab_widget.currentIndex():
                self._tab_widget.widget(i).clearSelection()

    def reject(self):
        return

    def closeEvent(self, QCloseEvent):
        if self._run_model.isFinished():
            self.simulation_done.emit(self._run_model.hasRunFailed(),
                                      self._run_model.getFailMessage())
        else:
            # Kill jobs if dialog is closed
            if self.killJobs() != QMessageBox.Yes:
                QCloseEvent.ignore()

    def startSimulation(self):
        self._run_model.reset()
        self._snapshot_model.reset()
        self._tab_widget.clear()

        def run():
            asyncio.set_event_loop(asyncio.new_event_loop())
            self._run_model.startSimulations(self._simulations_argments)

        simulation_thread = Thread(name="ert_gui_simulation_thread")
        simulation_thread.setDaemon(True)
        simulation_thread.run = run
        simulation_thread.start()

        self._ticker.start(1000)

        tracker = create_tracker(
            self._run_model,
            num_realizations=self._simulations_argments["active_realizations"].
            count(),
            ee_config=self._simulations_argments.get("ee_config", None),
        )

        worker = TrackerWorker(tracker)
        worker_thread = QThread()
        worker.done.connect(worker_thread.quit)
        worker.consumed_event.connect(self._on_tracker_event)
        worker.moveToThread(worker_thread)
        self.simulation_done.connect(worker.stop)
        self._worker = worker
        self._worker_thread = worker_thread
        worker_thread.started.connect(worker.consume_and_emit)
        self._worker_thread.start()

    def killJobs(self):

        msg = "Are you sure you want to kill the currently running simulations?"
        if self._run_model.getQueueStatus().get(
                JobStatusType.JOB_QUEUE_UNKNOWN, 0) > 0:
            msg += "\n\nKilling a simulation with unknown status will not kill the realizations already submitted!"
        kill_job = QMessageBox.question(self, "Kill simulations?", msg,
                                        QMessageBox.Yes | QMessageBox.No)

        if kill_job == QMessageBox.Yes:
            # Normally this slot would be invoked by the signal/slot system,
            # but the worker is busy tracking the evaluation.
            self._worker.request_termination()
            self.reject()
        return kill_job

    @Slot(bool, str)
    def _on_simulation_done(self, failed, failed_msg):
        self.processing_animation.hide()
        self.kill_button.setHidden(True)
        self.done_button.setHidden(False)
        self.restart_button.setVisible(self.has_failed_realizations())
        self.restart_button.setEnabled(self._run_model.support_restart)
        self._total_progress_bar.setValue(100)
        self._total_progress_label.setText(
            _TOTAL_PROGRESS_TEMPLATE.format(100))

        if failed:
            QMessageBox.critical(
                self,
                "Simulations failed!",
                f"The simulation failed with the following error:\n\n{failed_msg}",
            )

    @Slot()
    def _on_ticker(self):
        runtime = self._run_model.get_runtime()
        self.running_time.setText(format_running_time(runtime))

    @Slot(object)
    def _on_tracker_event(self, event):
        if isinstance(event, EndEvent):
            self.simulation_done.emit(event.failed, event.failed_msg)
            self._worker.stop()
            self._ticker.stop()

        elif isinstance(event, FullSnapshotEvent):
            if event.snapshot is not None:
                self._snapshot_model._add_snapshot(event.snapshot,
                                                   event.iteration)
            self._progress_view.setIndeterminate(event.indeterminate)
            progress = int(event.progress * 100)
            self._total_progress_bar.setValue(progress)
            self._total_progress_label.setText(
                _TOTAL_PROGRESS_TEMPLATE.format(progress))

        elif isinstance(event, SnapshotUpdateEvent):
            if event.partial_snapshot is not None:
                self._snapshot_model._add_partial_snapshot(
                    event.partial_snapshot, event.iteration)
            self._progress_view.setIndeterminate(event.indeterminate)
            progress = int(event.progress * 100)
            self._total_progress_bar.setValue(progress)
            self._total_progress_label.setText(
                _TOTAL_PROGRESS_TEMPLATE.format(progress))

    def has_failed_realizations(self):
        completed = self._run_model.completed_realizations_mask
        initial = self._run_model.initial_realizations_mask
        for (index, successful) in enumerate(completed):
            if initial[index] and not successful:
                return True
        return False

    def count_successful_realizations(self):
        """
        Counts the realizations completed in the prevoius ensemble run
        :return:
        """
        completed = self._run_model.completed_realizations_mask
        return completed.count(True)

    def create_mask_from_failed_realizations(self):
        """
        Creates a BoolVector mask representing the failed realizations
        :return: Type BoolVector
        """
        completed = self._run_model.completed_realizations_mask
        initial = self._run_model.initial_realizations_mask
        inverted_mask = BoolVector(default_value=False)
        for (index, successful) in enumerate(completed):
            inverted_mask[index] = initial[index] and not successful
        return inverted_mask

    def restart_failed_realizations(self):

        msg = QMessageBox(self)
        msg.setIcon(QMessageBox.Information)
        msg.setText(
            "Note that workflows will only be executed on the restarted realizations and that this might have unexpected consequences."
        )
        msg.setWindowTitle("Restart Failed Realizations")
        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        result = msg.exec_()

        if result == QMessageBox.Ok:
            self.restart_button.setVisible(False)
            self.kill_button.setVisible(True)
            self.done_button.setVisible(False)
            active_realizations = self.create_mask_from_failed_realizations()
            self._simulations_argments[
                "active_realizations"] = active_realizations
            self._simulations_argments[
                "prev_successful_realizations"] = self._simulations_argments.get(
                    "prev_successful_realizations", 0)
            self._simulations_argments[
                "prev_successful_realizations"] += self.count_successful_realizations(
                )
            self.startSimulation()

    @Slot()
    def toggle_detailed_progress(self):
        if self._isDetailedDialog:
            self._setSimpleDialog()
        else:
            self._setDetailedDialog()

        self.adjustSize()