Ejemplo n.º 1
0
def DataFactory(path, mimetype=None, **kwargs):
    path = Path(path)
    default_content = kwargs[
        'default_content'] if 'default_content' in kwargs else None
    dtype = kwargs.pop('dtype', None)

    if path.isfile():
        if default_content is not None:
            raise ValueError(
                "got multiple values for content (parameter and '%s')" %
                path.name)
        else:
            path, mimetype = arrange_data_args(path, mimetype, dtype)
            klass = DataClass(mimetype)
            return klass(path=path, mimetype=mimetype)
    elif path.exists():
        raise ValueError("'%s' exists but is not a file" % path)
    elif not path.exists():
        if default_content is None:
            default_content = b''
        try:
            f = path.open('wb')
        except IOError:
            content = default_content
        else:
            f.write(default_content)
            f.close()
            content = None

        path, mimetype = arrange_data_args(path, mimetype, dtype)
        klass = DataClass(mimetype)
        return klass(path=path, mimetype=mimetype, content=content)
Ejemplo n.º 2
0
    def load(self, name, projectdir=None, **kwargs):
        """
        Load existing project

        :use:
            >>> project1 = project_manager.load('project1')
            >>> project2 = project_manager.load('project2', '/path/to/project') # doctest: +SKIP

        :param name: name of project to load. Must be a string.
        :param projectdir: path of project to load. Must be a path (see module path.py).
                           By default, try to guess with name only.
                           If there are various projects with the same name, return the first.
        :return: Project
        """
        project = None
        if 'proj_path' in kwargs:
            projectdir = kwargs['proj_path']
        elif 'path' in kwargs:
            projectdir = kwargs['path']

        if not projectdir:
            try:
                project = self.item(name)
            except UnknownItemError:
                pass
        else:
            full_path = Path(projectdir) / name
            if full_path.exists():
                project = Project(full_path)
            else:
                print 'Project %s in repository %s does not exist' % (name, projectdir)

        if project:
            self.cproject = project
            return self.cproject
Ejemplo n.º 3
0
    def discover(self, config_name='oaproject.cfg'):
        """
        Discover projects from your disk and put them in self.projects.

        Projects are not loaded, only metadata are.

        :use:
            >>> project_manager.discover()
            >>> list_of_projects = project_manager.projects

        To discover new projects, you can add path into *self.repositories*

        .. code-block:: python

            project_manager.repositories.append('path/to/search/projects')
            project_manager.discover()
        """
        projects = {}
        for _path in self.repositories:
            _path = Path(_path)
            if not _path.exists():
                continue
            for p in _path.walkfiles(config_name):
                project = Project(p.parent)
                projects[project.path] = project
        self.projects = projects.values()
Ejemplo n.º 4
0
def DataFactory(path, mimetype=None, **kwargs):
    path = Path(path)
    default_content = kwargs['default_content'] if 'default_content' in kwargs else None
    dtype = kwargs.pop('dtype', None)

    if path.isfile():
        if default_content is not None:
            raise ValueError(
                "got multiple values for content (parameter and '%s')" % path.name)
        else:
            path, mimetype = arrange_data_args(path, mimetype, dtype)
            klass = DataClass(mimetype)
            return klass(path=path, mimetype=mimetype)
    elif path.exists():
        raise ValueError("'%s' exists but is not a file" % path)
    elif not path.exists():
        if default_content is None:
            default_content = b''
        try:
            f = path.open('wb')
        except IOError:
            content = default_content
        else:
            f.write(default_content)
            f.close()
            content = None

        path, mimetype = arrange_data_args(path, mimetype, dtype)
        klass = DataClass(mimetype)
        return klass(path=path, mimetype=mimetype, content=content)
Ejemplo n.º 5
0
 def load(self, filename):
     """
     :param filename: filename to convert into python object
     :return: a python object interpreted from string "text"
     """
     filename = Path(filename)
     if filename.exists():
         obj = open(filename, 'rU').read()
         return obj
Ejemplo n.º 6
0
def list_colormaps():
    colormap_names = []
    colormaps_path = Path(shared_data(openalea.oalab, 'colormaps/grey.lut')).parent

    for colormap_file in colormaps_path.walkfiles('*.lut'):
        colormap_name = str(colormap_file.name[:-4])
        colormap_names.append(colormap_name)
    colormap_names.sort()
    return colormap_names
Ejemplo n.º 7
0
 def load(self, filename):
     """
     :param filename: filename to convert into python object
     :return: a python object interpreted from string "text"
     """
     filename = Path(filename)
     if filename.exists():
         obj = open(filename, 'rU').read()
         return obj
Ejemplo n.º 8
0
def list_colormaps():
    colormap_names = []
    colormaps_path = Path(shared_data(openalea.oalab,
                                      'colormaps/grey.lut')).parent

    for colormap_file in colormaps_path.walkfiles('*.lut'):
        colormap_name = str(colormap_file.name[:-4])
        colormap_names.append(colormap_name)
    colormap_names.sort()
    return colormap_names
Ejemplo n.º 9
0
def load_colormaps():
    from openalea.oalab.colormap.colormap_utils import Colormap, colormap_from_file
    colormaps = {}
    colormaps_path = Path(shared_data(openalea.oalab, 'colormaps/grey.lut')).parent

    for colormap_file in colormaps_path.walkfiles('*.lut'):
        colormap_name = str(colormap_file.name[:-4])
        colormaps[colormap_name] = colormap_from_file(
            colormap_file, name=colormap_name)
    return colormaps
Ejemplo n.º 10
0
    def _rename_item(self, category, old, new):
        pold = Path(old)
        pnew = Path(new)
        if pold.isabs() or pnew.isabs() or pnew.name != new or pold.name != old:
            raise ValueError('You must give filename only, not path')

        new_path = self.path / category / new
        data = self.get_item(category, old)
        data.move(new_path)
        self._remove_item(category, filename=old)
        self._add_item(category, data)
Ejemplo n.º 11
0
    def _rename_item(self, category, old, new):
        pold = Path(old)
        pnew = Path(new)
        if pold.isabs() or pnew.isabs() or pnew.name != new or pold.name != old:
            raise ValueError('You must give filename only, not path')

        new_path = self.path / category / new
        data = self.get_item(category, old)
        data.move(new_path)
        self._remove_item(category, filename=old)
        self._add_item(category, data)
Ejemplo n.º 12
0
def load_colormaps():
    from openalea.oalab.colormap.colormap_utils import Colormap, colormap_from_file
    colormaps = {}
    colormaps_path = Path(shared_data(openalea.oalab,
                                      'colormaps/grey.lut')).parent

    for colormap_file in colormaps_path.walkfiles('*.lut'):
        colormap_name = str(colormap_file.name[:-4])
        colormaps[colormap_name] = colormap_from_file(colormap_file,
                                                      name=colormap_name)
    return colormaps
