Beispiel #1
0
    def unserialize(self, data):
        """
			Parses the values received from the server and update our value accordingly.
			:param data: The data dictionary received.
			:type data: dict
		"""
        if self.boneName in data.keys():
            val = data[self.boneName]
            if isinstance(val, list):
                if len(val) > 0:
                    val = val[0]
                else:
                    val = None

            if isinstance(val, dict):
                self.setSelection(val)
                if self.using:
                    if self.ie:
                        self.removeChild(self.ie)

                    self.ie = InternalEdit(self.using,
                                           val["rel"], {},
                                           readOnly=self.readOnly,
                                           defaultCat=self.usingDescr)
                    self.ie.addClass("relationwrapper")
                    self.appendChild(self.ie)
            else:
                self.setSelection(None)
Beispiel #2
0
    def __init__(self,
                 parent,
                 module,
                 data,
                 using,
                 errorInfo=None,
                 *args,
                 **kwargs):
        super(RecordMultiBoneEntry, self).__init__(*args, **kwargs)
        self.sinkEvent("onDrop", "onDragOver", "onDragLeave", "onDragStart",
                       "onDragEnd", "onChange")

        self.addClass("recordbone-entry")

        self.parent = parent
        self.module = module
        self.data = data

        self.mask = InternalEdit(using,
                                 data,
                                 errorInfo,
                                 readOnly=parent.readOnly,
                                 defaultCat=None)
        self.appendChild(self.mask)

        if not parent.readOnly:
            remBtn = html5.ext.Button(translate("Remove"), self.onRemove)
            remBtn["class"].append("icon")
            remBtn["class"].append("cancel")
            self.appendChild(remBtn)
Beispiel #3
0
    def unserialize(self, data):
        if self.boneName in data:
            val = data[self.boneName]
            if isinstance(val, list):
                if len(val) > 0:
                    val = val[0]
                else:
                    val = None

            if not isinstance(val, dict):
                val = {}

            if self.mask:
                self.removeChild(self.mask)

            self.mask = InternalEdit(self.using,
                                     val, {},
                                     readOnly=self.readOnly,
                                     defaultCat=None)
            self.appendChild(self.mask)
Beispiel #4
0
    def setSelection(self, selection):
        """
			Set our current value to 'selection'
			:param selection: The new entry that this bone should reference
			:type selection: dict
		"""
        if not selection:
            selection = {}
            self.selection = None

        if not self.selection:
            self.selection = {}

        self.selection.update(selection)

        if selection:
            NetworkService.request(
                self.destModule,
                "view/%s" % selection["dest"]["key"],
                self.context or {},
                successHandler=self.onSelectionDataAvailable,
                cacheable=True)

            self.selectionTxt["value"] = translate("Loading...")

            if self.using and not self.ie:
                self.ie = InternalEdit(self.using,
                                       getDefaultValues(self.using), {},
                                       readOnly=self.readOnly,
                                       defaultCat=self.usingDescr)
                self.ie.addClass("relationwrapper")

                self.appendChild(self.ie)
        else:
            self.selectionTxt["value"] = ""

        self.updateButtons()
