NodeMonitor.cpp

//-
// ==========================================================================
// Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All 
// rights reserved.
//
// The coded instructions, statements, computer programs, and/or related 
// material (collectively the "Data") in these files contain unpublished 
// information proprietary to Autodesk, Inc. ("Autodesk") and/or its 
// licensors, which is protected by U.S. and Canadian federal copyright 
// law and by international treaties.
//
// The Data is provided for use exclusively by You. You have the right 
// to use, modify, and incorporate this Data into other products for 
// purposes authorized by the Autodesk software license agreement, 
// without fee.
//
// The copyright notices in the Software and this entire statement, 
// including the above license grant, this restriction and the 
// following disclaimer, must be included in all copies of the 
// Software, in whole or in part, and all derivative works of 
// the Software, unless such copies or derivative works are solely 
// in the form of machine-executable object code generated by a 
// source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. 
// AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED 
// WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF 
// NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 
// PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR 
// TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS 
// BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, 
// DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK 
// AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY 
// OR PROBABILITY OF SUCH DAMAGES.
//
// ==========================================================================
//+

// NodeMonitor.cpp

// DESCRIPTION: This class monitors a given node. 
//
// TODO: Take care of renamed nodes.
//
// AUTHOR: Christian Laforte
//

#include <assert.h>
#include "NodeMonitor.h"

MObject getObjFromName(MString name, MStatus& stat)
{
        MObject obj;
        
        MSelectionList list;
        
        // Attempt to add the given name to the selection list,
        // then get the corresponding dependency node handle.
        if (!list.add(name) ||
                !list.getDependNode(0, obj))
        {
                // Failed.
                stat = MStatus::kInvalidParameter;
                return obj;
        }

        // Successful.
        stat = MStatus::kSuccess;
        return obj;
}

// If a problem occurs, this function returns an empty string.
MString getNameFromObj(MObject obj)
{
        MString nodeName;

        // If this object is a MFnDagNode, we should store the dag name.
        // Otherwise, use the MFnDependencyNode name.
        if (obj.hasFn(MFn::kDagNode))
        {
                MFnDagNode dagNode(obj);
                nodeName = dagNode.fullPathName();
        }
        else if (obj.hasFn(MFn::kDependencyNode))
        {
                MFnDependencyNode node(obj);
                nodeName = node.name();
        }

        return nodeName;
}


//-----------------------------------------------------------
// Public interface:
//-----------------------------------------------------------

NodeMonitor::NodeMonitor(NodeMonitorManager* manager /* = NULL */)
{
        fNodeName = "";
        fIsDirty = false;
        
        fRenamedCallbackId = 0;
        fDirtyCallbackId = 0;

        fManager = manager;
}

NodeMonitor::~NodeMonitor()
{
        stopWatching();
}

bool NodeMonitor::watch(MString nodeName)
{
        // if already watching another object, release the callbacks.
        stopWatching();

        fNodeName = nodeName;
        return attachCallbacks();
}

bool NodeMonitor::watch(MObject nodeObj)
{
        MString newNodeName = getNameFromObj(nodeObj);

        // If already watching another object, release the callbacks.
        stopWatching();

        // Get the name of the given object... since an MObject is not
        // persistent. We'll use the name of the object to attach/re-attach
        // callbacks when necessary.
        if (newNodeName == "")
        {
                // This is bad. We've been given an invalid node object.
                // return false to indicate that an error occured.

                return false;
        }

        fNodeName = newNodeName;
        return attachCallbacks();       
}

void NodeMonitor::stopWatching()
{
        if (fNodeName != "")
        {
                // Clean up the callbacks
                detachCallbacks();

                fNodeName = "";
                fIsDirty = false;
        }
}

bool NodeMonitor::dirty()
{
        return fIsDirty;
}

void NodeMonitor::cleanIt()
{
        if (dirty())
        {
                // We have to re-attach the callback.
                attachCallbacks();
        }

        fIsDirty = false;
}


//----------------------------------------------------------------
// Private interface:
//----------------------------------------------------------------

bool NodeMonitor::attachCallbacks()
{
        // Make sure that there are no callbacks currently enabled.
        detachCallbacks();

        MStatus stat;
        MObject node = getObjFromName(fNodeName, stat);
        if (!stat)
        {
                detachCallbacks();
                return false;
        }

        fIsDirty = false;

        fDirtyCallbackId = MNodeMessage::addNodeDirtyCallback(node, watchedObjectDirtyCallback, this, &stat );
        if (stat)
        {
                fRenamedCallbackId = MNodeMessage::addNameChangedCallback (node, watchedObjectRenamedCallback, this, &stat); 
        }

        // If an error occured, detach any valid callback.
        if (!stat)
        {
                detachCallbacks();
                return false;
        }

        return true;
}

void NodeMonitor::detachCallbacks()
{
        MStatus stat;

        if (fDirtyCallbackId)
        {
                stat = MMessage::removeCallback(fDirtyCallbackId);
                assert(stat);
        }

        if (fRenamedCallbackId)
        {
                stat = MMessage::removeCallback(fRenamedCallbackId);
                assert(stat);
        }

        fRenamedCallbackId = 0;
        fDirtyCallbackId = 0;
}

void NodeMonitor::callbackOccured()
{
        fIsDirty = true;

        // Detach the callback so that we don't get called needlessly. We'll
        // re-attach when the dirty bit is read back.
        detachCallbacks();
}

// Callback functions. Those are called, respectively, when a node is dirty (has changed substantially),
// or when a node is renamed.

/*static*/ void NodeMonitor::watchedObjectDirtyCallback(void* clientData)
{
        NodeMonitor* pMon = (NodeMonitor*) clientData;

        pMon->callbackOccured();
}

/*static*/ void NodeMonitor::watchedObjectRenamedCallback(MObject & node, void* clientData)
{
        NodeMonitor* pMon = (NodeMonitor*) clientData;

        // Get the new name of the node, and use it from now on.
        MString oldName = pMon->fNodeName;
        pMon->fNodeName = getNameFromObj(node);
        
        // Call the manager, if there's one.
        if (pMon->fManager != NULL)
                pMon->fManager->onNodeRenamed(node, oldName, pMon->fNodeName);

        pMon->callbackOccured();
}

Autodesk® Maya® 2009 © 1997-2008 Autodesk, Inc. All rights reserved. Generated with doxygen 1.5.6