/*========================================================================= Program: bbtk Module: $RCSfile: bbtkBlackBox.h,v $ Language: C++ Date: $Date: 2009/03/23 13:06:41 $ Version: $Revision: 1.22 $ =========================================================================*/ /* --------------------------------------------------------------------- * Copyright (c) CREATIS-LRMN (Centre de Recherche en Imagerie Medicale) * Authors : Eduardo Davila, Laurent Guigues, Jean-Pierre Roux * * This software is governed by the CeCILL-B license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/ or redistribute the software under the terms of the CeCILL-B * license as circulated by CEA, CNRS and INRIA at the following URL * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html * or in the file LICENSE.txt. * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided only * with a limited warranty and the software's author, the holder of the * economic rights, and the successive licensors have only limited * liability. * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-B license and that you accept its terms. * ------------------------------------------------------------------------ */ /** * \file * \brief Class bbtk::BlackBox : abstract black-box interface. */ /** * \class bbtk::BlackBox * \brief Abstract black-box interface */ #ifndef __bbtkBlackBox_h__ #define __bbtkBlackBox_h__ #include "bbtkSystem.h" #include "bbtkBlackBoxDescriptor.h" #include "bbtkBlackBoxInputConnector.h" //#include "bbtkBlackBoxOutputConnector.h" #include // Signal/slot mechanism for output change events #include #include namespace bbtk { struct Void { Void(int = 0) {} }; class Factory; class Connection; class BlackBoxOutputConnector; class BBTK_EXPORT BlackBox : public Object { BBTK_ABSTRACT_OBJECT_INTERFACE(BlackBox); public: //================================================================== // INTERFACE //================================================================== typedef boost::signals::trackable OutputChangeObserverType; typedef boost::signal OutputChangeSignalType; typedef OutputChangeSignalType::slot_function_type OutputChangeCallbackType; /// The type of map of output connector pointers typedef std::map OutputConnectorMapType; /// The type of map of input connector pointers typedef std::map InputConnectorMapType; /// Returns the pointer on the descriptor of the box virtual BlackBoxDescriptor::Pointer bbGetDescriptor() const = 0; /// Returns a pointer on a clone of the box with name virtual BlackBox::Pointer bbClone(const std::string& name) = 0; /// User overloadable destruction method of a black box virtual void bbUserDelete(); /// Returns the Name of the Type of the BlackBox const std::string& bbGetTypeName() const { return bbGetDescriptor()->GetTypeName(); } /// Returns the name of the BlackBox (instance) const std::string& bbGetName() const { return bbmName; } /// Returns the full name of the BlackBox (instance+type) virtual std::string bbGetFullName() const; /// Returns the name with the name of the parent prepended if any virtual std::string bbGetNameWithParent() const; /// Returns the parent of the BlackBox, i.e the BlackBox that contains it (0 if none) BlackBox::Pointer bbGetParent() const { return bbmParent.lock(); } /// Main processing method of the box. virtual void bbExecute(bool force = false); /// Returns true iff the BlackBox has an input of name label virtual bool bbHasInput(const std::string& label) const; /// Returns true iff the BlackBox has an output of name label virtual bool bbHasOutput(const std::string& label) const; /// Gets the input type of a given label virtual TypeInfo bbGetInputType( const std::string &label ) const; /// Gets the output type of a given label virtual TypeInfo bbGetOutputType( const std::string &label ) const; /// Gets the data of the input called virtual Data bbGetInput( const std::string &name ) = 0; /// Gets the data of the output called virtual Data bbGetOutput( const std::string &name ) = 0; /// Sets the data of the input called . /// If update_time is false then does not update ChangeTime of input virtual void bbSetInput( const std::string &name, Data data, bool update_time = true ) = 0; virtual void bbBruteForceSetInputPointer( const std::string &name, void* data, bool update_time = true) =0; /// Sets the data of the output called virtual void bbSetOutput( const std::string &name, Data data) = 0; /// Gets the status of the input called IOStatus bbGetInputStatus( const std::string &name ) const { return mInputConnectorMap.find(name)->second->GetStatus(); } /// Returns the input connectors map InputConnectorMapType& bbGetInputConnectorMap() { return mInputConnectorMap; } /// Returns the output connectors map OutputConnectorMapType& bbGetOutputConnectorMap() { return mOutputConnectorMap; } /// Returns the input connectors map (const) const InputConnectorMapType& bbGetInputConnectorMap() const { return mInputConnectorMap; } /// Returns the output connectors map (const) const OutputConnectorMapType& bbGetOutputConnectorMap() const { return mOutputConnectorMap; } /// Returns the input connector BlackBoxInputConnector& bbGetInputConnector(const std::string& n) { return *(mInputConnectorMap.find(n)->second); } /// Returns the output connector BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n) { return *(mOutputConnectorMap.find(n)->second); } /// Returns the input connector (const) const BlackBoxInputConnector& bbGetInputConnector(const std::string& n) const { return *(mInputConnectorMap.find(n)->second); } /// Returns the output connector (const) const BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n) const { return *(mOutputConnectorMap.find(n)->second); } /// Prints the Help on the BlackBox type virtual void bbGetHelp(bool full=true) const; //================================================================== /// Adds the function f to the list of functions to call when /// the output changes. /// f is of type ChangeCallbackType which is basically: /// void (*ChangeCallbackType)(bbtk::BlackBox::Pointer, /// const std::string&, /// bbtk::IOStatus) /// To pass a member function 'f' of an instance 'c' of a class 'C' /// as callback you have to 'bind' it, i.e. call: /// bbAddOutputObserver ( "Out", boost::bind( &C::f , c, _1, _2, _3 ) ); /// The convenience macro BBTK_BIND_OUTPUT_OBSERVER ( c, C::f ) does it for you void bbAddOutputObserver(const std::string& output_name, OutputChangeCallbackType f); /// Removes the function f from the list of functions to call when /// the output changes (TO WRITE) void bbRemoveOutputObserver(const std::string& output_name, OutputChangeCallbackType f); //================================================================== //================================================================== /// Signals that the BlackBox outputs have been modified /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !). /// This method should be used by widgets in response /// to user interaction when **ALL** outputs have been modified /// (after the outputs has been updated !). /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY /// ** USER INTENDED ** virtual void bbSignalOutputModification(bool reaction = true); /// Signals that the BlackBox output "output_name" has been modified /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !). /// This method should be used by widgets in response to user interaction /// only when **ONE** output has been modified /// (after the output has been updated !) /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY /// ** USER INTENDED ** virtual void bbSignalOutputModification( const std::string& output_name, bool reaction = true); /// Signals that the BlackBox vector of outputs "output_name" /// have been modified. /// Should be used when more than ONE output is modified but not ALL /// (optimization issue). /// (without marking the box as MODIFIED because its output state is ok). /// This method should be used by widgets in response to user interaction /// When more than one output has been changed but not all /// (after the outputs have been updated of course!) /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY /// ** USER INTENDED ** virtual void bbSignalOutputModification( const std::vector& output_name, bool reaction = true); //================================================================== //================================================================== // Common inputs / outputs to all boxes /// Returns the value of the input "BoxProcessMode" std::string bbGetInputBoxProcessMode() { return bbmBoxProcessMode; } /// Sets the value of the input "BoxProcessMode" void bbSetInputBoxProcessMode(std::string a) { bbmBoxProcessMode = a; } typedef enum { Pipeline, Always, Reactive } BoxProcessModeValue; /// Returns the "decoded" value of the input "BoxProcessMode" BoxProcessModeValue bbGetBoxProcessModeValue() const; virtual bool bbBoxProcessModeIsReactive() const; virtual bool bbBoxProcessModeIsAlways() const; /// Returns the value of the input "Execute" Void bbGetInputBoxExecute() { return Void(); } /// Sets the value of the input "Execute" void bbSetInputBoxExecute(Void = 0) {} /// Returns the value of the output "Change" Void bbGetOutputBoxChange() { return Void(); } /// Sets the value of the output "Change" : signal a modification void bbSetOutputBoxChange(Void = 0) { } //bbSetModifiedStatus(); } //================================================================== //================================================================== /// Does nothing here : overloaded in ComplexBlackBox void bbInsertHTMLGraph( std::ofstream& s, int detail, int level, bool instanceOrtype, const std::string& output_dir, bool relative_link ) {} /// Write Graphviz-dot description in file. /// Here dumps a single box description (i/o) but overloaded /// in ComplexBlackBox to dump the internal pipeline representation /// recursing into internal boxes descriptions if level>0. /// detail = 1 : draw inputs and outputs (do not draw otherwise) /// instanceOrtype = true : draw inputs and outputs VALUES /// (uses bbGetInputAsString / bbGetOutputAsString which use adaptors) /// If relative_link is true then creates relative hrefs virtual void bbWriteDotFileBlackBox(FILE *ff, BlackBox::Pointer parentblackbox, int detail, int level, bool instanceOrtype, bool relative_link ); /// Auxiliary method for bbWriteDotFileBlackBox virtual void bbWriteDotInputOutputName(FILE *ff, bool inputoutput, int detail, int level); virtual void bbShowRelations(BlackBox::Pointer parentblackbox, int detail, int level ); std::string bbGetOutputAsString( const std::string &output ); //,Factory *factory); std::string bbGetInputAsString( const std::string &input); //,Factory *factory); virtual BlackBox::Pointer bbFindBlackBox(const std::string &blackboxname) { return BlackBox::Pointer();} virtual void Check(bool recursive = true); virtual void bbUserOnShow() { } void bbUserOnShowWidget(std::string nameInput); protected: //================================================================== // PROTECTED PART : ACCESSIBLE TO THE BlackBox DEVELOPER // (IN INHERITED CLASSES) /// Constructor that take the BlackBox's name BlackBox(const std::string &name); /// Constructor from an existing box (copy) with a new name BlackBox(BlackBox& from, const std::string &name); //================================================================== //================================================================== /// Signals that the input whose connector is c has changed /// and propagates the info downward /// ** NOT USER INTENDED ** virtual void bbSetStatusAndPropagate(BlackBoxInputConnector* c, IOStatus s); //================================================================== private: //================================================================== friend class Connection; friend class ComplexBlackBox; /// Sets the parent of the BlackBox void bbSetParent(BlackBox::Pointer p) { bbmParent = p; } /// Connects the input to the connection c virtual void bbConnectInput( const std::string& name, Connection* c); /// Connects the output to the connection c virtual void bbConnectOutput( const std::string& name, Connection* c); /// Disconnects the input from the connection c virtual void bbDisconnectInput( const std::string& name, Connection* c); /// Disconnects the output from the connection c virtual void bbDisconnectOutput( const std::string& name, Connection* c); //================================================================== protected: /// @name Pipeline processing methods /// Methods which participate to pipeline processing. //@{ //================================================================== /// Recursive execution method /// /// \param caller : The connection which invoked the method; null if called by bbExecute virtual void bbRecursiveExecute(Connection::Pointer caller); //================================================================== //================================================================== /// Updates the BlackBox inputs /// Calls RecursiveExecute on all BlackBoxInputConnector /// \returns The maximum of final IOStatus after each input update IOStatus bbUpdateInputs(); //================================================================== //================================================================== /// Actual CreateWidget method (vitual) /// Overloaded in AtomicBlacBox and descendants virtual void bbCreateWidget() { // bbtkError("BlackBox::bbCreateWidget called : how can this happen ?"); } //================================================================== //================================================================== /// Actual ShowWidget method (vitual) /// Overloaded in AtomicBlacBox and descendants virtual void bbShowWidget() { // bbtkError("BlackBox::bbShowWidget called : how can this happen ?"); } //================================================================== //================================================================== /// Actual processing method (vitual) /// Overloaded in AtomicBlacBox and descendants virtual void bbProcess() { bbtkError("BlackBox::bbProcess called : how can this happen ?"); // this->bbUserProcess(); } //================================================================== //================================================================== /// Computes the final IOStatus of inputs and outputs after processing void bbComputePostProcessStatus(); //================================================================== //================================================================== /// Specific methods for window creation during pipeline execution /// Creates the window associated to the box (called after bbUpdateInputs) /// Does nothing here. Overloaded in WxBlackBox. // virtual void bbCreateWindow() { } /// Shows the window associated to the box /// (called after bbProcess during bbExecute) /// Does nothing here but overloaded in WxBlackBox and WxContainerBlackBox // virtual void bbShowWindow(Connection::Pointer caller) { } // virtual void bbHideWindow() {} // virtual void bbCloseWindow() { } //================================================================== //@} public: static bool bbGlobalGetSomeBoxExecuting(); static void bbGlobalSetSomeBoxExecuting(bool b); static void bbGlobalSetFreezeExecution(bool b); static bool bbGlobalGetFreezeExecution(); /// Returns true if the box can "react", /// which means execute in response to an input change virtual bool bbCanReact() const; /// Returns true iff the box is executing bool bbGetExecuting() const { return bbmExecuting; } protected: static void bbGlobalAddToExecutionList( BlackBox::Pointer b ); static void bbGlobalProcessExecutionList(); /// Sets the bbmExecuting bool returned by bbGetExecuting void bbSetExecuting(bool b) { bbmExecuting = b; } //================================================================== protected: //================================================================== /// Allocates the i/o connectors of the black box virtual void bbAllocateConnectors(); /// Desallocates the i/o connectors of the black box virtual void bbDesallocateConnectors(); /// Copies the values of the inputs/output from the BlackBox from virtual void bbCopyIOValues(BlackBox& from); //================================================================== //================================================================== // Black box objects have a special deleter // which must take care of releasing the descriptor // **AFTER** the box is deleted // (Releasing it in the destructor may cause dl close and crash) /// Black box deleter /// 1) Calls the user overloadable bbDelete method /// 2) Releases the box descriptor struct BBTK_EXPORT Deleter : public Object::Deleter { Deleter(); void Delete(Object* p); }; //================================================================== //================================================================== template static boost::shared_ptr MakeBlackBoxPointer(U* s, bool lock = false) { return MakePointer(s,BlackBox::Deleter(),lock); } //================================================================== //================================================================== virtual void bbDelete() { delete this; } //================================================================== //================================================================== private: //================================================================== //================================================================== // ATTRIBUTES /// Is the box executing ? bool bbmExecuting; /// The name of the black-box std::string bbmName; /// The name of the package to which it belongs std::string bbmPackageName; /// The box processing mode /// 0 : "Pipeline" mode /// 1 : "Always" mode /// 2 : "Reactive" mode std::string bbmBoxProcessMode; /// The parent of the black box in the ComplexBlackBox hierarchy BlackBox::WeakPointer bbmParent; //================================================================== //================================================================== // ATTRIBUTES /// Map that contains the output connectors of the black box OutputConnectorMapType mOutputConnectorMap; /// Map that contains the input connectors of the black box InputConnectorMapType mInputConnectorMap; //================================================================== }; // Class BlackBox /// Convenient macro to create output observer callbacks (freehand functions) from object and method pointer (see samples/SampleOutputObserver) #define BBTK_MAKE_OUTPUT_OBSERVER(OBJECT,METHOD) \ boost::bind( METHOD, OBJECT, _1, _2, _3) } // namespace bbtk #endif