Exemple #1
0
 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)
Exemple #2
0
        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)
Exemple #3
0
 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)
Exemple #4
0
 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)
Exemple #5
0
    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)
Exemple #6
0
 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
Exemple #7
0
 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)
Exemple #8
0
 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)
Exemple #9
0
 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)
Exemple #10
0
 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))
Exemple #11
0
 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))
Exemple #12
0
 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)
Exemple #13
0
 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)
Exemple #14
0
 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)
Exemple #15
0
    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
Exemple #16
0
 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
Exemple #17
0
 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))
Exemple #18
0
 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))
Exemple #19
0
 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))
Exemple #20
0
 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'))
Exemple #21
0
 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)
Exemple #22
0
    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))
Exemple #23
0
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
Exemple #24
0
    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())
Exemple #25
0
    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())
Exemple #26
0
 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)
Exemple #27
0
 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))
Exemple #28
0
    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
Exemple #29
0
 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))
Exemple #30
0
    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()
Exemple #31
0
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)
Exemple #32
0
    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