Beispiel #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)
Beispiel #2
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)
Beispiel #3
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
Beispiel #4
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()
Beispiel #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
 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
Beispiel #7
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)
Beispiel #8
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)
Beispiel #9
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
Beispiel #10
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
Beispiel #11
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")
Beispiel #12
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")
Beispiel #13
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
Beispiel #14
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
Beispiel #15
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
Beispiel #16
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
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_()
Beispiel #18
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()
Beispiel #19
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()
Beispiel #20
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()
Beispiel #21
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_()