void ScriptNode::paste( Node *parent ) { ApplicationRoot *app = applicationRoot(); if( !app ) { throw( "ScriptNode has no ApplicationRoot" ); } IECore::ConstStringDataPtr s = IECore::runTimeCast<const IECore::StringData>( app->getClipboardContents() ); if( s ) { parent = parent ? parent : this; // set up something to catch all the newly created nodes StandardSetPtr newNodes = new StandardSet; parent->childAddedSignal().connect( boost::bind( (bool (StandardSet::*)( IECore::RunTimeTypedPtr ) )&StandardSet::add, newNodes.get(), ::_2 ) ); // do the paste execute( s->readable(), parent ); // transfer the newly created nodes into the selection selection()->clear(); for( size_t i = 0, e = newNodes->size(); i < e; i++ ) { StandardSet::Member *member = newNodes->member( i ); if( member->isInstanceOf( Node::staticTypeId() ) ) { selection()->add( member ); } } } }
SetPtr setConstructor( boost::python::object o ) { StandardSetPtr result = new StandardSet; std::vector<Set::MemberPtr> members; boost::python::container_utils::extend_container( members, o ); result->add( members.begin(), members.end() ); return result; }
bool ScriptNode::importFile( const std::string &fileName, Node *parent, bool continueOnError ) { DirtyPropagationScope dirtyScope; ScriptNodePtr script = new ScriptNode(); script->fileNamePlug()->setValue( fileName ); bool result = script->load( continueOnError ); StandardSetPtr nodeSet = new StandardSet(); nodeSet->add( NodeIterator( script.get() ), NodeIterator( script->children().end(), script->children().end() ) ); const std::string nodeSerialisation = script->serialise( script.get(), nodeSet.get() ); result |= execute( nodeSerialisation, parent, continueOnError ); return result; }
void Box::exportForReference( const std::string &fileName ) const { const ScriptNode *script = scriptNode(); if( !script ) { throw IECore::Exception( "Box::exportForReference called without ScriptNode" ); } // we only want to save out our child nodes and plugs that are visible in the UI, so we build a filter // to specify just the things to export. boost::regex invisiblePlug( "^__.*$" ); StandardSetPtr toExport = new StandardSet; for( ChildIterator it = children().begin(), eIt = children().end(); it != eIt; ++it ) { if( (*it)->isInstanceOf( Node::staticTypeId() ) ) { toExport->add( *it ); } else if( const Plug *plug = IECore::runTimeCast<Plug>( it->get() ) ) { if( !boost::regex_match( plug->getName().c_str(), invisiblePlug ) ) { toExport->add( *it ); } } } ContextPtr context = new Context; context->set( "valuePlugSerialiser:resetParentPlugDefaults", true ); context->set( "serialiser:includeParentMetadata", true ); context->set( "serialiser:includeVersionMetadata", true ); Context::Scope scopedContext( context.get() ); script->serialiseToFile( fileName, this, toExport.get() ); }
BoxPtr Box::create( Node *parent, const Set *childNodes ) { BoxPtr result = new Box; parent->addChild( result ); // it's pretty natural to call this function passing childNodes == ScriptNode::selection(). // unfortunately nodes will be removed from the selection as we reparent // them, so we have to make a copy of childNodes so our iteration isn't befuddled by // the changing contents. we can use this opportunity to weed out anything in childNodes // which isn't a direct child of parent though. StandardSetPtr verifiedChildNodes = new StandardSet(); for( NodeIterator nodeIt( parent ); nodeIt != nodeIt.end(); nodeIt++ ) { if( childNodes->contains( nodeIt->get() ) ) { verifiedChildNodes->add( *nodeIt ); } } // when a node we're putting in the box has connections to // a node remaining outside, we need to reroute the connection // via an intermediate plug on the box. this mapping maps input // plugs (be they internal or external) to intermediate input plugs. typedef std::pair<const Plug *, Plug *> PlugPair; typedef std::map<const Plug *, Plug *> PlugMap; PlugMap plugMap; for( size_t i = 0, e = verifiedChildNodes->size(); i < e; i++ ) { Node *childNode = static_cast<Node *>( verifiedChildNodes->member( i ) ); // reroute any connections to external nodes for( RecursivePlugIterator plugIt( childNode ); plugIt != plugIt.end(); plugIt++ ) { Plug *plug = plugIt->get(); if( plug->direction() == Plug::In ) { Plug *input = plug->getInput<Plug>(); if( input && !verifiedChildNodes->contains( input->node() ) ) { PlugMap::const_iterator mapIt = plugMap.find( input ); if( mapIt == plugMap.end() ) { PlugPtr intermediateInput = plug->createCounterpart( result->promotedCounterpartName( plug ), Plug::In ); // we want intermediate inputs to appear on the same side of the node as the // equivalent internal plug, so we copy the relevant metadata over. copyMetadata( plug, intermediateInput.get() ); intermediateInput->setFlags( Plug::Dynamic, true ); result->addChild( intermediateInput ); intermediateInput->setInput( input ); mapIt = plugMap.insert( PlugPair( input, intermediateInput.get() ) ).first; } plug->setInput( mapIt->second ); plugIt.prune(); } } else { // take a copy of the outputs, because we might be modifying the // original as we iterate. Plug::OutputContainer outputs = plug->outputs(); if( !outputs.empty() ) { typedef Plug::OutputContainer::const_iterator OutputIterator; for( OutputIterator oIt = outputs.begin(), eIt = outputs.end(); oIt != eIt; oIt++ ) { Plug *output = *oIt; const Node *outputNode = output->node(); if( outputNode->parent<Node>() == parent && !verifiedChildNodes->contains( outputNode ) ) { PlugMap::const_iterator mapIt = plugMap.find( plug ); if( mapIt == plugMap.end() ) { PlugPtr intermediateOutput = plug->createCounterpart( result->promotedCounterpartName( plug ), Plug::Out ); copyMetadata( plug, intermediateOutput.get() ); intermediateOutput->setFlags( Plug::Dynamic, true ); result->addChild( intermediateOutput ); intermediateOutput->setInput( plug ); mapIt = plugMap.insert( PlugPair( plug, intermediateOutput.get() ) ).first; } output->setInput( mapIt->second ); } } plugIt.prune(); } } } // reparent the child under the Box. it's important that we do this after adding the intermediate // input plugs, so that when they are serialised and reloaded, the inputs to the box are set before // the inputs to the nodes inside the box - see GafferSceneTest.ShaderAssignmentTest.testAssignShaderFromOutsideBox // for a test case highlighting this necessity. result->addChild( childNode ); } return result; }