示例#1
0
    def __new__(cls, *args, captionTitle=None, **kwargs):
        self = super().__new__(cls, None, cls.get_flags())
        QDialog.__init__(self, None, self.get_flags())
        OWComponent.__init__(self)
        WidgetMessagesMixin.__init__(self)
        WidgetSignalsMixin.__init__(self)

        stored_settings = kwargs.get('stored_settings', None)
        if self.settingsHandler:
            self.settingsHandler.initialize(self, stored_settings)

        self.signalManager = kwargs.get('signal_manager', None)
        self.__env = _asmappingproxy(kwargs.get("env", {}))

        self.graphButton = None
        self.report_button = None

        OWWidget.widget_id += 1
        self.widget_id = OWWidget.widget_id

        captionTitle = self.name if captionTitle is None else captionTitle

        # must be set without invoking setCaption
        self.captionTitle = captionTitle
        self.setWindowTitle(captionTitle)

        self.setFocusPolicy(Qt.StrongFocus)

        self.__blocking = False

        # flag indicating if the widget's position was already restored
        self.__was_restored = False

        self.__statusMessage = ""

        self.__msgwidget = None
        self.__msgchoice = 0

        self.left_side = None
        self.controlArea = self.mainArea = self.buttonsArea = None
        self.splitter = None
        if self.want_basic_layout:
            self.set_basic_layout()

        sc = QShortcut(QKeySequence(Qt.ShiftModifier | Qt.Key_F1), self)
        sc.activated.connect(self.__quicktip)

        sc = QShortcut(QKeySequence.Copy, self)
        sc.activated.connect(self.copy_to_clipboard)
        if self.controlArea is not None:
            # Otherwise, the first control has focus
            self.controlArea.setFocus(Qt.ActiveWindowFocusReason)
        return self
示例#2
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setRenderHint(QPainter.Antialiasing)
        self.setRenderHint(QPainter.TextAntialiasing)

        self.__layoutMode = ThumbnailView.AutoReflow
        self.__columnCount = -1

        self.__grid = GraphicsThumbnailGrid()
        self.__grid.currentThumbnailChanged.connect(
            self.__onCurrentThumbnailChanged)
        self.__previewWidget = None
        scene = GraphicsScene(self)
        scene.addItem(self.__grid)
        scene.selectionRectPointChanged.connect(self.__ensureVisible,
                                                Qt.QueuedConnection)
        self.setScene(scene)

        sh = QShortcut(Qt.Key_Space,
                       self,
                       context=Qt.WidgetWithChildrenShortcut)
        sh.activated.connect(self.__previewToogle)

        self.__grid.geometryChanged.connect(self.__updateSceneRect)
