Beispiel #1
0
    def __init__(self, base, profile):
        self.base = unicode(base or "", sys.getfilesystemencoding())
        self.profile = unicode(profile or "", sys.getfilesystemencoding())

        self.pm = ProfileManager(self.base, self.profile)

        if self.profile:
            self.pm.ensureProfile()
        else:
            # defaulting to first frofile found
            name = self.pm.profiles()[0];
            self.pm = ProfileManager(self.base, name)
            self.pm.ensureProfile()

        self.collection = Collection(self.pm.collectionPath())
def temporary_user(dir_name, name="__Temporary Test User__", lang="en_US"):

    # prevent popping up language selection dialog
    original = ProfileManager.setDefaultLang

    def set_default_lang(profileManager):
        profileManager.setLang(lang)

    ProfileManager.setDefaultLang = set_default_lang

    pm = ProfileManager(base=dir_name)

    pm.setupMeta()

    # create profile no matter what (since we are starting in a unique temp directory)
    pm.create(name)

    # this needs to be called explicitly
    pm.setDefaultLang()

    pm.name = name

    yield name

    # cleanup
    pm.remove(name)
    ProfileManager.setDefaultLang = original
Beispiel #3
0
def main(delay):
    from PyQt4.QtCore import QTimer
    app = AnkiApp(sys.argv)
    QCoreApplication.setApplicationName("Anki")

    if app.secondInstance():
        print('Anki is already running')
        return

    from aqt.profiles import ProfileManager
    pm = ProfileManager('', '')
    setupLang(pm, app)
    pm.load('bz')
    pm.profile['autoSync'] = True
    pm.ensureProfile()

    def dummy(*args, **kwargs):
        pass

    # load the main window
    import aqt.main
    mw = aqt.main.AnkiQt(app, pm, [])

    # prevent Anki from showing main window
    mw.show = dummy
    mw.activateWindow = dummy
    mw.raise_ = dummy

    def handler():
        if mw.state == 'sync':
            # print('state sync')
            set_timer()
            return
        else:
            # print('state NOT sync')
            mw.onClose()
            mw.close()
            app.closeAllWindows()
            app.quit()

    def set_timer():
        timer = QTimer(mw)
        timer.setSingleShot(True)
        timer.connect(timer, SIGNAL('timeout()'), handler)
        timer.start(delay)

    def start_sync():
        # print('timer start_sync')
        mw.onSync(auto=True)

    set_timer()
    QTimer.singleShot(5000, start_sync)

    # print(dir(mw))
    #print('executing app')
    #mw.setupProgress()
    #mw.progress.start(immediate=True)
    #mw.progress._lastUpdate = time.time()
    #mw.onSync()
    app.exec_()
Beispiel #4
0
def run():
    global mw
    from anki.utils import isWin, isMac

    # on osx we'll need to add the qt plugins to the search path
    if isMac and getattr(sys, 'frozen', None):
        rd = os.path.abspath(moduleDir + "/../../..")
        QCoreApplication.setLibraryPaths([rd])

    # create the app
    app = AnkiApp(sys.argv)
    QCoreApplication.setApplicationName("Anki")
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return

    # parse args
    opts, args = parseArgs(sys.argv)
    opts.base = unicode(opts.base or "", sys.getfilesystemencoding())
    opts.profile = unicode(opts.profile or "", sys.getfilesystemencoding())

    # profile manager
    from aqt.profiles import ProfileManager
    pm = ProfileManager(opts.base, opts.profile)

    # i18n
    setupLang(pm, app, opts.lang)

    # remaining pm init
    pm.ensureProfile()

    # load the main window
    import aqt.main
    mw = aqt.main.AnkiQt(app, pm, args)
    app.exec_()
Beispiel #5
0
def _run():
    global mw

    # parse args
    opts, args = parseArgs(sys.argv)
    opts.base = unicode(opts.base or "", sys.getfilesystemencoding())
    opts.profile = unicode(opts.profile or "", sys.getfilesystemencoding())

    # on osx we'll need to add the qt plugins to the search path
    if isMac and getattr(sys, 'frozen', None):
        rd = os.path.abspath(moduleDir + "/../../..")
        QCoreApplication.setLibraryPaths([rd])

    if isMac:
        QFont.insertSubstitution(".Lucida Grande UI", "Lucida Grande")

    # create the app
    app = AnkiApp(sys.argv)
    QCoreApplication.setApplicationName("Anki")
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return

    # disable icons on mac; this must be done before window created
    if isMac:
        app.setAttribute(Qt.AA_DontShowIconsInMenus)

    # we must have a usable temp dir
    try:
        tempfile.gettempdir()
    except:
        QMessageBox.critical(
            None, "Error", """\
No usable temporary folder found. Make sure C:\\temp exists or TEMP in your \
environment points to a valid, writable folder.""")
        return

    # qt version must be up to date
    if qtmajor <= 4 and qtminor <= 6:
        QMessageBox.warning(
            None, "Error", "Your Qt version is known to be buggy. Until you "
          "upgrade to a newer Qt, you may experience issues such as images "
          "failing to show up during review.")

    # profile manager
    from aqt.profiles import ProfileManager
    pm = ProfileManager(opts.base, opts.profile)

    # i18n
    setupLang(pm, app, opts.lang)

    # remaining pm init
    pm.ensureProfile()

    # load the main window
    import aqt.main
    mw = aqt.main.AnkiQt(app, pm, args)
    app.exec_()