Beispiel #5
0
class RecordMultiBoneEntry(html5.Div):
    """
		Wrapper-class that holds one referenced entry in a RecordMultiBone.
		Provides the UI to display its data and a button to remove it from the bone.
	"""
    def __init__(self,
                 parent,
                 module,
                 data,
                 using,
                 errorInfo=None,
                 *args,
                 **kwargs):
        super(RecordMultiBoneEntry, self).__init__(*args, **kwargs)
        self.sinkEvent("onDrop", "onDragOver", "onDragLeave", "onDragStart",
                       "onDragEnd", "onChange")

        self.addClass("recordbone-entry")

        self.parent = parent
        self.module = module
        self.data = data

        self.mask = InternalEdit(using,
                                 data,
                                 errorInfo,
                                 readOnly=parent.readOnly,
                                 defaultCat=None)
        self.appendChild(self.mask)

        if not parent.readOnly:
            remBtn = html5.ext.Button(translate("Remove"), self.onRemove)
            remBtn["class"].append("icon")
            remBtn["class"].append("cancel")
            self.appendChild(remBtn)

    def onDragStart(self, event):
        if self.parent.readOnly:
            return

        self.addClass("is-dragging")

        self.parent.currentDrag = self
        event.dataTransfer.setData("application/json", json.dumps(self.data))
        event.stopPropagation()

    def onDragOver(self, event):
        if self.parent.readOnly:
            return

        if self.parent.currentDrag is not self:
            self.addClass("is-dragging-over")
            self.parent.currentOver = self

        event.preventDefault()

    def onDragLeave(self, event):
        if self.parent.readOnly:
            return

        self.removeClass("is-dragging-over")
        self.parent.currentOver = None

        event.preventDefault()

    def onDragEnd(self, event):
        if self.parent.readOnly:
            return

        self.removeClass("is-dragging")
        self.parent.currentDrag = None

        if self.parent.currentOver:
            self.parent.currentOver.removeClass("is-dragging-over")
            self.parent.currentOver = None

        event.stopPropagation()

    def onDrop(self, event):
        if self.parent.readOnly:
            return

        event.preventDefault()
        event.stopPropagation()

        if self.parent.currentDrag and self.parent.currentDrag != self:
            if self.element.offsetTop > self.parent.currentDrag.element.offsetTop:
                if self.parent.entries[-1] is self:
                    self.parent.moveEntry(self.parent.currentDrag)
                else:
                    self.parent.moveEntry(
                        self.parent.currentDrag,
                        self.parent.entries[self.parent.entries.index(self) +
                                            1])
            else:
                self.parent.moveEntry(self.parent.currentDrag, self)

        self.parent.currentDrag = None

    def onChange(self, event):
        data = self.data.copy()
        data["rel"].update(self.ie.doSave())

        self.updateLabel(data)

    def onRemove(self, *args, **kwargs):
        self.parent.removeEntry(self)
        self.parent.changeEvent.fire(self.parent)

    def serializeForPost(self):
        return self.mask.serializeForPost()

    def serializeForDocument(self):
        return self.mask.serializeForDocument()
Beispiel #6
0
class RecordSingleBone(html5.Div):
    """
		Provides the widget for a recordBone with multiple=False
	"""
    def __init__(self, moduleName, boneName, using, readOnly, required, *args,
                 **kwargs):
        super(RecordSingleBone, self).__init__(*args, **kwargs)

        self.addClass("recordbone", "recordbone-single")

        self.moduleName = moduleName
        self.boneName = boneName
        self.readOnly = readOnly
        self.required = required
        self.using = using

        self.mask = None

        self.changeEvent = EventDispatcher("boneChange")

        if self.readOnly:
            self["disabled"] = True

    def _setDisabled(self, disable):
        super(RecordSingleBone, self)._setDisabled(disable)
        if not disable and not self._disabledState:
            self.parent().removeClass("is_active")

    @classmethod
    def fromSkelStructure(cls, moduleName, boneName, skelStructure, *args,
                          **kwargs):
        readOnly = skelStructure[boneName].get("readonly", False)
        required = skelStructure[boneName].get("required", False)
        using = skelStructure[boneName]["using"]

        return cls(
            moduleName,
            boneName,
            using,
            readOnly,
            required,
        )

    def unserialize(self, data):
        if self.boneName in data:
            val = data[self.boneName]
            if isinstance(val, list):
                if len(val) > 0:
                    val = val[0]
                else:
                    val = None

            if not isinstance(val, dict):
                val = {}

            if self.mask:
                self.removeChild(self.mask)

            self.mask = InternalEdit(self.using,
                                     val, {},
                                     readOnly=self.readOnly,
                                     defaultCat=None)
            self.appendChild(self.mask)

    def serializeForPost(self):
        res = self.mask.serializeForPost()
        return {"%s.%s" % (self.boneName, k): v for (k, v) in res.items()}

    def serializeForDocument(self):
        return {self.boneName: self.mask.serializeForDocument()}

    @staticmethod
    def checkFor(moduleName, boneName, skelStructure, *args, **kwargs):
        isMultiple = "multiple" in skelStructure[boneName] and skelStructure[
            boneName]["multiple"]
        return not isMultiple and (
            skelStructure[boneName]["type"] == "record"
            or skelStructure[boneName]["type"].startswith("record."))
