#include <maya/MIOStream.h>
#include <maya/MString.h>
#include <maya/MArgList.h>
#include <maya/MFnPlugin.h>
#include <maya/MPxCommand.h>
#include <maya/MSyntax.h>
#include <maya/MArgDatabase.h>
#include <maya/MMessage.h>
#include <maya/MLockMessage.h>
#include <maya/MObject.h>
#include <maya/MSelectionList.h>
#include <maya/MFn.h>
#include <maya/MItSelectionList.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MStringArray.h>
#include <maya/MString.h>
#include <maya/MGlobal.h>
#include <maya/MDagPath.h>
#include <maya/MCallbackIdArray.h>
#define MEL_COMMAND_NAME "lockEvent"
#define VENDOR_TAG "Autodesk"
#define PLUGIN_VERSION "1.0"
#define checkStdError(stat,msg) \
if ( MS::kSuccess != stat ) { \
cerr << msg; \
return MS::kFailure; \
}
#define kClearCBLong "-clearCB"
#define kClearCB "-ccb"
#define kClearCBDV false
#define kOverrideLong "-override"
#define kOverride "-o"
#define kOverrideDV false
#define kAttachLong "-attach"
#define kAttach "-a"
#define kAttachDV 0
#define MLM MLockMessage
class lockEvent : public MPxCommand
{
public:
lockEvent( );
virtual ~lockEvent( );
MStatus doIt( const MArgList & );
MStatus parseArgs( const MArgList &args );
MCallbackId installCallback( MItSelectionList & );
static MSyntax newSyntax( );
static void* creator( );
static bool clearCallbackIds();
private:
MSelectionList theList;
unsigned int fAttach;
bool fOverrideFlag, fOverrideVal, fClearCB;
};
static MCallbackIdArray callbackIds;
static bool overrideMode = false;
void lockDagDecision( MDagPath &path, MDagPath &other,
void *clientData, MLM::LockDAGEvent,
bool &decision );
void lockDecision( MObject &node, MObject &aux,
void *clientData, MLM::LockEvent,
bool &decision );
void plugDecision( MPlug &p1, MPlug &p2,
void *clientData, MLM::LockPlugEvent,
bool &decision );
void nodePlugDecision( MPlug &p1, MPlug &p2,
void *clientData, MLM::LockPlugEvent,
bool &decision );
MStatus initializePlugin( MObject obj );
MStatus uninitializePlugin( MObject obj );
lockEvent::lockEvent( ) :
fOverrideFlag(kOverrideDV),
fOverrideVal(false),
fAttach(kAttachDV)
{
}
lockEvent::~lockEvent( )
{
}
MCallbackId lockEvent::installCallback( MItSelectionList &iter )
{
MStatus status;
MCallbackId id = 0;
MObject node, component;
MDagPath path;
switch (fAttach) {
case 1: {
status = iter.getDependNode( node );
if ( status ) {
id = MLM::setNodeLockQueryCallback( node, lockDecision,
NULL, &status );
}
} break;
case 2: {
status = iter.getDagPath( path, component );
if ( status ) {
id = MLM::setNodeLockDAGQueryCallback( path, lockDagDecision,
NULL, &status );
}
} break;
case 3: {
status = iter.getDependNode( node );
MStringArray plugName;
iter.getStrings( plugName );
if ( status && plugName.length() > 0 ) {
MFnDependencyNode depNode( node );
MStringArray attrName;
plugName[0].split( '.', attrName );
MPlug plug = depNode.findPlug( attrName[1], &status );
if ( status ) {
id = MLM::setPlugLockQueryCallback( plug, plugDecision,
NULL,&status );
}
} else {
status = MS::kFailure;
}
} break;
case 4: {
status = iter.getDependNode( node );
if ( status ) {
id = MLM::setPlugLockQueryCallback( node, nodePlugDecision,
NULL, &status );
}
} break;
default:
MGlobal::displayError( "Invalid callback attach type" );
status = MS::kFailure;
};
MFnDependencyNode fnNode( node );
if ( !status || !id ) {
MString msg;
msg = "Unable to add callback for node ";
msg += fnNode.name();
MGlobal::displayError( msg );
status.perror( msg );
} else {
cerr << "Callback attached to " << fnNode.name();
cerr << "; attachment type = " << fAttach << endl;
callbackIds.append( (int)id );
}
return id;
}
MStatus lockEvent::doIt( const MArgList &args )
{
MStatus status;
int result = 0;
if ( !parseArgs( args ) ) {
return MS::kFailure;
}
if ( fAttach ) {
MItSelectionList iter( theList, MFn::kDependencyNode, &status );
for ( ; status && !iter.isDone(); iter.next() ) {
MCallbackId id = installCallback( iter );
if ( id ) {
result ++;
} else {
status = MS::kFailure;
}
}
} else if ( fOverrideFlag ) {
overrideMode = fOverrideVal;
} else if ( fClearCB ) {
clearCallbackIds();
result++;
}
clearResult();
setResult( result );
return status;
}
void *lockEvent::creator( )
{
return new lockEvent;
}
MStatus lockEvent::parseArgs( const MArgList &args )
{
MStatus status;
MArgDatabase argData( syntax(), args );
fAttach = kAttachDV;
fOverrideFlag = kOverrideDV;
fClearCB = kClearCBDV;
if ( argData.isFlagSet( kClearCB ) ) {
fClearCB = !kClearCBDV;
}
if ( argData.isFlagSet( kOverride ) ) {
bool tmp;
status = argData.getFlagArgument( kOverride, 0, tmp );
if ( !status ) {
MGlobal::displayError( "override flag parsing failed" );
return status;
}
fOverrideFlag = !kOverrideDV;
fOverrideVal = tmp;
}
if ( argData.isFlagSet( kAttach ) ) {
unsigned int tmp;
status = argData.getFlagArgument( kAttach, 0, tmp );
if ( !status ) {
MGlobal::displayError( "attach flag parsing failed" );
return status;
}
fAttach = tmp;
}
if ( fAttach ) {
status = argData.getObjects( theList );
if ( theList.length() == 0 ) {
MString msg = "You must specify a node/plug to attach to!";
MGlobal::displayError(msg);
status = MS::kFailure;
}
}
if ( status && fAttach && fOverrideFlag ) {
MString msg = "You specified too many flags!" ;
MGlobal::displayError(msg);
status = MS::kFailure;
}
return status;
}
MSyntax lockEvent::newSyntax( )
{
MSyntax syntax;
syntax.addFlag( kClearCB, kClearCBLong );
syntax.addFlag( kOverride, kOverrideLong, MSyntax::kBoolean );
syntax.addFlag( kAttach, kAttachLong, MSyntax::kUnsigned );
syntax.useSelectionAsDefault( true );
syntax.setObjectType( MSyntax::kSelectionList, 0 );
return syntax;
}
void nodePlugDecision( MPlug &p1, MPlug &p2,
void *clientData, MLM::LockPlugEvent event,
bool &decision )
{
MString msg, eventString;
msg = "nodePlugDecision called";
switch (event) {
case MLM::kPlugLockAttr:
eventString = "kPlugLockAttr";
break;
case MLM::kPlugUnlockAttr:
eventString = "kPlugUnlockAttr";
break;
case MLM::kPlugAttrValChange:
eventString = "kPlugAttrValChange";
break;
case MLM::kPlugRemoveAttr:
eventString = "kPlugRemoveAttr";
break;
case MLM::kPlugRenameAttr:
eventString = "kPlugRenameAttr";
break;
case MLM::kPlugConnect:
eventString = "kPlugConnect";
break;
case MLM::kPlugDisconnect:
eventString = "kPlugDisconnect";
break;
default:
eventString = "kLastPlug";
break;
};
cerr << msg << "; event = " << eventString;
cerr << "; override = " << overrideMode << endl;
decision = !overrideMode;
}
void plugDecision( MPlug &p1, MPlug &p2,
void *clientData, MLM::LockPlugEvent event,
bool &decision )
{
MString msg, eventString;
msg = "plugDecision called";
switch (event) {
case MLM::kPlugLockAttr:
eventString = "kPlugLockAttr";
break;
case MLM::kPlugUnlockAttr:
eventString = "kPlugUnlockAttr";
break;
case MLM::kPlugAttrValChange:
eventString = "kPlugAttrValChange";
break;
case MLM::kPlugRemoveAttr:
eventString = "kPlugRemoveAttr";
break;
case MLM::kPlugRenameAttr:
eventString = "kPlugRenameAttr";
break;
case MLM::kPlugConnect:
eventString = "kPlugConnect";
break;
case MLM::kPlugDisconnect:
eventString = "kPlugDisconnect";
break;
default:
eventString = "kInvalidPlug";
break;
};
cerr << msg << "; event = " << eventString;
cerr << "; override = " << overrideMode << endl;
decision = !overrideMode;
}
void lockDagDecision( MDagPath &path, MDagPath &other,
void *clientData, MLM::LockDAGEvent event,
bool &decision )
{
MString eventString;
cerr << "lockDagDecision called ";
switch (event) {
case MLM::kGroup:
eventString = "kGroup";
break;
case MLM::kUnGroup:
eventString = "kUnGroup";
break;
case MLM::kReparent:
eventString = "kReparent";
break;
case MLM::kChildReorder:
eventString = "kChildReorder";
break;
case MLM::kCreateNodeInstance:
eventString = "kCreateNodeInstance";
break;
case MLM::kCreateChildInstance:
eventString = "kCreateChildInstance";
break;
case MLM::kCreateParentInstance:
eventString = "kCreateParentInstance";
break;
case MLM::kInvalidDAG:
default:
eventString = "kInvalid";
};
cerr << "on " << eventString << " event";
cerr << "; overrideMode = " << overrideMode << endl;
decision = !overrideMode;
}
void lockDecision( MObject &node, MObject &attr,
void *clientData, MLM::LockEvent event,
bool &decision )
{
MString eventString;
cerr << "lockDecision called ";
switch ( event ) {
case MLM::kDelete:
eventString = "kDelete";
break;
case MLM::kRename:
eventString = "kRename";
break;
case MLM::kLockNode:
eventString = "kLockNode";
break;
case MLM::kUnlockNode:
eventString = "kUnlockNode";
break;
case MLM::kAddAttr:
eventString = "kAddAttr";
break;
case MLM::kRemoveAttr:
eventString = "kRemoveAttr";
break;
case MLM::kRenameAttr:
eventString = "kRemoveAttr";
break;
case MLM::kUnlockAttr:
eventString = "kUnlockAttr";
break;
case MLM::kLockAttr:
eventString = "kLockAttr";
break;
case MLM::kInvalid:
default:
eventString = "kInvalid";
};
cerr << "on " << eventString << " event";
cerr << "; overrideMode = " << overrideMode << endl;
decision = !overrideMode;
}
bool lockEvent::clearCallbackIds( )
{
unsigned int idCount = callbackIds.length();
for ( unsigned int i = 0; i < idCount; i ++ ) {
cerr << "callback #" << i << "; id = " << (unsigned)callbackIds[i] << endl;
MMessage::removeCallback( (MCallbackId) callbackIds[i] );
}
callbackIds.clear();
return true;
}
MStatus initializePlugin( MObject obj )
{
MStatus status;
MFnPlugin plugin( obj, VENDOR_TAG, PLUGIN_VERSION, "Any" );
status = plugin.registerCommand( MEL_COMMAND_NAME,
lockEvent::creator,
lockEvent::newSyntax );
callbackIds.clear();
return status;
}
MStatus uninitializePlugin( MObject obj )
{
MFnPlugin plugin( obj );
MStatus status;
status = plugin.deregisterCommand( MEL_COMMAND_NAME );
if ( status ) {
lockEvent::clearCallbackIds();
}
return status;
}