Ejemplo n.º 13
0
    def _open_file(self, path):
        filename = Path(path)
        if filename.isdir():
            print 'BUG: filename is a dir'
            return

        try:
            file_ = open(filename, "w")
        except IOError:
            newdir, fn = filename.splitpath()
            if not Path(newdir).isdir():
                newdir.makedirs()
            file_ = open(filename, "w")
        return file_
Ejemplo n.º 14
0
 def load(self, filename):
     """
     :param filename: filename to convert into python object
     :return: a python object interpreted from string "text"
     """
     filename = Path(filename)
     if filename.exists():
         obj = open(filename, 'rU').read()
         try:
             return eval(obj)
         except SyntaxError:
             return obj
         except NameError:
             return obj
Ejemplo n.º 15
0
    def _open_file(self, path):
        filename = Path(path)
        if filename.isdir():
            print 'BUG: filename is a dir'
            return

        try:
            file_ = open(filename, "w")
        except IOError:
            newdir, fn = filename.splitpath()
            if not Path(newdir).isdir():
                newdir.makedirs()
            file_ = open(filename, "w")
        return file_
Ejemplo n.º 16
0
 def load(self, filename):
     """
     :param filename: filename to convert into python object
     :return: a python object interpreted from string "text"
     """
     filename = Path(filename)
     if filename.exists():
         obj = open(filename, 'rU').read()
         try:
             return eval(obj)
         except SyntaxError:
             return obj
         except NameError:
             return obj
Ejemplo n.º 17
0
def qicon(filename):
    if filename is None:
        return QtGui.QIcon(get_shared_data('icons/oxygen_application-x-desktop.png'))
    if filename.startswith(':/'):
        return QtGui.QIcon(filename)
    else:
        path = Path(filename)
        if not path.isfile():
            path = get_shared_data(filename)
            if path is None:
                path = get_shared_data('icons/%s' % filename)

        if path:
            return QtGui.QIcon(path)
        else:
            return QtGui.QIcon(":/images/resources/%s" % filename)
Ejemplo n.º 18
0
 def load(self, filename):
     """
     :param filename: filename to convert into python object
     :return: a python object interpreted from string "text"
     """
     filename = Path(filename)
     if filename.exists():
         try:
             from openalea.plantgl.all import Scene
             sc = Scene()
             sc.clear()
             sc.read(str(filename), "BGEOM")
             return sc
         except ImportError:
             warnings.warn("You must install PlantGL if you want to load a BGEOM object.")
         except Exception, e:
             print e
             warnings.warn("Impossible to load the scene")
Ejemplo n.º 19
0
def arrange_path(path, path_class=Path):
    u"""
    Return a Path, FilePath or DirPath dependings on path nature.
    Path is used for special path like device "files" or path not existing on disk.
    If path is empty, returns None.

    If path do not exists on disk or is not file nor directory
    (like /dev/xyz on linux),it return a path_class.
    """
    if not path:
        return None
    path = Path(unicode(path))
    if path.isfile():
        return FilePath(path)
    elif path.isdir():
        return DirPath(path)
    else:
        return path_class(path)
Ejemplo n.º 20
0
def arrange_path(path, path_class=Path):
    """
    Return a Path, FilePath or DirPath dependings on path nature.
    Path is used for special path like device "files" or path not existing on disk.
    If path is empty, returns None.

    If path do not exists on disk or is not file nor directory
    (like /dev/xyz on linux),it return a path_class.
    """
    if not path:
        return None
    path = Path(str(path))
    if path.isfile():
        return FilePath(path)
    elif path.isdir():
        return DirPath(path)
    else:
        return path_class(path)
Ejemplo n.º 21
0
    def search_path():
        """
        Return a list of all path containing projects
        """
        repositories = set()

        # 1. Add default user project dir
        repositories.add(Path(settings.get_project_dir()))

        # 2. Add project repositories defined by packages
        for plugin in plugins(
                'oalab.plugin',
                criteria=dict(implement="ProjectRepositoryList")):
            for repository in plugin():
                repositories.add(repository)

        # 3. Read repositories defined by users and saved in config
        config = settings.Settings()
        lst = list(repositories)
        try:
            s = config.get("ProjectManager", "Path")
            lst = eval(s, {"path": Path})
        except NoSectionError:
            config.add_section("ProjectManager")
            config.add_option("ProjectManager", "Path",
                              str([str(path) for path in lst]))
        except NoOptionError:
            config.add_option("ProjectManager", "Path",
                              str([str(path) for path in lst]))

        for repo in lst:
            repositories.add(repo)

        # Remove all paths to directories that don't exist
        final_list = set()
        for p in repositories:
            p = Path(p).abspath()
            if not p.isdir():
                continue
            final_list.add(p)

        return list(final_list)
Ejemplo n.º 22
0
    def save(self, obj, path, protocol=None, **kwds):
        mode = kwds.pop('mode', 'all')

        path = Path(path)
        config_filename = kwds.get('config_filename', 'oaproject.cfg')
        config_path = path / config_filename

        if mode == 'all':
            if not path.exists():
                path.makedirs()
            self._save_metadata(obj, config_path)
            lines = self._save_controls(obj)
            with open(path / 'control.py', 'w') as f:
                for line in lines:
                    f.write(line)
        elif mode == 'metadata':
            if path.exists():
                self._save_metadata(obj, config_path)
        else:
            raise NotImplementedError('mode=%s' % mode)
Ejemplo n.º 23
0
    def save(self, obj, path, protocol=None, **kwds):
        mode = kwds.pop('mode', 'all')

        path = Path(path)
        config_filename = kwds.get('config_filename', 'oaproject.cfg')
        config_path = path / config_filename

        if mode == 'all':
            if not path.exists():
                path.makedirs()
            self._save_metadata(obj, config_path)
            lines = self._save_controls(obj)
            with open(path / 'control.py', 'w') as f:
                for line in lines:
                    f.write(line)
        elif mode == 'metadata':
            if path.exists():
                self._save_metadata(obj, config_path)
        else:
            raise NotImplementedError('mode=%s' % mode)
Ejemplo n.º 24
0
 def load(self, filename):
     """
     :param filename: filename to convert into python object
     :return: a python object interpreted from string "text"
     """
     filename = Path(filename)
     if filename.exists():
         try:
             from openalea.plantgl.all import Scene
             sc = Scene()
             sc.clear()
             sc.read(str(filename), "BGEOM")
             return sc
         except ImportError:
             warnings.warn(
                 "You must install PlantGL if you want to load a BGEOM object."
             )
         except Exception, e:
             print e
             warnings.warn("Impossible to load the scene")
Ejemplo n.º 25
0
def _normpath(path):
    """
    Replace all symlink in path with real path and return its absolute path
    For example, if given path is "local/bin/python" and "local" is a symbolic link to "/usr/local",
    returned path will be "/usr/local/bin/python"
    """
    if hasattr(os, 'readlink'):
        parts = Path(path).splitall()
        _path = Path('')
        for p in parts:
            _path = _path / p
            if _path.islink():
                # readlink return an absolute path or relative path depending on symlink.
                # If symlink is a relative link, parent path is used to generate an absolute path
                # Default path behaviour when concatenating two absolute paths is to keep only second one:
                # path('/a/1')/path('/b/2') -> path('/b/2')
                # So, if symlink is absolute, all is ok
                _path = _path.parent / _path.readlink()
        return _path.abspath()
    else:
        return path.abspath()
