示例#1
0
class DataFactoryManager(AbstractDataFactoryManager):

    data_created              = QtCore.Signal(object)
    data_property_set_request = QtCore.Signal(object, str, object)

    def __init__(self):
        AbstractDataFactoryManager.__init__(self)
        self.__mimeMap = {}

    def gather_items(self, refresh=False):
        items = AbstractDataFactoryManager.gather_items(self, refresh)
        if refresh:
            self.__mimeMap.clear()
            for datatype in items.itervalues():
                if not datatype.started:
                    datatype._start_0()
                if datatype is None or not datatype.supports_open():
                    continue
                fmts = datatype.opened_mimetypes
                for fmt in fmts:
                    self.__mimeMap.setdefault(fmt, set()).add(datatype)
        return items

    def get_handlers_for_mimedata(self, formats):
        datatypes = self.gather_items()
        handlers = set() # for unicity
        for fm in formats:
            fmt_datatypes = self.__mimeMap.get(fm)
            if fmt_datatypes is not None:
                handlers.update(fmt_datatypes)
        return list(handlers)
class ProjectManager(QtCore.QObject):

    __metaclass__ = make_metaclass((ProxySingleton, ),
                                   (QtCore.pyqtWrapperType, ))

    active_project_changed = QtCore.Signal(Project, Project)
    data_added = QtCore.Signal(object, object)

    mimeformat = "application/secondnature-project-data-id"

    def __init__(self):
        QtCore.QObject.__init__(self)
        self.__activeProject = None

    def new_active_project(self, name):
        proj = Project(name)
        return self.set_active_project(proj)

    def has_active_project(self):
        return self.__activeProject is not None

    def set_active_project(self, project):
        if self.has_active_project() and self.get_active_project().is_modified(
        ):
            return False  # raise something
        old = self.__activeProject
        self.__activeProject = project
        self.__activeProject.data_added.connect(self.data_added)
        self.active_project_changed.emit(self.__activeProject, old)
        return True

    def get_active_project(self):
        return self.__activeProject

    def close_active_project(self):
        if self.__activeProject:
            self.__activeProject.close()
        self.__activeProject = None

    def save_active_project(self, filepath):
        self.__activeProject.save_to(filepath)

    def add_data_to_active_project(self, data):
        if data and data.registerable and self.__activeProject:
            self.__activeProject.add_data(data)

    def set_property_to_active_project(self, data, key, value):
        if data and self.__activeProject:
            self.__activeProject.set_data_property(data, key, value)
示例#3
0
class FilterBox(QtGui.QWidget):
    filter_changed = QtCore.Signal(str)

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self._layout = QtGui.QHBoxLayout(self)
        self.setContentsMargins(0, 0, 0, 0)
        self._layout.setContentsMargins(0, 0, 0, 0)

        self._cb_groupby = QtGui.QComboBox()
        self._cb_groupby.currentIndexChanged.connect(
            self._on_current_index_changed)

        self._layout.addWidget(self._cb_groupby)

    def _on_current_index_changed(self, idx):
        self.filter_changed.emit(self._criteria[idx][0])

    def set_criteria(self, criteria):
        self._criteria = criteria
        for criterion in self._criteria:
            self._cb_groupby.addItem(criterion[1])

    def set_filter(self, name):
        for i, criterion in enumerate(self._criteria):
            if criterion[0] == name:
                self._cb_groupby.setCurrentIndex(i)
                return
示例#4
0
class ColormapRectangle(QColormapBar, AbstractQtControlWidget):
    valueChanged = QtCore.Signal(dict)

    def __init__(self):
        QColormapBar.__init__(self)

        self.setAutoFillBackground(True)

        AbstractQtControlWidget.__init__(self)
        self.setMinimumHeight(40)

        self.value_changed_signal = self.valueChanged

    def reset(self,
              value=dict(name='grey',
                         color_points=dict([(0.0, (0.0, 0.0, 0.0)),
                                            (1.0, (1.0, 1.0, 1.0))])),
              **kwargs):
        self.setValue(value)

    def read(self, control):
        self.reset(control.value)

    def apply(self, control):
        AbstractQtControlWidget.apply(self, control)
示例#5
0
class AleaQGraphicsEmitingTextItem(QtGui.QGraphicsTextItem):
    """A QtGui.QGraphicsTextItem that emits geometryModified whenever
    its geometry can have changed."""

    ######################
    # The Missing Signal #
    ######################
    geometryModified = QtCore.Signal(QtCore.QRectF)

    def __init__(self, *args, **kwargs):
        QtGui.QGraphicsTextItem.__init__(self, *args, **kwargs)
        self.document().contentsChanged.connect(self.__onDocumentChanged)
        self.hoveredIn = AleaSignal()
        self.hoveredOut = AleaSignal()

    def __onDocumentChanged(self):
        self.geometryModified.emit(self.boundingRect())

    def hoverEnterEvent(self, event):
        QtGui.QGraphicsTextItem.hoverEnterEvent(self, event)
        self.hoveredIn.emit(event)

    def hoverLeaveEvent(self, event):
        QtGui.QGraphicsTextItem.hoverLeaveEvent(self, event)
        self.hoveredOut.emit(event)
示例#6
0
class QFloatSlider(QtGui.QSlider):

    floatValueChanged = QtCore.Signal(float)

    def __init__(self, orientation=QtCore.Qt.Horizontal):
        QtGui.QSlider.__init__(self, orientation)
        self.connect(self, QtCore.SIGNAL('valueChanged(int)'), self.notifyValueChanged)
        self.slider_step = 0.1
        self.floatValue = 0.0

    def notifyValueChanged(self, value):
        self.floatValue = value * self.slider_step
        self.floatValueChanged.emit(self.floatValue)

    def setFloatValue(self, value):
        self.floatValue = value
        self.setValue(round(value / self.slider_step))
        # self.floatValueChanged.emit(self.floatValue)
        # self.setValue(int(float(value)/self.slider_step))

    def value(self):
        return self.floatValue

    def setStep(self, step):
        self.slider_step = step
示例#7
0
class IntRangeSpinBoxes(QtGui.QWidget, AbstractIntRangeWidget):
    valueChanged = QtCore.Signal(tuple)

    def __init__(self):
        QtGui.QWidget.__init__(self)

        self.start_spinbox = QtGui.QSpinBox()
        self.end_spinbox = QtGui.QSpinBox()

        # Fill background to avoid to see text or widget behind
        self.setAutoFillBackground(True)

        AbstractIntRangeWidget.__init__(self)

        self.start_spinbox.setMinimumHeight(18)
        self.end_spinbox.setMinimumHeight(18)

        self.start_spinbox.valueChanged.connect(self.end_spinbox.setMinimum)
        self.end_spinbox.valueChanged.connect(self.start_spinbox.setMaximum)
        self.start_spinbox.valueChanged.connect(
            self.notify_start_value_changed)
        self.end_spinbox.valueChanged.connect(self.notify_end_value_changed)

        layout = QtGui.QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        layout.addWidget(self.start_spinbox)
        layout.addWidget(self.end_spinbox)

        self.value_changed_signal = self.valueChanged

    def reset(self, value=(0, 255), minimum=None, maximum=None, **kwargs):
        if minimum is not None:
            self.start_spinbox.setMinimum(minimum)
        if maximum is not None:
            self.end_spinbox.setMaximum(maximum)
        self.start_spinbox.setMaximum(value[1])
        self.end_spinbox.setMinimum(value[0])

        self.setValue(value)

    def apply(self, control):
        AbstractQtControlWidget.apply(self, control)
        control.interface.min = self.start_spinbox.minimum()
        control.interface.max = self.end_spinbox.maximum()

    def value(self, interface=None):
        return (self.start_spinbox.value(), self.end_spinbox.value())

    def setValue(self, value):
        self.start_spinbox.setValue(value[0])
        self.start_spinbox.setMaximum(value[1])
        self.end_spinbox.setValue(value[1])
        self.end_spinbox.setMinimum(value[0])

    def notify_start_value_changed(self, value):
        self.valueChanged.emit((value, self.end_spinbox.value()))

    def notify_end_value_changed(self, value):
        self.valueChanged.emit((self.start_spinbox.value(), value))