Beispiel #7
0
    def __init__(self,
                 parent,
                 module,
                 data,
                 using=None,
                 errorInfo=None,
                 *args,
                 **kwargs):
        """
			:param parent: Reference to the RelationalMultiSelectionBone we belong to
			:type parent: RelationalMultiSelectionBone
			:param module: Name of the module which references
			:type module: str
			:param data: Values of the entry we shall display
			:type data: dict
		"""
        super(RelationalMultiSelectionBoneEntry,
              self).__init__(*args, **kwargs)
        self.sinkEvent("onDrop", "onDragOver", "onDragLeave", "onDragStart",
                       "onDragEnd", "onChange")

        self.relationalBone = parent
        self.module = module
        self.data = data

        self.txtLbl = html5.Label()
        self.txtLbl["draggable"] = not parent.readOnly

        self.addClass("selectioncontainer-entry")

        wrapperDiv = html5.Div()
        wrapperDiv.appendChild(self.txtLbl)
        wrapperDiv["class"].append("labelwrapper")

        if not parent.readOnly:
            remBtn = html5.ext.Button(translate("Remove"), self.onRemove)
            remBtn["class"].append("icon")
            remBtn["class"].append("cancel")
            wrapperDiv.appendChild(remBtn)

        self.appendChild(wrapperDiv)

        if using:
            self.ie = InternalEdit(using,
                                   data["rel"],
                                   errorInfo,
                                   readOnly=parent.readOnly,
                                   defaultCat=parent.usingDescr)
            self.ie.addClass("relationwrapper")
            self.appendChild(self.ie)
        else:
            self.ie = None

        # Edit button
        if (self.relationalBone.destModule in conf["modules"].keys()
                and ("root" in conf["currentUser"]["access"]
                     or self.relationalBone.destModule + "-edit"
                     in conf["currentUser"]["access"])):

            self.editBtn = html5.ext.Button(translate("Edit"), self.onEdit)
            self.editBtn["class"].append("icon")
            self.editBtn["class"].append("edit")
            wrapperDiv.appendChild(self.editBtn)

        else:
            self.editBtn = None

        self.updateLabel()
