def make_plugins(self): """ Package built-in plugins into ZIP archives. """ if isdir('@plugins/'): mkdir(os.path.join(self.build_exe, 'plugins')) for file_or_directory in os.listdir(expandPath('@plugins/')): plugin = os.path.join(expandPath('@plugins/'), file_or_directory) if isdir(plugin): distutils.log.info('packaging plugin: %s', file_or_directory) zippath = os.path.join(self.build_exe, 'plugins', '%s.zip' % file_or_directory) with zipfile.ZipFile(zippath, 'w', zipfile.ZIP_STORED) as zipf: for root, dirs, files in os.walk(plugin): if not root.endswith('__pycache__'): for filename in files: path = expandPath(os.path.join(root, filename)) if path.endswith('.py'): new_path = '%s.pyc' % rstrip(path, '.py') py_compile.compile(path, new_path) arcname = os.path.join(file_or_directory, os.path.relpath(new_path, plugin)) zipf.write(new_path, arcname) fremove(new_path) else: arcname = os.path.join(file_or_directory, os.path.relpath(path, plugin)) zipf.write(path, arcname)
def buildDMG(self): """ Build the DMG image. """ if not isdir('@support/createdmg') or not fexists('@support/createdmg/create-dmg'): raise OSError('unable to find create-dmg utility: please clone Eddy with all its submodules' ) if fexists(self.dmgName): os.unlink(self.dmgName) stagingDir = os.path.join(self.buildDir, 'tmp') if isdir(stagingDir): rmdir(stagingDir) self.mkpath(stagingDir) # Move the app bundle into a separate folder that will be used as source folder for the DMG image if subprocess.call(['cp', '-R', self.bundleDir, stagingDir]) != 0: raise OSError('could not move app bundle in staging directory') # We create the DMG disk image using the create-dmg submodule. params = [expandPath('@support/createdmg/create-dmg')] params.extend(['--volname', self.volume_label]) params.extend(['--text-size', '12']) params.extend(['--icon-size', '48']) params.extend(['--icon', '{0}.app'.format(self.bundleName), '60', '50']) params.extend(['--hide-extension', '{0}.app'.format(self.bundleName)]) if self.applications_shortcut: params.extend(['--app-drop-link', '60', '130']) if self.volume_background: if not fexists(self.volume_background): raise OSError('DMG volume background image not found at {0}'.format(self.volume_background)) print('Using DMG volume background: {0}'.format(self.volume_background)) from PIL import Image w, h = Image.open(self.volume_background).size params.extend(['--background', self.volume_background, '--window-size', str(w), str(h)]) if self.volume_icon: if not fexists(self.volume_icon): raise OSError('DMG volume icon not found at {0}'.format(self.volume_icon)) print('Using DMG volume icon: {0}'.format(self.volume_icon)) params.extend(['--volicon', self.volume_icon]) params.extend([self.dmgName, stagingDir]) subprocess.call(params) rmdir(stagingDir)
def doUpdateRecentProjects(self): """ Update the list of recent projects. """ # UPDATE THE RECENT PROJECT LIST recentList = [] settings = QtCore.QSettings() for path in map(expandPath, settings.value('project/recent', None, str) or []): if isdir(path): recentList.append(path) settings.setValue('project/recent', recentList) settings.sync() # CLEAR CURRENT LAYOUT for i in reversed(range(self.innerLayoutL.count())): item = self.innerLayoutL.itemAt(i) self.innerLayoutL.removeItem(item) # DISPOSE NEW PROJECT BLOCK if recentList: self.placeholder.setVisible(False) for path in recentList: project = ProjectBlock(path, self.innerWidgetL) connect(project.sgnDeleteProject, self.doDeleteProject) connect(project.sgnOpenProject, self.doOpenProject) connect(project.sgnRemoveProject, self.doRemoveProject) self.innerLayoutL.addWidget(project, 0, QtCore.Qt.AlignTop) else: self.placeholder.setVisible(True)
def import_plugin_from_directory(self, directory): """ Import a plugin from the given directory: * Lookup for the plugin .spec configuration file. * Search for the module where the plugin is implemented. * Search for the class implementing the plugin. * Import the plugin module. :type directory: str :rtype: tuple """ if isdir(directory): plugin_spec_path = os.path.join(directory, 'plugin.spec') if fexists(plugin_spec_path): try: LOGGER.debug('Found plugin .spec: %s', plugin_spec_path) plugin_spec = self.spec(fread(plugin_spec_path)) plugin_name = plugin_spec.get('plugin', 'id') for extension in ('.pyc', '.pyo', '.py'): plugin_path = os.path.join(directory, '%s%s' % (plugin_name, extension)) if fexists(plugin_path): LOGGER.debug('Found plugin module: %s', plugin_path) plugin_module = SourceFileLoader(plugin_name, plugin_path).load_module() plugin_class = self.find_class(plugin_module, plugin_name) return plugin_spec, plugin_class else: raise PluginError('missing plugin module: %s.py(c|o)' % os.path.join(directory, plugin_name)) except Exception as e: LOGGER.exception('Failed to import plugin: %s', e)
def find_spec(cls, file_or_directory): """ Searches the given file or directory for a 'plugin.spec' file and tries to load it, or returns 'None' if no such file exists. :type file_or_directory: str :rtype: PluginSpec """ file_or_directory = expandPath(file_or_directory) try: if os.path.exists(file_or_directory) and os.access( file_or_directory, os.R_OK): # READ SPEC FILE FROM DIRECTORY if isdir(file_or_directory): plugin_spec_path = os.path.join(file_or_directory, 'plugin.spec') if fexists(plugin_spec_path): return cls.spec(fread(plugin_spec_path)) # READ SPEC FILE FROM ZIP ARCHIVE elif is_zipfile(file_or_directory): zf = ZipFile(file_or_directory) zf_name_list = zf.namelist() if 'plugin.spec' in zf_name_list: plugin_spec_content = zf.read('plugin.spec').decode( 'utf8') return cls.spec(plugin_spec_content) except Exception as e: LOGGER.exception('Failed to load plugin spec: %s', e)
def scan(cls, *args, **kwargs): """ Scan the given paths looking for plugins. This method can also scan setuptools entry points when called with the 'entry_point' keyword argument set to the entry point name to scan. """ info = [] # SCAN THE GIVEN PATHS for base in map(expandPath, args): if isdir(base): LOGGER.info('Looking for plugins in %s', base) for file_or_directory in os.listdir(base): file_or_directory_path = os.path.join( base, file_or_directory) info.append( cls.import_plugin_from_path(file_or_directory_path)) # SCAN THEN GIVEN ENTRY POINTS if not hasattr(sys, 'frozen'): from pkg_resources import iter_entry_points entry_point_name = kwargs.get('entry_point', None) if entry_point_name: LOGGER.info('Looking for plugins in entry point %s', entry_point_name) for entry_point in iter_entry_points( group=os.path.basename(entry_point_name)): info.append( PluginManager.import_plugin_from_entry_point( entry_point)) # BUILD THE PLUGIN CACHE for entry in filter(None, info): plugin_id = entry[0].get('plugin', 'id') if plugin_id not in cls.info: cls.info[plugin_id] = entry
def import_plugin_from_directory(cls, directory): """ Import a plugin from the given directory: * Lookup for the plugin .spec configuration file. * Search for the module where the plugin is implemented. * Search for the class implementing the plugin. * Import the plugin module. :type directory: str :rtype: tuple """ if isdir(directory): plugin_spec_path = os.path.join(directory, 'plugin.spec') if fexists(plugin_spec_path): try: #LOGGER.debug('Found plugin .spec: %s', plugin_spec_path) plugin_spec = PluginManager.spec(fread(plugin_spec_path)) plugin_name = plugin_spec.get('plugin', 'id') for extension in ('.pyc', '.pyo', '.py'): plugin_path = os.path.join(directory, '%s%s' % (plugin_name, extension)) if fexists(plugin_path): #LOGGER.debug('Found plugin module: %s', plugin_path) plugin_module = SourceFileLoader(plugin_name, plugin_path).load_module() plugin_class = PluginManager.find_class(plugin_module, plugin_name) return plugin_spec, plugin_class else: raise PluginError('missing plugin module: %s.py(c|o)' % os.path.join(directory, plugin_name)) except Exception as e: LOGGER.exception('Failed to import plugin: %s', e)
def import_reasoner_from_directory(cls, directory): """ Import a reasoner from the given directory: * Lookup for the reasoner .spec configuration file. * Search for the module where the reasoner is implemented. * Search for the class implementing the reasoner. * Import the reasoner module. :type directory: str :rtype: tuple """ if isdir(directory): reasoner_spec_path = os.path.join(directory, 'reasoner.spec') if fexists(reasoner_spec_path): try: #LOGGER.debug('Found reasoner .spec: %s', reasoner_spec_path) reasoner_spec = ReasonerManager.spec(fread(reasoner_spec_path)) reasoner_name = reasoner_spec.get('reasoner', 'id') for extension in ('.pyc', '.pyo', '.py'): reasoner_path = os.path.join(directory, '%s%s' % (reasoner_name, extension)) if fexists(reasoner_path): #LOGGER.debug('Found reasoner module: %s', reasoner_path) reasoner_module = SourceFileLoader(reasoner_name, reasoner_path).load_module() reasoner_class = ReasonerManager.find_class(reasoner_module, reasoner_name) return reasoner_spec, reasoner_class else: raise ReasonerError('missing reasoner module: %s.py(c|o)' % os.path.join(directory, reasoner_name)) except Exception as e: LOGGER.exception('Failed to import reasoner: %s', e)
def doDeleteProject(self, path): """ Delete the given project. :type path: str """ msgbox = QtWidgets.QMessageBox(self) msgbox.setFont(Font('Roboto', 11)) msgbox.setIconPixmap( QtGui.QIcon(':/icons/48/ic_question_outline_black').pixmap(48)) msgbox.setInformativeText( '<b>NOTE: This action is not reversible!</b>') msgbox.setStandardButtons(QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Yes) msgbox.setTextFormat(QtCore.Qt.RichText) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('Remove project: {0}?'.format( os.path.basename(path))) msgbox.setText( 'Are you sure you want to remove project: <b>{0}</b>'.format( os.path.basename(path))) msgbox.exec_() if msgbox.result() == QtWidgets.QMessageBox.Yes: try: # REMOVE THE PROJECT FROM DISK rmdir(path) except Exception as e: msgbox = QtWidgets.QMessageBox(self) msgbox.setDetailedText(format_exception(e)) msgbox.setIconPixmap( QtGui.QIcon(':/icons/48/ic_error_outline_black').pixmap( 48)) msgbox.setStandardButtons(QtWidgets.QMessageBox.Close) msgbox.setTextFormat(QtCore.Qt.RichText) msgbox.setText( 'Eddy could not remove the specified project: <b>{0}</b>!'. format(os.path.basename(path))) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('ERROR!') msgbox.exec_() else: # UPDATE THE RECENT PROJECT LIST recentList = [] settings = QtCore.QSettings(ORGANIZATION, APPNAME) for path in map(expandPath, settings.value('project/recent')): if isdir(path): recentList.append(path) settings.setValue('project/recent', recentList) settings.sync() # CLEAR CURRENT LAYOUT for i in reversed(range(self.innerLayoutL.count())): item = self.innerLayoutL.itemAt(i) self.innerLayoutL.removeItem(item) # DISPOSE NEW PROJECT BLOCK for path in recentList: project = ProjectBlock(path, self.innerWidgetL) connect(project.sgnDeleteProject, self.doDeleteProject) connect(project.sgnOpenProject, self.doOpenProject) self.innerLayoutL.addWidget(project, 0, QtCore.Qt.AlignTop)
def start(self, options): """ Run the application by showing the welcome dialog. :type options: Namespace """ self.welcome = Welcome(self) self.welcome.show() if options.open and isdir(options.open): self.sgnCreateSession.emit(expandPath(options.open))
def uninstall(self, plugin): """ Uninstall the given plugin. :type plugin: AbstractPlugin """ if self.dispose(plugin): self.session.removePlugin(plugin) path = plugin.path() if isdir(path): rmdir(path) elif fexists(path): fremove(path)
def uninstall(self, reasoner): """ Uninstall the given reasoner. :type reasoner: AbstractReasoner """ if self.dispose(reasoner): self.session.removeReasoner(reasoner) path = reasoner.path() if isdir(path): rmdir(path) elif fexists(path): fremove(path)
def start(self): """ Run the application by showing the welcome dialog. """ # CONFIGURE THE WORKSPACE settings = QtCore.QSettings() workspace = expandPath(settings.value('workspace/home', WORKSPACE, str)) if not isdir(workspace): window = WorkspaceDialog() if window.exec_() == WorkspaceDialog.Rejected: raise SystemExit # PROCESS COMMAND LINE ARGUMENTS args = self.options.positionalArguments() if self.openFilePath: args.append(self.openFilePath) self.openFilePath = None # SHOW WELCOME DIALOG self.welcome = Welcome(self) self.welcome.show() # PROCESS ADDITIONAL COMMAND LINE OPTIONS if self.options.isSet(CommandLineParser.OPEN): value = self.options.value(CommandLineParser.OPEN) if value: project = os.path.join(workspace, value) if project and isdir(os.path.join(workspace, project)): self.sgnCreateSession.emit(project) else: LOGGER.warning('Unable to open project: %s', project) # POSITIONAL ARGUMENTS elif args: fname = expandPath(args[0]) if fexists(fname): project = os.path.dirname(fname) self.sgnCreateSession.emit(project) else: LOGGER.warning('Unable to open file: %s', fname) # COMPLETE STARTUP self.started = True
def stylesheet(self): """ Returns the stylesheet for this proxystyle. :rtype: str """ if not self._stylesheet: if hasattr(sys, 'frozen'): resources = expandPath('@resources/styles/') if isdir(resources): self._stylesheet = fread(os.path.join(resources, 'default.qss')) else: self._stylesheet = pkgutil.get_data(__name__, 'default.qss').decode('utf-8') return self._stylesheet
def scan(cls, *args): """ Scan the given paths looking for reasoners. """ info = [] for base in map(expandPath, args): if isdir(base): LOGGER.info('Looking for reasoners in %s', base) for file_or_directory in os.listdir(base): file_or_directory_path = os.path.join(base, file_or_directory) info.append(ReasonerManager.import_reasoner_from_directory(file_or_directory_path)) info.append(ReasonerManager.import_reasoner_from_zip(file_or_directory_path)) ReasonerManager.info = list(filter(None, info))
def lookup(self, base): """ Lookup for a plugin in the given base path. :type base: str :rtype: list """ info = [] if isdir(base): LOGGER.info('Looking for plugins in %s', base) for file_or_directory in os.listdir(base): file_or_directory_path = os.path.join(base, file_or_directory) info.append(self.import_plugin_from_directory(file_or_directory_path)) info.append(self.import_plugin_from_zip(file_or_directory_path)) return list(filter(None, info))
def scan(cls, *args): """ Scan the given paths looking for plugins. :type args: tuple """ info = [] for base in map(expandPath, args): if isdir(base): LOGGER.info('Looking for plugins in %s', base) for file_or_directory in os.listdir(base): file_or_directory_path = os.path.join(base, file_or_directory) info.append(PluginManager.import_plugin_from_directory(file_or_directory_path)) info.append(PluginManager.import_plugin_from_zip(file_or_directory_path)) PluginManager.info = list(filter(None, info))
def make_win32(self): """ Makes sure text files from directory have 'Windows style' end of lines. """ if sys.platform == 'win32': for root, dirs, files in os.walk(self.build_exe): for filename in files: path = expandPath(os.path.join(root, filename)) if not isdir(path) and path.rsplit('.', 1)[-1] in ('txt', 'md'): with open(path, mode='rb') as f: data = f.read() new_data = re.sub("\r?\n", "\r\n", data.decode(encoding='UTF-8')) if new_data != data: with open(path, mode='wb') as f: f.write(new_data.encode(encoding='UTF-8'))
def doDeleteProject(self, path): """ Delete the given project. :type path: str """ msgbox = QtWidgets.QMessageBox(self) msgbox.setFont(Font('Roboto', 11)) msgbox.setIconPixmap(QtGui.QIcon(':/icons/48/ic_question_outline_black').pixmap(48)) msgbox.setInformativeText('<b>NOTE: This action is not reversible!</b>') msgbox.setStandardButtons(QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Yes) msgbox.setTextFormat(QtCore.Qt.RichText) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('Remove project: {0}?'.format(os.path.basename(path))) msgbox.setText('Are you sure you want to remove project: <b>{0}</b>'.format(os.path.basename(path))) msgbox.exec_() if msgbox.result() == QtWidgets.QMessageBox.Yes: try: # REMOVE THE PROJECT FROM DISK rmdir(path) except Exception as e: msgbox = QtWidgets.QMessageBox(self) msgbox.setDetailedText(format_exception(e)) msgbox.setIconPixmap(QtGui.QIcon(':/icons/48/ic_error_outline_black').pixmap(48)) msgbox.setStandardButtons(QtWidgets.QMessageBox.Close) msgbox.setTextFormat(QtCore.Qt.RichText) msgbox.setText('Eddy could not remove the specified project: <b>{0}</b>!'.format(os.path.basename(path))) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('ERROR!') msgbox.exec_() else: # UPDATE THE RECENT PROJECT LIST recentList = [] settings = QtCore.QSettings(ORGANIZATION, APPNAME) for path in map(expandPath, settings.value('project/recent')): if isdir(path): recentList.append(path) settings.setValue('project/recent', recentList) settings.sync() # CLEAR CURRENT LAYOUT for i in reversed(range(self.innerLayoutL.count())): item = self.innerLayoutL.itemAt(i) self.innerLayoutL.removeItem(item) # DISPOSE NEW PROJECT BLOCK for path in recentList: project = ProjectBlock(path, self.innerWidgetL) connect(project.sgnDeleteProject, self.doDeleteProject) connect(project.sgnOpenProject, self.doOpenRecentProject) self.innerLayoutL.addWidget(project, 0, QtCore.Qt.AlignTop)
def make_jre(self): """ Bundles a Java Runtime Environment. """ if self.no_jre: distutils.log.info('Skip bundling of Java Runtime Environment in the distribution') return try: dest_dir = os.path.join(self.build_exe, 'resources', 'java', 'jre') if isdir(os.path.join(self.jre_dir, 'jre')): # Probably a JDK distribution self.jre_dir = os.path.join(self.jre_dir, 'jre') distutils.log.info("Copying JRE from {0}".format(self.jre_dir)) distutils.dir_util.copy_tree(self.jre_dir, os.path.join(self.build_exe, dest_dir)) except Exception as e: raise distutils.errors.DistutilsFileError('Failed to bundle JRE: {0}'.format(e))
def qapp(qapp_args, tmpdir_factory): """ Overrides pytest-qt default qapp fixture to provide an instance of Eddy. You can use the ``qapp`` fixture in tests which require a ``QApplication`` to run, but where you don't need full ``qtbot`` functionality. """ app = QtWidgets.QApplication.instance() if app is None: global _qapp_instance os.environ['JAVA_HOME'] = findJavaHome() or '' if IS_WIN: path = os.getenv('PATH', '') path = path.split(os.pathsep) # FOR JAVA 8 if isdir(os.path.join(os.environ['JAVA_HOME'], 'jre', 'bin')): bindir = os.path.join(os.environ['JAVA_HOME'], 'jre', 'bin') # FOR JAVA 9+ else: bindir = os.path.join(os.environ['JAVA_HOME'], 'bin') path.insert(0, bindir) if platform.architecture()[0] == '32bit': path.insert(0, os.path.join(bindir, 'client')) else: path.insert(0, os.path.join(bindir, 'server')) os.environ['PATH'] = os.pathsep.join(path) for path in pkg_resources.resource_listdir(eddy.core.jvm.__name__, 'lib'): if File.forPath(path) is File.Jar: addJVMClasspath(pkg_resources.resource_filename(eddy.core.jvm.__name__, os.path.join('lib', path))) # noinspection PyTypeChecker addJVMOptions('-ea', '-Xmx512m') _qapp_instance = Eddy(qapp_args) workspace_tmpdir = tmpdir_factory.mktemp('settings') QtCore.QSettings.setPath(QtCore.QSettings.NativeFormat, QtCore.QSettings.UserScope, str(workspace_tmpdir)) settings = QtCore.QSettings() settings.setValue('workspace/home', str(workspace_tmpdir)) settings.setValue('update/check_on_startup', False) _qapp_instance.configure() yield _qapp_instance else: yield app
def doAcceptForm(self): """ Validate project settings. """ caption = '' enabled = True ############################################# # CHECK NAME ################################# if not self.name(): caption = '' enabled = False else: if isdir(self.path()): caption = "Project '{0}' already exists!".format(self.name()) enabled = False elif not isPathValid(self.path()): caption = "'{0}' is not a valid project name!".format( self.name()) enabled = False ############################################# # CHECK PREFIX ################################# if enabled: #if not self.prefix(): if not self.prefixes(): caption = '' enabled = False ############################################# # CHECK IRI ################################# if enabled: if not self.iri(): caption = '' enabled = False self.caption.setText(caption) self.caption.setVisible(not isEmpty(caption)) self.confirmationBox.button( QtWidgets.QDialogButtonBox.Ok).setEnabled(enabled) self.setFixedSize(self.sizeHint())
def doProjectPathValidate(self): """ Validate project settings. """ caption = '' enabled = True ############################################# # CHECK NAME ################################# name = self.nameField.value() path = self.pathField.value() if not name: caption = '' enabled = False else: if isdir(path): caption = "Project '{0}' already exists!".format(name) enabled = False elif not isPathValid(path): caption = "'{0}' is not a valid project name!".format(name) enabled = False ############################################# # CHECK PREFIX ################################# if enabled: if not self.prefixField.value(): caption = '' enabled = False ############################################# # CHECK IRI ################################# if enabled: if not self.iriField.value(): caption = '' enabled = False self.caption.setText(caption) self.caption.setVisible(not isEmpty(caption)) self.confirmationBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(enabled) self.setFixedSize(self.sizeHint())
def createProjectFile(self): """ Serialize a previously created QDomDocument to disk. """ try: currPath = self.exportPath if self.exportPath else self.project.path if not fexists(currPath): folderPath = os.path.dirname(currPath) if not isdir(folderPath): mkdir(folderPath) fd = os.open(currPath, os.O_CREAT) os.close(fd) #TODO filename = postfix(self.project.name, File.Graphol.extension) #TODO filepath = os.path.join(self.project.path, filename) #TODO fwrite(self.document.toString(2), filepath) fwrite(self.document.toString(2), currPath) except Exception as e: raise e else: LOGGER.info('Saved project %s to %s', self.project.name, currPath)
def assertDirectoryExists(self, dirpath, msg=None): """Assert for the given path to represent a file""" if not isdir(dirpath): standardMsg = '%s is not a directory' % safe_repr(expandPath(dirpath)) self.fail(self._formatMessage(msg, standardMsg))
def configure(self, options): """ Perform initial configuration tasks for Eddy to work properly. :type options: Namespace """ ############################################# # DRAW THE SPLASH SCREEN ################################# splash = None if not options.nosplash: splash = Splash(mtime=4) splash.show() ############################################# # CONFIGURE RECENT PROJECTS ################################# settings = QtCore.QSettings(ORGANIZATION, APPNAME) examples = [ expandPath('@examples/Animals'), expandPath('@examples/Diet'), expandPath('@examples/Family'), expandPath('@examples/LUBM'), expandPath('@examples/Pizza'), ] if not settings.contains('project/recent'): # From PyQt5 documentation: if the value of the setting is a container (corresponding # to either QVariantList, QVariantMap or QVariantHash) then the type is applied to the # contents of the container. So we can't use an empty list as default value because # PyQt5 needs to know the type of the contents added to the collection: we avoid # this problem by placing the list of example projects as recent project list. settings.setValue('project/recent', examples) else: # If we have some projects in our recent list, check whether they exists on the # filesystem. If they do not exists we remove them from our recent list. projects = [] for path in map(expandPath, settings.value('project/recent')): if isdir(path) and path not in projects: projects.append(path) settings.setValue('project/recent', projects or examples) settings.sync() ############################################# # CONFIGURE FONTS ################################# fontDB = QtGui.QFontDatabase() fontDB.addApplicationFont(':/fonts/Roboto-Black') fontDB.addApplicationFont(':/fonts/Roboto-BlackItalic') fontDB.addApplicationFont(':/fonts/Roboto-Bold') fontDB.addApplicationFont(':/fonts/Roboto-BoldItalic') fontDB.addApplicationFont(':/fonts/Roboto-Italic') fontDB.addApplicationFont(':/fonts/Roboto-Light') fontDB.addApplicationFont(':/fonts/Roboto-LightItalic') fontDB.addApplicationFont(':/fonts/Roboto-Medium') fontDB.addApplicationFont(':/fonts/Roboto-MediumItalic') fontDB.addApplicationFont(':/fonts/Roboto-Regular') fontDB.addApplicationFont(':/fonts/Roboto-Thin') fontDB.addApplicationFont(':/fonts/Roboto-ThinItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Bold') fontDB.addApplicationFont(':/fonts/RobotoCondensed-BoldItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Italic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Light') fontDB.addApplicationFont(':/fonts/RobotoCondensed-LightItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Regular') fontDB.addApplicationFont(':/fonts/RobotoMono-Bold') fontDB.addApplicationFont(':/fonts/RobotoMono-BoldItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Italic') fontDB.addApplicationFont(':/fonts/RobotoMono-Light') fontDB.addApplicationFont(':/fonts/RobotoMono-LightItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Medium') fontDB.addApplicationFont(':/fonts/RobotoMono-MediumItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Regular') fontDB.addApplicationFont(':/fonts/RobotoMono-Thin') fontDB.addApplicationFont(':/fonts/RobotoMono-ThinItalic') self.setFont(Font('Roboto', 12)) ############################################# # CONFIGURE LAYOUT ################################# buffer = '' resources = expandPath('@resources/styles/') for name in os.listdir(resources): path = os.path.join(resources, name) if fexists(path) and File.forPath(path) is File.Qss: buffer += fread(path) self.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps) self.setStyle(EddyProxyStyle('Fusion')) self.setStyleSheet(buffer) ############################################# # CLOSE THE SPLASH SCREEN ################################# if splash and not options.nosplash: splash.sleep() splash.close() ############################################# # CONFIGURE THE WORKSPACE ################################# workspace = expandPath(settings.value('workspace/home', WORKSPACE, str)) if not isdir(workspace): window = WorkspaceDialog() if window.exec_() == WorkspaceDialog.Rejected: raise SystemExit
def assertDirectoryExists(self, dirpath, msg=None): """Assert for the given path to represent a file""" if not isdir(dirpath): standardMsg = '%s is not a directory' % safe_repr( expandPath(dirpath)) self.fail(self._formatMessage(msg, standardMsg))
def configure(self): """ Perform initial configuration tasks for Eddy to work properly. """ ############################################# # CONFIGURE FONTS ################################# fontDB = QtGui.QFontDatabase() fonts = QtCore.QDirIterator(':/fonts/') while fonts.hasNext(): fontDB.addApplicationFont(fonts.next()) # FONT SUBSTITUTIONS QtGui.QFont.insertSubstitution('Sans Serif', 'Roboto') QtGui.QFont.insertSubstitution('Monospace', 'Roboto Mono') # APPLICATION DEFAULT FONT self.setFont(Font('Roboto', pixelSize=12)) ############################################# # CONFIGURE LAYOUT ################################# style = EddyProxyStyle('Fusion') self.setStyle(style) self.setStyleSheet(style.stylesheet) ############################################# # DRAW THE SPLASH SCREEN ################################# splash = None if not self.options.isSet(CommandLineParser.NO_SPLASH): splash = Splash(mtime=2) splash.show() ############################################# # CONFIGURE RECENT PROJECTS ################################# settings = QtCore.QSettings() if not settings.contains('project/recent'): # From PyQt5 documentation: if the value of the setting is a container (corresponding # to either QVariantList, QVariantMap or QVariantHash) then the type is applied to the # contents of the container. So we can't use an empty list as default value because # PyQt5 needs to know the type of the contents added to the collection: we avoid # this problem by placing the list of example projects as recent project list. examples = list( filter(lambda path: isdir(path), [ expandPath('@examples/Animals'), expandPath('@examples/Diet'), expandPath('@examples/Family'), expandPath('@examples/LUBM'), expandPath('@examples/Pizza'), ])) settings.setValue('project/recent', examples) else: # If we have some projects in our recent list, check whether they exists on the # filesystem. If they do not exists we remove them from our recent list. projects = [] for path in map(expandPath, settings.value('project/recent', None, str) or []): if isdir(path) and path not in projects: projects.append(path) settings.setValue('project/recent', projects) settings.sync() ############################################# # LOOKUP PLUGINS ################################# PluginManager.scan('@plugins/', '@home/plugins/') ############################################# # CLOSE THE SPLASH SCREEN ################################# if splash and not self.options.isSet(CommandLineParser.NO_SPLASH): splash.sleep() splash.close()
def main(): """ Application entry point. """ ############################################# # SETUP EXCEPTION HOOK ################################# sys.excepthook = base_except_hook ############################################# # PARSE ARGUMENTS AND CREATE THE APPLICATION ################################# # ENABLE HIGH-DPI SUPPORT QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps) QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_Use96Dpi) global app app = Eddy(sys.argv) if app.isRunning(): sys.exit(0) ############################################# # JVM SETUP ################################# JAVA_HOME = findJavaHome() if not JAVA_HOME or not os.path.isdir(JAVA_HOME): settings = QtCore.QSettings() shouldDisplayDialog = settings.value('dialogs/noJVM') if not shouldDisplayDialog: # CHECKBOX CALLBACK def checkboxStateChanged(state): settings.setValue('dialogs/noJVM', state == QtCore.Qt.Checked) settings.sync() chkbox = QtWidgets.QCheckBox("Don't show this warning again.") msgbox = QtWidgets.QMessageBox() #msgbox.setIconPixmap(QtGui.QPixmap(':/images/eddy-sad')) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('Missing Java Runtime Environment') msgbox.setText('Unable to locate a valid Java installation on your system.') msgbox.setInformativeText('<p>Some features in {0} require access to a <br/>' '<a href="{1}">Java Runtime Environment</a> ' 'and will not be available if you continue.</p>' '<p>You can download a copy of the Java Runtime Environment ' 'from the <a href={2}>Java Downloads</a> page.</p>' .format(APPNAME, 'https://www.java.com/download', 'https://www.oracle.com/technetwork/java/javase/downloads/index.html')) msgbox.setStandardButtons(QtWidgets.QMessageBox.Abort | QtWidgets.QMessageBox.Ok) msgbox.setDefaultButton(QtWidgets.QMessageBox.Abort) msgbox.setCheckBox(chkbox) buttonOk = msgbox.button(QtWidgets.QMessageBox.Ok) buttonOk.setText('Continue without JRE') buttonQuit = msgbox.button(QtWidgets.QMessageBox.Abort) buttonQuit.setText('Quit {0}'.format(APPNAME)) # noinspection PyArgumentList buttonQuit.clicked.connect(app.doQuit, QtCore.Qt.QueuedConnection) connect(chkbox.stateChanged, checkboxStateChanged) ret = msgbox.exec_() if ret == QtWidgets.QMessageBox.Abort: return 1 ############################################# # BEGIN ENVIRONMENT SPECIFIC SETUP ################################# os.environ['JAVA_HOME'] = JAVA_HOME or '' # ADD THE DIRECTORY CONTAINING JVM.DLL TO THE PATH VARIABLE ON WINDOWS if IS_WIN: path = os.getenv('PATH', '') path = path.split(os.pathsep) # FOR JAVA 8 if isdir(os.path.join(os.environ['JAVA_HOME'], 'jre', 'bin')): bindir = os.path.join(os.environ['JAVA_HOME'], 'jre', 'bin') # FOR JAVA 9+ else: bindir = os.path.join(os.environ['JAVA_HOME'], 'bin') path.insert(0, bindir) if platform.architecture()[0] == '32bit': path.insert(0, os.path.join(bindir, 'client')) else: path.insert(0, os.path.join(bindir, 'server')) os.environ['PATH'] = os.pathsep.join(path) # SET CLASSPATH AND OPTIONS if IS_FROZEN: resources = expandPath('@resources/lib/') if isdir(resources): for name in os.listdir(resources): path = os.path.join(resources, name) if os.path.isfile(path): addJVMClasspath(path) else: from pkg_resources import resource_filename, resource_listdir for path in resource_listdir(eddy.core.jvm.__name__, 'lib'): if File.forPath(path) is File.Jar: addJVMClasspath(resource_filename(eddy.core.jvm.__name__, os.path.join('lib', path))) addJVMOptions('-Xmx512m', '-XX:+DisableExplicitGC') ############################################# # START THE APPLICATION ################################# LOGGER.separator(separator='-') LOGGER.frame('%s v%s', APPNAME, VERSION, separator='|') LOGGER.frame(COPYRIGHT, separator='|') LOGGER.separator(separator='-') LOGGER.frame('OS: %s %s', platform.system(), platform.release(), separator='|') LOGGER.frame('Python version: %s', platform.python_version(), separator='|') LOGGER.frame('Qt version: %s', QtCore.QT_VERSION_STR, separator='|') LOGGER.frame('PyQt version: %s', QtCore.PYQT_VERSION_STR, separator='|') LOGGER.frame('SIP version: %s', sip.SIP_VERSION_STR, separator='|') LOGGER.separator(separator='-') app.configure() app.start() ret = app.exec_() if ret == Eddy.RestartCode: nargs = [] if os.path.basename(sys.argv[0]) == 'eddy': # LAUNCHED VIA LAUNCHER SCRIPT nargs.append(sys.argv[0]) elif IS_FROZEN: # LAUNCHED FROM DISTRIBUTION EXECUTABLE nargs.append(sys.executable) else: # LAUNCHED VIA THE INTERPRETER nargs.extend([sys.executable, sys.argv[0]]) nargs.extend(sys.argv[1:]) subprocess.Popen(nargs) sys.exit(ret)
def configure(self, options): """ Perform initial configuration tasks for Eddy to work properly. :type options: Namespace """ ############################################# # DRAW THE SPLASH SCREEN ################################# splash = None if not options.nosplash: splash = Splash(mtime=4) splash.show() ############################################# # CONFIGURE RECENT PROJECTS ################################# settings = QtCore.QSettings(ORGANIZATION, APPNAME) examples = [ expandPath('@examples/Animals'), expandPath('@examples/Diet'), expandPath('@examples/Family'), expandPath('@examples/LUBM'), expandPath('@examples/Pizza'), ] if not settings.contains('project/recent'): # From PyQt5 documentation: if the value of the setting is a container (corresponding # to either QVariantList, QVariantMap or QVariantHash) then the type is applied to the # contents of the container. So we can't use an empty list as default value because # PyQt5 needs to know the type of the contents added to the collection: we avoid # this problem by placing the list of example projects as recent project list. settings.setValue('project/recent', examples) else: # If we have some projects in our recent list, check whether they exists on the # filesystem. If they do not exists we remove them from our recent list. projects = [] for path in map(expandPath, settings.value('project/recent')): if isdir(path) and path not in projects: projects.append(path) settings.setValue('project/recent', projects or examples) settings.sync() ############################################# # CONFIGURE FONTS ################################# fontDB = QtGui.QFontDatabase() fontDB.addApplicationFont(':/fonts/Roboto-Black') fontDB.addApplicationFont(':/fonts/Roboto-BlackItalic') fontDB.addApplicationFont(':/fonts/Roboto-Bold') fontDB.addApplicationFont(':/fonts/Roboto-BoldItalic') fontDB.addApplicationFont(':/fonts/Roboto-Italic') fontDB.addApplicationFont(':/fonts/Roboto-Light') fontDB.addApplicationFont(':/fonts/Roboto-LightItalic') fontDB.addApplicationFont(':/fonts/Roboto-Medium') fontDB.addApplicationFont(':/fonts/Roboto-MediumItalic') fontDB.addApplicationFont(':/fonts/Roboto-Regular') fontDB.addApplicationFont(':/fonts/Roboto-Thin') fontDB.addApplicationFont(':/fonts/Roboto-ThinItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Bold') fontDB.addApplicationFont(':/fonts/RobotoCondensed-BoldItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Italic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Light') fontDB.addApplicationFont(':/fonts/RobotoCondensed-LightItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Regular') fontDB.addApplicationFont(':/fonts/RobotoMono-Bold') fontDB.addApplicationFont(':/fonts/RobotoMono-BoldItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Italic') fontDB.addApplicationFont(':/fonts/RobotoMono-Light') fontDB.addApplicationFont(':/fonts/RobotoMono-LightItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Medium') fontDB.addApplicationFont(':/fonts/RobotoMono-MediumItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Regular') fontDB.addApplicationFont(':/fonts/RobotoMono-Thin') fontDB.addApplicationFont(':/fonts/RobotoMono-ThinItalic') self.setFont(Font('Roboto', 12)) ############################################# # CONFIGURE LAYOUT ################################# buffer = '' resources = expandPath('@resources/styles/') for name in os.listdir(resources): path = os.path.join(resources, name) if fexists(path) and File.forPath(path) is File.Qss: buffer += fread(path) self.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps) self.setStyle(EddyProxyStyle('Fusion')) self.setStyleSheet(buffer) ############################################# # LOOKUP PLUGINS ################################# PluginManager.scan('@plugins/', '@home/plugins/') ############################################# # CLOSE THE SPLASH SCREEN ################################# if splash and not options.nosplash: splash.sleep() splash.close() ############################################# # CONFIGURE THE WORKSPACE ################################# workspace = expandPath(settings.value('workspace/home', WORKSPACE, str)) if not isdir(workspace): window = WorkspaceDialog() if window.exec_() == WorkspaceDialog.Rejected: raise SystemExit