Ejemplo n.º 26
0
def _normpath(path):
    """
    Replace all symlink in path with real path and return its absolute path
    For example, if given path is "local/bin/python" and "local" is a symbolic link to "/usr/local",
    returned path will be "/usr/local/bin/python"
    """
    if hasattr(os, 'readlink'):
        parts = Path(path).splitall()
        _path = Path('')
        for p in parts:
            _path = _path / p
            if _path.islink():
                # readlink return an absolute path or relative path depending on symlink.
                # If symlink is a relative link, parent path is used to generate an absolute path
                # Default path behaviour when concatenating two absolute paths is to keep only second one:
                # path('/a/1')/path('/b/2') -> path('/b/2')
                # So, if symlink is absolute, all is ok
                _path = _path.parent / _path.readlink()
        return _path.abspath()
    else:
        return path.abspath()
Ejemplo n.º 27
0
def MimeType(path=None, name=None):
    """
    Return mimetype for path.
    First, try to find extension in registery filled by models.
    If datatype is not found, use builtin module "mimetypes".
    If it cannot guess, returns False.

    Search in module allows to specify
    """
    if path:
        name = Path(path).ext[1:].lower()
        if name in REGISTERY_NAME_MIME:
            return REGISTERY_NAME_MIME[name]
        else:
            mtype, encoding = mimetypes.guess_type(path)
            return mtype
    else:
        name = name.lower()
        if name in REGISTERY_NAME_MIME:
            return REGISTERY_NAME_MIME[name]
        else:
            return False
Ejemplo n.º 28
0
def MimeType(path=None, name=None):
    """
    Return mimetype for path.
    First, try to find extension in registery filled by models.
    If datatype is not found, use builtin module "mimetypes".
    If it cannot guess, returns False.

    Search in module allows to specify
    """
    if path:
        name = Path(path).ext[1:].lower()
        if name in REGISTERY_NAME_MIME:
            return REGISTERY_NAME_MIME[name]
        else:
            mtype, encoding = mimetypes.guess_type(path)
            return mtype
    else:
        name = name.lower()
        if name in REGISTERY_NAME_MIME:
            return REGISTERY_NAME_MIME[name]
        else:
            return False
Ejemplo n.º 29
0
 def load(self, filename):
     """
     :param filename: filename to convert into python object
     :return: a python object interpreted from filename
     """
     filename = Path(filename)
     if filename.exists():
         cpik = "False"
         try:
             import cPickle
             cpik = "True"
         except ImportError:
             warnings.warn("You must install cPickle.")
         if cpik:
             try:
                 file_ = open(filename, "r")
                 ret = cPickle.load(file_)
                 file_.close()
                 return ret
             except Exception, e:
                 print "Can't load file " + filename + " with loader CPickleLoader. "
                 print e
Ejemplo n.º 30
0
 def load(self, filename):
     """
     :param filename: filename to convert into python object
     :return: a python object interpreted from filename
     """
     filename = Path(filename)
     if filename.exists():
         cpik = "False"
         try:
             import cPickle
             cpik = "True"
         except ImportError:
             warnings.warn("You must install cPickle.")
         if cpik:
             try:
                 file_ = open(filename, "r")
                 ret = cPickle.load(file_)
                 file_.close()
                 return ret
             except Exception, e:
                 print "Can't load file " + filename + " with loader CPickleLoader. "
                 print e
Ejemplo n.º 31
0
    def search_path():
        """
        Return a list of all path containing projects
        """
        repositories = set()

        # 1. Add default user project dir
        repositories.add(Path(settings.get_project_dir()))

        # 2. Add project repositories defined by packages
        for plugin in plugins('oalab.plugin', criteria=dict(implement="ProjectRepositoryList")):
            for repository in plugin():
                repositories.add(repository)

        # 3. Read repositories defined by users and saved in config
        config = settings.Settings()
        lst = list(repositories)
        try:
            s = config.get("ProjectManager", "Path")
            lst = eval(s, {"path": Path})
        except NoSectionError:
            config.add_section("ProjectManager")
            config.add_option("ProjectManager", "Path", str([str(path) for path in lst]))
        except NoOptionError:
            config.add_option("ProjectManager", "Path", str([str(path) for path in lst]))

        for repo in lst:
            repositories.add(repo)

        # Remove all paths to directories that don't exist
        final_list = set()
        for p in repositories:
            p = Path(p).abspath()
            if not p.isdir():
                continue
            final_list.add(p)

        return list(final_list)
Ejemplo n.º 32
0
    def __init__(self, **kwargs):
        """
        Classical use : *path* exists. Nothing is loaded in memory.
        Use :meth:`~Data.read` to get content
        """
        # TODO: document args
        self.path = Path(kwargs.pop('path')) if 'path' in kwargs else None
        self._filename = Path(kwargs.pop('filename')).name if 'filename' in kwargs else None

        if self._filename is None and self.path is None:
            raise ValueError('path or filename required')
        if self._filename and self.path and self.path.name != self._filename:
            raise ValueError("path '%s'  and filename '%s' are not compatible" % (self.path, self._filename))

        self.dtype = kwargs.pop('dtype', None)
        self._content = kwargs.pop('content', None)
        self.mimetype = kwargs.pop('mimetype', None)
Ejemplo n.º 33
0
    def _load_layout(self, layout=None, **kwds):
        layout_file = kwds.pop('layout_file', self.DEFAULT_LAYOUT_PATH)
        default_layout = kwds.pop('default_layout', self.DEFAULT_LAYOUT)

        self.layout_filepath = Path(layout_file).abspath()
        if layout is None:
            if self.layout_filepath.exists():
                with open(self.layout_filepath) as layout_file:
                    content = layout_file.read()
                    try:
                        layout = json.loads(content)
                    except ValueError:
                        l = eval(content)
                        layout = dict(children=l[0], parents=l[1], properties=l[2])

        if layout is None:
            layout = default_layout
        return layout
Ejemplo n.º 34
0
    def _load_layout(self, layout=None, **kwds):
        layout_file = kwds.pop('layout_file', self.DEFAULT_LAYOUT_PATH)
        default_layout = kwds.pop('default_layout', self.DEFAULT_LAYOUT)

        self.layout_filepath = Path(layout_file).abspath()
        if layout is None:
            if self.layout_filepath.exists():
                with open(self.layout_filepath) as layout_file:
                    content = layout_file.read()
                    try:
                        layout = json.loads(content)
                    except ValueError:
                        l = eval(content)
                        layout = dict(children=l[0], parents=l[1], properties=l[2])

        if layout is None:
            layout = default_layout
        return layout