示例#8
0
class QColormapBar(QtGui.QWidget):
    valueChanged = QtCore.Signal(dict)

    def __init__(self, orientation=QtCore.Qt.Horizontal):
        QtGui.QWidget.__init__(self)

        self.color_points = {}
        self.colormap_name = ""
        self.colormap_painter = PainterColormap()
        self.orientation = orientation

    def setValue(self, value):
        self.color_points = value['color_points']
        self.colormap_name = value['name']
        self.valueChanged.emit(dict(color_points=self.color_points, name=self.colormap_name))
        self.update()

    def value(self):
        return dict(color_points=self.color_points, name=self.colormap_name)

    def setOrientation(self, orientation):
        self.orientation = orientation

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        rectangle = event.rect()

        self.colormap_painter.paint_data(self.value(), painter, rectangle, orientation=self.orientation)
示例#9
0
class PluginSelector(WelcomePage):
    pluginSelected = QtCore.Signal(object)

    def __init__(self, category, parent=None):
        WelcomePage.__init__(self, parent=parent)

        self._actions = {}
        self._sorted_actions = []
        for plugin_class in plugins(category):
            action = QtGui.QAction(obj_icon(plugin_class), alias(plugin_class),
                                   self)
            action.triggered.connect(self._on_action_triggered)
            self._actions[action] = plugin_class
            self._sorted_actions.append(action)

        self.set_actions(self._sorted_actions)

    def _on_action_triggered(self):
        plugin_class = self._actions[self.sender()]
        self.plugin_class = plugin_class
        self.pluginSelected.emit(plugin_class)

    def resize(self, *args, **kwargs):
        WelcomePage.resize(self, *args, **kwargs)
        self.set_actions(self._sorted_actions)
示例#10
0
class ManagerItemSelector(WelcomePage):
    item_selected = QtCore.Signal(object)

    def __init__(self, manager, group='default', parent=None, style=None):
        """
        items: function returning items for a given group
        """
        self.manager = manager
        if style is None:
            style = WelcomePage.STYLE_MEDIUM
        WelcomePage.__init__(self, parent=parent, style=style)

        self._actions = {}
        items = sorted(self.manager.items(group), key=lambda item: item.label)
        self._sorted_actions = []
        for item in items:
            action = QtGui.QAction(obj_icon(item), item.label, self)
            action.triggered.connect(self._on_action_triggered)
            self._actions[action] = item
            self._sorted_actions.append(action)

        self.set_actions(self._sorted_actions)

    def _on_action_triggered(self):
        plugin_class = self._actions[self.sender()]
        self.plugin_class = plugin_class
        self.item_selected.emit(plugin_class)

    def resize(self, *args, **kwargs):
        WelcomePage.resize(self, *args, **kwargs)
        self.set_actions(self._sorted_actions)
示例#11
0
class IntRangeSimpleSlider(QSpanSlider, AbstractIntRangeWidget):
    valueChanged = QtCore.Signal(tuple)

    def __init__(self):
        QSpanSlider.__init__(self)
        AbstractIntRangeWidget.__init__(self)
        self.spanChanged.connect(self.notify_value_changed)
        self.value_changed_signal = self.valueChanged

    def reset(self, value=(0, 255), minimum=0, maximum=255, **kwargs):
        if minimum is not None:
            self.setMinimum(minimum)
        if maximum is not None:
            self.setMaximum(maximum)
        self.setSpan(value[0], value[1])

    def apply(self, control):
        AbstractQtControlWidget.apply(self, control)
        control.interface.min = self.minimum()
        control.interface.max = self.maximum()
        control.value = self.value()

    def notify_value_changed(self, lower_value, upper_value):
        self.valueChanged.emit((lower_value, upper_value))

    def setValue(self, value):
        self.setSpan(value[0], value[1])

    def value(self, interface=None):
        return (self.lowerValue(), self.upperValue())
class AbstractSource(QtCore.QObject):

    __metaclass__ = make_metaclass((ProxySingleton, ),
                                   (QtCore.pyqtWrapperType, ))

    # -- EXTENSION POINT SOURCES API ATTRIBUTES --
    __concrete_manager__ = None
    __key__ = "name"

    # -- SIGNALS --
    item_list_changed = QtCore.Signal(object, dict)

    # -- PROPERTIES --
    name = property(lambda x: x.__name)
    valid = property(lambda x: x.is_valid())

    def __init__(self):
        QtCore.QObject.__init__(self)
        self.__name = self.__class__.__name__
        mgrCls = self.__concrete_manager__
        if mgrCls is not None:
            mgrCls()._add_source(self)

    #################
    # EXTENSION API #
    #################
    def is_valid(self):
        raise NotImplementedError

    def gather_items(self):
        raise NotImplementedError

    def get_items(self):
        raise NotImplementedError
示例#13
0
class ParadigmCreator(QtCore.QObject):
    paradigm_clicked = QtCore.Signal(str)

    def __init__(self, parent=None):
        QtCore.QObject.__init__(self)
        self._parent = parent
        self.reload()

    def reload(self):
        self.dtype = None

        self._name_to_applet = {}
        self._name_to_action = {}
        self._action_to_name = {}

        for plugin in plugins('oalab.plugin',
                              criteria=dict(implement='IParadigmApplet')):
            applet = debug_plugin('oalab.plugin', func=plugin)
            if applet:
                name = applet.default_name
                self._name_to_applet[name] = applet
                action = QtGui.QAction(qicon(applet.icon), "New " + name,
                                       self._parent)
                action.triggered.connect(self._on_action_triggered)
                self._name_to_action[name] = action
                self._action_to_name[action] = name

    def applet(self, obj, dtype, mimetype=None):
        applet_class = None
        if dtype in self._name_to_applet:
            # Check in paradigm.default_name
            applet_class = self._name_to_applet[dtype]
        else:
            # Check in paradigm.extension
            for value in self._name_to_applet.values():
                if dtype == value.extension:
                    applet_class = value
        if applet_class is None:
            applet_class = self._name_to_applet["Textual"]

        return applet_class(data=obj).instantiate_widget()

    def actions(self):
        return self._action_to_name.keys()

    def action(self, paradigm):
        """
        action("Python") -> QAction "New Python" or None
        """
        return self._name_to_action.get(paradigm)

    def _on_action_triggered(self):
        try:
            self.dtype = self._action_to_name[self.sender()]
        except KeyError:
            self.dtype = None

        self.paradigm_clicked.emit(self.dtype)
示例#14
0
    class SimpleCurve2DView(Curve2DEditor):
        clicked = QtCore.Signal(object, object)
        deleteRequested = QtCore.Signal(object, object)

        def __init__(self, pos, curve, parent):
            Curve2DEditor.__init__(self, parent)
            self.pos = pos
            self.accessorType[NurbsCurve] = ProfileEditor.NurbsAccessor
            self.setFixedSize(100, 90)
            self.setEnabled(True)
            self.setAutoFillBackground(True)
            self.bkgdColor = self.backgroundColor()
            if curve:
                self.setCurve(curve)

        def highlight(self, val):
            if val:
                self.defaultColor = QtGui.QColor(100, 200, 100)
            else:
                self.defaultColor = self.bkgdColor
            self.update()

        def drawGrid(self):
            return

        def mousePressEvent(self, event):
            self.clicked.emit(self.pos, self.getCurve())

        def mouseDoubleClickEvent(self, event):
            QGLViewer.mouseDoubleClickEvent(self, event)

        def mouseReleaseEvent(self, event):
            QGLViewer.mouseReleaseEvent(self, event)

        def contextMenuEvent(self, event):
            menu = QtGui.QMenu(self)
            deleteAction = menu.addAction("Delete section")
            deleteAction.triggered.connect(self.__on_delete_request)
            menu.popup(event.globalPos())

        def __on_delete_request(self):
            self.deleteRequested.emit(self.pos, self.getCurve())
