1 /*=========================================================================
3 Module: $RCSfile: bbtkBlackBox.h,v $
5 Date: $Date: 2008/12/10 09:33:18 $
6 Version: $Revision: 1.20 $
7 =========================================================================*/
9 /* ---------------------------------------------------------------------
11 * Copyright (c) CREATIS-LRMN (Centre de Recherche en Imagerie Medicale)
12 * Authors : Eduardo Davila, Laurent Guigues, Jean-Pierre Roux
14 * This software is governed by the CeCILL-B license under French law and
15 * abiding by the rules of distribution of free software. You can use,
16 * modify and/ or redistribute the software under the terms of the CeCILL-B
17 * license as circulated by CEA, CNRS and INRIA at the following URL
18 * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
19 * or in the file LICENSE.txt.
21 * As a counterpart to the access to the source code and rights to copy,
22 * modify and redistribute granted by the license, users are provided only
23 * with a limited warranty and the software's author, the holder of the
24 * economic rights, and the successive licensors have only limited
27 * The fact that you are presently reading this means that you have had
28 * knowledge of the CeCILL-B license and that you accept its terms.
29 * ------------------------------------------------------------------------ */
35 * \brief Class bbtk::BlackBox : abstract black-box interface.
39 * \class bbtk::BlackBox
40 * \brief Abstract black-box interface
43 #ifndef __bbtkBlackBox_h__
44 #define __bbtkBlackBox_h__
46 #include "bbtkSystem.h"
47 #include "bbtkBlackBoxDescriptor.h"
48 #include "bbtkBlackBoxInputConnector.h"
49 //#include "bbtkBlackBoxOutputConnector.h"
52 // Signal/slot mechanism for output change events
53 #include <boost/signal.hpp>
54 #include <boost/bind.hpp>
60 struct Void { Void(int = 0) {} };
64 class BlackBoxOutputConnector;
67 #define BBTK_MAKE_OUTPUT_OBSERVER(OBJECT,METHOD) \
68 boost::bind( METHOD, OBJECT, _1, _2, _3)
70 class BBTK_EXPORT BlackBox : public Object
72 BBTK_ABSTRACT_OBJECT_INTERFACE(BlackBox);
74 //==================================================================
76 //==================================================================
77 typedef boost::signals::trackable OutputChangeObserverType;
78 typedef boost::signal<void (bbtk::BlackBox::Pointer,
80 IOStatus)> OutputChangeSignalType;
81 typedef OutputChangeSignalType::slot_function_type
82 OutputChangeCallbackType;
84 /// The type of map of output connector pointers
85 typedef std::map<std::string, BlackBoxOutputConnector*>
86 OutputConnectorMapType;
87 /// The type of map of input connector pointers
88 typedef std::map<std::string, BlackBoxInputConnector*>
89 InputConnectorMapType;
91 /// Returns the pointer on the descriptor of the box
92 virtual BlackBoxDescriptor::Pointer bbGetDescriptor() const = 0;
94 /// Returns a pointer on a clone of the box with name <name>
95 virtual BlackBox::Pointer bbClone(const std::string& name) = 0;
97 /// User overloadable destruction method of a black box
98 virtual void bbUserDelete();
100 /// Returns the Name of the Type of the BlackBox
101 const std::string& bbGetTypeName() const
102 { return bbGetDescriptor()->GetTypeName(); }
105 /// Returns the name of the BlackBox (instance)
106 const std::string& bbGetName() const { return bbmName; }
108 /// Returns the full name of the BlackBox (instance+type)
109 virtual std::string bbGetFullName() const;
111 /// Returns the name with the name of the parent prepended if any
112 virtual std::string bbGetNameWithParent() const;
114 /// Returns the parent of the BlackBox, i.e the BlackBox that contains it (0 if none)
115 BlackBox::Pointer bbGetParent() const { return bbmParent.lock(); }
118 /// Main processing method of the box.
119 virtual void bbExecute(bool force = false);
122 /// The type of callback function when an output changes
123 // typedef BlackBoxOutputConnector::ChangeCallbackType OutputChangeCallbackType;
125 /// Adds the function f to the list of functions to call when
126 /// the output changes.
127 /// f is of type ChangeCallbackType which is basically:
128 /// void (*ChangeCallbackType)(bbtk::BlackBox::Pointer,
129 /// const std::string&,
131 /// To pass a member function 'f' of an instance 'c' of a class 'C'
132 /// as callback you have to 'bind' it, i.e. call:
133 /// bbAddOutputObserver ( "Out", boost::bind( &C::f , c, _1, _2, _3 ) );
134 /// The convenience macro BBTK_BIND_OUTPUT_OBSERVER ( c, C::f ) does it for you
135 void bbAddOutputObserver(const std::string& output_name,
136 OutputChangeCallbackType f);
138 /// Removes the function f from the list of functions to call when
139 /// the output changes (TO WRITE)
140 void bbRemoveOutputObserver(const std::string& output_name,
141 OutputChangeCallbackType f);
144 /// Signals that the BlackBox outputs have been modified
145 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
146 /// This method should be used by widgets in response
147 /// to user interaction when **ALL** outputs have been modified
148 /// (after the outputs has been updated !).
149 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
150 /// ** USER INTENDED **
151 virtual void bbSignalOutputModification(bool reaction = true);
152 /// Signals that the BlackBox output "output_name" has been modified
153 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
154 /// This method should be used by widgets in response to user interaction
155 /// only when **ONE** output has been modified
156 /// (after the output has been updated !)
157 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
158 /// ** USER INTENDED **
159 virtual void bbSignalOutputModification( const std::string& output_name,
160 bool reaction = true);
161 /// Signals that the BlackBox vector of outputs "output_name"
162 /// have been modified.
163 /// Should be used when more than ONE output is modified but not ALL
164 /// (optimization issue).
165 /// (without marking the box as MODIFIED because its output state is ok).
166 /// This method should be used by widgets in response to user interaction
167 /// When more than one output has been changed but not all
168 /// (after the outputs have been updated of course!)
169 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
170 /// ** USER INTENDED **
171 virtual void bbSignalOutputModification( const std::vector<std::string>&
173 bool reaction = true);
175 /// Gets the status of the box
176 // virtual const IOStatus& bbGetStatus() const { return bbmStatus; }
179 /// Returns true iff the BlackBox has an input of name label
180 virtual bool bbHasInput(const std::string& label) const;
181 /// Returns true iff the BlackBox has an output of name label
182 virtual bool bbHasOutput(const std::string& label) const;
184 /// Gets the input type of a given label
185 virtual TypeInfo bbGetInputType( const std::string &label ) const;
186 /// Gets the output type of a given label
187 virtual TypeInfo bbGetOutputType( const std::string &label ) const;
189 /// Gets the data of the input called <name>
190 virtual Data bbGetInput( const std::string &name ) = 0;
191 /// Gets the data of the output called <name>
192 virtual Data bbGetOutput( const std::string &name ) = 0;
194 /// Sets the data of the input called <name>.
195 /// If update_time is false then does not update ChangeTime of input
196 virtual void bbSetInput( const std::string &name, Data data,
197 bool update_time = true ) = 0;
198 virtual void bbBruteForceSetInputPointer( const std::string &name,
200 bool update_time = true) =0;
201 /// Sets the data of the output called <name>
202 virtual void bbSetOutput( const std::string &name, Data data) = 0;
205 /// Gets the status of the input called <name>
206 IOStatus bbGetInputStatus( const std::string &name ) const
207 { return mInputConnectorMap.find(name)->second->GetStatus(); }
209 /// Returns the input connectors map
210 InputConnectorMapType& bbGetInputConnectorMap()
211 { return mInputConnectorMap; }
212 /// Returns the output connectors map
213 OutputConnectorMapType& bbGetOutputConnectorMap()
214 { return mOutputConnectorMap; }
215 /// Returns the input connectors map (const)
216 const InputConnectorMapType& bbGetInputConnectorMap() const
217 { return mInputConnectorMap; }
218 /// Returns the output connectors map (const)
219 const OutputConnectorMapType& bbGetOutputConnectorMap() const
220 { return mOutputConnectorMap; }
222 /// Returns the input connector
223 BlackBoxInputConnector& bbGetInputConnector(const std::string& n)
224 { return *(mInputConnectorMap.find(n)->second); }
225 /// Returns the output connector
226 BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n)
227 { return *(mOutputConnectorMap.find(n)->second); }
228 /// Returns the input connector (const)
229 const BlackBoxInputConnector& bbGetInputConnector(const std::string& n) const
230 { return *(mInputConnectorMap.find(n)->second); }
231 /// Returns the output connector (const)
232 const BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n) const
233 { return *(mOutputConnectorMap.find(n)->second); }
238 /// Prints the Help on the BlackBox type
239 virtual void bbGetHelp(bool full=true) const;
242 // Returns true iff the box is up-to-date
243 // (ChangeTime of inputs are all lower strictly to ChangeTime of outputs -
244 // i.e. max(inputs)<=min(outputs) )
245 // bool bbIsUpToDate() { return mMaxInputChangeTime < mMinOutputChangeTime; }
246 // Returns true iff the box is out-of-date
247 // (At least one ChangeTime of an input is greater than one ChangeTime
248 // of an output - i.e. max(inputs)>min(outputs))
250 // bool bbIsOutOfDate() { return mMaxInputChangeTime >= mMinOutputChangeTime; }
252 //==================================================================
253 // Common inputs / outputs to all boxes
254 /// Returns the value of the input "BoxProcessMode"
255 std::string bbGetInputBoxProcessMode() { return bbmBoxProcessMode; }
256 /// Sets the value of the input "BoxProcessMode"
257 void bbSetInputBoxProcessMode(std::string a) { bbmBoxProcessMode = a; }
265 /// Returns the "decoded" value of the input "BoxProcessMode"
266 BoxProcessModeValue bbGetBoxProcessModeValue() const;
268 virtual bool bbBoxProcessModeIsReactive() const;
270 virtual bool bbBoxProcessModeIsAlways() const;
272 /// Returns the value of the input "Execute"
273 Void bbGetInputBoxExecute() { return Void(); }
274 /// Sets the value of the input "Execute"
275 void bbSetInputBoxExecute(Void = 0) {}
277 /// Returns the value of the output "Change"
278 Void bbGetOutputBoxChange() { return Void(); }
279 /// Sets the value of the output "Change" : signal a modification
280 void bbSetOutputBoxChange(Void = 0) { } //bbSetModifiedStatus(); }
282 //==================================================================
285 //==================================================================
287 /// Does nothing here : overloaded in ComplexBlackBox
288 void bbInsertHTMLGraph( std::ofstream& s,
292 const std::string& output_dir,
296 /// Write Graphviz-dot description in file.
297 /// Here dumps a single box description (i/o) but overloaded
298 /// in ComplexBlackBox to dump the internal pipeline representation
299 /// recursing into internal boxes descriptions if level>0.
300 /// detail = 1 : draw inputs and outputs (do not draw otherwise)
301 /// instanceOrtype = true : draw inputs and outputs VALUES
302 /// (uses bbGetInputAsString / bbGetOutputAsString which use adaptors)
303 /// If relative_link is true then creates relative hrefs
304 virtual void bbWriteDotFileBlackBox(FILE *ff,
305 BlackBox::Pointer parentblackbox,
306 int detail, int level,
308 bool relative_link );
309 /// Auxiliary method for bbWriteDotFileBlackBox
310 virtual void bbWriteDotInputOutputName(FILE *ff,
312 int detail, int level);
315 virtual void bbShowRelations(BlackBox::Pointer parentblackbox,
316 int detail, int level
319 std::string bbGetOutputAsString( const std::string &output ); //,Factory *factory);
320 std::string bbGetInputAsString( const std::string &input); //,Factory *factory);
321 virtual BlackBox::Pointer bbFindBlackBox(const std::string &blackboxname)
322 { return BlackBox::Pointer();}
324 virtual void Check(bool recursive = true);
326 virtual void bbUserOnShow() { }
327 void bbUserOnShowWidget(std::string nameInput);
330 //==================================================================
331 // PROTECTED PART : ACCESSIBLE TO THE BlackBox DEVELOPER
332 // (IN INHERITED CLASSES)
333 /// Constructor that take the BlackBox's name
334 BlackBox(const std::string &name);
335 /// Constructor from an existing box (copy) with a new name
336 BlackBox(BlackBox& from, const std::string &name);
337 //==================================================================
340 //==================================================================
341 /// Signals that the input whose connector is c has changed
342 /// and propagates the info downward
343 /// ** NOT USER INTENDED **
344 virtual void bbSetStatusAndPropagate(BlackBoxInputConnector* c,
346 //==================================================================
349 //==================================================================
350 friend class Connection;
351 friend class ComplexBlackBox;
353 /// Sets the parent of the BlackBox
354 void bbSetParent(BlackBox::Pointer p) { bbmParent = p; }
357 /// Connects the input <name> to the connection c
358 virtual void bbConnectInput( const std::string& name,
360 /// Connects the output <name> to the connection c
361 virtual void bbConnectOutput( const std::string& name,
363 /// Disconnects the input <name> from the connection c
364 virtual void bbDisconnectInput( const std::string& name,
366 /// Disconnects the output <name> from the connection c
367 virtual void bbDisconnectOutput( const std::string& name,
370 //==================================================================
372 /// @name Pipeline processing methods
373 /// Methods which participate to pipeline processing.
374 /// Some are pure virtual and prepare particular update mechanism which are implemented by descendents
375 /// The main method is bbBackwardUpdate which is called by bbExecute and implemented in UserBlackBox and ComplexBlackBox.
380 //==================================================================
381 /// Recursive pipeline processing in backward direction
382 /// (recursion is in backward direction however execution always
384 /// Pure virtual; defined in AtomicBlackBox and ComplexBlackBox
386 /// \param caller : The connection which invoked the method; null if called by bbExecute
387 virtual void bbBackwardUpdate(Connection::Pointer caller) = 0;
388 //==================================================================
390 //==================================================================
391 /// Updates the BlackBox inputs
392 /// Calls BackwardUpdate on all BlackBoxInputConnector
393 /// \returns The maximum of final IOStatus after each input update
394 IOStatus bbUpdateInputs();
395 //==================================================================
397 //==================================================================
398 /// Computes the final IOStatus of inputs and outputs after processing
399 void bbComputePostProcessStatus();
400 //==================================================================
403 //==================================================================
404 /// Specific methods for window creation during pipeline execution
405 /// Creates the window associated to the box (called after bbUpdateInputs)
406 /// Does nothing here. Overloaded in WxBlackBox.
407 // virtual void bbCreateWindow() { }
408 /// Shows the window associated to the box
409 /// (called after bbProcess during bbExecute)
410 /// Does nothing here but overloaded in WxBlackBox and WxContainerBlackBox
411 virtual void bbShowWindow(Connection::Pointer caller) { }
413 virtual void bbHideWindow() {}
414 virtual void bbCloseWindow() { }
415 //==================================================================
420 static bool bbGlobalGetSomeBoxExecuting();
421 static void bbGlobalSetSomeBoxExecuting(bool b);
423 static void bbGlobalSetFreezeExecution(bool b);
424 static bool bbGlobalGetFreezeExecution();
426 /// Returns true if the box can "react",
427 /// which means execute in response to an input change
428 virtual bool bbCanReact() const;
430 /// Returns true iff the box is executing
431 bool bbGetExecuting() const { return bbmExecuting; }
434 static void bbGlobalAddToExecutionList( BlackBox::Pointer b );
435 static void bbGlobalProcessExecutionList();
436 /// Sets the bbmExecuting bool returned by bbGetExecuting
437 void bbSetExecuting(bool b) { bbmExecuting = b; }
439 //==================================================================
441 //==================================================================
442 /// Allocates the i/o connectors of the black box
443 virtual void bbAllocateConnectors();
444 /// Desallocates the i/o connectors of the black box
445 virtual void bbDesallocateConnectors();
446 /// Copies the values of the inputs/output from the BlackBox from
447 virtual void bbCopyIOValues(BlackBox& from);
448 //==================================================================
450 //==================================================================
451 // Black box objects have a special deleter
452 // which must take care of releasing the descriptor
453 // **AFTER** the box is deleted
454 // (Releasing it in the destructor may cause dl close and crash)
455 /// Black box deleter
456 /// 1) Calls the user overloadable bbDelete method
457 /// 2) Releases the box descriptor
458 struct BBTK_EXPORT Deleter : public Object::Deleter
461 void Delete(Object* p);
463 //==================================================================
465 //==================================================================
467 static boost::shared_ptr<U> MakeBlackBoxPointer(U* s, bool lock = false)
469 return MakePointer(s,BlackBox::Deleter(),lock);
471 //==================================================================
473 //==================================================================
474 virtual void bbDelete() { delete this; }
475 //==================================================================
478 //==================================================================
480 //==================================================================
482 //==================================================================
484 /// The status of the box
485 // IOStatus bbmStatus;
486 /// Is the box executing ?
488 /// The name of the black-box
490 /// The name of the package to which it belongs
491 std::string bbmPackageName;
492 /// The box processing mode
493 /// 0 : "Pipeline" mode
494 /// 1 : "Always" mode
495 /// 2 : "Reactive" mode
496 std::string bbmBoxProcessMode;
497 /// The parent of the black box in the ComplexBlackBox hierarchy
498 BlackBox::WeakPointer bbmParent;
499 //==================================================================
502 //==================================================================
504 /// Map that contains the output connectors of the black box
505 OutputConnectorMapType mOutputConnectorMap;
506 /// Map that contains the input connectors of the black box
507 InputConnectorMapType mInputConnectorMap;
508 //==================================================================
510 /// The maximum ChangeTime of the inputs
511 // ChangeTime mMaxInputChangeTime;
512 /// The minimum ChangeTime of the outputs
513 // ChangeTime mMinOutputChangeTime;
517 //=========================================================================
518 /// Sets the ChangeTime of input
520 void bbSetInputChangeTime(BlackBoxInputConnector* c,
521 const ChangeTime& t);
522 /// Sets the ChangeTime of output
523 void bbSetOutputChangeTime(BlackBoxOutputConnector* c,
524 const ChangeTime& t);
526 // void bbUpdateMaxInputChangeTime(const ChangeTime& t);
527 // void bbUpdateMinOutputChangeTime(const ChangeTime& t);
529 /// Set the change time of the input
530 // void bbSetInputChangeTime(const std::string& n, ChangeTime);
531 /// Set the change time of the output
532 // void bbSetOutputChangeTime(const std::string& n, ChangeTime);