def populateFields(self): # Fill in all the fields in the About dialog iconPic = appPath("icons/Manuskript/icon-64px.png") self.setWindowIcon(QIcon(iconPic)) logoPic = QPixmap(appPath("icons/Manuskript/logo-400x104.png")) self.labelLogo.setPixmap(logoPic) self.labelManuskriptVersion.setText( "<b>" + self.tr("Version") + " " + getVersion() + "</b><br>" + " " * 5 + """<a href="http://www.theologeek.ch/manuskript/"> http://www.theologeek.ch/manuskript/ </a><br>""" + " " * 5 + "Copyright © 2015-2017 Olivier Keshavjee<br>" + " " * 5 + """<a href="https://www.gnu.org/licenses/gpl-3.0.en.html"> GNU General Public License Version 3 </a><br>""") self.labelManuskriptVersion.setOpenExternalLinks(True) self.labelSoftwareVersion.setText( "<b>" + self.tr("Software Versions in Use:") + "</b><br>" + " " * 5 + self.tr("Python") + " " + python_version() + "<br>" + " " * 5 + self.tr("PyQt") + " " + PYQT_VERSION_STR + "<br>" + " " * 5 + self.tr("Qt") + " " + QT_VERSION_STR)
def run(): app = QApplication(sys.argv) app.setOrganizationName("manuskript") app.setOrganizationDomain("www.theologeek.ch") app.setApplicationName("manuskript") app.setApplicationVersion(getVersion()) print("Running manuskript version {}.".format(getVersion())) icon = QIcon() for i in [16, 32, 64, 128, 256, 512]: icon.addFile(appPath("icons/Manuskript/icon-{}px.png".format(i))) qApp.setWindowIcon(icon) app.setStyle("Fusion") # Load style from QSettings settings = QSettings(app.organizationName(), app.applicationName()) if settings.contains("applicationStyle"): style = settings.value("applicationStyle") app.setStyle(style) # Translation process locale = QLocale.system().name() appTranslator = QTranslator() # By default: locale translation = appPath(os.path.join("i18n", "manuskript_{}.qm".format(locale))) # Load translation from settings if settings.contains("applicationTranslation"): translation = appPath(os.path.join("i18n", settings.value("applicationTranslation"))) print("Found translation in settings:", translation) if appTranslator.load(translation): app.installTranslator(appTranslator) print(app.tr("Loaded translation: {}.").format(translation)) else: print(app.tr("Note: No translator found or loaded for locale {}.").format(locale)) QIcon.setThemeSearchPaths(QIcon.themeSearchPaths() + [appPath("icons")]) QIcon.setThemeName("NumixMsk") # qApp.setWindowIcon(QIcon.fromTheme("im-aim")) # Seperating launch to avoid segfault, so it seem. # Cf. http://stackoverflow.com/questions/12433491/is-this-pyqt-4-python-bug-or-wrongly-behaving-code launch()
def prepare(tests=False): app = QApplication(sys.argv) app.setOrganizationName("manuskript" + ("_tests" if tests else "")) app.setOrganizationDomain("www.theologeek.ch") app.setApplicationName("manuskript" + ("_tests" if tests else "")) app.setApplicationVersion(getVersion()) print("Running manuskript version {}.".format(getVersion())) icon = QIcon() for i in [16, 32, 64, 128, 256, 512]: icon.addFile(appPath("icons/Manuskript/icon-{}px.png".format(i))) qApp.setWindowIcon(icon) app.setStyle("Fusion") # Load style from QSettings settings = QSettings(app.organizationName(), app.applicationName()) if settings.contains("applicationStyle"): style = settings.value("applicationStyle") app.setStyle(style) # Translation process appTranslator = QTranslator(app) # By default: locale def tryLoadTranslation(translation, source): """Tries to load and activate a given translation for use.""" if appTranslator.load(translation, appPath("i18n")): app.installTranslator(appTranslator) print("Loaded translation: {}".format(translation)) # Note: QTranslator.load() does some fancy heuristics where it simplifies # the given locale until it is 'close enough' if the given filename does # not work out. For example, if given 'i18n/manuskript_en_US.qm', it tries: # * i18n/manuskript_en_US.qm.qm # * i18n/manuskript_en_US.qm # * i18n/manuskript_en_US # * i18n/manuskript_en.qm # * i18n/manuskript_en # * i18n/manuskript.qm # * i18n/manuskript # We have no way to determining what it eventually went with, so mind your # filenames when you observe strange behaviour with the loaded translations. return True else: print("No translation found or loaded. ({})".format(translation)) return False def activateTranslation(translation, source): """Loads the most suitable translation based on the available information.""" using_builtin_translation = True if (translation != ""): # empty string == 'no translation, use builtin' if isinstance(translation, str): if tryLoadTranslation(translation, source): using_builtin_translation = False else: # A list of language codes to try. Once something works, we're done. # This logic is loosely based on the working of QTranslator.load(QLocale, ...); # it allows us to more accurately detect the language used for the user interface. for language_code in translation: lc = language_code.replace('-', '_') if lc.lower() == 'en_US'.lower(): break if tryLoadTranslation("manuskript_{}.qm".format(lc), source): using_builtin_translation = False break if using_builtin_translation: print("Using the builtin translation.") # Load application translation translation = "" source = "default" if settings.contains("applicationTranslation"): # Use the language configured by the user. translation = settings.value("applicationTranslation") source = "user setting" else: # Auto-detect based on system locale. translation = QLocale().uiLanguages() source = "available ui languages" print("Preferred translation: {} (based on {})".format( ("builtin" if translation == "" else translation), source)) activateTranslation(translation, source) def respectSystemDarkThemeSetting(): """Adjusts the Qt theme to match the OS 'dark theme' setting configured by the user.""" if platform.system() is not 'Windows': return # Basic Windows 10 Dark Theme support. # Source: https://forum.qt.io/topic/101391/windows-10-dark-theme/4 themeSettings = QSettings( "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", QSettings.NativeFormat) if themeSettings.value("AppsUseLightTheme") == 0: darkPalette = QPalette() darkColor = QColor(45, 45, 45) disabledColor = QColor(127, 127, 127) darkPalette.setColor(QPalette.Window, darkColor) darkPalette.setColor(QPalette.WindowText, Qt.GlobalColor.white) darkPalette.setColor(QPalette.Base, QColor(18, 18, 18)) darkPalette.setColor(QPalette.AlternateBase, darkColor) darkPalette.setColor(QPalette.ToolTipBase, Qt.GlobalColor.white) darkPalette.setColor(QPalette.ToolTipText, Qt.GlobalColor.white) darkPalette.setColor(QPalette.Text, Qt.GlobalColor.white) darkPalette.setColor(QPalette.Disabled, QPalette.Text, disabledColor) darkPalette.setColor(QPalette.Button, darkColor) darkPalette.setColor(QPalette.ButtonText, Qt.GlobalColor.white) darkPalette.setColor(QPalette.Disabled, QPalette.ButtonText, disabledColor) darkPalette.setColor(QPalette.BrightText, Qt.GlobalColor.red) darkPalette.setColor(QPalette.Link, QColor(42, 130, 218)) darkPalette.setColor(QPalette.Highlight, QColor(42, 130, 218)) darkPalette.setColor(QPalette.HighlightedText, Qt.GlobalColor.black) darkPalette.setColor(QPalette.Disabled, QPalette.HighlightedText, disabledColor) # Fixes ugly (not to mention hard to read) disabled menu items. # Source: https://bugreports.qt.io/browse/QTBUG-10322?focusedCommentId=371060#comment-371060 darkPalette.setColor(QPalette.Disabled, QPalette.Light, Qt.GlobalColor.transparent) app.setPalette(darkPalette) # This broke the Settings Dialog at one point... and then it stopped breaking it. # TODO: Why'd it break? Check if tooltips look OK... and if not, make them look OK. #app.setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }") respectSystemDarkThemeSetting() QIcon.setThemeSearchPaths(QIcon.themeSearchPaths() + [appPath("icons")]) QIcon.setThemeName("NumixMsk") # Font siue if settings.contains("appFontSize"): f = qApp.font() f.setPointSize(settings.value("appFontSize", type=int)) app.setFont(f) # Main window from manuskript.mainWindow import MainWindow MW = MainWindow() # We store the system default cursor flash time to be able to restore it # later if necessary MW._defaultCursorFlashTime = qApp.cursorFlashTime() # Command line project if len(sys.argv) > 1 and sys.argv[1][-4:] == ".msk": if os.path.exists(sys.argv[1]): path = os.path.abspath(sys.argv[1]) MW._autoLoadProject = path return app, MW
def prepare(tests=False): app = QApplication(sys.argv) app.setOrganizationName("manuskript"+("_tests" if tests else "")) app.setOrganizationDomain("www.theologeek.ch") app.setApplicationName("manuskript"+("_tests" if tests else "")) app.setApplicationVersion(getVersion()) print("Running manuskript version {}.".format(getVersion())) icon = QIcon() for i in [16, 32, 64, 128, 256, 512]: icon.addFile(appPath("icons/Manuskript/icon-{}px.png".format(i))) qApp.setWindowIcon(icon) app.setStyle("Fusion") # Load style from QSettings settings = QSettings(app.organizationName(), app.applicationName()) if settings.contains("applicationStyle"): style = settings.value("applicationStyle") app.setStyle(style) # Translation process locale = QLocale.system().name() appTranslator = QTranslator(app) # By default: locale def extractLocale(filename): # len("manuskript_") = 13, len(".qm") = 3 return filename[11:-3] if len(filename) >= 16 else "" def tryLoadTranslation(translation, source): if appTranslator.load(appPath(os.path.join("i18n", translation))): app.installTranslator(appTranslator) print(app.tr("Loaded translation from {}: {}.").format(source, translation)) return True else: print(app.tr("Note: No translator found or loaded from {} for locale {}."). format(source, extractLocale(translation))) return False # Load translation from settings translation = "" if settings.contains("applicationTranslation"): translation = settings.value("applicationTranslation") print("Found translation in settings:", translation) if (translation != "" and not tryLoadTranslation(translation, "settings")) or translation == "": # load from settings failed or not set, fallback translation = "manuskript_{}.qm".format(locale) tryLoadTranslation(translation, "system locale") QIcon.setThemeSearchPaths(QIcon.themeSearchPaths() + [appPath("icons")]) QIcon.setThemeName("NumixMsk") # Font siue if settings.contains("appFontSize"): f = qApp.font() f.setPointSize(settings.value("appFontSize", type=int)) app.setFont(f) # Main window from manuskript.mainWindow import MainWindow MW = MainWindow() # We store the system default cursor flash time to be able to restore it # later if necessary MW._defaultCursorFlashTime = qApp.cursorFlashTime() # Command line project if len(sys.argv) > 1 and sys.argv[1][-4:] == ".msk": if os.path.exists(sys.argv[1]): path = os.path.abspath(sys.argv[1]) MW._autoLoadProject = path return app, MW
def logRuntimeInformation(logger=None): """Logs all important runtime information neatly together. Due to the generic nature, use the manuskript logger by default.""" if not logger: logger = logging.getLogger("manuskript") vt2s = versionTupleToString afom = attributesFromOptionalModule # Basic system information. from platform import python_version, platform, processor, machine logger.info("Operating System: %s", platform()) logger.info("Hardware: %s / %s", machine(), processor()) # Information about the running instance. See: # https://pyinstaller.readthedocs.io/en/v3.3.1/runtime-information.html # http://www.py2exe.org/index.cgi/Py2exeEnvironment # https://cx-freeze.readthedocs.io/en/latest/faq.html#data-files frozen = getattr(sys, 'frozen', False) if frozen: logger.info("Running in a frozen (packaged) state.") logger.debug("* sys.frozen = %s", pformat(frozen)) # PyInstaller, py2exe and cx_Freeze modules are not accessible while frozen, # so logging their version is (to my knowledge) impossible without including # special steps into the distribution process. But some traces do exist... logger.debug("* sys._MEIPASS = %s", getattr(sys, '_MEIPASS', "N/A")) # PyInstaller bundle # cx_Freeze and py2exe do not appear to leave anything similar exposed. else: logger.info("Running from unpackaged source code.") # File not found? These bits of information might help. logger.debug("* sys.executable = %s", pformat(sys.executable)) logger.debug("* sys.argv = %s", pformat(sys.argv)) logger.debug("* sys.path = %s", pformat(sys.path)) logger.debug("* sys.prefix = %s", pformat(sys.prefix)) # Manuskript and Python info. from manuskript.functions import getGitRevisionAsString, getManuskriptPath from manuskript.version import getVersion logger.info("Manuskript %s%s (Python %s)", getVersion(), getGitRevisionAsString(getManuskriptPath(), short=True), python_version()) # Installed Python packages. # PyQt + Qt from PyQt5.Qt import PYQT_VERSION_STR, qVersion from PyQt5.QtCore import QT_VERSION_STR logger.info("* PyQt %s (compiled against Qt %s)", PYQT_VERSION_STR, QT_VERSION_STR) logger.info(" * Qt %s (runtime)", qVersion()) # Lxml # See: https://lxml.de/FAQ.html#i-think-i-have-found-a-bug-in-lxml-what-should-i-do from lxml import etree logger.info("* lxml.etree %s", vt2s(etree.LXML_VERSION)) logger.info(" * libxml %s (compiled: %s)", vt2s(etree.LIBXML_VERSION), vt2s(etree.LIBXML_COMPILED_VERSION)) logger.info(" * libxslt %s (compiled: %s)", vt2s(etree.LIBXSLT_VERSION), vt2s(etree.LIBXSLT_COMPILED_VERSION)) # Spellcheckers. (Optional) enchant_mod_ver, enchant_lib_ver = afom("enchant", "__version__", "get_enchant_version") if enchant_lib_ver: enchant_lib_ver = enchant_lib_ver() if isinstance(enchant_lib_ver, bytes): # PyEnchant version < 3.0.2 enchant_lib_ver = enchant_lib_ver.decode('utf-8') logger.info("* pyEnchant %s (libenchant: %s)", enchant_mod_ver or "N/A", enchant_lib_ver or "N/A") logger.info("* pySpellChecker %s", afom("spellchecker", "__version__") or "N/A") logger.info("* Symspellpy %s", afom("symspellpy", "__version__") or "N/A") # Markdown. (Optional) logger.info("* Markdown %s", afom("markdown", "__version__") or "N/A") # Web rendering engine from manuskript.ui.views.webView import webEngine logger.info("Web rendering engine: %s", webEngine)