Beispiel #6
0
def _run():
    global mw

    # parse args
    opts, args = parseArgs(sys.argv)
    opts.base = opts.base or ""
    opts.profile = opts.profile or ""

    # work around pyqt loading wrong GL library
    if isLin:
        import ctypes
        ctypes.CDLL('libGL.so.1', ctypes.RTLD_GLOBAL)

    # opt in to full hidpi support
    QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)

    # create the app
    app = AnkiApp(sys.argv)
    QCoreApplication.setApplicationName("Anki")
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return

    # disable icons on mac; this must be done before window created
    if isMac:
        app.setAttribute(Qt.AA_DontShowIconsInMenus)

    # we must have a usable temp dir
    try:
        tempfile.gettempdir()
    except:
        QMessageBox.critical(
            None, "Error", """\
No usable temporary folder found. Make sure C:\\temp exists or TEMP in your \
environment points to a valid, writable folder.""")
        return

    # profile manager
    from aqt.profiles import ProfileManager
    pm = ProfileManager(opts.base, opts.profile)

    # i18n
    setupLang(pm, app, opts.lang)

    # remaining pm init
    pm.ensureProfile()

    print(
        "This is an BETA build - please do not package it up for Linux distributions"
    )

    # load the main window
    import aqt.main
    mw = aqt.main.AnkiQt(app, pm, args)
    app.exec_()
Beispiel #7
0
def _run():
    global mw

    # parse args
    opts, args = parseArgs(sys.argv)
    opts.base = opts.base or ""
    opts.profile = opts.profile or ""

    # on osx we'll need to add the qt plugins to the search path
    if isMac and getattr(sys, 'frozen', None):
        rd = os.path.abspath(moduleDir + "/../../../plugins")
        QCoreApplication.setLibraryPaths([rd])

    # work around pyqt loading wrong GL library
    if isLin:
        import ctypes
        ctypes.CDLL('libGL.so.1', ctypes.RTLD_GLOBAL)

    # create the app
    app = AnkiApp(sys.argv)
    QCoreApplication.setApplicationName("Anki")
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return

    # disable icons on mac; this must be done before window created
    if isMac:
        app.setAttribute(Qt.AA_DontShowIconsInMenus)

    # we must have a usable temp dir
    try:
        tempfile.gettempdir()
    except:
        QMessageBox.critical(
            None, "Error", """\
No usable temporary folder found. Make sure C:\\temp exists or TEMP in your \
environment points to a valid, writable folder.""")
        return

    # profile manager
    from aqt.profiles import ProfileManager
    pm = ProfileManager(opts.base, opts.profile)

    # i18n
    setupLang(pm, app, opts.lang)

    # remaining pm init
    pm.ensureProfile()

    # load the main window
    import aqt.main
    mw = aqt.main.AnkiQt(app, pm, args)
    app.exec_()
Beispiel #8
0
def run():
    global mw
    from anki.utils import isWin, isMac

    # on osx we'll need to add the qt plugins to the search path
    if isMac and getattr(sys, 'frozen', None):
        rd = os.path.abspath(moduleDir + "/../../..")
        QCoreApplication.setLibraryPaths([rd])

    # create the app
    app = AnkiApp(sys.argv)
    QCoreApplication.setApplicationName("Anki")
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return

    # we must have a usable temp dir
    try:
        tempfile.gettempdir()
    except:
        QMessageBox.critical(
            None, "Error", """\
No usable temporary folder found. Make sure C:\\temp exists or TEMP in your \
environment points to a valid, writable folder.""")
        return

    # parse args
    opts, args = parseArgs(sys.argv)
    opts.base = unicode(opts.base or "", sys.getfilesystemencoding())
    opts.profile = unicode(opts.profile or "", sys.getfilesystemencoding())

    # profile manager
    from aqt.profiles import ProfileManager
    pm = ProfileManager(opts.base, opts.profile)

    # i18n
    setupLang(pm, app, opts.lang)

    # remaining pm init
    pm.ensureProfile()

    # load the main window
    import aqt.main
    mw = aqt.main.AnkiQt(app, pm, args)
    app.exec_()