示例#15
0
class GenericFileBrowser(QtGui.QWidget):
    pathSelected = QtCore.Signal(object)

    def __init__(self):
        super(GenericFileBrowser, self).__init__()
        self.model = QtGui.QFileSystemModel()
        self.tree = QtGui.QTreeView()
        self.tree.setModel(self.model)
        self.tree.header().setResizeMode(QtGui.QHeaderView.ResizeToContents)
        self._home_dir = settings.get_default_home_dir()
        self._cwd = Path(".").abspath()
        self.model.setRootPath(self._home_dir)
        self.tree.setRootIndex(self.model.index(self._home_dir))

        layout = QtGui.QGridLayout(self)
        layout.addWidget(self.tree)

        self._create_actions()
        self._create_connections()

    def _create_connections(self):
        self.tree.doubleClicked.connect(self._on_index_clicked)

    def _create_actions(self):
        self._action_go_to_parent = QtGui.QAction(qicon('oxygen_go-up.png'),
                                                  'Parent dir', self)
        self._action_go_to_parent.triggered.connect(self.go_to_parent)

    def toolbar_actions(self):
        return [self._action_go_to_parent]

    def go_to(self, path):
        self.model.setRootPath(path)
        self.tree.setRootIndex(self.model.index(path))

    def go_to_parent(self):
        path = Path(self.model.filePath(self.tree.rootIndex()))
        self.go_to(path.parent)

    def _on_index_clicked(self, index):
        filename = self.model.filePath(index)
        self.pathSelected.emit(Path(filename))

    def set_properties(self, properties):
        columns = properties.get('columns', [0])
        for icol in range(self.model.columnCount()):
            self.tree.setColumnHidden(icol, icol not in columns)

    def properties(self):
        columns = [
            i for i in range(self.model.columnCount())
            if not self.tree.isColumnHidden(i)
        ]
        return dict(columns=columns)
示例#16
0
class NodeFactoryTreeView(QtGui.QTreeView, NodeFactoryView):

    compositeFactoryOpenRequest = QtCore.Signal(CompositeNodeFactory)

    def __init__(self, siblings=[], parent=None):
        QtGui.QTreeView.__init__(self, parent)
        NodeFactoryView.__init__(self, siblings)
        self.setDragEnabled(True)
        self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
        self.setIconSize(QtCore.QSize(25,25))
        self.setHeaderHidden(True)
class CustomSplittable(SplittableUI):

    paneMenuRequest = QtCore.Signal(object, int, QtCore.QPoint)

    def getPlaceHolder(self):
        proj = ProjectManager().get_active_project()
        return AppletSpace(proj)

    def _install_child(self, paneId, widget, **kwargs):
        w = SplittableUI._install_child(self, paneId, widget, **kwargs)
        self._raise_overlays(paneId)
        return w
示例#18
0
class IntSlider(QtGui.QWidget, AbstractIntWidget):
    valueChanged = QtCore.Signal(int)

    def __init__(self):
        QtGui.QWidget.__init__(self)

        self.slider = QtGui.QSlider(QtCore.Qt.Horizontal)
        self.spinbox = QtGui.QSpinBox()

        # Fill background to avoid to see text or widget behind
        self.setAutoFillBackground(True)

        AbstractIntWidget.__init__(self)

        # To be compatible with tree or table views, slider must keep focus
        self.slider.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.setMinimumHeight(22)
        self.spinbox.setMinimumHeight(18)
        self.slider.setMinimumHeight(18)

        self.slider.valueChanged.connect(self.spinbox.setValue)
        self.spinbox.valueChanged.connect(self.slider.setValue)
        self.slider.valueChanged.connect(self.valueChanged)

        layout = QtGui.QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        layout.addWidget(self.spinbox)
        layout.addWidget(self.slider)

        self.value_changed_signal = self.valueChanged

    def reset(self, value=1, minimum=None, maximum=None, **kwargs):
        if minimum is not None:
            self.slider.setMinimum(minimum)
            self.spinbox.setMinimum(minimum)
        if maximum is not None:
            self.slider.setMaximum(maximum)
            self.spinbox.setMaximum(maximum)

        self.setValue(value)

    def apply(self, control):
        AbstractQtControlWidget.apply(self, control)
        control.interface.min = self.slider.minimum()
        control.interface.max = self.slider.maximum()

    def value(self, interface=None):
        return self.spinbox.value()

    def setValue(self, value):
        self.slider.setValue(value)
        self.spinbox.setValue(value)
示例#19
0
class ManagerExplorerView(QtGui.QTreeView):
    item_changed = QtCore.Signal(object)
    search_item_request = QtCore.Signal()

    def __init__(self, parent=None):
        QtGui.QTreeView.__init__(self, parent=parent)
        self.setContentsMargins(0, 0, 0, 0)
        self._model = ManagerExplorerModel()
        self.setModel(self._model)

        self.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.setIconSize(QtCore.QSize(24, 24))

        self.setHeaderHidden(True)

    def set_items(self, items):
        self._model.set_items(items)
        if len(items):
            first = self._model._group.values()[0][0]
            self.setCurrentIndex(self._model.indexFromItem(first))
        self.expandAll()

    def selectionChanged(self, selected, deselected):
        for idx in selected.indexes():
            if self._model.search_item_selected(idx):
                self.search_item_request.emit()
            else:
                self.item_changed.emit(self._model.item(idx))
        return QtGui.QTreeView.selectionChanged(self, selected, deselected)

    def groupby(self, **kwds):
        self._model.groupby(**kwds)
        self.expandAll()

    def set_default_group_icon(self, icon_path):
        self._model.default_group_icon = icon_path

    def set_default_item_icon(self, icon_path):
        self._model.default_item_icon = icon_path
示例#20
0
class QControlContainer(QtCore.QObject, ControlContainer):
    controlValueChanged = QtCore.Signal(object, object)

    def __init__(self, *args, **kwargs):
        QtCore.QObject.__init__(self)
        ControlContainer.__init__(self, *args, **kwargs)
        self._action = {}
        self._control = {}

    def notify(self, sender, event):
        ControlContainer.notify(self, sender, event)
        if isinstance(sender, Control):
            signal, data = event
            if signal == 'value_changed':
                self.controlValueChanged.emit(sender, data)
                if 'IBool' in str(sender.interface.__class__):
                    action = self._action[sender]
                    action.setChecked(sender.value)

    def create_actions(self, parent):
        for control in self.controls():
            interface = control.interface
            label = control.label
            action = QtGui.QAction(label, parent)
            self._control[action] = control
            self._action[control] = action
            if 'IBool' in str(interface.__class__):
                action.setCheckable(True)
                action.setChecked(control.value)
                action.toggled.connect(self._on_action_toggled)
            else:
                action.triggered.connect(self._on_action_triggered)

    def actions(self):
        return self._action.values()

    def _on_action_triggered(self, *args):
        control = self._control[self.sender()]

        from openalea.oalab.service.qt_control import qt_dialog
        value = qt_dialog(control, autoapply=False)
        if value is not None:
            control.value = value

    def _on_action_toggled(self, toggled):
        control = self._control[self.sender()]
        control.value = toggled