Beispiel #8
0
class RelationalMultiSelectionBoneEntry(html5.Div):
    """
		Wrapper-class that holds one referenced entry in a RelationalMultiSelectionBone.
		Provides the UI to display its data and a button to remove it from the bone.
	"""
    def __init__(self,
                 parent,
                 module,
                 data,
                 using=None,
                 errorInfo=None,
                 *args,
                 **kwargs):
        """
			:param parent: Reference to the RelationalMultiSelectionBone we belong to
			:type parent: RelationalMultiSelectionBone
			:param module: Name of the module which references
			:type module: str
			:param data: Values of the entry we shall display
			:type data: dict
		"""
        super(RelationalMultiSelectionBoneEntry,
              self).__init__(*args, **kwargs)
        self.sinkEvent("onDrop", "onDragOver", "onDragLeave", "onDragStart",
                       "onDragEnd", "onChange")

        self.relationalBone = parent
        self.module = module
        self.data = data

        self.txtLbl = html5.Label()
        self.txtLbl["draggable"] = not parent.readOnly

        self.addClass("selectioncontainer-entry")

        wrapperDiv = html5.Div()
        wrapperDiv.appendChild(self.txtLbl)
        wrapperDiv["class"].append("labelwrapper")

        if not parent.readOnly:
            remBtn = html5.ext.Button(translate("Remove"), self.onRemove)
            remBtn["class"].append("icon")
            remBtn["class"].append("cancel")
            wrapperDiv.appendChild(remBtn)

        self.appendChild(wrapperDiv)

        if using:
            self.ie = InternalEdit(using,
                                   data["rel"],
                                   errorInfo,
                                   readOnly=parent.readOnly,
                                   defaultCat=parent.usingDescr)
            self.ie.addClass("relationwrapper")
            self.appendChild(self.ie)
        else:
            self.ie = None

        # Edit button
        if (self.relationalBone.destModule in conf["modules"].keys()
                and ("root" in conf["currentUser"]["access"]
                     or self.relationalBone.destModule + "-edit"
                     in conf["currentUser"]["access"])):

            self.editBtn = html5.ext.Button(translate("Edit"), self.onEdit)
            self.editBtn["class"].append("icon")
            self.editBtn["class"].append("edit")
            wrapperDiv.appendChild(self.editBtn)

        else:
            self.editBtn = None

        self.updateLabel()

    def updateLabel(self, data=None):
        if data is None:
            data = self.data

        self.txtLbl.removeAllChildren()
        txt = utils.formatString(self.relationalBone.format,
                                 data["dest"],
                                 self.relationalBone.relskel,
                                 prefix=["dest"],
                                 language=conf["currentlanguage"])

        if self.ie:
            txt = utils.formatString(txt,
                                     self.ie.serializeForDocument(),
                                     self.relationalBone.using,
                                     prefix=["rel"],
                                     language=conf["currentlanguage"])

        html5.utils.textToHtml(self.txtLbl, txt)

    def onDragStart(self, event):
        if self.relationalBone.readOnly:
            return

        self.addClass("is-dragging")

        self.relationalBone.currentDrag = self
        event.dataTransfer.setData("application/json", json.dumps(self.data))
        event.stopPropagation()

    def onDragOver(self, event):
        if self.relationalBone.readOnly:
            return

        if self.relationalBone.currentDrag is not self:
            self.addClass("is-dragging-over")
            self.relationalBone.currentOver = self

        event.preventDefault()

    def onDragLeave(self, event):
        if self.relationalBone.readOnly:
            return

        self.removeClass("is-dragging-over")
        self.relationalBone.currentOver = None

        event.preventDefault()

    def onDragEnd(self, event):
        if self.relationalBone.readOnly:
            return

        self.removeClass("is-dragging")
        self.relationalBone.currentDrag = None

        if self.relationalBone.currentOver:
            self.relationalBone.currentOver.removeClass("is-dragging-over")
            self.relationalBone.currentOver = None

        event.stopPropagation()

    def onDrop(self, event):
        if self.relationalBone.readOnly:
            return

        event.preventDefault()
        event.stopPropagation()

        if self.relationalBone.currentDrag and self.relationalBone.currentDrag != self:
            if self.element.offsetTop > self.relationalBone.currentDrag.element.offsetTop:
                if self.relationalBone.entries[-1] is self:
                    self.relationalBone.moveEntry(
                        self.relationalBone.currentDrag)
                else:
                    self.relationalBone.moveEntry(
                        self.relationalBone.currentDrag,
                        self.relationalBone.entries[
                            self.relationalBone.entries.index(self) + 1])
            else:
                self.relationalBone.moveEntry(self.relationalBone.currentDrag,
                                              self)

        self.relationalBone.currentDrag = None

    def onChange(self, event):
        data = self.data.copy()
        data["rel"].update(self.ie.doSave())

        self.updateLabel(data)

    def onRemove(self, *args, **kwargs):
        self.relationalBone.removeEntry(self)
        self.relationalBone.changeEvent.fire(self.relationalBone)

    def onEdit(self, sender=None):
        pane = Pane(translate("Edit"),
                    closeable=True,
                    iconClasses=[
                        "module_%s" % self.relationalBone.destModule,
                        "apptype_list", "action_edit"
                    ])
        conf["mainWindow"].stackPane(pane, focus=True)

        try:
            edwg = EditWidget(self.relationalBone.destModule,
                              EditWidget.appList,
                              key=self.data["dest"]["key"],
                              context=self.relationalBone.context)
            pane.addWidget(edwg)

        except AssertionError:
            conf["mainWindow"].removePane(pane)

    def serializeForPost(self):
        if self.ie:
            res = self.ie.serializeForPost()
            res["key"] = self.data["dest"]["key"]
            return res
        else:
            return {"key": self.data["dest"]["key"]}

    def serializeForDocument(self):
        res = {"rel": {}, "dest": {}}

        if self.ie:
            res["rel"] = self.ie.serializeForDocument()

        res["dest"]["key"] = self.data["dest"]["key"]
        return res

    def onAttach(self):
        super(RelationalMultiSelectionBoneEntry, self).onAttach()
        NetworkService.registerChangeListener(self)

        if self.relationalBone["disabled"]:
            self.disable()

    def onDetach(self):
        NetworkService.removeChangeListener(self)
        super(RelationalMultiSelectionBoneEntry, self).onDetach()

    def onDataChanged(self, module, key=None, **kwargs):
        if module != self.relationalBone.destModule or key != self.data[
                "dest"]["key"]:
            return

        self.update()

    def update(self):
        NetworkService.request(self.relationalBone.destModule,
                               "view",
                               params={"key": self.data["dest"]["key"]},
                               successHandler=self.onModuleViewAvailable)

    def onModuleViewAvailable(self, req):
        answ = NetworkService.decode(req)
        self.data["dest"] = answ["values"]
        self.updateLabel()