示例#3
0
    def create_widget_instance(self, node):
        """
        Create a OWWidget instance for the node.
        """
        desc = node.description
        klass = widget = None
        initialized = False
        error = None
        # First try to actually retrieve the class.
        try:
            klass = name_lookup(desc.qualified_name)
        except (ImportError, AttributeError):
            sys.excepthook(*sys.exc_info())
            error = "Could not import {0!r}\n\n{1}".format(
                node.description.qualified_name, traceback.format_exc())
        except Exception:
            sys.excepthook(*sys.exc_info())
            error = "An unexpected error during import of {0!r}\n\n{1}".format(
                node.description.qualified_name, traceback.format_exc())

        if klass is None:
            widget = mock_error_owwidget(node, error)
            initialized = True

        if widget is None:
            log.info("WidgetManager: Creating '%s.%s' instance '%s'.",
                     klass.__module__, klass.__name__, node.title)

            widget = klass.__new__(
                klass,
                None,
                captionTitle=node.title,
                signal_manager=self.signal_manager(),
                stored_settings=node.properties,
                # NOTE: env is a view of the real env and reflects
                # changes to the environment.
                env=self.scheme().runtime_env())
            initialized = False

        # Init the node/widget mapping and state before calling __init__
        # Some OWWidgets might already send data in the constructor
        # (should this be forbidden? Raise a warning?) triggering the signal
        # manager which would request the widget => node mapping or state
        # Furthermore they can (though they REALLY REALLY REALLY should not)
        # explicitly call qApp.processEvents.
        assert node not in self.__widget_for_node
        self.__widget_for_node[node] = widget
        self.__node_for_widget[widget] = node
        self.__widget_processing_state[widget] = WidgetManager.Initializing
        self.__initstate_for_node[node] = \
            WidgetManager.PartiallyInitialized(node, widget)

        if not initialized:
            try:
                widget.__init__()
            except Exception:
                sys.excepthook(*sys.exc_info())
                msg = traceback.format_exc()
                msg = "Could not create {0!r}\n\n{1}".format(
                    node.description.name, msg)
                # remove state tracking for widget ...
                del self.__widget_for_node[node]
                del self.__node_for_widget[widget]
                del self.__widget_processing_state[widget]

                # ... and substitute it with a mock error widget.
                widget = mock_error_owwidget(node, msg)
                self.__widget_for_node[node] = widget
                self.__node_for_widget[widget] = node
                self.__widget_processing_state[widget] = 0
                self.__initstate_for_node[node] = \
                    WidgetManager.Materialized(node, widget)

        self.__initstate_for_node[node] = \
            WidgetManager.Materialized(node, widget)
        # Clear Initializing flag
        self.__widget_processing_state[widget] &= ~WidgetManager.Initializing

        node.title_changed.connect(widget.setCaption)

        # Widget's info/warning/error messages.
        widget.messageActivated.connect(self.__on_widget_state_changed)
        widget.messageDeactivated.connect(self.__on_widget_state_changed)

        # Widget's statusTip
        node.set_status_message(widget.statusMessage())
        widget.statusMessageChanged.connect(node.set_status_message)

        # Widget's progress bar value state.
        widget.progressBarValueChanged.connect(node.set_progress)

        # Widget processing state (progressBarInit/Finished)
        # and the blocking state.
        widget.processingStateChanged.connect(
            self.__on_processing_state_changed)
        widget.blockingStateChanged.connect(self.__on_blocking_state_changed)

        if widget.isBlocking():
            # A widget can already enter blocking state in __init__
            self.__widget_processing_state[widget] |= self.BlockingUpdate

        if widget.processingState != 0:
            # It can also start processing (initialization of resources, ...)
            self.__widget_processing_state[widget] |= self.ProcessingUpdate
            node.set_processing_state(1)
            node.set_progress(widget.progressBarValue)

        # Install a help shortcut on the widget
        help_action = widget.findChild(QAction, "action-help")
        if help_action is not None:
            help_action.setEnabled(True)
            help_action.setVisible(True)
            help_action.triggered.connect(self.__on_help_request)

        # Up shortcut (activate/open parent)
        up_shortcut = QShortcut(QKeySequence(Qt.ControlModifier + Qt.Key_Up),
                                widget)
        up_shortcut.activated.connect(self.__on_activate_parent)

        # Call setters only after initialization.
        widget.setWindowIcon(icon_loader.from_description(desc).get(desc.icon))
        widget.setCaption(node.title)
        # befriend class Report
        widget._Report__report_view = self.scheme().report_view

        self.__set_float_on_top_flag(widget)

        # Schedule an update with the signal manager, due to the cleared
        # implicit Initializing flag
        self.signal_manager()._update()

        return widget
    def __add_widget_for_node(self, node):
        # type: (SchemeNode) -> None
        item = self.__item_for_node.get(node)
        if item is not None:
            return
        if self.__workflow is None:
            return

        if node not in self.__workflow.nodes:
            return

        if node in self.__init_queue:
            self.__init_queue.remove(node)

        item = Item(node, None, -1)
        # Insert on the node -> item mapping.
        self.__item_for_node[node] = item
        log.debug("Creating widget for node %s", node)
        try:
            w = self.create_widget_for_node(node)
        except Exception:  # pylint: disable=broad-except
            log.critical("", exc_info=True)
            lines = traceback.format_exception(*sys.exc_info())
            text = "".join(lines)
            errorwidget = QLabel(textInteractionFlags=Qt.TextSelectableByMouse,
                                 wordWrap=True,
                                 objectName="widgetmanager-error-placeholder",
                                 text="<pre>" + escape(text) + "</pre>")
            item.errorwidget = errorwidget
            node.set_state_message(UserMessage(text, UserMessage.Error, ""))
            raise
        else:
            item.widget = w
            self.__item_for_widget[w] = item

        self.__set_float_on_top_flag(w)

        if w.windowIcon().isNull():
            desc = node.description
            w.setWindowIcon(icon_loader.from_description(desc).get(desc.icon))
        if not w.windowTitle():
            w.setWindowTitle(node.title)

        w.installEventFilter(self.__activation_monitor)
        # Up shortcut (activate/open parent)
        up_shortcut = QShortcut(QKeySequence(Qt.ControlModifier + Qt.Key_Up),
                                w)
        up_shortcut.activated.connect(self.__on_activate_parent)

        # send all the post creation notification events
        workflow = self.__workflow
        assert workflow is not None
        inputs = workflow.find_links(sink_node=node)
        for link in inputs:
            ev = LinkEvent(LinkEvent.InputLinkAdded, link)
            QCoreApplication.sendEvent(w, ev)
        outputs = workflow.find_links(source_node=node)
        for link in outputs:
            ev = LinkEvent(LinkEvent.OutputLinkAdded, link)
            QCoreApplication.sendEvent(w, ev)

        self.widget_for_node_added.emit(node, w)