示例#21
0
class SenderWidget(QtCore.QObject):
    """A helper class that reemits signals from its inner widget
    with self as first argument, to identify the origin of a signal."""
    valueChanged = QtCore.Signal(QtCore.QObject, object, object)

    def __init__(self, widget, typ, parent):
        QtCore.QObject.__init__(self, parent)
        self.inner = widget
        self.type = typ
        if hasattr(widget, "valueChanged"):
            widget.valueChanged.connect(self.__on_value_changed)
            self.setValue = lambda x, y: x.inner.setValue(y)
        elif hasattr(widget, "stateChanged"):
            widget.stateChanged.connect(self.__on_value_changed)
            self.setValue = lambda x, y: x.inner.setCheckState(
                QtCore.Qt.Checked if y else QtCore.Qt.Unchecked)
        elif hasattr(widget, "textChanged"):
            widget.textChanged.connect(self.__on_value_changed)
            self.setValue = lambda x, y: x.inner.setText(str(y))

    def __on_value_changed(self, value):
        self.valueChanged.emit(self, value, self.type)
示例#22
0
class ValueControlDelegate(QtGui.QStyledItemDelegate):

    external_edit_required = QtCore.Signal(QtCore.QModelIndex)

    def createEditor(self, parent, option, index):
        model = index.model()
        control = model.control(index)
        widget = qt_editor(control, shape='hline', preferred=control.widget)
        if widget is None:
            self.external_edition(index)
        else:
            widget.setParent(parent)
            widget.set(control, True, True)
        return widget

    def setEditorData(self, editor, index):
        pass

    def paint(self, painter, option, index):
        model = index.model()
        control = model.control(index)
        paint = qt_painter(control, shape='hline')
        if paint:
            paint(control, painter, option.rect, option)
        else:
            QtGui.QStyledItemDelegate.paint(self, painter, option, index)

    def setModelData(self, editor, model, index):
        model.setData(index, str(editor.value()), QtCore.Qt.DisplayRole)
        model.setData(index, editor.value(), QtCore.Qt.EditRole)
        control = model.control(index)
        editor.set(control, False, False)

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)

    def external_edition(self, index):
        self.external_edit_required.emit(index)
示例#23
0
class WorldControlPanel(QtGui.QWidget, AbstractListener):
    StyleTableView = 0
    StylePanel = 1
    DEFAULT_STYLE = StylePanel

    attributeChanged = QtCore.Signal(str, dict)

    def __init__(self, parent=None, style=None):
        AbstractListener.__init__(self)
        QtGui.QWidget.__init__(self, parent=parent)

        self.world = None
        self.model = WorldModel()

        if style is None:
            style = self.DEFAULT_STYLE
        self.style = style

        self._manager = {}

        self._cb_world_object = QtGui.QComboBox()
        p = QtGui.QSizePolicy
        self._cb_world_object.setSizePolicy(p(p.Expanding, p.Maximum))
        self._cb_world_object.currentIndexChanged.connect(
            self._selected_object_changed)

        self._current = None
        self._default_manager = self._create_manager()

        self.interpreter = get_interpreter()
        self.interpreter.locals['world_control'] = self

        actionClearWorld = QtGui.QAction(
            QtGui.QIcon(":/images/resources/plant.png"), "Clear World", self)
        actionClearWorld.triggered.connect(self.clear)
        self._actions = [["Project", "World", actionClearWorld, 0]]

        self._layout = QtGui.QVBoxLayout(self)
        self._layout.addWidget(self._cb_world_object)

        if self.style == self.StyleTableView:
            self._view = ControlManagerWidget(manager=self._default_manager)
            self._layout.addWidget(self._view)
        elif self.style == self.StylePanel:
            self._view = None
            self._set_manager(self._default_manager)
        else:
            raise NotImplementedError('style %s' % self.style)

    def set_properties(self, properties):
        if self.style == self.StyleTableView:
            self._view.set_properties(properties)

    def properties(self):
        if self.style == self.StyleTableView:
            return self._view.properties()
        else:
            return []

    def set_style(self, style):
        if style == self.style:
            return

        world = self.world
        self.clear()
        if self.style == self.StyleTableView:
            view = self._view
        elif self.style == self.StylePanel:
            if self._view and self._view():
                view = self._view()
            else:
                return

        # Remove old view
        view.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self._layout.removeWidget(view)
        view.close()
        del view
        self._view = None

        self.style = style
        if style == self.StyleTableView:
            self._view = ControlManagerWidget(manager=self._default_manager)
            self._layout.addWidget(self._view)

        self.set_world(world)

    def __getitem__(self, key):
        return self._manager[self._current].control(name=key)

    def initialize(self):
        from openalea.oalab.world.world import World
        from openalea.core.service.ipython import interpreter
        world = World()
        world.update_namespace(interpreter())
        self.set_world(world)

    def actions(self):
        return self._actions

    def toolbar_actions(self):
        return self.actions()

    def notify(self, sender, event=None):
        signal, data = event
        if signal == 'world_changed':
            self.refresh()
        elif signal == 'world_object_removed':
            self.refresh()
        elif signal == 'world_object_changed':
            world, old_object, world_object = data
            self.refresh_manager(world_object)
        elif signal == 'world_object_item_changed':
            world, world_object, item, old, new = data
            self.refresh_manager(world_object)
            #self.refresh_item(world_object, item, old, new)
        elif signal == 'world_sync':
            self.refresh()

    def clear_managers(self):
        self._current = None
        self._cb_world_object.clear()
        for name, manager in self._manager.items():
            manager.clear_followers()
            del self._manager[name]
        self._set_manager(self._default_manager)

    def clear(self):
        self.clear_managers()
        if self.world:
            self.world.unregister_listener(self)
            self.world = None

    def set_world(self, world):
        self.clear()

        self.world = world
        self.world.register_listener(self)

        if self.style == self.StyleTableView:
            self.model.set_world(world)

        for object_name in world.keys():
            self.refresh_manager(world[object_name])

    def _fill_manager(self, manager, world_object):
        if world_object:
            for attribute in world_object.attributes:
                manager.add(attribute['name'],
                            interface=attribute['interface'],
                            value=attribute['value'],
                            alias=attribute['alias'],
                            constraints=attribute['constraints'])
                manager.register_follower(
                    attribute['name'],
                    self._attribute_changed(world_object, attribute['name']))

    def _get_manager(self, world_object):
        object_name = world_object.name
        if object_name not in self._manager:
            manager = self._create_manager(world_object)
            self._manager[object_name] = manager
            self._cb_world_object.addItem(object_name)
        return self._manager[object_name]

    def _create_manager(self, world_object=None):
        from openalea.core.control.manager import ControlContainer
        manager = ControlContainer()
        self._fill_manager(manager, world_object)
        return manager

    def _selected_object_changed(self, idx):
        if idx != -1:
            self.select_world_object(self._cb_world_object.itemText(idx))

    def _set_manager(self, manager):
        if self.style == self.StylePanel:
            view = self._view
            if self._view is not None:
                view = self._view()
            if view:
                self._layout.removeWidget(view)
                view.close()
                del view
            from openalea.oalab.service.qt_control import edit
            view = edit(manager)
            view.setAttribute(QtCore.Qt.WA_DeleteOnClose)
            self._view = weakref.ref(view)
            self._layout.addWidget(view)
            view.show()
            self.repaint()
        elif self.style == self.StyleTableView:
            self._view.model.set_manager(manager)
        else:
            raise NotImplementedError('style %s' % self.style)

    def select_world_object(self, object_name):
        if object_name != self._current:
            self._current = object_name
            object_manager = self._manager[object_name]
            object_manager.disable_followers()
            self._set_manager(object_manager)
            object_manager.enable_followers()

    def refresh_item(self, world_object, item, old, new):
        object_name = world_object.name
        if item == 'attribute':
            manager = self._get_manager(world_object)
            attr_name = new['name']
            attr_value = new['value']
            control = manager.control(name=attr_name)
            if control:
                control.value = attr_value
        else:
            self.refresh_manager(world_object)

    def refresh_manager(self, world_object):
        object_name = world_object.name
        object_manager = self._get_manager(world_object)

        manager_attr_names = [
            c.name for c in self._manager[object_name].controls()
        ]
        object_attr_names = [a['name'] for a in world_object.attributes]
        if manager_attr_names != object_attr_names:
            object_manager.clear_followers()
            object_manager.clear()
            self._fill_manager(object_manager, world_object)
            if self._current == object_name:
                self._set_manager(object_manager)
                object_manager.enable_followers()
        else:
            for a in world_object.attributes:
                if a['value'] != self._manager[object_name].control(
                        a['name']).value:
                    self._manager[object_name].control(a['name']).set_value(
                        a['value'])

    def refresh(self):
        if self.world is not None:
            self.set_world(self.world)

    def _attribute_changed(self, world_object, attribute_name):
        def _changed(old, new):
            self._object_attribute_changed(world_object.name, attribute_name,
                                           old, new)

        return _changed

    def _object_attribute_changed(self, object_name, attribute_name, old, new):
        self.world[object_name].set_attribute(attribute_name, new)