Beispiel #9
0
    def _init_load_collection(self, base, path):
        """Load the Anki collection"""
        from pathlib import Path
        from sqlite3 import OperationalError

        import anki
        from aqt.profiles import ProfileManager

        import click

        # Save CWD (because Anki changes it)
        save_cwd = os.getcwd()

        if path is None:
            basepath = Path(base)
            if not (basepath / 'prefs21.db').exists():
                click.echo('Invalid base path!')
                click.echo(f'path = {basepath.absolute()}')
                raise click.Abort()

            # Initialize a profile manager to get an interface to the profile
            # settings and main database path; also required for syncing
            self.pm = ProfileManager(base)
            self.pm.setupMeta()
            self.pm.load(self.pm.profiles()[0])

            # Load the main Anki database/collection
            path = self.pm.collectionPath()
        else:
            self.pm = None

        try:
            self.col = anki.Collection(path)
        except AssertionError:
            click.echo('Path to database is not valid!')
            click.echo(f'path = {path}')
            raise click.Abort()
        except OperationalError:
            click.echo('Database is NA/locked!')
            raise click.Abort()

        # Restore CWD (because Anki changes it)
        os.chdir(save_cwd)
Beispiel #10
0
    def _init_load_collection(self, base, path, profile):
        """Load the Anki collection"""
        # Save CWD (because Anki changes it)
        save_cwd = os.getcwd()

        if path is None:
            if base is None:
                click.echo('Base path is not properly set!')
                raise click.Abort()

            basepath = Path(base)
            if not (basepath / 'prefs21.db').exists():
                click.echo('Invalid base path!')
                click.echo(f'path = {basepath.absolute()}')
                raise click.Abort()

            # Initialize a profile manager to get an interface to the profile
            # settings and main database path; also required for syncing
            self.pm = ProfileManager(base)
            self.pm.setupMeta()

            if profile is None:
                profile = self.pm.profiles()[0]

            # Load the main Anki database/collection
            self.pm.load(profile)
            path = self.pm.collectionPath()
        else:
            self.pm = None

        try:
            self.col = anki.Collection(path)
        except AssertionError:
            click.echo('Path to database is not valid!')
            click.echo(f'path = {path}')
            raise click.Abort()
        except anki.errors.DBError:
            click.echo('Database is NA/locked!')
            raise click.Abort()

        # Restore CWD (because Anki changes it)
        os.chdir(save_cwd)
Beispiel #11
0
def run():
    global mw
    from anki.utils import isWin, isMac

    # on osx we'll need to add the qt plugins to the search path
    if isMac and getattr(sys, 'frozen', None):
        rd = os.path.abspath(moduleDir + "/../../..")
        QCoreApplication.setLibraryPaths([rd])

    # create the app
    app = AnkiApp(sys.argv)
    QCoreApplication.setApplicationName("Anki")

    # parse args
    import optparse
    parser = optparse.OptionParser()
    parser.usage = "%prog [OPTIONS]"
    parser.add_option("-b", "--base", help="Path to base folder")
    parser.add_option("-p", "--profile", help="Profile name to load")
    (opts, args) = parser.parse_args(sys.argv[1:])

    # profile manager
    from aqt.profiles import ProfileManager
    pm = ProfileManager(opts.base, opts.profile)

    # qt translations
    translationPath = ''
    if False:  # not isWin and not isMac:
        translationPath = "/usr/share/qt4/translations/"
        long = conf['interfaceLang']
        short = long.split('_')[0]
        qtTranslator = QTranslator()
        if qtTranslator.load("qt_" + long, translationPath) or \
               qtTranslator.load("qt_" + short, translationPath):
            app.installTranslator(qtTranslator)

    import aqt.main
    mw = aqt.main.AnkiQt(app, pm)
    app.exec_()
Beispiel #12
0
def run():
    global mw
    from anki.utils import isWin, isMac

    # on osx we'll need to add the qt plugins to the search path
    if isMac and getattr(sys, 'frozen', None):
        rd = os.path.abspath(moduleDir + "/../../..")
        QCoreApplication.setLibraryPaths([rd])

    # create the app
    app = AnkiApp(sys.argv)
    QCoreApplication.setApplicationName("Anki")

    # parse args
    import optparse
    parser = optparse.OptionParser()
    parser.usage = "%prog [OPTIONS]"
    parser.add_option("-b", "--base", help="path to base folder")
    parser.add_option("-p", "--profile", help="profile name to load")
    parser.add_option("-l", "--lang", help="interface language (en, de, etc)")
    (opts, args) = parser.parse_args(sys.argv[1:])
    opts.base = unicode(opts.base or "", sys.getfilesystemencoding())
    opts.profile = unicode(opts.profile or "", sys.getfilesystemencoding())

    # profile manager
    from aqt.profiles import ProfileManager
    pm = ProfileManager(opts.base, opts.profile)

    # i18n
    setupLang(pm, app, opts.lang)

    # remaining pm init
    pm.checkPid()
    pm.ensureProfile()

    # load the main window
    import aqt.main
    mw = aqt.main.AnkiQt(app, pm)
    app.exec_()