示例#5
0
def welcome_dialog_paged(self):
    # type: (CanvasMainWindow) -> None
    """
    Show a modal multipaged welcome screen.
    """
    dlg = PagedDialog(
        self,
        windowTitle=self.tr("Orange Data Mining"),
    )
    dlg.setWindowModality(Qt.ApplicationModal)
    dlg.setAttribute(Qt.WA_DeleteOnClose)
    dlg.layout().setSizeConstraint(QVBoxLayout.SetFixedSize)
    dlg.setStyleSheet("""
        TabView::item:selected {
               background: rgb(243, 171, 86);
        }
    """)
    main = FancyWelcomeScreen()
    spec = welcome_screen_specs()
    if spec.image:
        background = QImage(spec.image)
    else:
        background = QImage("canvas_icons:orange-start-background.png")
    main.setImage(background)

    if spec.css:
        main.setStyleSheet(spec.css)
    else:
        main.setStyleSheet(
            "StartItem { background-color: rgb(123, 164, 214) }")

    def decorate_icon(icon):
        return decorate_welcome_icon(icon, "#6dacb2")

    for i, item in zip(range(3), spec.items):
        main.setItemText(i, item.text)
        main.setItemToolTip(i, item.tooltip)
        main.setItemIcon(i, decorate_icon(QIcon(item.icon)))
        main.setItemActiveIcon(i, decorate_icon(QIcon(item.active_icon)))
        main.item(i).setProperty("path", item.path)

    main.setCurrentIndex(0)
    main.activated.connect(lambda: openselectedbutton.click())

    PageWelcome = dlg.addPage(sc_icon("Welcome.svg"), "Welcome", main)
    examples_ = examples.workflows(config.default)
    items = [previewmodel.PreviewItem(path=t.abspath()) for t in examples_]
    model = previewmodel.PreviewModel(items=items)
    model.delayedScanUpdate()
    browser = previewbrowser.PreviewBrowser()
    browser.setModel(model)

    PageTemplates = dlg.addPage(sc_icon("Templates.svg"), "Templates", browser)
    browser.activated.connect(lambda: openselectedbutton.click())

    recent = [
        previewmodel.PreviewItem(name=item.title, path=item.path)
        for item in self.recent_schemes
    ]
    model = previewmodel.PreviewModel(items=recent)
    browser = previewbrowser.PreviewBrowser()
    browser.setModel(model)
    model.delayedScanUpdate()

    PageRecent = dlg.addPage(self.recent_action.icon(), "Recent", browser)
    browser.activated.connect(lambda: openselectedbutton.click())
    dlg.setPageEnabled(PageRecent, model.rowCount() > 0)

    page = SingleLinkPage(
        image=QImage(
            resource_path("icons/getting-started-video-tutorials.png")),
        heading="Getting Started",
        link=QUrl("https://www.youtube.com/watch?v=3nMcI4Hxm7c"),
    )
    page.setContentsMargins(25, 25, 25, 25)
    PageGetStarted = dlg.addPage(
        canvas_icons("YouTube.svg"),
        "Get Started",
        page,
    )
    buttons = dlg.buttonBox()
    buttons.setVisible(True)
    buttons.setStandardButtons(QDialogButtonBox.Open | QDialogButtonBox.Cancel)
    # choose the selected workflow button
    openselectedbutton = buttons.button(QDialogButtonBox.Open)
    openselectedbutton.setText(self.tr("Open"))
    openselectedbutton.setToolTip("Open the selected workflow")
    openselectedbutton.setDefault(True)

    newbutton = QPushButton("New", toolTip="Create a new workflow")
    s = QShortcut(QKeySequence.New, newbutton)
    s.activated.connect(newbutton.click)
    buttons.addButton(newbutton, QDialogButtonBox.AcceptRole)

    openexisting = QPushButton("Open Existing\N{HORIZONTAL ELLIPSIS}",
                               toolTip="Open an existing workflow file")
    s = QShortcut(QKeySequence.Open, dlg)
    s.activated.connect(openexisting.click)
    buttons.addButton(openexisting, QDialogButtonBox.AcceptRole)

    settings = QSettings()

    show_start_key = "startup/show-welcome-screen"
    show_start = QCheckBox("Show at startup",
                           checked=settings.value(show_start_key,
                                                  True,
                                                  type=bool))
    # Abusing ResetRole to push the check box to the left in all button
    # layouts.
    buttons.addButton(show_start, QDialogButtonBox.ResetRole)

    def update_show_at_startup(value):
        settings.setValue(show_start_key, value)

    show_start.toggled.connect(update_show_at_startup)

    def on_page_changed(index):
        if index == PageWelcome:
            openselectedbutton.setEnabled(True)
        elif index == PageTemplates:
            openselectedbutton.setEnabled(bool(examples))
        elif index == PageRecent:
            openselectedbutton.setEnabled(bool(recent))
        elif index == PageGetStarted:
            openselectedbutton.setEnabled(False)
        else:
            openselectedbutton.setEnabled(False)

    dlg.currentIndexChanged.connect(on_page_changed)

    def open_example_workflow(path):
        # open a workflow without filename/directory tracking.
        wf = self.new_scheme_from(path)
        if self.is_transient():
            window = self
        else:
            window = self.create_new_window()
            window.show()
            window.raise_()
            window.activateWindow()
        window.set_new_scheme(wf)

    def open_url(url):
        return QDesktopServices.openUrl(QUrl(url))

    def on_clicked(button):
        current = dlg.currentIndex()
        path = None
        open_workflow_file = None

        if current == PageWelcome:
            open_workflow_file = open_url
        elif current == PageTemplates:
            open_workflow_file = open_example_workflow
        elif current == PageRecent:
            open_workflow_file = self.open_scheme_file

        if button is openselectedbutton and \
                        current in {PageTemplates, PageRecent}:
            w = dlg.widget(current)
            assert isinstance(w, previewbrowser.PreviewBrowser)
            assert w.currentIndex() != -1
            model = w.model()
            item = model.item(w.currentIndex())
            path = item.path()
        elif button is openselectedbutton and current == PageWelcome:
            w = dlg.widget(current)
            assert isinstance(w, FancyWelcomeScreen)
            assert w.currentIndex() != -1
            path = w.item(w.currentIndex()).property("path")

        if path is not None:
            open_workflow_file(path)
            dlg.accept()

    buttons.clicked.connect(on_clicked)

    def on_open_existing():
        filedlg = self._open_workflow_dialog()
        filedlg.fileSelected.connect(self.open_scheme_file)
        filedlg.accepted.connect(dlg.accept)
        filedlg.exec()

    openexisting.clicked.connect(on_open_existing)

    def new_window():
        if not self.is_transient():
            self.new_workflow_window()
        dlg.accept()

    newbutton.clicked.connect(new_window)

    dlg.show()