示例#24
0
class ProfileViewer(QGLViewer):

    _posCurveColorF = [0.0, 1.0, 0.0]

    positionChanged = QtCore.Signal(int)
    userSectionHighlighted = QtCore.Signal(object, object)

    def __init__(self, parent, profile=None):
        QGLViewer.__init__(self, parent)
        self.__profile = None
        self.__position = 0
        self.__positionCurve = None
        self.increment = 0.01
        self._axisScaleTolerance = abs(pi / 8.)  # (radians)

        #states
        self.__oldY = None
        self.__scalingDirection = None

        #ranges
        self.__param_min = 0.0
        self.__param_max = 1.0

        # --rendering components --
        self.factor = [1., 1., 1.]  #x, y, z scene scaling factors.
        self.discretizer = Discretizer()
        self.renderer = GLRenderer(self.discretizer)
        self.renderer.renderingMode = GLRenderer.Dynamic

        # -- addons --
        self._addons = []
        self.visualSections = VisualCrossSectionsAddOn(self)
        self.grids = GridAddOn(self)
        self.userSlices = UserSlicesAddOn(self)

    def init(self):
        self.camera().setUpVector(Vec(0, 1, 0))
        self.camera().setType(Camera.ORTHOGRAPHIC)
        self.camConstraint = WorldConstraint()
        self.camera().frame().setConstraint(self.camConstraint)
        self.camera().setZClippingCoefficient(4)  #arbitrary.
        self.showEntireScene()

    def set_axis_scale_tolerance(self, tolerance):
        self._axisScaleTolerance = abs(tolerance)

    def set_profile(self, profile):
        if profile is not None:
            profile.add_update_callback(self.__profileChanged)
            self.__profile = profile
            # -- recompute stuff --
            self.__param_min, self.__param_max = profile.get_param_range()
            self.increment = (self.__param_max - self.__param_min) / 100
            for addon in self._addons:
                addon._init_from_profile(profile)
            self.set_position(self.range()[0])
        else:
            self.__clearCaches()
            self.__profile = None

    def profile(self):
        return self.__profile

    def range(self):
        return self.__param_min, self.__param_max

    def position(self):
        return self.__position

    def set_position(self, position):
        # -- clamp position --
        min, max = self.range()
        if position > max: position = max
        if position < min: position = min
        self.__position = position
        self.update_displayed_geometry()
        self.positionChanged.emit(position)
        if position not in self.__profile:
            position = self.round_within_increment(position)
        if position in self.__profile:
            self.userSectionHighlighted.emit(position,
                                             self.__profile[position])

    def round_within_increment(self, pos):
        keys = map(self.unnormalised_parameter, self.__profile.iterkeys())
        for k in keys:
            if abs(k - pos) <= self.increment:
                return k
        return pos

    #########################
    # Normalisation Helpers #
    #########################
    def normalised_parameter(self, par, **kwargs):
        if self.__profile:
            return self.__profile.normalised_parameter(par, **kwargs)

    def normalised_abscissa(self, par, **kwargs):
        if self.__profile:
            return self.__profile.normalised_abscissa(par, **kwargs)

    def unnormalised_parameter(self, par, **kwargs):
        if self.__profile:
            return self.__profile.unnormalised_parameter(par, **kwargs)

    def unnormalised_abscissa(self, par, **kwargs):
        if self.__profile:
            return self.__profile.unnormalised_abscissa(par, **kwargs)

    #################
    # Painting code #
    #################
    def draw(self):
        self.setBackgroundColor(QtGui.QColor(0, 0, 0))
        glDisable(GL_LIGHTING)
        glEnable(GL_LINE_SMOOTH)
        glEnable(GL_BLEND)
        glEnable(GL_ALPHA_TEST)
        glAlphaFunc(GL_GREATER, 0.1)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)

        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        mat = 16 * [0]
        mat[0] = self.factor[0]
        mat[5] = self.factor[1]
        mat[10] = self.factor[2]
        mat[15] = 1.
        glMultMatrixd(mat)

        if self.__profile is not None:
            self.discretizer.clear()
            if self.__positionCurve:
                for addon in self._addons:
                    addon._draw(self.renderer)
                glColor4f(0.0, 1.0, 0.0, 1.0)
                glDisable(GL_DEPTH_TEST)
                self.__positionCurve.apply(self.renderer)
                glEnable(GL_DEPTH_TEST)
        glPopMatrix()

    ###############################
    # Qt Event Handlers overloads #
    ###############################
    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.MidButton:
            self.__oldX = event.x()
            self.__oldY = event.y()
        else:
            QGLViewer.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        self.__oldX = None
        self.__oldY = None
        self.__scalingDirection = None
        QGLViewer.mouseReleaseEvent(self, event)

    def mouseMoveEvent(self, event):
        if self.__oldY is not None:
            pos = self.__position

            #some values that are used a bit everywhere
            newX, newY = event.x(), event.y()
            xDiff = float(newX - self.__oldX)
            yDiff = float(newY - self.__oldY)
            cartDist = sqrt(yDiff**2 + xDiff**2)

            mod = event.modifiers()
            if mod != QtCore.Qt.ControlModifier:
                delta = newY - self.__oldY
                if delta > 0:
                    pos += self.increment
                elif delta < 0:
                    pos -= self.increment
                self.__oldY = newY

                self.set_position(pos)
            elif self.__scalingDirection is None:
                if cartDist < 50:  #pixels
                    return

                #compute direction coefficient of the mouse pointer to the screen center
                if xDiff == 0.0:
                    return
                pA = atan2(yDiff, xDiff)
                tol = self._axisScaleTolerance

                #compute projected direction coefficients of axes
                camera = self.camera()
                origin = camera.getProjectedCoordinatesOf(Vec(0., 0., 0.))
                xProj = camera.getProjectedCoordinatesOf(Vec(1., 0., 0.))
                yProj = camera.getProjectedCoordinatesOf(Vec(0., 1., 0.))
                zProj = camera.getProjectedCoordinatesOf(Vec(0., 0., 1.))

                xVec = (xProj[0] - origin[0]), (xProj[1] - origin[1])
                yVec = (yProj[0] - origin[0]), (yProj[1] - origin[1])
                zVec = (zProj[0] - origin[0]), (zProj[1] - origin[1])

                #angles
                if xVec[0] == 0.0 or yVec[0] == 0.0 or zVec[0] == 0.0:
                    return

                xA = atan(xVec[1] / xVec[0])
                yA = atan(yVec[1] / yVec[0])
                zA = atan(zVec[1] / zVec[0])

                dire = min((abs(xA % pi - pA % pi), 0, pA, xVec),
                           (abs(yA % pi - pA % pi), 1, pA, yVec),
                           (abs(zA % pi - pA % pi), 2, pA, zVec))
                self.__scalingDirection = dire if (dire[0] <= tol) else None

            elif self.__scalingDirection is not None:
                angD, dire, angle, vec = self.__scalingDirection

                #cartDist is used to obtain a significant difference
                #or else computations are screwed.
                if xDiff != 0.0 and yDiff != 0 and cartDist > 5:
                    pA = atan2(yDiff, xDiff)
                    if pA < 0: pA += 2 * pi
                    if angle < 0: angle += 2 * pi
                    angleDiv = int(angle / pi * 2)
                    mouseDiv = int(pA / pi * 2)
                    positive = angleDiv == mouseDiv

                    f = self.factor[dire]
                    f = f * 1.02 if positive else f * 0.98
                    self.factor[dire] = f

                    self.__oldY = newY
                    self.__oldX = newX
                    self.update()

        else:
            QGLViewer.mouseMoveEvent(self, event)

    def keyPressEvent(self, event):
        key = event.key()
        if key in [QtCore.Qt.Key_Return, QtCore.Qt.Key_Return]:
            self.__profile.create_cross_section(self.__position)
        elif key == QtCore.Qt.Key_Delete:
            position = self.round_within_increment(self.__position)
            if position in self.__profile:
                del self.__profile[position]

    ##############################
    # Internal State Maintenance #
    ##############################
    def update_displayed_geometry(self):
        if self.__profile:
            # -- 'add-ons' --
            for addon in self._addons:
                addon._compute(self.__profile)
            self.__positionCurve = self.__profile(self.__position)
            self.update()

    def __clearCaches(self):
        for addon in self._addons:
            addon.clear_caches()

    def __profileChanged(self):
        # -- cleanup caches --
        self.__clearCaches()
        # -- recompute stuff --
        self.__param_min, self.__param_max = self.__profile.get_param_range()
        self.increment = (self.__param_max - self.__param_min) / 100
        for addon in self._addons:
            addon._interpolation_changed()
        self.update_displayed_geometry()
