def __quicktipOnce(self): filename = os.path.join(settings.widget_settings_dir(), "user-session-state.ini") namespace = ( "user-message-history/{0.__module__}.{0.__qualname__}".format( type(self))) session_hist = QSettings(filename, QSettings.IniFormat) session_hist.beginGroup(namespace) messages = self.UserAdviceMessages def _ispending(msg): return not session_hist.value("{}/confirmed".format( msg.persistent_id), defaultValue=False, type=bool) messages = [msg for msg in messages if _ispending(msg)] if not messages: return message = messages[self.__msgchoice % len(messages)] self.__msgchoice += 1 self.__showMessage(message) def _userconfirmed(): session_hist = QSettings(filename, QSettings.IniFormat) session_hist.beginGroup(namespace) session_hist.setValue("{}/confirmed".format(message.persistent_id), True) session_hist.sync() self.__msgwidget.accepted.connect(_userconfirmed)
def __quicktipOnce(self): filename = os.path.join(settings.widget_settings_dir(), "user-session-state.ini") namespace = ("user-message-history/{0.__module__}.{0.__qualname__}" .format(type(self))) session_hist = QSettings(filename, QSettings.IniFormat) session_hist.beginGroup(namespace) messages = self.UserAdviceMessages def _ispending(msg): return not session_hist.value( "{}/confirmed".format(msg.persistent_id), defaultValue=False, type=bool) messages = [msg for msg in messages if _ispending(msg)] if not messages: return message = messages[self.__msgchoice % len(messages)] self.__msgchoice += 1 self.__showMessage(message) def _userconfirmed(): session_hist = QSettings(filename, QSettings.IniFormat) session_hist.beginGroup(namespace) session_hist.setValue( "{}/confirmed".format(message.persistent_id), True) session_hist.sync() self.__msgwidget.accepted.connect(_userconfirmed)
def setup_application(self): super().setup_application() clear_settings_flag = os.path.join(widget_settings_dir(), "DELETE_ON_START") # NOTE: No OWWidgetBase subclass should be imported before this options = self.options if options.clear_widget_settings or \ os.path.isfile(clear_settings_flag): log.info("Clearing widget settings") shutil.rmtree(widget_settings_dir(), ignore_errors=True) notif_server = NotificationServer() canvas.notification_server_instance = notif_server self._update_check = check_for_updates() self._send_stat = send_usage_statistics() self._pull_notifs = pull_notifications() settings = QSettings() settings.setValue('startup/launch-count', settings.value('startup/launch-count', 0, int) + 1) if settings.value("reporting/send-statistics", False, type=bool) \ and is_release: UsageStatistics.set_enabled(True) app = self.application # set pyqtgraph colors def onPaletteChange(): p = app.palette() bg = p.base().color().name() fg = p.windowText().color().name() log.info('Setting pyqtgraph background to %s', bg) pyqtgraph.setConfigOption('background', bg) log.info('Setting pyqtgraph foreground to %s', fg) pyqtgraph.setConfigOption('foreground', fg) app.setProperty('darkMode', p.color(QPalette.Base).value() < 127) app.paletteChanged.connect(onPaletteChange) onPaletteChange()
def __init__(self, parent=None): QObject.__init__(self, parent=None) assert QThread.currentThread() is QApplication.instance().thread() netmanager = self._NETMANAGER_REF and self._NETMANAGER_REF() if netmanager is None: netmanager = QNetworkAccessManager() cache = QNetworkDiskCache() cache.setCacheDirectory( os.path.join(settings.widget_settings_dir(), __name__ + ".ImageLoader.Cache")) netmanager.setCache(cache) ImageLoader._NETMANAGER_REF = weakref.ref(netmanager) self._netmanager = netmanager
def __init__(self, parent=None): QObject.__init__(self, parent) assert QThread.currentThread() is QApplication.instance().thread() netmanager = self._NETMANAGER_REF and self._NETMANAGER_REF() if netmanager is None: netmanager = QNetworkAccessManager() cache = QNetworkDiskCache() cache.setCacheDirectory( os.path.join(settings.widget_settings_dir(), __name__ + ".ImageLoader.Cache") ) netmanager.setCache(cache) ImageLoader._NETMANAGER_REF = weakref.ref(netmanager) self._netmanager = netmanager
def main(argv=None): # Allow termination with CTRL + C signal.signal(signal.SIGINT, signal.SIG_DFL) # Disable pyqtgraph's atexit and QApplication.aboutToQuit cleanup handlers. pyqtgraph.setConfigOption("exitCleanup", False) if argv is None: argv = sys.argv usage = "usage: %prog [options] [workflow_file]" parser = optparse.OptionParser(usage=usage) parser.add_option("--no-discovery", action="store_true", help="Don't run widget discovery " "(use full cache instead)") parser.add_option("--force-discovery", action="store_true", help="Force full widget discovery " "(invalidate cache)") parser.add_option("--clear-widget-settings", action="store_true", help="Remove stored widget setting") parser.add_option("--no-welcome", action="store_true", help="Don't show welcome dialog.") parser.add_option("--no-splash", action="store_true", help="Don't show splash screen.") parser.add_option("-l", "--log-level", help="Logging level (0, 1, 2, 3, 4)", type="int", default=1) parser.add_option("--style", help="QStyle to use", type="str", default=None) parser.add_option("--stylesheet", help="Application level CSS style sheet to use", type="str", default=None) parser.add_option("--qt", help="Additional arguments for QApplication", type="str", default=None) (options, args) = parser.parse_args(argv[1:]) levels = [ logging.CRITICAL, logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG ] # Fix streams before configuring logging (otherwise it will store # and write to the old file descriptors) fix_win_pythonw_std_stream() # Try to fix macOS automatic window tabbing (Sierra and later) fix_macos_nswindow_tabbing() logging.basicConfig( level=levels[options.log_level], handlers=[make_stdout_handler(levels[options.log_level])]) # set default application configuration config_ = config.Config() canvasconfig.set_default(config_) log.info("Starting 'Orange Canvas' application.") qt_argv = argv[:1] style = options.style defaultstylesheet = "orange.qss" fusiontheme = None if style is not None: if style.startswith("fusion:"): qt_argv += ["-style", "fusion"] _, _, fusiontheme = style.partition(":") else: qt_argv += ["-style", style] if options.qt is not None: qt_argv += shlex.split(options.qt) qt_argv += args if QT_VERSION >= 0x50600: CanvasApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) log.debug("Starting CanvasApplicaiton with argv = %r.", qt_argv) app = CanvasApplication(qt_argv) config_.init() if app.style().metaObject().className() == "QFusionStyle": if fusiontheme == "breeze-dark": app.setPalette(breeze_dark()) defaultstylesheet = "darkorange.qss" palette = app.palette() if style is None and palette.color(QPalette.Window).value() < 127: log.info("Switching default stylesheet to darkorange") defaultstylesheet = "darkorange.qss" # Initialize SQL query and execution time logger (in SqlTable) sql_level = min(levels[options.log_level], logging.INFO) make_sql_logger(sql_level) clear_settings_flag = os.path.join(widget_settings_dir(), "DELETE_ON_START") if options.clear_widget_settings or \ os.path.isfile(clear_settings_flag): log.info("Clearing widget settings") shutil.rmtree(widget_settings_dir(), ignore_errors=True) # Set http_proxy environment variables, after (potentially) clearing settings fix_set_proxy_env() # Setup file log handler for the select logger list - this is always # at least INFO level = min(levels[options.log_level], logging.INFO) file_handler = logging.FileHandler(filename=os.path.join( config.log_dir(), "canvas.log"), mode="w") formatter = logging.Formatter( "%(asctime)s:%(levelname)s:%(name)s: %(message)s") file_handler.setFormatter(formatter) file_handler.setLevel(level) stream = TextStream() stream_handler = logging.StreamHandler(stream) stream_handler.setFormatter(formatter) stream_handler.setLevel(level) for namespace in ["orangecanvas", "orangewidget", "Orange"]: logger = logging.getLogger(namespace) logger.setLevel(level) logger.addHandler(file_handler) logger.addHandler(stream_handler) # intercept any QFileOpenEvent requests until the main window is # fully initialized. # NOTE: The QApplication must have the executable ($0) and filename # arguments passed in argv otherwise the FileOpen events are # triggered for them (this is done by Cocoa, but QApplicaiton filters # them out if passed in argv) open_requests = [] def onrequest(url): log.info("Received an file open request %s", url) path = url.path() exists = QFile(path).exists() if exists and \ ('pydevd.py' not in url.path() and # PyCharm debugger 'run_profiler.py' not in url.path()): # PyCharm profiler open_requests.append(url) app.fileOpenRequest.connect(onrequest) settings = QSettings() settings.setValue('startup/launch-count', settings.value('startup/launch-count', 0, int) + 1) if settings.value("reporting/send-statistics", False, type=bool) \ and is_release: UsageStatistics.set_enabled(True) stylesheet = options.stylesheet or defaultstylesheet stylesheet_string = None if stylesheet != "none": if os.path.isfile(stylesheet): with open(stylesheet, "r") as f: stylesheet_string = f.read() else: if not os.path.splitext(stylesheet)[1]: # no extension stylesheet = os.path.extsep.join([stylesheet, "qss"]) pkg_name = orangecanvas.__name__ resource = "styles/" + stylesheet if pkg_resources.resource_exists(pkg_name, resource): stylesheet_string = \ pkg_resources.resource_string(pkg_name, resource).decode() base = pkg_resources.resource_filename(pkg_name, "styles") pattern = re.compile( r"^\s@([a-zA-Z0-9_]+?)\s*:\s*([a-zA-Z0-9_/]+?);\s*$", flags=re.MULTILINE) matches = pattern.findall(stylesheet_string) for prefix, search_path in matches: QDir.addSearchPath(prefix, os.path.join(base, search_path)) log.info("Adding search path %r for prefix, %r", search_path, prefix) stylesheet_string = pattern.sub("", stylesheet_string) else: log.info("%r style sheet not found.", stylesheet) # Add the default canvas_icons search path dirpath = os.path.abspath(os.path.dirname(orangecanvas.__file__)) QDir.addSearchPath("canvas_icons", os.path.join(dirpath, "icons")) canvas_window = MainWindow() canvas_window.setAttribute(Qt.WA_DeleteOnClose) canvas_window.setWindowIcon(config.application_icon()) canvas_window.connect_output_stream(stream) # initialize notification server, set to initial canvas notif_server = NotificationServer() canvas.notification_server_instance = notif_server canvas_window.set_notification_server(notif_server) if stylesheet_string is not None: canvas_window.setStyleSheet(stylesheet_string) if not options.force_discovery: reg_cache = cache.registry_cache() else: reg_cache = None widget_registry = qt.QtWidgetRegistry() widget_discovery = config_.widget_discovery(widget_registry, cached_descriptions=reg_cache) want_splash = \ settings.value("startup/show-splash-screen", True, type=bool) and \ not options.no_splash if want_splash: pm, rect = config.splash_screen() splash_screen = SplashScreen(pixmap=pm, textRect=rect) splash_screen.setFont(QFont("Helvetica", 12)) color = QColor("#FFD39F") def show_message(message): splash_screen.showMessage(message, color=color) widget_registry.category_added.connect(show_message) log.info("Running widget discovery process.") cache_filename = os.path.join(config.cache_dir(), "widget-registry.pck") if options.no_discovery: with open(cache_filename, "rb") as f: widget_registry = pickle.load(f) widget_registry = qt.QtWidgetRegistry(widget_registry) else: if want_splash: splash_screen.show() widget_discovery.run(config.widgets_entry_points()) if want_splash: splash_screen.hide() splash_screen.deleteLater() # Store cached descriptions cache.save_registry_cache(widget_discovery.cached_descriptions) with open(cache_filename, "wb") as f: pickle.dump(WidgetRegistry(widget_registry), f) set_global_registry(widget_registry) canvas_window.set_widget_registry(widget_registry) canvas_window.show() canvas_window.raise_() want_welcome = \ settings.value("startup/show-welcome-screen", True, type=bool) \ and not options.no_welcome # Process events to make sure the canvas_window layout has # a chance to activate (the welcome dialog is modal and will # block the event queue, plus we need a chance to receive open file # signals when running without a splash screen) app.processEvents() app.fileOpenRequest.connect(canvas_window.open_scheme_file) if args: log.info("Loading a scheme from the command line argument %r", args[0]) canvas_window.load_scheme(args[0]) elif open_requests: log.info("Loading a scheme from an `QFileOpenEvent` for %r", open_requests[-1]) canvas_window.load_scheme(open_requests[-1].toLocalFile()) else: swp_loaded = canvas_window.ask_load_swp_if_exists() if not swp_loaded and want_welcome: canvas_window.welcome_dialog() # local references prevent destruction update_check = check_for_updates() send_stat = send_usage_statistics() pull_notifs = pull_notifications() # Tee stdout and stderr into Output dock log_view = canvas_window.output_view() stdout = TextStream() stdout.stream.connect(log_view.write) if sys.stdout: stdout.stream.connect(sys.stdout.write) stdout.flushed.connect(sys.stdout.flush) stderr = TextStream() error_writer = log_view.formatted(color=Qt.red) stderr.stream.connect(error_writer.write) if sys.stderr: stderr.stream.connect(sys.stderr.write) stderr.flushed.connect(sys.stderr.flush) log.info("Entering main event loop.") excepthook = ExceptHook(stream=stderr) excepthook.handledException.connect(handle_exception) try: with closing(stdout),\ closing(stderr),\ closing(stream), \ patch('sys.excepthook', excepthook),\ patch('sys.stderr', stderr),\ patch('sys.stdout', stdout): status = app.exec_() except BaseException: log.error("Error in main event loop.", exc_info=True) status = 42 del canvas_window del update_check del send_stat del pull_notifs app.processEvents() app.flush() # Collect any cycles before deleting the QApplication instance gc.collect() del app if status == 96: log.info('Restarting via exit code 96.') run_after_exit([sys.executable, sys.argv[0]]) return status
def _local_settings(cls): # type: () -> QSettings """Return a QSettings instance with local persistent settings.""" filename = "{}.ini".format(qname(cls)) fname = os.path.join(settings.widget_settings_dir(), filename) return QSettings(fname, QSettings.IniFormat)
def clear_widget_settings(self): log.info("Clearing widget settings") self._rm_tree(widget_settings_dir(versioned=True)) self._rm_tree(widget_settings_dir(versioned=False))