/*========================================================================= Program: bbtk Module: $RCSfile: bbtkBlackBox.h,v $ Language: C++ Date: $Date: 2012/07/26 08:28:31 $ Version: $Revision: 1.33 $ =========================================================================*/ /* --------------------------------------------------------------------- * 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 "bbtkMessageManager.h" #include "bbtkBlackBoxDescriptor.h" #include "bbtkBlackBoxInputConnector.h" //#include "bbtkBlackBoxOutputConnector.h" #include // Signal/slot mechanism for output change events #include #include #define bbtkBlackBoxMessage(key,level,mess) \ bbtkMessage(key,level,"["< 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; //================================================================== //================================================================== /// @name Pipeline processing methods /// Methods which participate to pipeline processing. //@{ /// Main processing method of the box. virtual void bbExecute(bool force = false); //@} //================================================================== //================================================================== /// Returns a pointer on a clone of the box with name virtual BlackBox::Pointer bbClone(const std::string& name) = 0; //================================================================== //================================================================== /// @name General accessors /// Methods which give access to general informations on the box //@{ /// Returns the pointer on the descriptor of the box virtual BlackBoxDescriptor::Pointer bbGetDescriptor() const = 0; /// 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(); } //@} //================================================================== //================================================================== /// @name Inputs/Outputs related methods /// Methods related to the box inputs and outputs //@{ /// Returns true iff the BlackBox has an input of name label virtual bool bbHasInput(const std::string& label) const; /// Gets the input type of a given label virtual TypeInfo bbGetInputType( const std::string &label ) const; /// Gets the status of the input called IOStatus bbGetInputStatus( const std::string &name ) const { return mInputConnectorMap.find(name)->second->GetStatus(); } /// Gets the data of the input called virtual Data bbGetInput( const std::string &name ) = 0; /// Gets the data of the input called as a string using an Adaptor if possible (else returns empty string) std::string bbGetInputAsString( const std::string &input); /// 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; /// [SYSTEM]: Sets the data of the input called which **MUST* be a pointer virtual void bbBruteForceSetInputPointer( const std::string &name, void* data, bool update_time = true) =0; /// Returns true iff the BlackBox has an output of name label virtual bool bbHasOutput(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 output called virtual Data bbGetOutput( const std::string &name ) = 0; /// Gets the data of the output called as a string using an Adaptor if possible (else returns empty string) std::string bbGetOutputAsString( const std::string &output ); //,Factory *factory); /// Sets the data of the output called virtual void bbSetOutput( const std::string &name, Data data) = 0; /// Returns the input connectors map InputConnectorMapType& bbGetInputConnectorMap() { return mInputConnectorMap; } /// Returns the input connectors map (const) const InputConnectorMapType& bbGetInputConnectorMap() const { return mInputConnectorMap; } /// Returns the input connector BlackBoxInputConnector& bbGetInputConnector(const std::string& n) { return *(mInputConnectorMap.find(n)->second); } /// Returns the input connector (const) const BlackBoxInputConnector& bbGetInputConnector(const std::string& n) const { return *(mInputConnectorMap.find(n)->second); } /// Returns the output connectors map OutputConnectorMapType& bbGetOutputConnectorMap() { return mOutputConnectorMap; } /// Returns the output connectors map (const) const OutputConnectorMapType& bbGetOutputConnectorMap() const { return mOutputConnectorMap; } /// Returns the output connector BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n) { return *(mOutputConnectorMap.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; //================================================================== /// @name Output signals / observers related methods /// Methods related to signals emitted by outputs and the //@{ //================================================================== /// 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); //================================================================== //@} //================================================================== /// @name 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; } /// The possible values of the input 'BoxProcessMode' typedef enum { bbPipeline, bbAlways, bbReactive, bbManual } BoxProcessModeValue; /// Returns the "decoded" value of the input "BoxProcessMode" BoxProcessModeValue bbGetBoxProcessModeValue() const; /// Returns true iff the input 'BoxProcessMode' is set to 'Reactive' (or a synonym) virtual bool bbBoxProcessModeIsReactive() const; /// Returns true iff the input 'BoxProcessMode' is set to 'Always' (or a synonym) virtual bool bbBoxProcessModeIsAlways() const; /// Returns true iff the input 'BoxProcessMode' is set to 'Manual' (or a synonym) virtual bool bbBoxProcessModeIsManual() const; /// Returns the value of the input 'BoxExecute' Void bbGetInputBoxExecute() { return Void(); } /// Sets the value of the input 'BoxExecute' void bbSetInputBoxExecute(Void = 0) { } /// Returns the value of the output 'BoxChange' Void bbGetOutputBoxChange() { return Void(); } /// Sets the value of the output 'BoxChange' void bbSetOutputBoxChange(Void = 0) { } //@} //================================================================== virtual void bbPrintHelp(BlackBox::Pointer parentblackbox, int detail, int level ); /// 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 ) {} //================================================================== /// @name Window related methods //@{ virtual void bbSetShown(bool) {} virtual bool bbIsShown() { return false; } //@} //================================================================== //JCP changed to public 09-06-09 //================================================================== /// @name Manage the execution //@{ static bool bbGlobalGetSomeBoxExecuting(); static void bbGlobalSetSomeBoxExecuting(bool b); static void bbGlobalSetFreezeExecution(bool b); static bool bbGlobalGetFreezeExecution(); static void bbGlobalAddToExecutionList( BlackBox::Pointer b ); static void bbGlobalProcessExecutionList(); //@} //JCP 09-06-09 protected: //================================================================== /// @name User redefinable methods /// Virtual methods which can be redefined by inherited classes //@{ //================================================================== /// User can redefine this method to set /// the default values of the box inputs and outputs /// (it is called in the box constructor) virtual void bbUserSetDefaultValues() {} /// User can redefine this method to initialize what must be /// initialized for the box to work, for example allocate dynamic data. /// It is called once and only once before any call to bbUserCreateWidget /// or bbUserProcess. /// What has been allocated here must be desalocated in /// bbFinalizeProcessing virtual void bbUserInitializeProcessing() {} /// User must redefine this method to uninitialize what has been /// initialized in bbUserInitializeProcessing, /// typically desallocate memory that has been allocated dynamically. /// It is called in the box destructor if and only if (iff) /// bbUserInitializeProcessing has been called previously. virtual void bbUserFinalizeProcessing() {} /// virtual void bbUserOnShow() {} //================================================================== // @} //================================================================== //================================================================== /// 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 BlackBox::Pointer bbFindBlackBox(const std::string &blackboxname) { return BlackBox::Pointer();} virtual void Check(bool recursive = true); //================================================================== // 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); //================================================================== //================================================================== /// @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 CreateWindow method (vitual) /// Overloaded in AtomicBlacBox and descendants virtual void bbCreateWindow() { // bbtkError("BlackBox::bbCreateWidget called : how can this happen ?"); } //================================================================== //================================================================== /// Actual ShowWindow method (vitual) /// Overloaded in AtomicBlacBox and descendants virtual void bbShowWindow() { // 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(); //@} //================================================================== //================================================================== /// 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); //================================================================== //================================================================== /// @name Box con(des)struction / initi(fin)alization methods //@{ //================================================================== /// 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); //================================================================== //================================================================== /// Initializes processing IF NEEDED. /// Calls bbRecursiveInitializeProcessing if the box is in /// "uninitialized" state and put it in "initialized" state. /// On construction, boxes are "uninitialized". /// See also bbFinalizeProcessing void bbInitializeProcessing(); /// Finalizes processing IF NEEDED. /// Calls bbRecursiveFinalizeProcessing if the box is in /// "initialized" state and put it in "uninitialized" state. /// On construction, boxes are "uninitialized". /// See also bbInitializeProcessing void bbFinalizeProcessing(); /// Abstract prototype of the method which /// Recursively calls itself for the parent black box and then /// calls bbUserInitializeProcessing for its own class. /// It is redefined in each black box descendant. /// Allows to call bbUserInitializeProcessing for all inherited classes /// (like a constructor does) virtual void bbRecursiveInitializeProcessing() {} /// Abstract prototype of the method which /// calls bbUserFinalizeProcessing for its own class and then /// recursively calls itself for the parent black box. /// It is redefined in each black box descendant. /// Allows to call bbUserFinalizeProcessing for all inherited classes /// (like a destructor does) virtual void bbRecursiveFinalizeProcessing() {} //================================================================== //@} //================================================================== private: //================================================================== friend class Connection; friend class ComplexBlackBox; /// Sets the parent of the BlackBox void bbSetParent(BlackBox::Pointer p) { bbmParent = p; } //================================================================== /// @name Input/output connection/disconnection /// INTERNAL METHODS used by a Connection to connect/disconnect /// itself to the i/o connectors of the box //@{ /// 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); //@} //================================================================== /// 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; } /// Sets the bbmExecuting bool returned by bbGetExecuting void bbSetExecuting(bool b) { bbmExecuting = b; } protected: //================================================================== protected: //================================================================== /// 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(); int Delete(Object* p); }; //================================================================== //================================================================== /// Like Object::MakePointer but returns a boost::shared_pointer which uses a BlackBox::Deleter to delete the object instead of the default Object::Deleter template static boost::shared_ptr MakeBlackBoxPointer(U* s, bool lock = false) { return MakePointer(s,BlackBox::Deleter(),lock); } //================================================================== //================================================================== /// Effective deletion method called by the Deleter. /// The default implementation is to issue 'delete this' /// but it can be redefined in inherited classes to handle special deletion mechanisms (e.g. ref counting, private destructors, such as vtk objects deletion with method Delete, etc.). /// \return The number of remaining references on the object after the call (if meaningfull...): used by bbtk to warn a user if another smart pointing system is still holding the object... //JCP 21-09-20 09 delete this throws and exception change due to compiler version changing and boost version virtual int bbDelete() { delete this; return 0; } //================================================================== //================================================================== private: //================================================================== //================================================================== // ATTRIBUTES /// Is the box initialized ? bool bbmInitialized; /// 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 /// 3 : "Manual" 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; //================================================================== bool bbLetRecursiveExecuteManualMode; }; // 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