示例#6
0
    def __init__(self, parent=None, select=SELECTNONE):
        QWidget.__init__(self)
        OWComponent.__init__(self, parent)

        self.parent = parent

        self.selection_type = select
        self.saving_enabled = hasattr(self.parent, "save_graph")
        self.clear_data(init=True)
        self.subset = None  # current subset input
        self.subset_indices = None  # boolean index array with indices in self.data

        self.plotview = pg.PlotWidget(background="w", viewBox=InteractiveViewBoxC(self))
        self.plot = self.plotview.getPlotItem()
        self.plot.setDownsampling(auto=True, mode="peak")

        self.markings = []
        self.vLine = pg.InfiniteLine(angle=90, movable=False)
        self.hLine = pg.InfiniteLine(angle=0, movable=False)
        self.proxy = pg.SignalProxy(self.plot.scene().sigMouseMoved, rateLimit=20, slot=self.mouseMoved, delay=0.1)
        self.plot.scene().sigMouseMoved.connect(self.plot.vb.mouseMovedEvent)
        self.plot.vb.sigRangeChanged.connect(self.resized)
        self.pen_mouse = pg.mkPen(color=(0, 0, 255), width=2)
        self.pen_normal = defaultdict(lambda: pg.mkPen(color=(200, 200, 200, 127), width=1))
        self.pen_subset = defaultdict(lambda: pg.mkPen(color=(0, 0, 0, 127), width=1))
        self.pen_selected = defaultdict(lambda: pg.mkPen(color=(0, 0, 0, 127), width=2, style=Qt.DotLine))
        self.label = pg.TextItem("", anchor=(1, 0))
        self.label.setText("", color=(0, 0, 0))
        self.discrete_palette = None
        QPixmapCache.setCacheLimit(max(QPixmapCache.cacheLimit(), 100 * 1024))
        self.curves_cont = PlotCurvesItem()
        self.important_decimals = 4, 4

        # whether to rescale at next update
        self.rescale_next = True

        self.MOUSE_RADIUS = 20

        self.clear_graph()

        # interface settings
        self.location = True  # show current position
        self.markclosest = True  # mark
        self.crosshair = True
        self.crosshair_hidden = True

        layout = QVBoxLayout()
        self.setLayout(layout)
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().addWidget(self.plotview)

        actions = []

        resample_curves = QAction(
            "Resample curves", self, shortcut=Qt.Key_R,
            triggered=lambda x: self.resample_curves(self.sample_seed+1)
        )
        actions.append(resample_curves)
        reset_curves = QAction(
            "Resampling reset", self, shortcut=QKeySequence(Qt.ControlModifier | Qt.Key_R),
            triggered=lambda x: self.resample_curves(0)
        )
        actions.append(reset_curves)

        zoom_in = QAction(
            "Zoom in", self, triggered=self.plot.vb.set_mode_zooming
        )
        zoom_in.setShortcuts([Qt.Key_Z, QKeySequence(QKeySequence.ZoomIn)])
        zoom_in.setShortcutContext(Qt.WidgetWithChildrenShortcut)
        actions.append(zoom_in)
        zoom_fit = QAction(
            "Zoom to fit", self,
            triggered=lambda x: (self.plot.vb.autoRange(), self.plot.vb.set_mode_panning())
        )
        zoom_fit.setShortcuts([Qt.Key_Backspace, QKeySequence(Qt.ControlModifier | Qt.Key_0)])
        zoom_fit.setShortcutContext(Qt.WidgetWithChildrenShortcut)
        actions.append(zoom_fit)
        rescale_y = QAction(
            "Rescale Y to fit", self, shortcut=Qt.Key_D,
            triggered=self.rescale_current_view_y
        )

        actions.append(rescale_y)
        self.view_average_menu = QAction(
            "Show averages", self, shortcut=Qt.Key_A, checkable=True,
            triggered=lambda x: self.viewtype_changed()
        )
        actions.append(self.view_average_menu)

        self.show_grid = False
        self.show_grid_a = QAction(
            "Show grid", self, shortcut=Qt.Key_G, checkable=True,
            triggered=self.grid_changed
        )
        actions.append(self.show_grid_a)
        self.invertX_menu = QAction(
            "Invert X", self, shortcut=Qt.Key_X, checkable=True,
            triggered=self.invertX_changed
        )
        actions.append(self.invertX_menu)
        if self.selection_type == SELECTMANY:
            select_curves = QAction(
                "Select (line)", self, triggered=self.plot.vb.set_mode_select,
            )
            select_curves.setShortcuts([Qt.Key_S])
            select_curves.setShortcutContext(Qt.WidgetWithChildrenShortcut)
            actions.append(select_curves)
        if self.saving_enabled:
            save_graph = QAction(
                "Save graph", self, triggered=self.save_graph,
            )
            save_graph.setShortcuts([QKeySequence(Qt.ControlModifier | Qt.Key_S)])
            actions.append(save_graph)

        range_menu = MenuFocus("Define view range", self)
        range_action = QWidgetAction(self)
        layout = QGridLayout()
        range_box = gui.widgetBox(self, margin=5, orientation=layout)
        range_box.setFocusPolicy(Qt.TabFocus)
        self.range_e_x1 = lineEditFloatOrNone(None, self, "range_x1", label="e")
        range_box.setFocusProxy(self.range_e_x1)
        self.range_e_x2 = lineEditFloatOrNone(None, self, "range_x2", label="e")
        layout.addWidget(QLabel("X"), 0, 0, Qt.AlignRight)
        layout.addWidget(self.range_e_x1, 0, 1)
        layout.addWidget(QLabel("-"), 0, 2)
        layout.addWidget(self.range_e_x2, 0, 3)
        self.range_e_y1 = lineEditFloatOrNone(None, self, "range_y1", label="e")
        self.range_e_y2 = lineEditFloatOrNone(None, self, "range_y2", label="e")
        layout.addWidget(QLabel("Y"), 1, 0, Qt.AlignRight)
        layout.addWidget(self.range_e_y1, 1, 1)
        layout.addWidget(QLabel("-"), 1, 2)
        layout.addWidget(self.range_e_y2, 1, 3)
        b = gui.button(None, self, "Apply", callback=self.set_limits)
        layout.addWidget(b, 2, 3, Qt.AlignRight)
        range_action.setDefaultWidget(range_box)
        range_menu.addAction(range_action)

        layout = QGridLayout()
        self.plotview.setLayout(layout)
        self.button = QPushButton("View", self.plotview)
        self.button.setAutoDefault(False)
        layout.setRowStretch(1, 1)
        layout.setColumnStretch(1, 1)
        layout.addWidget(self.button, 0, 0)
        view_menu = MenuFocus(self)
        self.button.setMenu(view_menu)
        view_menu.addActions(actions)
        view_menu.addMenu(range_menu)
        self.addActions(actions)

        choose_color_action = QWidgetAction(self)
        choose_color_box = gui.hBox(self)
        choose_color_box.setFocusPolicy(Qt.TabFocus)
        model = VariableListModel()
        self.attrs = []
        model.wrap(self.attrs)
        label = gui.label(choose_color_box, self, "Color by")
        label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.attrCombo = gui.comboBox(
            choose_color_box, self, value="color_attr", contentsLength=12,
            callback=self.update_view)
        self.attrCombo.setModel(model)
        choose_color_box.setFocusProxy(self.attrCombo)
        choose_color_action.setDefaultWidget(choose_color_box)
        view_menu.addAction(choose_color_action)

        cycle_colors = QShortcut(Qt.Key_C, self, self.cycle_color_attr, context=Qt.WidgetWithChildrenShortcut)

        labels_action = QWidgetAction(self)
        layout = QGridLayout()
        labels_box = gui.widgetBox(self, margin=0, orientation=layout)
        t = gui.lineEdit(None, self, "label_title", label="Title:",
                         callback=self.labels_changed, callbackOnType=self.labels_changed)
        layout.addWidget(QLabel("Title:"), 0, 0, Qt.AlignRight)
        layout.addWidget(t, 0, 1)
        t = gui.lineEdit(None, self, "label_xaxis", label="X-axis:",
                         callback=self.labels_changed, callbackOnType=self.labels_changed)
        layout.addWidget(QLabel("X-axis:"), 1, 0, Qt.AlignRight)
        layout.addWidget(t, 1, 1)
        t = gui.lineEdit(None, self, "label_yaxis", label="Y-axis:",
                         callback=self.labels_changed, callbackOnType=self.labels_changed)
        layout.addWidget(QLabel("Y-axis:"), 2, 0, Qt.AlignRight)
        layout.addWidget(t, 2, 1)
        labels_action.setDefaultWidget(labels_box)
        view_menu.addAction(labels_action)
        self.labels_changed()  # apply saved labels

        self.invertX_apply()
        self.plot.vb.set_mode_panning()

        self.reports = {}  # current reports

        self.viewhelpers_show()