def temporary_user(dir_name, name="__Temporary Test User__", lang="en_US"):

    # prevent popping up language selection dialog
    original = ProfileManager._setDefaultLang

    def set_default_lang(profileManager):
        profileManager.setLang(lang)

    ProfileManager._setDefaultLang = set_default_lang

    pm = ProfileManager(base=dir_name)

    if name in pm.profiles():
        warn(f"Temporary user named {name} already exists")
    else:
        pm.create(name)

    pm.name = name

    yield name

    pm.remove(name)
    ProfileManager._setDefaultLang = original
Beispiel #14
0
def _run(argv=None, exec=True):
    """Start AnkiQt application or reuse an existing instance if one exists.

    If the function is invoked with exec=False, the AnkiQt will not enter
    the main event loop - instead the application object will be returned.

    The 'exec' and 'argv' arguments will be useful for testing purposes.

    If no 'argv' is supplied then 'sys.argv' will be used.
    """
    global mw

    if argv is None:
        argv = sys.argv

    # parse args
    opts, args = parseArgs(argv)
    opts.base = opts.base or ""
    opts.profile = opts.profile or ""

    # work around pyqt loading wrong GL library
    if isLin:
        import ctypes
        ctypes.CDLL('libGL.so.1', ctypes.RTLD_GLOBAL)

    # opt in to full hidpi support
    QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)

    # create the app
    app = AnkiApp(argv)
    QCoreApplication.setApplicationName("Anki")
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return

    # disable icons on mac; this must be done before window created
    if isMac:
        app.setAttribute(Qt.AA_DontShowIconsInMenus)

    # we must have a usable temp dir
    try:
        tempfile.gettempdir()
    except:
        QMessageBox.critical(
            None, "Error", """\
No usable temporary folder found. Make sure C:\\temp exists or TEMP in your \
environment points to a valid, writable folder.""")
        return

    # profile manager
    from aqt.profiles import ProfileManager
    pm = ProfileManager(opts.base, opts.profile)

    # i18n
    setupLang(pm, app, opts.lang)

    # remaining pm init
    pm.ensureProfile()

    print("This is an BETA build - please do not package it up for Linux distributions")

    # load the main window
    import aqt.main
    mw = aqt.main.AnkiQt(app, pm, args)
    if exec:
        app.exec()
    else:
        return app