Ejemplo n.º 35
0
def compile_ui_files(module, import_instructions=None):
    """
    Reads recursively all *.py files in root directory looking for
    "generate_pyfile_from_uifile" calls.
    If this call is found, execute it in order to compile ui file.

    import_instructions : python code containing required imports.
    example :

    >>> import_instructions = 'from openalea.plantgl.gui.qt.designer import generate_pyfile_from_uifile\n'

    if None, uses default imports : generate_pyfile_from_uifile, Path, hardbook and get_data
    """
    import ast
    from openalea.core import codegen

    if import_instructions is None:
        import_instructions = "from openalea.plantgl.gui.qt.designer import generate_pyfile_from_uifile\n"

    module = __import__(module)
    paths = []
    for root in module.__path__:
        root = Path(root)
        for py in root.walkfiles('*.py'):
            paths.append((root, py))

    for root, py in paths:
        f = open(py)
        lines = f.readlines()
        f.close()

        code = ''.join(lines)
        try:
            r = ast.parse(code)
        except SyntaxError:
            print('SYNTAX ERROR: cannot read ...', py)
        else:
            for instr in r.body:
                if isinstance(instr, ast.Expr):
                    value = instr.value
                    if isinstance(value, ast.Call):
                        try:
                            func_name = value.func.id
                        except AttributeError:
                            pass
                        else:
                            if func_name == 'generate_pyfile_from_uifile':
                                true = ast.parse('True').body[0]

                                for keyword in value.keywords:
                                    if keyword.arg == 'force':
                                        keyword.value = true
                                        break
                                else:
                                    value.keywords.append(ast.keyword('force', true))
                                src = codegen.to_source(instr)

                                if py.startswith('./') or py.startswith('.\\'):
                                    py = Path(py[2:])
                                name = replaceext(root.parent.relpathto(py), '').replace(os.sep, '.')
                                src = src.replace('__name__', repr(name))
                                try:
                                    code = compile(import_instructions + src, "<string>", "exec")
                                    exec(code)
                                except Exception as e:
                                    print(repr(e))
                                    print('COMPILATION ERROR: cannot compile', py)
                                    print()
Ejemplo n.º 36
0
def compile_ui_files(module, import_instructions=None):
    """
    Reads recursively all *.py files in root directory looking for
    "generate_pyfile_from_uifile" calls.
    If this call is found, execute it in order to compile ui file.

    import_instructions : python code containing required imports.
    example :

    >>> import_instructions = 'from openalea.vpltk.qt.designer import generate_pyfile_from_uifile\n'

    if None, uses default imports : generate_pyfile_from_uifile, Path, hardbook and get_data
    """
    import ast
    from openalea.core import codegen

    if import_instructions is None:
        import_instructions = "from openalea.vpltk.qt.designer import generate_pyfile_from_uifile\n"

    module = __import__(module)
    paths = []
    for root in module.__path__:
        root = Path(root)
        for py in root.walkfiles('*.py'):
            paths.append((root, py))

    for root, py in paths:
        f = open(py)
        lines = f.readlines()
        f.close()

        code = ''.join(lines)
        try:
            r = ast.parse(code)
        except SyntaxError:
            print 'SYNTAX ERROR: cannot read ...', py
        else:
            for instr in r.body:
                if isinstance(instr, ast.Expr):
                    value = instr.value
                    if isinstance(value, ast.Call):
                        try:
                            func_name = value.func.id
                        except AttributeError:
                            pass
                        else:
                            if func_name == 'generate_pyfile_from_uifile':
                                true = ast.parse('True').body[0]

                                for keyword in value.keywords:
                                    if keyword.arg == 'force':
                                        keyword.value = true
                                        break
                                else:
                                    value.keywords.append(ast.keyword('force', true))
                                src = codegen.to_source(instr)

                                if py.startswith('./') or py.startswith('.\\'):
                                    py = Path(py[2:])
                                name = replaceext(root.parent.relpathto(py), '').replace(os.sep, '.')
                                src = src.replace('__name__', repr(name))
                                try:
                                    code = compile(import_instructions + src, "<string>", "exec")
                                    exec code
                                except Exception as e:
                                    print repr(e)
                                    print 'COMPILATION ERROR: cannot compile', py
                                    print
