- Main Page
- Related Pages
- Modules
- Classes
- Examples

# nodeCreatedCBCmd.cpp

    //-
    // ==========================================================================
    // Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
    //
    // Use of this software is subject to the terms of the Autodesk
    // license agreement provided at the time of installation or download,
    // or which otherwise accompanies this software in either electronic
    // or hard copy form.
    // ==========================================================================
    //+

    // MEL Command: nodeCreatedCB
    //
    // Description:
    //      A simple plugin to register a mel proc to be called whenever a node is
    //      created. Registered Mel procedures should be declared to take a single
    //      string argument (the name of the added node).
    //
    //      Warning: mel procedures registered with this method will be called
    //               whenever a node is added to the DG. This may cause problems
    //               in certain cases. For example: each time a reference is
    //               reloaded, each of its nodes is re-added to the DG.
    //
    // Flags:
    //      -register/-r string: registers a mel callback. There is no limit
    //                           to the number of callbacks that can be registered.
    //
    //      -unregister/-u string: unregister the specified callback.
    //
    //      -filter/-f string: by default all registered callbacks will be called
    //                         whenever any node is created. Using the filter flag
    //                         you can indicate that callbacks should only be
    //                         called when certain node types are created.
    //                         To determine the type of a particular node see the
    //                         'objectType' and 'nodeType' commands.
    //
    //                         Note: only one filter can be in affect at a time,
    //                         and it will be applied to all registered callbacks.
    //
    //      -fullDagPath/-fdp: if this flag is specified when registering a
    //                         callback, any dag node names passed into the mel
    //                         procedure will include the full dag path.
    //
    // Note:
    //      The -register, -unregister, and -filter flags are mutually exclusive,
    //      only one should be used per command invocation.
    //
    // Important:
    //      Do not delete the node in your callback.
    //
    // Example Usage:
    //
    // // Appends the suffix '_ply' to all created mesh nodes
    // //
    // global proc myCB( string $node )
    // {
    //      print("calling polyCB " + $node + "\n");
    //      string $type = `objectType $node`;
    //      if ( $type == "mesh" ) {
    //          rename $node ($node+"_ply");
    //      }
    // }
    //
    // nodeCreatedCB -register "myCB";
    //
    #include <nodeCreatedCBCmd.h>
    #include <maya/MFnPlugin.h>
    #include <maya/MObject.h>
    #include <maya/MFnDependencyNode.h>
    #include <maya/MFnDagNode.h>
    #include <maya/MDGMessage.h>
    #include <maya/MArgDatabase.h>
    #include <maya/MSyntax.h>
    #include <maya/MGlobal.h>

    #define kRegisterFlagLong       "-register"
    #define kRegisterFlag           "-r"
    #define kUnregisterFlagLong     "-unregister"
    #define kUnregisterFlag         "-u"
    #define kFilterFlagLong         "-filter"
    #define kFilterFlag             "-f"
    #define kFullDagPathFlagLong    "-fullDagPath"
    #define kFullDagPathFlag        "-fdp"

    // The id of the API callback. The API callback must be removed when this
    // plug-in is unloaded.
    //
    MCallbackId     nodeCreatedCB::sId;
    // The array of all registered Mel procedures.
    //
    MStringArray    nodeCreatedCB::sMelProcs;
    // Flags to indicate whether or not a mel procedure should be passed the
    // short or long names of dag nodes.
    //
    MIntArray       nodeCreatedCB::sFullDagPath;

    MStatus nodeCreatedCB::doIt( const MArgList& args )
    //
    //  Description:
    //      implements the MEL nodeCreatedCB command.
    //
    {
        MStatus stat = MS::kSuccess;

        MArgDatabase argData( syntax(), args );

        // Parse command flags.
        //
        if ( argData.isFlagSet( kRegisterFlag ) ) {
            // Register a new procedure.
            //
            MString proc;
            argData.getFlagArgument( kRegisterFlag, 0, proc );
            stat = registerMelProc( proc, argData.isFlagSet( kFullDagPathFlag ) );
        } else if ( argData.isFlagSet( kUnregisterFlag ) ) {
            // Unregister a procedure.
            //
            MString proc;
            argData.getFlagArgument( kUnregisterFlag, 0, proc );
            stat = unregisterMelProc( proc );
        } else if ( argData.isFlagSet( kFilterFlag ) ) {
            // Change the filter being applied.
            //
            MString filter;
            argData.getFlagArgument( kFilterFlag, 0, filter );
            stat = changeFilter( filter );
        }

        if ( stat.error() ) {
            MGlobal::displayError( stat.errorString() );
        }

        return stat;
    }

    MStatus nodeCreatedCB::registerMelProc( MString melProc, bool fullDagPath )
    //
    // Register a Mel procedure to be called whenever a node is added.
    //
    {
        MStatus stat = MS::kSuccess;
        if ( melProc.length() == 0 ) {
            // Basic error checking. An empty string is not a valid mel procedure
            // name
            //
            stat = MS::kFailure;
            stat.perror("invalid mel callback: " + melProc);
            return stat;
        }
        nodeCreatedCB::sMelProcs.append( melProc );
        nodeCreatedCB::sFullDagPath.append( fullDagPath );
        return stat;
    }

    MStatus nodeCreatedCB::unregisterMelProc( MString melProc )
    //
    // Unregister a Mel procedure.
    //
    {
        MStatus stat = MS::kFailure;
        int numProcs = nodeCreatedCB::sMelProcs.length();
        for ( int i = 0; i < numProcs; i++ ) {
            // Search the array of registered callbacks for melProc and
            // remove it. If melProc exists more than once, only one instance
            // of it will be removed.
            //
            if ( nodeCreatedCB::sMelProcs[i] == melProc ) {
                nodeCreatedCB::sMelProcs.remove(i);
                nodeCreatedCB::sFullDagPath.remove(i);
                stat = MS::kSuccess;
                break;
            }
        }

        if ( !stat ) {
            // Report an error if melProc was not found.
            //
            stat.perror(melProc + " is not a registered callback.");
        }

        return stat;
    }

    MStatus nodeCreatedCB::changeFilter( MString filter )
    //
    // Change the node type filter.
    //
    {
        MStatus stat = MS::kSuccess;
        // We don't want to add sCallbackFunc more than once as that will cause
        // all registered Mel procs to be called multiple times. So we first
        // remove, then re-add the callback.
        //
        MDGMessage::removeCallback( nodeCreatedCB::sId );
        nodeCreatedCB::sId = MDGMessage::addNodeAddedCallback( nodeCreatedCB::sCallbackFunc, filter );
        return stat;
    }

    void nodeCreatedCB::sCallbackFunc( MObject& node, void* clientData )
    //
    // The API callback called whenever a node is added. This function handles
    // calling all registered MEL callbacks and passing them the appropriate
    // node name argument.
    //
    {
        int numProcs = nodeCreatedCB::sMelProcs.length();
        for ( int i = 0; i < numProcs; i++ ) {
            MString melCmd = nodeCreatedCB::sMelProcs[i];
            MString nodeName;
            if ( nodeCreatedCB::sFullDagPath[i] &&
                 node.hasFn( MFn::kDagNode ) ) {
                MFnDagNode dagObj( node );
                nodeName = dagObj.fullPathName();
            } else {
                MFnDependencyNode dn( node );
                nodeName = dn.name();
            }
            melCmd += " \"" + nodeName + "\"";
            MGlobal::executeCommand( melCmd );
        }
    }

    MSyntax nodeCreatedCB::newSyntax()
    //
    // Create the syntax object for the nodeCreateCB command.
    //
    {
        MSyntax syntax;

        syntax.addFlag( kRegisterFlag, kRegisterFlagLong, MSyntax::kString );
        syntax.addFlag( kUnregisterFlag, kUnregisterFlagLong, MSyntax::kString );
        syntax.addFlag( kFilterFlag, kFilterFlagLong, MSyntax::kString );
        syntax.addFlag( kFullDagPathFlag, kFullDagPathFlagLong );

        return syntax;
    }

    void* nodeCreatedCB::creator()
    {
        return new nodeCreatedCB;
    }

    MStatus initializePlugin( MObject obj )
    {
        MFnPlugin   plugin( obj, PLUGIN_COMPANY, "6.0" );
        MStatus     stat;
        stat = plugin.registerCommand( "nodeCreatedCB",
                                        nodeCreatedCB::creator,
                                        nodeCreatedCB::newSyntax );
        if ( !stat )
            stat.perror("registerCommand");

        // add the API callback.
        //
        nodeCreatedCB::sId = MDGMessage::addNodeAddedCallback( nodeCreatedCB::sCallbackFunc );

        return stat;
    }
    MStatus uninitializePlugin( MObject obj )
    {
        MFnPlugin   plugin( obj );
        MStatus     stat;
        stat = plugin.deregisterCommand( "nodeCreatedCB" );
        if ( !stat )
            stat.perror("deregisterCommand");

        // Remove the API callback, necessary to prevent crashes.
        //
        MDGMessage::removeCallback( nodeCreatedCB::sId );

        nodeCreatedCB::sMelProcs.clear();
        nodeCreatedCB::sFullDagPath.clear();

        return stat;
    }