Beispiel #15
0
def _run(argv=None, exec=True) -> Optional[AnkiApp]:
    """Start AnkiQt application or reuse an existing instance if one exists.

    If the function is invoked with exec=False, the AnkiQt will not enter
    the main event loop - instead the application object will be returned.

    The 'exec' and 'argv' arguments will be useful for testing purposes.

    If no 'argv' is supplied then 'sys.argv' will be used.
    """
    global mw
    global profiler

    if argv is None:
        argv = sys.argv

    # parse args
    opts, args = parseArgs(argv)

    if opts.version:
        print(f"Anki {appVersion}")
        return None
    elif opts.syncserver:
        from anki.syncserver import serve

        serve()
        return None

    if PROFILE_CODE:

        profiler = cProfile.Profile()
        profiler.enable()

    # default to specified/system language before getting user's preference so that we can localize some more strings
    lang = anki.lang.get_def_lang(opts.lang)
    anki.lang.set_lang(lang[1], locale_dir())

    # profile manager
    pm = None
    try:
        pm = ProfileManager(opts.base)
        pmLoadResult = pm.setupMeta()
    except AnkiRestart as error:
        if error.exitcode:
            sys.exit(error.exitcode)
        return None
    except:
        # will handle below
        traceback.print_exc()
        pm = None

    if pm:
        # gl workarounds
        setupGL(pm)
        # apply user-provided scale factor
        os.environ["QT_SCALE_FACTOR"] = str(pm.uiScale())

    # opt in to full hidpi support?
    if not os.environ.get("ANKI_NOHIGHDPI"):
        QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
        os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1"
        os.environ["QT_SCALE_FACTOR_ROUNDING_POLICY"] = "PassThrough"

    # Opt into software rendering. Useful for buggy systems.
    if os.environ.get("ANKI_SOFTWAREOPENGL"):
        QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL)

    if (
        isWin
        and (qtminor == 14 or (qtminor == 15 and qtpoint == 0))
        and "QT_QPA_PLATFORM" not in os.environ
    ):
        os.environ["QT_QPA_PLATFORM"] = "windows:altgr"

    # create the app
    QCoreApplication.setApplicationName("Anki")
    QGuiApplication.setDesktopFileName("anki.desktop")
    app = AnkiApp(argv)
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return None

    if not pm:
        QMessageBox.critical(
            None,
            tr(TR.QT_MISC_ERROR),
            tr(TR.PROFILES_COULD_NOT_CREATE_DATA_FOLDER),
        )
        return None

    # disable icons on mac; this must be done before window created
    if isMac:
        app.setAttribute(Qt.AA_DontShowIconsInMenus)

    # disable help button in title bar on qt versions that support it
    if isWin and qtminor >= 10:
        QApplication.setAttribute(Qt.AA_DisableWindowContextHelpButton)

    # proxy configured?
    from urllib.request import getproxies, proxy_bypass

    disable_proxies = False
    try:
        if "http" in getproxies():
            # if it's not set up to bypass localhost, we'll
            # need to disable proxies in the webviews
            if not proxy_bypass("127.0.0.1"):
                disable_proxies = True
    except UnicodeDecodeError:
        # proxy_bypass can't handle unicode in hostnames; assume we need
        # to disable proxies
        disable_proxies = True

    if disable_proxies:
        print("webview proxy use disabled")
        proxy = QNetworkProxy()
        proxy.setType(QNetworkProxy.NoProxy)
        QNetworkProxy.setApplicationProxy(proxy)

    # we must have a usable temp dir
    try:
        tempfile.gettempdir()
    except:
        QMessageBox.critical(
            None,
            tr(TR.QT_MISC_ERROR),
            tr(TR.QT_MISC_NO_TEMP_FOLDER),
        )
        return None

    if pmLoadResult.firstTime:
        pm.setDefaultLang(lang[0])

    if pmLoadResult.loadError:
        QMessageBox.warning(
            None,
            tr(TR.PROFILES_PREFS_CORRUPT_TITLE),
            tr(TR.PROFILES_PREFS_FILE_IS_CORRUPT),
        )

    if opts.profile:
        pm.openProfile(opts.profile)

    # i18n & backend
    backend = setupLangAndBackend(pm, app, opts.lang, pmLoadResult.firstTime)

    driver = pm.video_driver()
    if isLin and driver == VideoDriver.OpenGL:
        from aqt.utils import gfxDriverIsBroken

        if gfxDriverIsBroken():
            pm.set_video_driver(driver.next())
            QMessageBox.critical(
                None,
                tr(TR.QT_MISC_ERROR),
                tr(TR.QT_MISC_INCOMPATIBLE_VIDEO_DRIVER),
            )
            sys.exit(1)

    # load the main window
    import aqt.main

    mw = aqt.main.AnkiQt(app, pm, backend, opts, args)
    if exec:
        app.exec()
    else:
        return app

    if PROFILE_CODE:
        write_profile_results()

    return None
Beispiel #16
0
def _run(argv=None, exec=True):
    """Start AnkiQt application or reuse an existing instance if one exists.

    If the function is invoked with exec=False, the AnkiQt will not enter
    the main event loop - instead the application object will be returned.

    The 'exec' and 'argv' arguments will be useful for testing purposes.

    If no 'argv' is supplied then 'sys.argv' will be used.
    """
    global mw

    if argv is None:
        argv = sys.argv

    # parse args
    opts, args = parseArgs(argv)

    # profile manager
    from aqt.profiles import ProfileManager
    pm = ProfileManager(opts.base)

    # gl workarounds
    setupGL(pm)

    # opt in to full hidpi support?
    if not os.environ.get("ANKI_NOHIGHDPI"):
        QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)

    # Opt into software rendering. Useful for buggy systems.
    if os.environ.get("ANKI_SOFTWAREOPENGL"):
        QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL)

    # create the app
    QCoreApplication.setApplicationName("Anki")
    QGuiApplication.setDesktopFileName("anki.desktop")
    app = AnkiApp(argv)
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return

    # disable icons on mac; this must be done before window created
    if isMac:
        app.setAttribute(Qt.AA_DontShowIconsInMenus)

    # proxy configured?
    from urllib.request import proxy_bypass, getproxies
    if 'http' in getproxies():
        # if it's not set up to bypass localhost, we'll
        # need to disable proxies in the webviews
        if not proxy_bypass("127.0.0.1"):
            print("webview proxy use disabled")
            proxy = QNetworkProxy()
            proxy.setType(QNetworkProxy.NoProxy)
            QNetworkProxy.setApplicationProxy(proxy)

    # we must have a usable temp dir
    try:
        tempfile.gettempdir()
    except:
        QMessageBox.critical(
            None, "Error", """\
No usable temporary folder found. Make sure C:\\temp exists or TEMP in your \
environment points to a valid, writable folder.""")
        return

    pm.setupMeta()

    if opts.profile:
        pm.openProfile(opts.profile)

    # i18n
    setupLang(pm, app, opts.lang)

    if isLin and pm.glMode() == "auto":
        from aqt.utils import gfxDriverIsBroken
        if gfxDriverIsBroken():
            pm.nextGlMode()
            QMessageBox.critical(
                None, "Error",
                "Your video driver is incompatible. Please start Anki again, and Anki will switch to a slower, more compatible mode."
            )
            sys.exit(1)

    # load the main window
    import aqt.main
    mw = aqt.main.AnkiQt(app, pm, opts, args)
    if exec:
        app.exec()
    else:
        return app
