SOLVED Check the user switch documents in CommandData plugins

Hi,
I want to refresh the dialog when switching documents. I tried to use the following code, but it seems that this cannot be achieved .
When I switch documents, it seems that I only receive type==c4d.MSG_COMMANDINFORMATION

code:

    def Message(self, type, data):
        print("msg type:{}".format(type))
        print("data:{}".format(data))
        if type == c4d.MSG_DOCUMENTINFO:
            if data['type'] == c4d.MSG_DOCUMENTINFO_TYPE_SETACTIVE:
                print("doc Change!")
        return True

Thanks for any help!

Hello @chuanzhen,

Thank you for reaching out to us. Your question is a little bit ambiguous as you do not clearly state what this message function of yours is a member of.

As explained in the Message System Manual, there are multiple types of message methods. Important in your specific use case is that there are two method 'groups' which have the general signature Message(a: int, b: typing.Any) -> bool, one attached to C4DAtom and one attached to GeDialog, GeUserArea and CommandData. There is a slight difference in their argument naming convention, but argument names do not carry any meaning here:

C4DAtom.Message(self, type, data=None) # This is a node message method.
NodeData.Message(self, node, type, data) # This is the node plugin hook counter part of it.

CommandData/GeDialog/GeUserArea.Message(self, msg, result) # This is a GUI/CommandData message method.

So, from the context - you said "I want to refresh the dialog" - I would assume you are implementing a GeDialog or CommandData and have there the code snippet you posted. Using the argument naming convention of C4DAtom.Message will do not any direct harm except for confusing an experienced C4D API reader, but you must understand that these are different methods which are called for different sets of events (i.e., message IDs). A GeDialog.Message will not be called for node events and a C4DAtom.Message will not be called for GUI events.

  • MSG_DOCUMENTINFO is a node message sent to node instances, you will not receive it in dialogs.
  • MSG_COMMANDINFORMATION is a plugin message sent to CommandData plugins.

Inside a CommandData or GeDialog there is no dedicated message you can listen to for being notified about document changes (the whole MSG_DOCUMENTINFO message family is not being broadcasted to these methods). You must keep track of the active document yourself.

I have shown here what would be good pattern to implement such thing, at the slightly more complex case of tracking objects. The principal algorithm would be:

  1. Overwrite GeDialog.CoreMessage.
  2. On a EVMSG_CHANGE event, get the active document.
  3. Get the MAXON_CREATOR_ID of the document to identify the document (documents are also nodes, so you can just call myDoc.FindUniqueID(c4d.MAXON_CREATOR_ID) on your document).
  4. Compare the unique id against a lookup value MyDialog._activeDocUuid.
  5. When the comparison in 4. fails, the document has changed.
  6. Store that UUID hash from 3. as the new MyDialog._activeDocUuid.

You must take this route over UUIDs, as nodes can be reallocated and destroyed, and you will then encounter false positives when you just store a BaseDocument in the lookup _activeDocUuid instead of its MAXON_CREATOR_ID hash. As shown in the lights example linked above, there are multiple levels of complexity you can implement this with, and for example implement _activeDocUuid as a list or hash map which tracks more than one thing.

I hope this helps and cheers,
Ferdinand

Hello @chuanzhen,

Thank you for reaching out to us. Your question is a little bit ambiguous as you do not clearly state what this message function of yours is a member of.

As explained in the Message System Manual, there are multiple types of message methods. Important in your specific use case is that there are two method 'groups' which have the general signature Message(a: int, b: typing.Any) -> bool, one attached to C4DAtom and one attached to GeDialog, GeUserArea and CommandData. There is a slight difference in their argument naming convention, but argument names do not carry any meaning here:

C4DAtom.Message(self, type, data=None) # This is a node message method.
NodeData.Message(self, node, type, data) # This is the node plugin hook counter part of it.

CommandData/GeDialog/GeUserArea.Message(self, msg, result) # This is a GUI/CommandData message method.

So, from the context - you said "I want to refresh the dialog" - I would assume you are implementing a GeDialog or CommandData and have there the code snippet you posted. Using the argument naming convention of C4DAtom.Message will do not any direct harm except for confusing an experienced C4D API reader, but you must understand that these are different methods which are called for different sets of events (i.e., message IDs). A GeDialog.Message will not be called for node events and a C4DAtom.Message will not be called for GUI events.

  • MSG_DOCUMENTINFO is a node message sent to node instances, you will not receive it in dialogs.
  • MSG_COMMANDINFORMATION is a plugin message sent to CommandData plugins.

Inside a CommandData or GeDialog there is no dedicated message you can listen to for being notified about document changes (the whole MSG_DOCUMENTINFO message family is not being broadcasted to these methods). You must keep track of the active document yourself.

I have shown here what would be good pattern to implement such thing, at the slightly more complex case of tracking objects. The principal algorithm would be:

  1. Overwrite GeDialog.CoreMessage.
  2. On a EVMSG_CHANGE event, get the active document.
  3. Get the MAXON_CREATOR_ID of the document to identify the document (documents are also nodes, so you can just call myDoc.FindUniqueID(c4d.MAXON_CREATOR_ID) on your document).
  4. Compare the unique id against a lookup value MyDialog._activeDocUuid.
  5. When the comparison in 4. fails, the document has changed.
  6. Store that UUID hash from 3. as the new MyDialog._activeDocUuid.

You must take this route over UUIDs, as nodes can be reallocated and destroyed, and you will then encounter false positives when you just store a BaseDocument in the lookup _activeDocUuid instead of its MAXON_CREATOR_ID hash. As shown in the lights example linked above, there are multiple levels of complexity you can implement this with, and for example implement _activeDocUuid as a list or hash map which tracks more than one thing.

I hope this helps and cheers,
Ferdinand

@ferdinand Thanks for your help!