Beispiel #9
0
class RelationalSingleSelectionBone(html5.Div):
    """
		Provides the widget for a relationalBone with multiple=False
	"""
    def __init__(self,
                 srcModule,
                 boneName,
                 readOnly,
                 destModule,
                 format="$(dest.name)",
                 required=False,
                 using=None,
                 usingDescr=None,
                 context=None,
                 *args,
                 **kwargs):
        """
			:param srcModule: Name of the module from which is referenced
			:type srcModule: string
			:param boneName: Name of the bone thats referencing
			:type boneName: str
			:param readOnly: Prevents modifying its value if set to True
			:type readOnly: bool
			:param destModule: Name of the module which gets referenced
			:type destModule: str
			:param format: Specifies how entries should be displayed.
			:type format: str
		"""
        super(RelationalSingleSelectionBone, self).__init__(*args, **kwargs)
        self.srcModule = srcModule
        self.boneName = boneName
        self.readOnly = readOnly
        self.destModule = destModule
        self.format = format
        self.using = using
        self.usingDescr = usingDescr

        self.selection = None
        self.selectionTxt = html5.Input()
        self.selectionTxt["readonly"] = True
        self.selectionTxt["type"] = "text"
        self.appendChild(self.selectionTxt)
        self.ie = None

        self.baseContext = context
        self.context = self.baseContext.copy() if self.baseContext else None

        self.changeEvent = EventDispatcher("boneChange")

        # Selection button
        if (destModule in conf["modules"].keys() and
            ("root" in conf["currentUser"]["access"]
             or destModule + "-view" in conf["currentUser"]["access"])):

            self.selectBtn = html5.ext.Button(translate("Select"),
                                              self.onShowSelector)
            self.selectBtn["class"].append("icon")
            self.selectBtn["class"].append("select")
            self.appendChild(self.selectBtn)
        else:
            self.selectBtn = None

        # Edit button
        if (destModule in conf["modules"].keys() and
            ("root" in conf["currentUser"]["access"]
             or destModule + "-edit" in conf["currentUser"]["access"])):
            self.editBtn = html5.ext.Button(translate("Edit"), self.onEdit)
            self.editBtn["class"].append("icon")
            self.editBtn["class"].append("edit")
            self.appendChild(self.editBtn)
        else:
            self.editBtn = None

        # Remove button
        if (not required and not readOnly and
            ("root" in conf["currentUser"]["access"]
             or destModule + "-view" in conf["currentUser"]["access"])):
            # Yes, we check for "view" on the remove button, because removal of relations
            # is only useful when viewing the destination module is still allowed.

            self.remBtn = html5.ext.Button(translate("Remove"), self.onRemove)
            self.remBtn["class"].append("icon")
            self.remBtn["class"].append("cancel")
            self.appendChild(self.remBtn)
        else:
            self.remBtn = None

        if self.readOnly:
            self["disabled"] = True

    def _setDisabled(self, disable):
        """
			Reset the is_active flag (if any)
		"""
        super(RelationalSingleSelectionBone, self)._setDisabled(disable)
        if not disable and not self._disabledState and "is_active" in self.parent(
        )["class"]:
            self.parent()["class"].remove("is_active")

    @classmethod
    def fromSkelStructure(cls, moduleName, boneName, skelStructure, *args,
                          **kwargs):
        """
			Constructs a new RelationalSingleSelectionBone from the parameters given in skelStructure.
			:param moduleName: Name of the module which send us the skelStructure
			:type moduleName: str
			:param boneName: Name of the bone which we shall handle
			:type boneName: str
			:param skelStructure: The parsed skeleton structure send by the server
			:type skelStructure: dict
		"""
        readOnly = "readonly" in skelStructure[boneName].keys(
        ) and skelStructure[boneName]["readonly"]

        if "required" in skelStructure[boneName].keys(
        ) and skelStructure[boneName]["required"]:
            required = True
        else:
            required = False

        if "module" in skelStructure[boneName].keys():
            destModule = skelStructure[boneName]["module"]
        else:
            destModule = skelStructure[boneName]["type"].split(".")[1]

        format = "$(name)"
        if "format" in skelStructure[boneName].keys():
            format = skelStructure[boneName]["format"]

        if "using" in skelStructure[boneName].keys(
        ) and skelStructure[boneName]["using"]:
            using = skelStructure[boneName]["using"]
        else:
            using = None

        if ("params" in skelStructure[boneName].keys()
                and skelStructure[boneName]["params"]
                and "usingDescr" in skelStructure[boneName]["params"].keys()):
            usingDescr = skelStructure[boneName]["params"]["usingDescr"]
        else:
            usingDescr = skelStructure[boneName].get("descr", boneName)

        if ("params" in skelStructure[boneName].keys()
                and skelStructure[boneName]["params"]
                and "context" in skelStructure[boneName]["params"].keys()):
            context = skelStructure[boneName]["params"]["context"]
        else:
            context = None

        return cls(moduleName,
                   boneName,
                   readOnly,
                   destModule=destModule,
                   format=format,
                   required=required,
                   using=using,
                   usingDescr=usingDescr,
                   context=context)

    def setContext(self, context):
        self.context = {}

        if context:
            self.context.update(context)

        if self.baseContext:
            self.context.update(self.baseContext)

    def onEdit(self, *args, **kwargs):
        """
			Edit the reference.
		"""
        if not self.selection:
            return

        pane = Pane(translate("Edit"),
                    closeable=True,
                    iconClasses=[
                        "module_%s" % self.destModule, "apptype_list",
                        "action_edit"
                    ])
        conf["mainWindow"].stackPane(pane, focus=True)

        try:
            edwg = EditWidget(self.destModule,
                              EditWidget.appList,
                              key=self.selection["dest"]["key"],
                              context=self.context)
            pane.addWidget(edwg)

        except AssertionError:
            conf["mainWindow"].removePane(pane)

    def onRemove(self, *args, **kwargs):
        self.setSelection(None)
        self.changeEvent.fire(self)

    def unserialize(self, data):
        """
			Parses the values received from the server and update our value accordingly.
			:param data: The data dictionary received.
			:type data: dict
		"""
        if self.boneName in data.keys():
            val = data[self.boneName]
            if isinstance(val, list):
                if len(val) > 0:
                    val = val[0]
                else:
                    val = None

            if isinstance(val, dict):
                self.setSelection(val)
                if self.using:
                    if self.ie:
                        self.removeChild(self.ie)

                    self.ie = InternalEdit(self.using,
                                           val["rel"], {},
                                           readOnly=self.readOnly,
                                           defaultCat=self.usingDescr)
                    self.ie.addClass("relationwrapper")
                    self.appendChild(self.ie)
            else:
                self.setSelection(None)

    def serializeForPost(self):
        """
			Serializes our value into something that can be transferred to the server using POST.
			:returns: dict
		"""
        res = {}

        if not (self.selection and "dest" in self.selection.keys()
                and "key" in self.selection["dest"].keys()):
            return res

        if self.ie:
            res.update(self.ie.serializeForPost())

        res["key"] = self.selection["dest"]["key"]

        return {"%s.0.%s" % (self.boneName, k): v for (k, v) in res.items()}

    def serializeForDocument(self):
        res = {"rel": {}, "dest": {}}

        if (self.selection and "dest" in self.selection.keys()):
            if self.ie:
                res["rel"].update(self.ie.serializeForDocument())

            res["dest"] = self.selection["dest"]

        return {self.boneName: res}

    def onShowSelector(self, *args, **kwargs):
        """
			Opens a ListWidget so that the user can select new values
		"""

        try:
            currentSelector = ListWidget(self.destModule,
                                         selectMode="single",
                                         context=self.context)
        except AssertionError:
            return

        currentSelector.selectionActivatedEvent.register(self)
        conf["mainWindow"].stackWidget(currentSelector)
        self.parent()["class"].append("is_active")

    def onSelectionActivated(self, table, selection):
        """
			Merges the selection made in the ListWidget into our value(s)
		"""
        if selection:
            self.setSelection({"dest": selection[0]})
        else:
            self.setSelection(None)

        self.changeEvent.fire(self)

    def setSelection(self, selection):
        """
			Set our current value to 'selection'
			:param selection: The new entry that this bone should reference
			:type selection: dict
		"""
        if not selection:
            selection = {}
            self.selection = None

        if not self.selection:
            self.selection = {}

        self.selection.update(selection)

        if selection:
            NetworkService.request(
                self.destModule,
                "view/%s" % selection["dest"]["key"],
                self.context or {},
                successHandler=self.onSelectionDataAvailable,
                cacheable=True)

            self.selectionTxt["value"] = translate("Loading...")

            if self.using and not self.ie:
                self.ie = InternalEdit(self.using,
                                       getDefaultValues(self.using), {},
                                       readOnly=self.readOnly,
                                       defaultCat=self.usingDescr)
                self.ie.addClass("relationwrapper")

                self.appendChild(self.ie)
        else:
            self.selectionTxt["value"] = ""

        self.updateButtons()

    def updateButtons(self):
        """
		Updates the display style of the Edit and Remove buttons.
		"""
        if self.selection:
            if self.editBtn:
                self.editBtn["disabled"] = False
            if self.remBtn:
                self.remBtn["disabled"] = False
        else:
            if self.editBtn:
                self.editBtn["disabled"] = True
            if self.remBtn:
                self.remBtn["disabled"] = True

    def onAttach(self):
        super(RelationalSingleSelectionBone, self).onAttach()
        NetworkService.registerChangeListener(self)

    def onDetach(self):
        NetworkService.removeChangeListener(self)
        super(RelationalSingleSelectionBone, self).onDetach()

    def onDataChanged(self, module, key=None, **kwargs):
        if module == self.destModule and self.selection and key == self.selection[
                "dest"]["key"]:
            self.setSelection(self.selection)

    def onSelectionDataAvailable(self, req):
        """
			We just received the full information for this entry from the server and can start displaying it
		"""
        data = NetworkService.decode(req)
        assert self.selection["dest"]["key"] == data["values"]["key"]

        if self.using:
            res = (utils.formatString(
                utils.formatString(self.format,
                                   data["values"],
                                   data["structure"],
                                   prefix=["dest"],
                                   language=conf["currentlanguage"]),
                self.selection["rel"],
                self.using,
                prefix=["rel"],
                language=conf["currentlanguage"]) or data["values"]["key"])
        else:
            res = (utils.formatString(
                utils.formatString(self.format,
                                   data["values"],
                                   data["structure"],
                                   prefix=["dest"],
                                   language=conf["currentlanguage"]),
                data["values"],
                data["structure"],
                language=conf["currentlanguage"]) or data["values"]["key"])

        self.selectionTxt["value"] = res