Beispiel #17
0
def _run(argv=None, exec=True):
    """Start AnkiQt application or reuse an existing instance if one exists.

    If the function is invoked with exec=False, the AnkiQt will not enter
    the main event loop - instead the application object will be returned.

    The 'exec' and 'argv' arguments will be useful for testing purposes.

    If no 'argv' is supplied then 'sys.argv' will be used.
    """
    global mw

    if argv is None:
        argv = sys.argv

    # parse args
    opts, args = parseArgs(argv)

    # profile manager
    pm = ProfileManager(opts.base)
    pmLoadResult = pm.setupMeta()

    # gl workarounds
    setupGL(pm)

    # opt in to full hidpi support?
    if not os.environ.get("ANKI_NOHIGHDPI"):
        QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
        os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1"
        os.environ["QT_SCALE_FACTOR_ROUNDING_POLICY"] = "PassThrough"

    # Opt into software rendering. Useful for buggy systems.
    if os.environ.get("ANKI_SOFTWAREOPENGL"):
        QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL)

    # apply user-provided scale factor
    os.environ["QT_SCALE_FACTOR"] = str(pm.uiScale())

    # create the app
    QCoreApplication.setApplicationName("Anki")
    QGuiApplication.setDesktopFileName("anki.desktop")
    app = AnkiApp(argv)
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return

    # disable icons on mac; this must be done before window created
    if isMac:
        app.setAttribute(Qt.AA_DontShowIconsInMenus)

    # disable help button in title bar on qt versions that support it
    if isWin and qtminor >= 10:
        QApplication.setAttribute(Qt.AA_DisableWindowContextHelpButton)

    # proxy configured?
    from urllib.request import proxy_bypass, getproxies

    if "http" in getproxies():
        # if it's not set up to bypass localhost, we'll
        # need to disable proxies in the webviews
        if not proxy_bypass("127.0.0.1"):
            print("webview proxy use disabled")
            proxy = QNetworkProxy()
            proxy.setType(QNetworkProxy.NoProxy)
            QNetworkProxy.setApplicationProxy(proxy)

    # we must have a usable temp dir
    try:
        tempfile.gettempdir()
    except:
        QMessageBox.critical(
            None,
            "Error",
            """\
No usable temporary folder found. Make sure C:\\temp exists or TEMP in your \
environment points to a valid, writable folder.""",
        )
        return

    if pmLoadResult.loadError:
        QMessageBox.warning(
            None,
            "Preferences Corrupt",
            """\
    Anki's prefs21.db file was corrupt and has been recreated. If you were using multiple \
    profiles, please add them back using the same names to recover your cards.""",
        )

    if opts.profile:
        pm.openProfile(opts.profile)

    # i18n
    setupLang(pm, app, opts.lang)

    if isLin and pm.glMode() == "auto":
        from aqt.utils import gfxDriverIsBroken

        if gfxDriverIsBroken():
            pm.nextGlMode()
            QMessageBox.critical(
                None,
                "Error",
                "Your video driver is incompatible. Please start Anki again, and Anki will switch to a slower, more compatible mode.",
            )
            sys.exit(1)

    # load the main window
    import aqt.main

    mw = aqt.main.AnkiQt(app, pm, opts, args)
    if exec:
        app.exec()
    else:
        return app