示例#25
0
class CurvePanel(QtGui.QScrollArea):
    class SimpleCurve2DView(Curve2DEditor):
        clicked = QtCore.Signal(object, object)
        deleteRequested = QtCore.Signal(object, object)

        def __init__(self, pos, curve, parent):
            Curve2DEditor.__init__(self, parent)
            self.pos = pos
            self.accessorType[NurbsCurve] = ProfileEditor.NurbsAccessor
            self.setFixedSize(100, 90)
            self.setEnabled(True)
            self.setAutoFillBackground(True)
            self.bkgdColor = self.backgroundColor()
            if curve:
                self.setCurve(curve)

        def highlight(self, val):
            if val:
                self.defaultColor = QtGui.QColor(100, 200, 100)
            else:
                self.defaultColor = self.bkgdColor
            self.update()

        def drawGrid(self):
            return

        def mousePressEvent(self, event):
            self.clicked.emit(self.pos, self.getCurve())

        def mouseDoubleClickEvent(self, event):
            QGLViewer.mouseDoubleClickEvent(self, event)

        def mouseReleaseEvent(self, event):
            QGLViewer.mouseReleaseEvent(self, event)

        def contextMenuEvent(self, event):
            menu = QtGui.QMenu(self)
            deleteAction = menu.addAction("Delete section")
            deleteAction.triggered.connect(self.__on_delete_request)
            menu.popup(event.globalPos())

        def __on_delete_request(self):
            self.deleteRequested.emit(self.pos, self.getCurve())

    curveEditRequested = QtCore.Signal(object, object)
    curveDeleteRequested = QtCore.Signal(object, object)
    curveMoveRequested = QtCore.Signal(object, object)

    def __init__(self, orientation=QtGui.QBoxLayout.LeftToRight, parent=None):
        QtGui.QScrollArea.__init__(self, parent)
        self.orientation = orientation
        self.setSizePolicy(QtGui.QSizePolicy.Preferred,
                           QtGui.QSizePolicy.Fixed)
        self.__curveViews = []
        self.__curveLabels = []
        self.__refreshTimout = QtCore.QTimer()
        self.__refreshTimout.setInterval(500)
        self.__refreshTimout.timeout.connect(self.__set_curves)
        self.__crvs = None

    def set_curves(self, crvs):
        self.__crvs = crvs
        if self.__refreshTimout.isActive():
            self.__refreshTimout.stop()
        self.__refreshTimout.start()

    def get_curve(self, id):
        w = self.widget().layout().itemAt(id).widget()
        return w.getCurve()

    def __set_curves(self):
        self.__refreshTimout.stop()
        crvs = self.__crvs
        if len(crvs) == len(self.__curveViews):  #refresh the existing views
            for i in range(len(crvs)):
                pos, c = crvs[i]
                v = self.__curveViews[i]
                v.setCurve(c)
                v.pos = pos
                self.__curveLabels[i].setValue(pos)
        else:  #recreate them
            del self.__curveViews[:]
            del self.__curveLabels[:]
            scrolledWidget = QtGui.QWidget(self)
            layout = QtGui.QBoxLayout(self.orientation)
            scrolledWidget.setLayout(layout)

            # -- used to lock the bounding cross section line edits --
            minPos = min(crvs, key=lambda x: x[0])[0]
            maxPos = max(crvs, key=lambda x: x[0])[0]

            for pos, c in crvs:
                frame = QtGui.QFrame(scrolledWidget)
                frame.setFrameShape(QtGui.QFrame.Panel)
                frame.setFrameShadow(QtGui.QFrame.Raised)
                subLay = QtGui.QBoxLayout(QtGui.QBoxLayout.TopToBottom)
                frame.setLayout(subLay)

                w = CurvePanel.SimpleCurve2DView(pos, c, frame)
                w.clicked.connect(self.curveEditRequested)
                w.deleteRequested.connect(self.curveDeleteRequested)

                label = QtGui.QDoubleSpinBox()
                label.setRange(-100000., 100000.)
                label.setValue(pos)
                label.setAlignment(QtCore.Qt.AlignHCenter)
                sender = SenderWidget(label, float, self)
                if pos in [minPos, maxPos]:
                    label.setEnabled(False)
                else:
                    sender.valueChanged.connect(self.__on_label_changed)

                subLay.addWidget(w, QtCore.Qt.AlignHCenter)
                subLay.addWidget(label, QtCore.Qt.AlignHCenter)
                layout.addWidget(frame)
                self.__curveViews.append(w)
                self.__curveLabels.append(label)
            self.setWidget(scrolledWidget)

    def highlight_curve_at_position(self, pos, crv):
        for cv in self.__curveViews:
            if cv.pos == pos:
                cv.highlight(True)
            else:
                cv.highlight(False)

    #################
    # Private stuff #
    #################
    def __on_label_changed(self, sender, value, typ):
        try:
            i = self.__curveLabels.index(sender.inner)
        except:
            return
        oldPosition = self.__curveViews[i].pos
        newPosition = value
        self.curveMoveRequested.emit(oldPosition, newPosition)