Ejemplo n.º 37
0
class OALabMainWin(QtGui.QMainWindow):
    appletSet = QtCore.Signal(object, object)
    DEFAULT_MENU_NAMES = ('File', 'Edit', 'View', 'Help')

    DEFAULT_LAYOUT = dict(
        name='default',
        alias='Default Layout',
        children={},
        parents={0: None},
        properties={
            0: {
                'widget': {
                    'properties': {'position': 0},
                    'applets': [{'name': 'ShellWidget'}]
                }
            }}
    )
    DEFAULT_LAYOUT_PATH = 'layout.oaui'
    LAB = None

    def __init__(self, layout=None, **kwds):
        QtGui.QMainWindow.__init__(self)
        self._lab = kwds.get('lab', None)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)

        self.DEFAULT_MENU_NAMES = list(self.DEFAULT_MENU_NAMES)
        if 'Edit' not in self.DEFAULT_MENU_NAMES:
            self.DEFAULT_MENU_NAMES.insert(0, 'Edit')
        if 'File' not in self.DEFAULT_MENU_NAMES:
            self.DEFAULT_MENU_NAMES.insert(0, 'File')
        if 'Help' not in self.DEFAULT_MENU_NAMES:
            self.DEFAULT_MENU_NAMES.append('Help')

        # Classic menu
        self._registered_applets = []

        self._create_menus()
        self._create_actions()
        self._pre_fill_menus()

        self._splittable_list = []

        self.layout_selector = LayoutSelector(parent=self)
        layout = self._load_layout(layout, **kwds)
        if isinstance(layout, (list, tuple)):
            layouts = layout
        else:
            layouts = [layout]

        for layout in layouts:
            title = layout.get('title', None)
            if 'children' not in layout:
                layout = None
            splittable = OALabSplittableUi(parent=self)
            splittable.setAttribute(QtCore.Qt.WA_DeleteOnClose)
            splittable.appletSet.connect(self.appletSet.emit)
            self.appletSet.connect(self._on_applet_set)
            if layout is None:
                container = AppletContainer()
                splittable.setContentAt(0, container)
            else:
                splittable.fromJSON(layout)
            self._splittable_list.append(splittable)
            self.layout_selector.add_widget(splittable, title=title)

        self.setCentralWidget(self.layout_selector)
        self._post_fill_menus()
        self.set_edit_mode(False)

        QtGui.QApplication.instance().focusChanged.connect(self._on_focus_changed)

    def emit_applet_set(self):
        self.splittable.emit_applet_set()

    @property
    def splittable(self):
        return self.layout_selector.widget()

    def _create_menus(self):
        self.menu_classic = {}
        menubar = QtGui.QMenuBar()
        self.setMenuBar(menubar)
        for menu_name in self.DEFAULT_MENU_NAMES:
            self.menu_classic[menu_name] = menubar.addMenu(menu_name)

    def _create_actions(self):
        self.action_edit = QtGui.QAction("Edit Layout", self.menu_classic['Edit'])
        self.action_edit.setCheckable(True)
        self.action_edit.toggled.connect(self.set_edit_mode)
        self.action_edit.setChecked(False)

        icon = QtGui.QApplication.style().standardIcon(QtGui.QStyle.SP_TitleBarCloseButton)
        self.action_quit = QtGui.QAction(icon, "Quit application", self.menu_classic['File'])
        self.action_quit.triggered.connect(self.close)
        self.action_quit.setChecked(False)

    def _pre_fill_menus(self):
        self.menu_classic['Edit'].addAction(self.action_edit)

    def _post_fill_menus(self):
        self.menu_classic['File'].addSeparator()
        self.menu_classic['File'].addAction(self.action_quit)

    def _load_layout(self, layout=None, **kwds):
        layout_file = kwds.pop('layout_file', self.DEFAULT_LAYOUT_PATH)
        default_layout = kwds.pop('default_layout', self.DEFAULT_LAYOUT)

        self.layout_filepath = Path(layout_file).abspath()
        if layout is None:
            if self.layout_filepath.exists():
                with open(self.layout_filepath) as layout_file:
                    content = layout_file.read()
                    try:
                        layout = json.loads(content)
                    except ValueError:
                        l = eval(content)
                        layout = dict(children=l[0], parents=l[1], properties=l[2])

        if layout is None:
            layout = default_layout
        return layout

    def _save_layout(self):
        with open(self.layout_filepath, 'w') as layout_file:
            json.dump(self.layout(), layout_file, sort_keys=True, indent=2)

    def closeEvent(self, event):
        close = True

        # If a lab is used, check if it can be close
        if hasattr(self._lab, 'readytoclose'):
            close = self._lab.readytoclose()

        # If lab is not ready, stop closing
        if close is False:
            event.ignore()
            return

        # If lab is ready to close, or no lab is used, close widget
        if self.splittable.close():
            if hasattr(self._lab, 'finalize'):
                self._lab.finalize()
            self._save_layout()
            if hasattr(self._lab, 'stop'):
                self._lab.stop()
            event.accept()
        else:
            event.ignore()

    def set_edit_mode(self, mode=True):
        for widget in self.splittable.getAllContents():
            if hasattr(widget, 'set_edit_mode'):
                widget.set_edit_mode(mode)
        if mode is True and self.LAB:
            print self.LAB.connections
        self.splittable.set_edit_mode(mode)

    def initialize(self):
        self.pm = PluginManager()
        for instance in plugin_instances('oalab.applet'):
            if hasattr(instance, 'initialize'):
                instance.initialize()

    def _widget_actions(self, obj):
        actions = None
        if hasattr(obj, 'toolbar_actions'):
            if isinstance(obj.toolbar_actions, list):
                actions = obj.toolbar_actions
            else:
                actions = obj.toolbar_actions()

        if actions is None:
            return []
        else:
            return actions

    def _widget_name(self, obj):
        if hasattr(obj, 'name'):
            return obj.name

    def _on_focus_changed(self, old, new):
        self.clear_toolbar()
        if old is new:
            return

        # Generally focus is on "leaf" widget on widget hierarchy.
        # We try to browse all tree to get widget defining actions
        # For example, if an editor is defined as MyEditor -> Container -> Editor -> QTextEdit
        # Widget with focus is QTextEdit but widget that define actions is MyEditor
        # Search stops if widget has no more parents or if widget is AppletContainer
        parent = new
        actions = self._widget_actions(parent)
        name = self._widget_name(parent)
        while parent is not None:
            try:
                parent = parent.parent()
            except TypeError:
                break
            else:
                if isinstance(parent, AppletContainer):
                    break
                name = name or self._widget_name(parent)
                actions += self._widget_actions(parent)

        if actions:
            self.fill_toolbar(name, actions)

        # toolbar creation/destruction set focus to toolbar so we reset it to widget
        if isinstance(new, QtGui.QWidget):
            new.setFocus(QtCore.Qt.OtherFocusReason)

    def fill_toolbar(self, name, actions):
        menus = plugin_instances('oalab.applet', 'ContextualMenu')
        for menu in menus:
            menu.set_actions(name, actions)

    def clear_toolbar(self):
        menus = plugin_instances('oalab.applet', 'ContextualMenu')
        for menu in menus:
            menu.clear()

    def _merge_menus(self, menus):
        parent = self
        default_menus = self.menu_classic
        menubar = self.menuBar()

        for _menu in menus:
            menu_name = _menu.title()
            if menu_name in default_menus:
                menu = default_menus[menu_name]
            else:
                menu = QtGui.QMenu(menu_name, parent)
                default_menus[menu_name] = menu
                menubar.addMenu(menu)

        for _menu in menus:
            menu_name = _menu.title()
            menu = default_menus[menu_name]
            for action in _menu.actions():
                if isinstance(action, QtGui.QAction):
                    menu.addAction(action)
                elif isinstance(action, QtGui.QMenu):
                    menu.addMenu(action)
                elif action == '-':
                    menu.addSeparator()

    def _on_applet_set(self, old, new):
        if new in self._registered_applets:
            return

        self._registered_applets.append(new)
        applet = plugin_instance('oalab.applet', new)

        # Add global menus
        if applet and hasattr(applet, 'menus'):
            menus = applet.menus()
            if menus is None:
                return
            self._merge_menus(menus)

        # Add global toolbars
        if applet and hasattr(applet, 'toolbars'):
            toolbars = applet.toolbars()
            if toolbars is None:
                return
            for toolbar in toolbars:
                self.addToolBar(QtCore.Qt.TopToolBarArea, toolbar)

    def layout(self):
        return self.splittable._repr_json_()
Ejemplo n.º 38
0
    def _add_item(self, category, obj=None, **kwargs):
        mode = kwargs.pop('mode', self.MODE_COPY)
        if obj and isinstance(obj, Data):
            # TODO: Check obj follow Data or Model interface ??
            new_path = self.path / category / obj.path.name
            if obj.path != new_path and mode == self.MODE_COPY:
                # TODO: use Data.copy instead
                return self._add_item(category, path=obj.path, **kwargs)

            category_dict = getattr(self, category)
            if obj.filename not in category_dict:
                category_dict[str(obj.filename)] = obj
            else:
                raise ValueError("data '%s' already exists in project '%s'" % (obj.filename, self.alias))
        elif obj:
            category_dict = getattr(self, category)
            if obj.name not in category_dict:
                category_dict[str(obj.name)] = obj
            else:
                raise ValueError("data '%s' already exists in project '%s'" % (obj.name, self.alias))
        else:
            filename = Path(kwargs.pop('filename')) if 'filename' in kwargs else None
            content = kwargs.pop('content', None)
            dtype = kwargs.pop('dtype', None)
            mimetype = kwargs.pop('mimetype', None)
            path = Path(kwargs.pop('path')) if 'path' in kwargs else None
            # If project path exists, ie project exists on disk,
            # Create category dir if necessary
            category_path = self.path / category
            if self.path.exists() and not category_path.exists():
                category_path.makedirs()

            if filename:
                new_path = self.path / category / filename.name
            elif path:
                if not path.exists():
                    raise ErrorInvalidItem("path '%s' doesn't exists" % path)
                filename = path.name
                new_path = self.path / category / filename
            else:
                raise ValueError("path or filename required")

            if path is None:
                path = new_path

            # If data was outside project, we try to fix it.
            # If mode is "prefer copy", we try to copy file inside project
            # If copy fails, we get original content and pass it to new data
            # If mode is "prefer link", we just keep original path (keep outside project)
            # TODO: Move to Data.copy
            data_obj = None
            if new_path.abspath() != path.abspath() and mode == self.MODE_COPY:
                try:
                    path.copyfile(new_path)
                except IOError:
                    data_obj = DataFactory(path, mimetype, dtype=dtype, default_content=content)
                    content = data_obj.read()
                else:
                    content = None
            elif new_path.abspath() != path.abspath() and mode == self.MODE_LINK:
                new_path = path
            else:
                pass
                # Nothing to do, data is yet in the right place

            data_obj = DataFactory(new_path, mimetype, dtype=dtype, default_content=content)
            obj = self._add_item(category, data_obj, **kwargs)

        obj.package = self
        return obj