Beispiel #18
0
def _run(argv=None, exec=True):
    """Start AnkiQt application or reuse an existing instance if one exists.

    If the function is invoked with exec=False, the AnkiQt will not enter
    the main event loop - instead the application object will be returned.

    The 'exec' and 'argv' arguments will be useful for testing purposes.

    If no 'argv' is supplied then 'sys.argv' will be used.
    """
    global mw

    if argv is None:
        argv = sys.argv

    # parse args
    opts, args = parseArgs(argv)
    opts.base = opts.base or ""
    opts.profile = opts.profile or ""

    # profile manager
    from aqt.profiles import ProfileManager
    pm = ProfileManager(opts.base)

    # gl workarounds
    setupGL(pm)

    # opt in to full hidpi support?
    if not os.environ.get("ANKI_NOHIGHDPI"):
        QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)

    # create the app
    app = AnkiApp(argv)
    QCoreApplication.setApplicationName("Anki")
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return

    # disable icons on mac; this must be done before window created
    if isMac:
        app.setAttribute(Qt.AA_DontShowIconsInMenus)

    # proxy configured?
    from urllib.request import proxy_bypass, getproxies
    if 'http' in getproxies():
        # if it's not set up to bypass localhost, we'll
        # need to disable proxies in the webviews
        if not proxy_bypass("127.0.0.1"):
            print("webview proxy use disabled")
            proxy = QNetworkProxy()
            proxy.setType(QNetworkProxy.NoProxy)
            QNetworkProxy.setApplicationProxy(proxy)

    # we must have a usable temp dir
    try:
        tempfile.gettempdir()
    except:
        QMessageBox.critical(
            None, "Error", """\
No usable temporary folder found. Make sure C:\\temp exists or TEMP in your \
environment points to a valid, writable folder.""")
        return

    pm.setupMeta()

    if opts.profile:
        pm.openProfile(opts.profile)

    # i18n
    setupLang(pm, app, opts.lang)

    # remaining pm init
    pm.ensureProfile()

    # load the main window
    import aqt.main
    mw = aqt.main.AnkiQt(app, pm, opts, args)
    if exec:
        app.exec()
    else:
        return app
Beispiel #19
0
def _run(argv: Optional[list[str]] = None,
         exec: bool = True) -> Optional[AnkiApp]:
    """Start AnkiQt application or reuse an existing instance if one exists.

    If the function is invoked with exec=False, the AnkiQt will not enter
    the main event loop - instead the application object will be returned.

    The 'exec' and 'argv' arguments will be useful for testing purposes.

    If no 'argv' is supplied then 'sys.argv' will be used.
    """
    global mw
    global profiler

    if argv is None:
        argv = sys.argv

    # parse args
    opts, args = parseArgs(argv)

    if opts.version:
        print(f"Anki {appVersion}")
        return None
    elif opts.syncserver:
        from anki.syncserver import serve

        serve()
        return None

    if PROFILE_CODE:

        profiler = cProfile.Profile()
        profiler.enable()

    if (getattr(sys, "frozen", False)
            and os.getenv("QT_QPA_PLATFORM") == "wayland"
            and not os.getenv("ANKI_WAYLAND")):
        # users need to opt in to wayland support, given the issues it has
        print("Wayland support is disabled by default due to bugs.")
        print("You can force it on with an env var: ANKI_WAYLAND=1")
        os.environ["QT_QPA_PLATFORM"] = "xcb"

    # default to specified/system language before getting user's preference so that we can localize some more strings
    lang = anki.lang.get_def_lang(opts.lang)
    anki.lang.set_lang(lang[1])

    # profile manager
    pm = None
    try:
        pm = ProfileManager(opts.base)
        pmLoadResult = pm.setupMeta()
    except:
        # will handle below
        traceback.print_exc()
        pm = None

    if pm:
        # gl workarounds
        setupGL(pm)
        # apply user-provided scale factor
        os.environ["QT_SCALE_FACTOR"] = str(pm.uiScale())

    # opt in to full hidpi support?
    if not os.environ.get("ANKI_NOHIGHDPI") and qtmajor == 5:
        QCoreApplication.setAttribute(
            Qt.ApplicationAttribute.AA_EnableHighDpiScaling)  # type: ignore
        QCoreApplication.setAttribute(
            Qt.ApplicationAttribute.AA_UseHighDpiPixmaps)  # type: ignore
        os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1"
        os.environ["QT_SCALE_FACTOR_ROUNDING_POLICY"] = "PassThrough"

    # Opt into software rendering. Useful for buggy systems.
    if os.environ.get("ANKI_SOFTWAREOPENGL"):
        QCoreApplication.setAttribute(
            Qt.ApplicationAttribute.AA_UseSoftwareOpenGL)

    if (isWin and qtmajor == 5
            and (qtminor == 14 or (qtminor == 15 and qtpoint == 0))
            and "QT_QPA_PLATFORM" not in os.environ):
        os.environ["QT_QPA_PLATFORM"] = "windows:altgr"

    # create the app
    QCoreApplication.setApplicationName("Anki")
    QGuiApplication.setDesktopFileName("anki.desktop")
    app = AnkiApp(argv)
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return None

    if not pm:
        QMessageBox.critical(
            None,
            tr.qt_misc_error(),
            tr.profiles_could_not_create_data_folder(),
        )
        return None

    # disable icons on mac; this must be done before window created
    if isMac:
        app.setAttribute(Qt.ApplicationAttribute.AA_DontShowIconsInMenus)

    # disable help button in title bar on qt versions that support it
    if isWin and qtmajor == 5 and qtminor >= 10:
        QApplication.setAttribute(
            QApplication.Attribute.
            AA_DisableWindowContextHelpButton  # type: ignore
        )

    # proxy configured?
    from urllib.request import getproxies, proxy_bypass

    disable_proxies = False
    try:
        if "http" in getproxies():
            # if it's not set up to bypass localhost, we'll
            # need to disable proxies in the webviews
            if not proxy_bypass("127.0.0.1"):
                disable_proxies = True
    except UnicodeDecodeError:
        # proxy_bypass can't handle unicode in hostnames; assume we need
        # to disable proxies
        disable_proxies = True

    if disable_proxies:
        print("webview proxy use disabled")
        proxy = QNetworkProxy()
        proxy.setType(QNetworkProxy.ProxyType.NoProxy)
        QNetworkProxy.setApplicationProxy(proxy)

    # we must have a usable temp dir
    try:
        tempfile.gettempdir()
    except:
        QMessageBox.critical(
            None,
            tr.qt_misc_error(),
            tr.qt_misc_no_temp_folder(),
        )
        return None

    # make image resources available
    from aqt.utils import aqt_data_folder

    QDir.addSearchPath("icons", os.path.join(aqt_data_folder(), "qt", "icons"))

    if pmLoadResult.firstTime:
        pm.setDefaultLang(lang[0])

    if pmLoadResult.loadError:
        QMessageBox.warning(
            None,
            tr.profiles_prefs_corrupt_title(),
            tr.profiles_prefs_file_is_corrupt(),
        )

    if opts.profile:
        pm.openProfile(opts.profile)

    # i18n & backend
    backend = setupLangAndBackend(pm, app, opts.lang, pmLoadResult.firstTime)

    driver = pm.video_driver()
    if isLin and driver == VideoDriver.OpenGL:
        from aqt.utils import gfxDriverIsBroken

        if gfxDriverIsBroken():
            pm.set_video_driver(driver.next())
            QMessageBox.critical(
                None,
                tr.qt_misc_error(),
                tr.qt_misc_incompatible_video_driver(),
            )
            sys.exit(1)

    # load the main window
    import aqt.main

    mw = aqt.main.AnkiQt(app, pm, backend, opts, args)
    if exec:
        app.exec()
    else:
        return app

    if PROFILE_CODE:
        write_profile_results()

    return None