示例#26
0
class ControlView(QtGui.QTreeView):
    controlsSelected = QtCore.Signal(list)

    def __init__(self):
        QtGui.QTreeView.__init__(self)
        self.setEditTriggers(self.DoubleClicked)
        self.setSelectionMode(self.SingleSelection)
        self.setSelectionBehavior(self.SelectRows)
        self.setDragEnabled(True)
        self.setDragDropMode(self.DragOnly)
        self.setSortingEnabled(False)
        self.delegate = ValueControlDelegate()
        self.delegate0 = NameControlDelegate()
        self.setItemDelegateForColumn(0, self.delegate0)
        self.setItemDelegateForColumn(1, self.delegate)
        self.setUniformRowHeights(True)
        self.setHeaderHidden(False)
        self._selected_indexes = None

    def contextMenuEvent(self, event):
        menu = QtGui.QMenu(self)
        action = QtGui.QAction("New control", menu)
        action.triggered.connect(self.new_control)
        menu.addAction(action)

        if self.selectedIndexes():
            self._selected_indexes = self.selectedIndexes()
            action = QtGui.QAction("Delete control", menu)
            action.triggered.connect(self.delete_control)
            menu.addAction(action)

        action = QtGui.QAction("Import L-Py controls", menu)
        action.triggered.connect(self.import_lpy)
        menu.addAction(action)
        action = QtGui.QAction("Export L-Py controls", menu)
        action.triggered.connect(self.export_lpy)
        menu.addAction(action)

        action = QtGui.QAction("Save controls", menu)
        action.triggered.connect(self.save_controls)
        menu.addAction(action)

        action = QtGui.QAction("Load controls", menu)
        action.triggered.connect(self.load_controls)
        menu.addAction(action)

        menu.exec_(event.globalPos())

    def new_control(self):
        editor = ControlEditor('control')
        dialog = ModalDialog(editor)
        if dialog.exec_():
            control = editor.control()
            if self.model()._manager.control(control.name):
                QtGui.QMessageBox.information(self, 'Error on adding control',
                                              'A control with name %s already exists' % control.name)
            else:
                self.model().add_control(control)

    def delete_control(self):
        if self._selected_indexes is None:
            return
        self.model().remove_controls(self._selected_indexes)
        self._selected_indexes = None

    def save_controls(self, filename=None):
        if not filename:
            filename = QtGui.QFileDialog.getSaveFileName(self, 'Select python file')
        if filename:
            save_controls(self.model()._manager.controls(), filename)

    def load_controls(self, filename=None):
        if not filename:
            filename = QtGui.QFileDialog.getOpenFileName(self, 'Select python file')
        if filename:
            if path(filename).exists():
                self.model()._manager.clear()
                code = file(filename, 'r').read()
                exec(code)

    def import_lpy(self):
        from openalea.plantlab.lpycontrol import import_lpy_controls
        filename = QtGui.QFileDialog.getOpenFileName(self, 'Select L-Py file')
        if filename:
            import_lpy_controls(filename)

    def export_lpy(self):
        from openalea.plantlab.lpycontrol import export_lpy_controls
        filename = QtGui.QFileDialog.getSaveFileName(self, 'Select L-Py file')
        if filename:
            mcontrols = [(c.name, c.interface, c.value) for c in self.model()._manager.controls()]
            export_lpy_controls(mcontrols, filename)

    def selectionChanged(self, selected, deselected):
        rows = set()
        for index in selected.indexes():
            rows.add(index.row())
        controls = []
        for row in rows:
            index = self.model().createIndex(row, 1)
            controls.append(self.model().control(index))
        self.controlsSelected.emit(controls)
        return QtGui.QTreeView.selectionChanged(self, selected, deselected)

    def onRowsInserted(self, *args, **kwargs):
        self.resizeColumnToContents(0)
class ImageStackViewerWidget(QtGui.QWidget):

    """
    Widget based on openalea.image.gui.slide_viewer.PixmapStackView
    """
    valueChanged = QtCore.Signal(object)
    stackChanged = QtCore.Signal(object)

    def __init__(self):
        QtGui.QWidget.__init__(self)
        self._im_view = PixmapStackView()
        self._label = ScalableLabel()

        self._layout = QtGui.QVBoxLayout(self)
        self._layout.addWidget(self._label)

        self._label.setMouseTracking(True)
        self._last_mouse_x = 0
        self._last_mouse_y = 0

        self.connect(self._label, QtCore.SIGNAL("mouse_press"), self.mouse_pressed)
        self.connect(self._label, QtCore.SIGNAL("mouse_move"), self.mouse_pressed)

        self.axis = 2
        self.inc = 1 # index increment
        self._palette_name = None

    ##############################################
    #        Qt Control API
    ##############################################

    def setValue(self, img):
        if img is self.value():
            return
        self._im_view.set_image(img)
        try:
            self.resolution = img.resolution[:]
        except AttributeError:
            pass

        self._im_view._reconstruct_pixmaps()
        self.change_axis(0)
        self.slice_changed((0 + self._im_view.nb_slices() - 1) / 2)

        self.emit_stack_changed()

    def value(self):
        return self._im_view.image()

    ##############################################
    #        slots
    ##############################################

    def emit_stack_changed(self):
        img = self.value()
        if img is None:
            self.stackChanged.emit(None)
        else:
            args = dict(shape=img.shape, axis=self.axis,
                        slice=self._im_view.current_slice(),
                        resolution=self.resolution, inc=self.inc,
                        palette_name=self._palette_name)
            self.stackChanged.emit(args)

    def change_axis(self, ind):
        if self.axis == ind:
            return
        try:
            res = list(self.resolution)
            del res[self.axis]
            tr = self._im_view._transform
            print res
            if tr % 180:
                self._label._resolution = res[1], res[0]
            else:
                self._label.set_resolution(*res[:2])
        except AttributeError:
            pass
        self._im_view._reconstruct_pixmaps(self.axis)
        self.emit_stack_changed()
        self.update_pix()
        #self.fill_infos()

    def mouse_pressed(self, event):
        self._last_mouse_x = event.x()
        self._last_mouse_y = event.y()

    def change_palette(self, palette_name):
        if palette_name == self._palette_name:
            return

        self._palette_name = palette_name
        self.emit_stack_changed()

        img = self._im_view.image()
        if img is None:
            return

        palette = palette_factory(palette_name, img.max())
        self._im_view.set_palette(palette, self.axis)
        self.update_pix()

    def update_pix(self):
        pix = self._im_view.pixmap()
        if pix is not None:
            self._label.setPixmap(pix)

    def get_pixel_value_str(self, img, x, y, z):
        px = img[x, y, z]
        if isinstance(px, np.ndarray):
            return str(px)
        else:
            return "%3d" % px

    def slice_changed(self, ind):
        img = self.value()
        if img is None:
            return

        if ind >= img.shape[self.axis]:
            ind = img.shape[self.axis] - 1
        if ind < 0:
            ind = 0
        if self._im_view.current_slice() == ind:
            return
        self._im_view.set_current_slice(ind)
        self.emit_stack_changed()
        self.update_pix()

    def snapshot(self):
        """write the current image
        """
        pix = self._im_view.pixmap()
        if pix is not None:
            pix.save("slice%.4d.png" % self.panel.img_slider.value())

    def wheelEvent(self, event):
        self.inc = event.delta() / 8 / 15
        idx = self._im_view.current_slice()
        self.slice_changed(idx + self.inc)

    def rotate_left(self):
        res = self._label._resolution
        self._label._resolution = res[1], res[0]
        self._im_view.rotate(-1)
        self.update_pix()

    def rotate_right(self):
        res = self._label._resolution
        self._label._resolution = res[1], res[0]
        self._im_view.rotate(1)
        self.update_pix()