Ejemplo n.º 39
0
def generate_pyfile_from_uifile(name, src=None, dest=None, uibasename=None, force=None):
    """
    Function searches ...

    if src is None, search in this order :
      - <moduledir>/designer/<modulename>.ui
      - <moduledir>/resources/<modulename>.ui
      - <moduledir>/<modulename>.ui
    else :
      - src

    File generated is
    if dest is None :
      - _<uifilebase>.py (Ex: mywdget.ui -> _mywidget.py)
    else :
      - dest

    .. warning ::

      To work, this function has to be called in an **imported** module.
      (__name__ must differ from __main__) else, nothing is done !

      Do not edit generated file because all data written here are lost.

    :param name:
    :type name: str

    :return: Qt class (corresponding to filename), Qt type class (type of first value)
    :rtype: couple
    """
    if force is None:
        force = FORCE_UI_GENERATION
    modulename = name
    if uibasename:
        name = uibasename
    else:
        name = name.split('.')[-1]
    if modulename == '__main__':
        return
    paths = []
    if src:
        filepath = Path(src)
        paths.append(filepath)
    else:
        path = 'designer/%s.ui' % name
        filepath = Path(get_data(modulename, path))
        paths.append(filepath)

        path = 'resources/%s.ui' % name
        filepath = Path(get_data(modulename, path))
        paths.append(filepath)

        path = '%s.ui' % name
        filepath = Path(get_data(modulename, path))
        paths.append(filepath)

    for path in paths:
        if path.isfile():
            break

#  tmpdir = mkdtempu()
    if dest is None:
        pyfilename = path.parent / '_' + path.name.replace('.ui', '.py')
    else:
        pyfilename = Path(dest)

    if not pyfilename.exists():
        generate = True
    else:
        mtime_py = mtime_datetime(pyfilename)
        mtime_ui = mtime_datetime(path)
        if mtime_py > mtime_ui:
            # If py file is more recent than ui, check user has not changed QT_API
            with open(pyfilename, 'r') as f:
                content = f.read()
                generate = QT_MODULE_NAME not in content
        else:
            generate = True

    if generate or force:
        module_dir = str(path.parent)
        if module_dir not in sys.path:
            sys.path.append(module_dir)

        if force:
            print 'build %s from %s\n' % (pyfilename, path)
        else:
            print '%s has changed, build %s\n' % (path, pyfilename)

        pyfile = open(pyfilename, 'w')
        compileUi(path, pyfile, **compile_args)
        pyfile.close()
Ejemplo n.º 40
0
def generate_pyfile_from_uifile(name, src=None, dest=None, uibasename=None, force=None):
    """
    Function searches ...

    if src is None, search in this order :
      - <moduledir>/designer/<modulename>.ui
      - <moduledir>/resources/<modulename>.ui
      - <moduledir>/<modulename>.ui
    else :
      - src

    File generated is
    if dest is None :
      - _<uifilebase>.py (Ex: mywdget.ui -> _mywidget.py)
    else :
      - dest

    .. warning ::

      To work, this function has to be called in an **imported** module.
      (__name__ must differ from __main__) else, nothing is done !

      Do not edit generated file because all data written here are lost.

    :param name:
    :type name: str

    :return: Qt class (corresponding to filename), Qt type class (type of first value)
    :rtype: couple
    """
    if force is None:
        force = FORCE_UI_GENERATION
    modulename = name
    if uibasename:
        name = uibasename
    else:
        name = name.split('.')[-1]
    if modulename == '__main__':
        return
    paths = []
    if src:
        filepath = Path(src)
        paths.append(filepath)
    else:
        path = 'designer/%s.ui' % name
        filepath = Path(get_data(modulename, path))
        paths.append(filepath)

        path = 'resources/%s.ui' % name
        filepath = Path(get_data(modulename, path))
        paths.append(filepath)

        path = '%s.ui' % name
        filepath = Path(get_data(modulename, path))
        paths.append(filepath)

    for path in paths:
        if path.isfile():
            break

#  tmpdir = mkdtempu()
    if dest is None:
        pyfilename = path.parent / '_' + path.name.replace('.ui', '.py')
    else:
        pyfilename = Path(dest)

    if not pyfilename.exists():
        generate = True
    else:
        mtime_py = mtime_datetime(pyfilename)
        mtime_ui = mtime_datetime(path)
        if mtime_py > mtime_ui:
            # If py file is more recent than ui, check user has not changed QT_API
            with open(pyfilename, 'r') as f:
                content = f.read()
                generate = QT_MODULE_NAME not in content
        else:
            generate = True

    if generate or force:
        module_dir = str(path.parent)
        if module_dir not in sys.path:
            sys.path.append(module_dir)

        if force:
            print('build %s from %s\n' % (pyfilename, path))
        else:
            print('%s has changed, build %s\n' % (path, pyfilename))

        pyfile = open(pyfilename, 'w')
        compileUi(path, pyfile, **compile_args)
        pyfile.close()
