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
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)
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)
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()
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()