Beispiel #20
0
def _run(argv=None, exec=True):
    """Start AnkiQt application or reuse an existing instance if one exists.

    If the function is invoked with exec=False, the AnkiQt will not enter
    the main event loop - instead the application object will be returned.

    The 'exec' and 'argv' arguments will be useful for testing purposes.

    If no 'argv' is supplied then 'sys.argv' will be used.
    """
    global mw

    if argv is None:
        argv = sys.argv

    # parse args
    opts, args = parseArgs(argv)
    opts.base = opts.base or ""
    opts.profile = opts.profile or ""
    if opts.dev:
        os.environ["ANKIDEV"] = "1"
        print("running in dev mode")

    if isMac:
        if getattr(sys, 'frozen', None):
            # on osx we'll need to add the qt plugins to the search path
            rd = os.path.abspath(moduleDir + "/../../..")
            QCoreApplication.setLibraryPaths([rd])
        QFont.insertSubstitution(".Lucida Grande UI", "Lucida Grande")

    # create the app
    QCoreApplication.setApplicationName("Anki")
    app = AnkiApp(argv)
    if app.secondInstance():
        # we've signaled the primary instance, so we should close
        return

    # disable icons on mac; this must be done before window created
    if isMac:
        app.setAttribute(Qt.AA_DontShowIconsInMenus)

    # disable help button in title bar on qt versions that support it
    if isWin and qtminor >= 10:
        QApplication.setAttribute(Qt.AA_DisableWindowContextHelpButton)

    # we must have a usable temp dir
    try:
        tempfile.gettempdir()
    except:
        QMessageBox.critical(
            None, "Error", """\
No usable temporary folder found. Make sure C:\\temp exists or TEMP in your \
environment points to a valid, writable folder.""")
        return

    # qt version must be up to date
    if qtmajor <= 4 and qtminor <= 6:
        QMessageBox.warning(
            None, "Error", "Your Qt version is known to be buggy. Until you "
            "upgrade to a newer Qt, you may experience issues such as images "
            "failing to show up during review.")

    # profile manager
    from aqt.profiles import ProfileManager
    pm = ProfileManager(opts.base, opts.profile)

    # i18n
    setupLang(pm, app, opts.lang)

    # remaining pm init
    pm.ensureProfile()

    # load the main window
    import aqt.main
    mw = aqt.main.AnkiQt(app, pm, args)
    if exec:
        app.exec_()
    else:
        return app