-/*=========================================================================
-
+/*=========================================================================
Program: bbtk
Module: $RCSfile: bbtkBlackBox.h,v $
Language: C++
- Date: $Date: 2008/04/22 14:30:25 $
- Version: $Revision: 1.8 $
-
- Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
- l'Image). All rights reserved. See doc/license.txt or
- http://www.creatis.insa-lyon.fr/Public/bbtk/License.html for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even
- the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- PURPOSE. See the above copyright notices for more information.
-
+ Date: $Date: 2008/12/11 09:50:35 $
+ Version: $Revision: 1.21 $
=========================================================================*/
+/* ---------------------------------------------------------------------
+
+* 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
#include "bbtkSystem.h"
#include "bbtkBlackBoxDescriptor.h"
#include "bbtkBlackBoxInputConnector.h"
-#include "bbtkBlackBoxOutputConnector.h"
+//#include "bbtkBlackBoxOutputConnector.h"
#include <set>
+// Signal/slot mechanism for output change events
+#include <boost/signal.hpp>
+#include <boost/bind.hpp>
+
namespace bbtk
{
class Factory;
class Connection;
+ class BlackBoxOutputConnector;
+
+
class BBTK_EXPORT BlackBox : public Object
{
//==================================================================
// INTERFACE
//==================================================================
+ typedef boost::signals::trackable OutputChangeObserverType;
+ typedef boost::signal<void (bbtk::BlackBox::Pointer,
+ const std::string&,
+ IOStatus)> OutputChangeSignalType;
+ typedef OutputChangeSignalType::slot_function_type
+ OutputChangeCallbackType;
/// The type of map of output connector pointers
typedef std::map<std::string, BlackBoxOutputConnector*>
/// Main processing method of the box.
virtual void bbExecute(bool force = false);
- /// Signals that the BlackBox has been modified through the input connector c
- /// and propagates it downward
- virtual void bbSetModifiedStatus(BlackBoxInputConnector* c = 0);
- /// Signals that the BlackBox outputs have been modified
- /// 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 **ALL** outputs have been modified
- /// (after the outputs has been updated !)
- virtual void bbSignalOutputModification(bool reaction = true);
- /// Signals that the BlackBox output "output_name" have been modified
- /// without marking the box as MODIFIED because its output state is ok.
- /// 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 !)
- virtual void bbSignalOutputModification( const std::string& output_name,
-bool reaction = true);
- /// Signals that the BlackBox vector of outputs "output_name"
- /// have been modified
- /// 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!)
- virtual void bbSignalOutputModification( const std::vector<std::string>& output_name,
-bool reaction = true);
- /// Gets the status of the box
- virtual const IOStatus& bbGetStatus() const { return bbmStatus; }
+
+
/// Returns true iff the BlackBox has an input of name label
virtual Data bbGetOutput( const std::string &name ) = 0;
/// Sets the data of the input called <name>.
- /// If setModified is false then does not call bbSetModifiedStatus()
+ /// If update_time is false then does not update ChangeTime of input
virtual void bbSetInput( const std::string &name, Data data,
- bool setModified = true ) = 0;
+ bool update_time = true ) = 0;
virtual void bbBruteForceSetInputPointer( const std::string &name,
void* data,
- bool setModified = true) =0;
+ bool update_time = true) =0;
/// Sets the data of the output called <name>
virtual void bbSetOutput( const std::string &name, Data data) = 0;
+ /// Gets the status of the input called <name>
+ 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 (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<std::string>&
+ output_name,
+ bool reaction = true);
+ //==================================================================
+
+
+
+ //==================================================================
// Common inputs / outputs to all boxes
/// Returns the value of the input "BoxProcessMode"
std::string bbGetInputBoxProcessMode() { return bbmBoxProcessMode; }
/// 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(); }
+ void bbSetOutputBoxChange(Void = 0) { } //bbSetModifiedStatus(); }
//==================================================================
virtual void Check(bool recursive = true);
+ virtual void bbUserOnShow() { }
+ void bbUserOnShowWidget(std::string nameInput);
+
protected:
//==================================================================
// PROTECTED PART : ACCESSIBLE TO THE BlackBox DEVELOPER
//==================================================================
- /// Sets the status of the box
- void bbSetStatus( IOStatus t) { bbmStatus = t; }
+ /// 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;
virtual void bbDisconnectOutput( const std::string& name,
Connection* c);
-
-
+ //==================================================================
+ protected:
/// @name Pipeline processing methods
- /// Methods which participate to (forward or backward) pipeline processing.
- /// Some are pure virtual and prepare particular update mechanism which are implemented by descendents (e.g. ForwardUpdate and UpdateChildren are made for WxContainerBlackBox particular update mechanism which must recurse a piece of the pipeline top-down).
- /// The main method is bbBackwardUpdate which is called by bbExecute and implemented in UserBlackBox and ComplexBlackBox.
- ///
+ /// Methods which participate to pipeline processing.
//@{
+
//==================================================================
- /// Recursive pipeline processing in backward direction
- /// (recursion is in backward direction however execution always goes forward).
- /// Pure virtual; defined in UserBlackBox and ComplexBlackBox
+ /// Recursive execution method
///
- /// \returns The final status of the box (UPTODATE or MODIFIED)
/// \param caller : The connection which invoked the method; null if called by bbExecute
- ///
- /// First checks that re-processing is needed (either Status==MODIFIED or InputProcessMode==Always)
- /// then :
- /// - updates its inputs by calling bbUpdateInputs (which recursively calls bbBackwardUpdate on upstream boxes)
- /// - calls bbCreateWidget
- /// - calls bbProcess which is the user callback which does the actual processing
- /// - calls bbUpdateChildren
- /// - calls bbShowWidget which shows the widget associated to the box (if any)
- protected:
- virtual IOStatus bbBackwardUpdate(Connection::Pointer caller) = 0;
+ virtual void bbRecursiveExecute(Connection::Pointer caller);
//==================================================================
-
+
//==================================================================
- /// Recursive pipeline processing in forward direction along "Child"-"Parent" connections
- /// Pure virtual; defined in UserBlackBox and ComplexBlackBox
- ///
- /// \param caller : The connection which invoked the method
- ///
- /// First checks that re-processing is needed (either Status==MODIFIED or InputProcessMode==Always)
- /// then :
- /// - calls bbCreateWidget
- /// - calls bbProcess which is the user callback which does the actual processing
- /// - calls bbUpdateChildren which recursively calls bbForwardUpdate on connections attached the "Child" output
- // virtual void bbForwardUpdate(Connection::Pointer caller) = 0;
+ /// Updates the BlackBox inputs
+ /// Calls RecursiveExecute on all BlackBoxInputConnector
+ /// \returns The maximum of final IOStatus after each input update
+ IOStatus bbUpdateInputs();
//==================================================================
- protected:
- //==================================================================
- /// Updates the BlackBox inputs and returns the final status of the inputs
- /// (==UPTODATE iff all inputs are UPTODATE)
- // If excludeParent == true then excludes the upstream box connected to input 'Parent' from recursive update
- IOStatus bbUpdateInputs(bool excludeParent=false);
+
+ //==================================================================
+ /// Actual processing method (vitual)
+ /// Overloaded in AtomicBlacBox and descendants
+ virtual void bbProcess()
+ {
+ bbtkError("BlackBox::bbProcess called : how can this happen ?");
+// this->bbUserProcess();
+ }
//==================================================================
//==================================================================
- /// Updates the pipeline in upstream-downstream direction along the "Child"-"Parent" connections only.
- /// Does nothing here. Overloaded in WxContainerBlackbox
- //virtual void bbUpdateChildren( Connection::Pointer caller ) { }
+ /// 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)
/// 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 bbShowWindow(Connection::Pointer caller) { }
+ // virtual void bbHideWindow() {}
+ // virtual void bbCloseWindow() { }
+ //==================================================================
//@}
public:
/// 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:
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
/// Black box deleter
/// 1) Calls the user overloadable bbDelete method
/// 2) Releases the box descriptor
- struct Deleter : public Object::Deleter
+ struct BBTK_EXPORT Deleter : public Object::Deleter
{
Deleter();
void Delete(Object* p);
};
+ //==================================================================
+ //==================================================================
template <class U>
static boost::shared_ptr<U> MakeBlackBoxPointer(U* s, bool lock = false)
{
return MakePointer(s,BlackBox::Deleter(),lock);
}
+ //==================================================================
+ //==================================================================
virtual void bbDelete() { delete this; }
+ //==================================================================
+
+
+ //==================================================================
private:
-
+ //==================================================================
//==================================================================
- // PRIVATE PART
- /// The status of the box
- IOStatus bbmStatus;
+ // 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;
-
- /// 0 : "Pipeline" mode : bbUpdate() only calls Process if Status == MODIFIED (normal pipeline processing)
- /// 1 : "Always" mode : bbUpdate() always calls Process
- /// 2 : "Reactive" mode : bbSetModifiedStatus() calls bbUpdate()
+ /// 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;
//==================================================================
+ /// 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)