Ejemplo n.º 41
0
class Data(object):
    mimetype = None
    default_name = 'Data'
    default_file_name = "filename.ext"
    pattern = "*.ext"
    extension = "ext"
    icon = "Crystal_Clear_app_kcmdf.png"

    def __init__(self, **kwargs):
        """
        Classical use : *path* exists. Nothing is loaded in memory.
        Use :meth:`~Data.read` to get content
        """
        # TODO: document args
        self.path = Path(kwargs.pop('path')) if 'path' in kwargs else None
        self._filename = Path(kwargs.pop('filename')).name if 'filename' in kwargs else None

        if self._filename is None and self.path is None:
            raise ValueError('path or filename required')
        if self._filename and self.path and self.path.name != self._filename:
            raise ValueError("path '%s'  and filename '%s' are not compatible" % (self.path, self._filename))

        self.dtype = kwargs.pop('dtype', None)
        self._content = kwargs.pop('content', None)
        self.mimetype = kwargs.pop('mimetype', None)

    def get_documentation(self):
        return "No documentation for %s" % self.filename

    def is_same_data(self, other):
        if self.exists() and other.exists():
            return self.path == other.path
        elif not self.exists() and not other.exists():
            return self._content == other._content
        else:
            return False

    def save(self):
        if self.path is None:
            raise ValueError('You must specify a path to be able to save data')
        if self._content is not None:
            with open(self.path, 'wb') as f:
                f.write(self._content)
            self._content = None

    def read(self):
        if self.exists():
            with open(self.path, 'rb') as f:
                return f.read()
        else:
            return self._content

    def rename(self, new):
        pnew = Path(new)
        if pnew.isabs() or pnew.name != new:
            raise ValueError('You must give filename only, not path')
        new_path = self.path.parent / new
        self.move(new_path)

    def move(self, new_path):
        new_path = Path(new_path)
        if self._filename is not None:
            self._filename = new_path.name

        if self.path.isfile():
            self.path.move(new_path)

        self.path = new_path

    def exists(self):
        if self.path:
            return self.path.exists()
        else:
            return False

    @property
    def filename(self):
        if self._filename is None:
            return self.path.name
        else:
            return self._filename

    @property
    def name(self):
        return self.filename

    @filename.setter
    def filename(self, value):
        self._filename = value

    def _set_content(self, content):
        self._content = content

    def _get_content(self):
        if self._content is None:
            return self.read()
        else:
            return self._content

    content = property(fget=_get_content, fset=_set_content)
    code = property()
Ejemplo n.º 42
0
    def _add_item(self, category, obj=None, **kwargs):
        mode = kwargs.pop('mode', self.MODE_COPY)
        if obj and isinstance(obj, Data):
            # TODO: Check obj follow Data or Model interface ??
            new_path = self.path / category / obj.path.name
            if obj.path != new_path and mode == self.MODE_COPY:
                # TODO: use Data.copy instead
                return self._add_item(category, path=obj.path, **kwargs)

            category_dict = getattr(self, category)
            if obj.filename not in category_dict:
                category_dict[str(obj.filename)] = obj
            else:
                raise ValueError("data '%s' already exists in project '%s'" %
                                 (obj.filename, self.alias))
        elif obj:
            category_dict = getattr(self, category)
            if obj.name not in category_dict:
                category_dict[str(obj.name)] = obj
            else:
                raise ValueError("data '%s' already exists in project '%s'" %
                                 (obj.name, self.alias))
        else:
            filename = Path(
                kwargs.pop('filename')) if 'filename' in kwargs else None
            content = kwargs.pop('content', None)
            dtype = kwargs.pop('dtype', None)
            mimetype = kwargs.pop('mimetype', None)
            path = Path(kwargs.pop('path')) if 'path' in kwargs else None
            # If project path exists, ie project exists on disk,
            # Create category dir if necessary
            category_path = self.path / category
            if self.path.exists() and not category_path.exists():
                category_path.makedirs()

            if filename:
                new_path = self.path / category / filename.name
            elif path:
                if not path.exists():
                    raise ErrorInvalidItem("path '%s' doesn't exists" % path)
                filename = path.name
                new_path = self.path / category / filename
            else:
                raise ValueError("path or filename required")

            if path is None:
                path = new_path

            # If data was outside project, we try to fix it.
            # If mode is "prefer copy", we try to copy file inside project
            # If copy fails, we get original content and pass it to new data
            # If mode is "prefer link", we just keep original path (keep outside project)
            # TODO: Move to Data.copy
            data_obj = None
            if new_path.abspath() != path.abspath() and mode == self.MODE_COPY:
                try:
                    path.copyfile(new_path)
                except IOError:
                    data_obj = DataFactory(path,
                                           mimetype,
                                           dtype=dtype,
                                           default_content=content)
                    content = data_obj.read()
                else:
                    content = None
            elif new_path.abspath() != path.abspath(
            ) and mode == self.MODE_LINK:
                new_path = path
            else:
                pass
                # Nothing to do, data is yet in the right place

            data_obj = DataFactory(new_path,
                                   mimetype,
                                   dtype=dtype,
                                   default_content=content)
            obj = self._add_item(category, data_obj, **kwargs)

        obj.package = self
        return obj