示例#28
0
class RichTextEditor(QtGui.QWidget):
    textChanged = QtCore.Signal()

    def __init__(self, parent=None):
        super(RichTextEditor, self).__init__(parent)

        self.completer = DictionaryCompleter(parent=self)

        self.editor = self._default_editor(parent=self)
        self.editor.textChanged.connect(self.textChanged.emit)
        # self.editor.setCompleter(self.completer)

        self.goto_widget = GoToWidget(parent=self.editor)
        self.search_widget = SearchWidget(parent=self.editor)

        self.layout = QtGui.QVBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.addWidget(self.editor)
        self.layout.addWidget(self.search_widget)
        self.setLayout(self.layout)

        self.search_widget.hide()

    def _default_editor(self, *args, **kwargs):
        return TextEditor(*args, **kwargs)

    def actions(self):
        """
        :return: list of actions to set in the menu.
        """
        return None

    def mainMenu(self):
        return "Project"

    def set_text(self, txt):
        """
        Set text in the editor

        :param text: text you want to set
        """
        self.editor.set_text(txt)

    set_script = set_text

    def get_selected_text(self):
        return self.editor.get_selected_text()

    def get_text(self, start='sof', end='eof'):
        """
        Return a part of the text.

        :param start: is the begining of what you want to get
        :param end: is the end of what you want to get
        :return: text which is contained in the editor between 'start' and 'end'
        """
        return self.editor.get_text(start=start, end=end)

    def get_code(self, start='sof', end='eof'):
        return self.get_text(start=start, end=end)

    def replace_tab(self):
        return self.editor.replace_tab()

    def goto(self):
        self.goto_widget.show()

    def comment(self):
        self.editor.comment()

    def uncomment(self):
        self.editor.uncomment()

    def undo(self):
        self.editor.undo()

    def redo(self):
        self.editor.redo()

    def search(self):
        if self.search_widget.hiden:
            cursor = self.editor.textCursor()
            cursor.setPosition(0)
            self.editor.setTextCursor(cursor)

            self.search_widget.show()
            # self.search_widget.raise_()
            self.search_widget.lineEdit.setFocus()
            txt = self.get_selected_text()
            self.search_widget.lineEdit.setText(txt)
            self.search_widget.hiden = False
        else:
            self.search_widget.hide()
            self.search_widget.hiden = True
class Project(QtCore.QObject):

    # -- SIGNALS --
    closed = QtCore.Signal(object)
    saved = QtCore.Signal(object)
    modified = QtCore.Signal(object)
    data_added = QtCore.Signal(object, object)
    data_name_changed = QtCore.Signal(object, object, str)
    project_name_changed = QtCore.Signal(object, str)

    # -- PROPERTIES --
    name = property(lambda x: x.__name, lambda x, y: x.set_name(y))

    def __init__(self, name):
        QtCore.QObject.__init__(self)
        self.__name = name
        self.__modified = False
        self.__names = set()
        self.__docIdCtr = 0
        self.__docs = {}
        self.__docToIds = {}
        self.__docprops = {}

    def set_name(self, value):
        self.__name = value
        self.project_name_changed.emit(self, value)

    def __fix_name(self, name):
        i = 1
        original = name
        candidate = name
        while candidate in self.__names:
            candidate = name + " (%i)" % i
            i += 1
        self.__names.add(candidate)
        return candidate

    def add_data(self, doc):

        name = self.__fix_name(doc.name)
        doc.name = name
        self.__docs[self.__docIdCtr] = doc
        self.__docToIds[doc] = self.__docIdCtr
        self.__docIdCtr += 1

        self.data_added.emit(self, doc)
        self.mark_as_modified()

    def get_data_id(self, data):
        return self.__docToIds.get(data, -1)

    def get_data(self, doc_id):
        return self.__docs.get(doc_id)

    def get_data_by_name(self, name):
        for datum in self.__docs.itervalues():
            if name == datum.name:
                return datum
        return None

    def del_data(self, doc_id):
        self.mark_as_modified()

    def has_data(self, doc):
        return doc in self.__docs.itervalues()

    def is_modified(self):
        return self.__modified

    def __iter__(self):
        return self.__docs.iteritems()

    def set_data_name(self, doc, name):
        if not self.has_data(doc):
            return  #raise something
        oldName = doc.name
        self.__names.discard(oldName)
        fixedName = self.__fix_name(name)
        doc.name = fixedName
        #        doc._set_name( fixedName )
        self.data_name_changed.emit(self, doc, fixedName)

    def set_data_property(self, doc, key, val):
        if doc not in self.__docToIds:
            raise Exception()
        self.__docprops.setdefault(doc, {})[key] = val

    def get_data_property(self, doc, key):
        if not self.has_data_property(doc, key):
            return None
        props = self.__docprops.get(doc)
        if props is not None:
            return props.get(key)

    def pop_data_property(self, doc, key):
        if not self.has_data_property(doc, key):
            return None
        props = self.__docprops.get(doc)
        if props is not None:
            return props.pop(key)

    def has_data_property(self, doc, key):
        props = self.__docprops.get(doc)
        if not props:
            return False  #TODO : raise something dude
        return key in props

    def close(self):
        self.closed.emit(self)

        self.__names.clear()
        self.__docs.clear()
        self.__docToIds.clear()
        self.__docprops.clear()

        # self.closed.disconnect()
        # self.saved.disconnect()
        # self.modified.disconnect()

    def mark_as_modified(self):
        self.__modified = True
        self.modified.emit(self)

    def mark_as_saved(self):
        self.__modified = False
        self.saved.emit(self)

    ############
    # Pickling #
    ############

    def save_to(self, filepath):
        docnames = [doc.name+":"+doc.factory_name+":"+doc.type \
                    for doc in self.__docs.itervalues()]
        manifest = reduce(lambda x, y: x + "\n" + y, docnames,
                          "name=" + self.name)
        print manifest
        with zipfile.ZipFile(filepath, "w") as z:
            z.writestr("manifest.txt", manifest)
            for d in self.__docs.itervalues():
                try:
                    stream = io.BytesIO()
                    d.to_stream(stream)
                except Exception, e:
                    print "couldn't write", f, " : ", e
                else:
                    z.writestr(d.name, stream.getvalue())
class AbstractSourceManager(QtCore.QObject):

    __metaclass__ = make_metaclass((ProxySingleton, ),
                                   (QtCore.pyqtWrapperType, ))

    item_list_changed = QtCore.Signal(list)

    __managers__ = []

    def __init__(self):
        QtCore.QObject.__init__(self)
        self._sources = {}
        self._items = {}
        self._customItems = {}
        AbstractSourceManager.__managers__.append(self)

    def __iter__(self):
        return self._items.iteritems()

    def add_custom_item(self, name, value):
        self._customItems[name] = value

    def _add_source(self, src):
        if src.name in self._sources:
            return  #TODO : raise something dude
        src.item_list_changed.connect(self.update_with_source)
        self._sources[src.name] = src

    def iter_sources(self):
        return self._sources.itervalues()

    def gather_items(self, refresh=False):
        if refresh:
            self._items = {}
            for src in self.iter_sources():
                if not src.is_valid():
                    continue
                src.gather_items()
                self._items.update(src.get_items())
            self._items.update(self._customItems)
            self.item_list_changed.emit(list(self._items.iterkeys()))
        return self._items.copy()

    def get(self, name):
        return self._items.get(name, None)

    def iter_item_names(self):
        return self.gather_items().iterkeys()

    def update_with_source(self, src, items):
        self._items.update(items)
        self.item_list_changed.emit(list(self._items.iterkeys()))

    @classmethod
    def init_sources(cls):
        raise NotImplementedError

    @classmethod
    def init(cls):
        from openalea.secondnature.layouts import LayoutManager
        from openalea.secondnature.applets import AppletFactoryManager
        from openalea.secondnature.data import DataFactoryManager

        lm = LayoutManager()
        am = AppletFactoryManager()
        dm = DataFactoryManager()

        lm.init_sources()
        am.init_sources()
        dm.init_sources()

        lm.gather_items(refresh=True)
        am.gather_items(refresh=True)
        dm.gather_items(refresh=True)

    @staticmethod
    def post_status_message(msg):
        app = QtCore.QCoreApplication.instance()
        app.post_status_message(msg)