Ejemplo n.º 43
0
class OALabMainWin(QtGui.QMainWindow):
    appletSet = QtCore.Signal(object, object)
    DEFAULT_MENU_NAMES = ('File', 'Edit', 'View', 'Help')

    DEFAULT_LAYOUT = dict(
        name='default',
        label='Default Layout',
        children={},
        parents={0: None},
        properties={
            0: {
                'widget': {
                    'properties': {'position': 0},
                    'applets': [{'name': 'ShellWidget'}]
                }
            }}
    )
    DEFAULT_LAYOUT_PATH = 'layout.oaui'
    LAB = None

    def __init__(self, layout=None, **kwds):
        QtGui.QMainWindow.__init__(self)
        self.autosave = kwds.get('autosave', False)
        self._lab = kwds.get('lab', None)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)

        self.DEFAULT_MENU_NAMES = list(self.DEFAULT_MENU_NAMES)
        if 'Edit' not in self.DEFAULT_MENU_NAMES:
            self.DEFAULT_MENU_NAMES.insert(0, 'Edit')
        if 'File' not in self.DEFAULT_MENU_NAMES:
            self.DEFAULT_MENU_NAMES.insert(0, 'File')
        if 'Help' not in self.DEFAULT_MENU_NAMES:
            self.DEFAULT_MENU_NAMES.append('Help')

        # Classic menu
        self._registered_applets = []

        self._create_menus()
        self._create_actions()
        self._pre_fill_menus()

        self._splittable_list = []

        self.layout_selector = LayoutSelector(parent=self)
        layout = self._load_layout(layout, **kwds)
        if isinstance(layout, (list, tuple)):
            layouts = layout
        else:
            layouts = [layout]

        for layout in layouts:
            title = layout.get('title', None)
            if 'children' not in layout:
                layout = None
            splittable = OALabSplittableUi(parent=self)
            splittable.setAttribute(QtCore.Qt.WA_DeleteOnClose)
            splittable.appletSet.connect(self.appletSet.emit)
            self.appletSet.connect(self._on_applet_set)
            if layout is None:
                container = AppletContainer()
                splittable.setContentAt(0, container)
            else:
                splittable.fromJSON(layout)
            self._splittable_list.append(splittable)
            self.layout_selector.add_widget(splittable, title=title)

        self.setCentralWidget(self.layout_selector)
        self._post_fill_menus()
        self.set_edit_mode(False)

        QtGui.QApplication.instance().focusChanged.connect(self._on_focus_changed)

    def emit_applet_set(self):
        self.splittable.emit_applet_set()

    @property
    def splittable(self):
        return self.layout_selector.widget()

    def _create_menus(self):
        self.menu_classic = {}
        menubar = QtGui.QMenuBar()
        self.setMenuBar(menubar)
        for menu_name in self.DEFAULT_MENU_NAMES:
            self.menu_classic[menu_name] = menubar.addMenu(menu_name)

    def _create_actions(self):
        self.action_edit = QtGui.QAction("Edit Layout", self.menu_classic['Edit'])
        self.action_edit.setCheckable(True)
        self.action_edit.toggled.connect(self.set_edit_mode)
        self.action_edit.setChecked(False)

        self.action_about = QtGui.QAction("About", self.menu_classic['Help'])
        self.action_about.triggered.connect(self.show_about)

        self.action_plugins = QtGui.QAction("Plugins", self.menu_classic['Help'])
        self.action_plugins.triggered.connect(self.show_plugins)

        icon = QtGui.QApplication.style().standardIcon(QtGui.QStyle.SP_TitleBarCloseButton)
        self.action_quit = QtGui.QAction(icon, "Quit application", self.menu_classic['File'])
        self.action_quit.triggered.connect(self.close)
        self.action_quit.setChecked(False)

    def _pre_fill_menus(self):
        self.menu_classic['Edit'].addAction(self.action_edit)
        self.menu_classic['Help'].addAction(self.action_about)
        self.menu_classic['Help'].addAction(self.action_plugins)

    def _post_fill_menus(self):
        self.menu_classic['File'].addSeparator()
        self.menu_classic['File'].addAction(self.action_quit)

    def _load_layout(self, layout=None, **kwds):
        layout_file = kwds.pop('layout_file', self.DEFAULT_LAYOUT_PATH)
        default_layout = kwds.pop('default_layout', self.DEFAULT_LAYOUT)

        self.layout_filepath = Path(layout_file).abspath()
        if layout is None:
            if self.layout_filepath.exists():
                with open(self.layout_filepath) as layout_file:
                    content = layout_file.read()
                    try:
                        layout = json.loads(content)
                    except ValueError:
                        l = eval(content)
                        layout = dict(children=l[0], parents=l[1], properties=l[2])

        if layout is None:
            layout = default_layout
        return layout

    def _save_layout(self):
        if self.autosave:
            with open(self.layout_filepath, 'w') as layout_file:
                json.dump(self.layout(), layout_file, sort_keys=True, indent=2)

    def closeEvent(self, event):
        close = True

        # If a lab is used, check if it can be close
        if hasattr(self._lab, 'readytoclose'):
            close = self._lab.readytoclose()

        # If lab is not ready, stop closing
        if close is False:
            event.ignore()
            return

        # If lab is ready to close, or no lab is used, close widget
        if self.splittable.close():
            if hasattr(self._lab, 'finalize'):
                self._lab.finalize()
            self._save_layout()
            if hasattr(self._lab, 'stop'):
                self._lab.stop()
            event.accept()
        else:
            event.ignore()

    def set_edit_mode(self, mode=True):
        for widget in self.splittable.getAllContents():
            if hasattr(widget, 'set_edit_mode'):
                widget.set_edit_mode(mode)
        if mode is True and self.LAB:
            print self.LAB.connections
        self.splittable.set_edit_mode(mode)

    def initialize(self):
        for instance in plugin_instances('oalab.applet'):
            if hasattr(instance, 'initialize'):
                instance.initialize()

    def _widget_actions(self, obj, methodname='toolbar_actions'):
        actions = None
        if hasattr(obj, methodname):
            method_or_list = getattr(obj, methodname)
            if isinstance(method_or_list, list):
                actions = method_or_list
            else:
                actions = method_or_list()

        if actions is None:
            return []
        else:
            return actions

    def _widget_name(self, obj):
        if hasattr(obj, 'name'):
            return obj.name

    def _on_focus_changed(self, old, new):
        self.clear_toolbar()
        if old is new:
            return

        # Generally focus is on "leaf" widget on widget hierarchy.
        # We try to browse all tree to get widget defining actions
        # For example, if an editor is defined as MyEditor -> Container -> Editor -> QTextEdit
        # Widget with focus is QTextEdit but widget that define actions is MyEditor
        # Search stops if widget has no more parents or if widget is AppletContainer
        parent = new
        actions = self._widget_actions(parent)
        name = self._widget_name(parent)
        while parent is not None:
            try:
                parent = parent.parent()
            except TypeError:
                break
            else:
                if isinstance(parent, AppletContainer):
                    break
                name = name or self._widget_name(parent)
                actions += self._widget_actions(parent)

        if actions:
            self.fill_toolbar(name, actions)

        # toolbar creation/destruction set focus to toolbar so we reset it to widget
        if isinstance(new, QtGui.QWidget):
            new.setFocus(QtCore.Qt.OtherFocusReason)

    def fill_toolbar(self, name, actions):
        menus = plugin_instances('oalab.applet', 'ContextualMenu')
        for menu in menus:
            menu.set_actions(name, actions)

    def clear_toolbar(self):
        menus = plugin_instances('oalab.applet', 'ContextualMenu')
        for menu in menus:
            menu.clear()

    def _merge_menus(self, menus):
        parent = self
        default_menus = self.menu_classic
        menubar = self.menuBar()

        for _menu in menus:
            menu_name = _menu.title()
            if menu_name in default_menus:
                menu = default_menus[menu_name]
            else:
                menu = QtGui.QMenu(menu_name, parent)
                default_menus[menu_name] = menu
                menubar.addMenu(menu)

        for _menu in menus:
            menu_name = _menu.title()
            menu = default_menus[menu_name]
            for action in _menu.actions():
                if isinstance(action, QtGui.QAction):
                    menu.addAction(action)
                elif isinstance(action, QtGui.QMenu):
                    menu.addMenu(action)
                elif action == '-':
                    menu.addSeparator()

    def _on_applet_set(self, old, new):
        if new in self._registered_applets:
            return

        self._registered_applets.append(new)
        applet = plugin_instance('oalab.applet', new)

        # Add global menus
        if applet and hasattr(applet, 'menus'):
            menus = applet.menus()
            if menus is None:
                return
            self._merge_menus(menus)

        # Add global toolbars
        if applet and hasattr(applet, 'toolbars'):
            toolbars = applet.toolbars()
            if toolbars is None:
                return
            for toolbar in toolbars:
                self.addToolBar(QtCore.Qt.TopToolBarArea, toolbar)

    def layout(self):
        return self.splittable._repr_json_()

    def show_about(self):
        about = About()
        dialog = ModalDialog(about)
        dialog.resize(400, 600)
        dialog.setWindowTitle("About OpenAleaLab ...")
        dialog.exec_()

    def show_plugins(self):
        explorer = PluginExplorer()
        dialog = ModalDialog(explorer)
        dialog.resize(600, 600)
        dialog.setWindowTitle("OpenAleaLab plugin's ...")
        dialog.exec_()
Ejemplo n.º 44
0
 def rename(self, new):
     pnew = Path(new)
     if pnew.isabs() or pnew.name != new:
         raise ValueError('You must give filename only, not path')
     new_path = self.path.parent / new
     self.move(new_path)