2 # ---------------------------------------------------------------------
4 # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image
6 # Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton
7 # Previous Authors : Laurent Guigues, Jean-Pierre Roux
8 # CreaTools website : www.creatis.insa-lyon.fr/site/fr/creatools_accueil
10 # This software is governed by the CeCILL-B license under French law and
11 # abiding by the rules of distribution of free software. You can use,
12 # modify and/ or redistribute the software under the terms of the CeCILL-B
13 # license as circulated by CEA, CNRS and INRIA at the following URL
14 # http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
15 # or in the file LICENSE.txt.
17 # As a counterpart to the access to the source code and rights to copy,
18 # modify and redistribute granted by the license, users are provided only
19 # with a limited warranty and the software's author, the holder of the
20 # economic rights, and the successive licensors have only limited
23 # The fact that you are presently reading this means that you have had
24 # knowledge of the CeCILL-B license and that you accept its terms.
25 # ------------------------------------------------------------------------ */
28 /*=========================================================================
30 Module: $RCSfile: bbtkBlackBox.h,v $
32 Date: $Date: 2012/11/16 08:49:01 $
33 Version: $Revision: 1.34 $
34 =========================================================================*/
40 * \brief Class bbtk::BlackBox : abstract black-box interface.
44 * \class bbtk::BlackBox
45 * \brief Abstract black-box interface
48 #ifndef __bbtkBlackBox_h__
49 #define __bbtkBlackBox_h__
51 #include "bbtkSystem.h"
52 #include "bbtkMessageManager.h"
53 #include "bbtkBlackBoxDescriptor.h"
54 #include "bbtkBlackBoxInputConnector.h"
55 //#include "bbtkBlackBoxOutputConnector.h"
58 // Signal/slot mechanism for output change events
59 #include <boost/signal.hpp>
60 #include <boost/bind.hpp>
63 #define bbtkBlackBoxMessage(key,level,mess) \
64 bbtkMessage(key,level,"["<<bbGetName()<<"] "<<mess)
65 #define bbtkBlackBoxDebugMessage(key,level,mess) \
66 bbtkDebugMessage(key,level,"["<<bbGetName()<<"] "<<mess)
71 struct Void { Void(int = 0) {} };
75 class BlackBoxOutputConnector;
77 class BBTK_EXPORT BlackBox : public Object
79 BBTK_ABSTRACT_OBJECT_INTERFACE(BlackBox);
84 //==================================================================
86 //==================================================================
87 typedef boost::signals::trackable OutputChangeObserverType;
88 typedef boost::signal<void (bbtk::BlackBox::Pointer,
90 IOStatus)> OutputChangeSignalType;
91 typedef OutputChangeSignalType::slot_function_type
92 OutputChangeCallbackType;
94 /// The type of map of output connector pointers
95 typedef std::map<std::string, BlackBoxOutputConnector*>
96 OutputConnectorMapType;
97 /// The type of map of input connector pointers
98 typedef std::map<std::string, BlackBoxInputConnector*>
99 InputConnectorMapType;
100 //==================================================================
103 //==================================================================
104 /// @name Pipeline processing methods
105 /// Methods which participate to pipeline processing.
107 /// Main processing method of the box.
108 virtual void bbExecute(bool force = false);
110 //==================================================================
116 //==================================================================
117 /// Returns a pointer on a clone of the box with name <name>
118 virtual BlackBox::Pointer bbClone(const std::string& name) = 0;
119 //==================================================================
122 //==================================================================
123 /// @name General accessors
124 /// Methods which give access to general informations on the box
127 /// Returns the pointer on the descriptor of the box
128 virtual BlackBoxDescriptor::Pointer bbGetDescriptor() const = 0;
130 /// Returns the Name of the Type of the BlackBox
131 const std::string& bbGetTypeName() const
132 { return bbGetDescriptor()->GetTypeName(); }
135 /// Returns the name of the BlackBox (instance)
136 const std::string& bbGetName() const { return bbmName; }
138 /// Returns the full name of the BlackBox (instance+type)
139 virtual std::string bbGetFullName() const;
141 /// Returns the name with the name of the parent prepended if any
142 virtual std::string bbGetNameWithParent() const;
144 /// Returns the parent of the BlackBox, i.e the BlackBox that contains it (0 if none)
145 BlackBox::Pointer bbGetParent() const { return bbmParent.lock(); }
148 //==================================================================
152 //==================================================================
153 /// @name Inputs/Outputs related methods
154 /// Methods related to the box inputs and outputs
157 /// Returns true iff the BlackBox has an input of name label
158 virtual bool bbHasInput(const std::string& label) const;
159 /// Gets the input type of a given label
160 virtual TypeInfo bbGetInputType( const std::string &label ) const;
161 /// Gets the status of the input called <name>
162 IOStatus bbGetInputStatus( const std::string &name ) const
163 { return mInputConnectorMap.find(name)->second->GetStatus(); }
164 /// Gets the data of the input called <name>
165 virtual Data bbGetInput( const std::string &name ) = 0;
166 /// Gets the data of the input called <name> as a string using an Adaptor if possible (else returns empty string)
167 std::string bbGetInputAsString( const std::string &input);
170 /// Sets the data of the input called <name>.
171 /// If update_time is false then does not update ChangeTime of input
172 virtual void bbSetInput( const std::string &name, Data data,
173 bool update_time = true ) = 0;
174 /// [SYSTEM]: Sets the data of the input called <name> which **MUST* be a pointer
175 virtual void bbBruteForceSetInputPointer( const std::string &name,
177 bool update_time = true) =0;
180 /// Returns true iff the BlackBox has an output of name label
181 virtual bool bbHasOutput(const std::string& label) const;
182 /// Gets the output type of a given label
183 virtual TypeInfo bbGetOutputType( const std::string &label ) const;
184 /// Gets the data of the output called <name>
185 virtual Data bbGetOutput( const std::string &name ) = 0;
186 /// Gets the data of the output called <name> as a string using an Adaptor if possible (else returns empty string)
187 std::string bbGetOutputAsString( const std::string &output ); //,Factory *factory);
189 /// Sets the data of the output called <name>
190 virtual void bbSetOutput( const std::string &name, Data data) = 0;
193 /// Returns the input connectors map
194 InputConnectorMapType& bbGetInputConnectorMap()
195 { return mInputConnectorMap; }
196 /// Returns the input connectors map (const)
197 const InputConnectorMapType& bbGetInputConnectorMap() const
198 { return mInputConnectorMap; }
199 /// Returns the input connector
200 BlackBoxInputConnector& bbGetInputConnector(const std::string& n)
201 { return *(mInputConnectorMap.find(n)->second); }
202 /// Returns the input connector (const)
203 const BlackBoxInputConnector& bbGetInputConnector(const std::string& n) const
204 { return *(mInputConnectorMap.find(n)->second); }
207 /// Returns the output connectors map
208 OutputConnectorMapType& bbGetOutputConnectorMap()
209 { return mOutputConnectorMap; }
210 /// Returns the output connectors map (const)
211 const OutputConnectorMapType& bbGetOutputConnectorMap() const
212 { return mOutputConnectorMap; }
213 /// Returns the output connector
214 BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n)
215 { return *(mOutputConnectorMap.find(n)->second); }
216 /// Returns the output connector (const)
217 const BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n) const
218 { return *(mOutputConnectorMap.find(n)->second); }
221 //==================================================================
223 /// Prints the Help on the BlackBox type
224 virtual void bbGetHelp(bool full=true) const;
228 //==================================================================
229 /// @name Output signals / observers related methods
230 /// Methods related to signals emitted by outputs and the
233 //==================================================================
234 /// Adds the function f to the list of functions to call when
235 /// the output changes.
236 /// f is of type ChangeCallbackType which is basically:
237 /// void (*ChangeCallbackType)(bbtk::BlackBox::Pointer,
238 /// const std::string&,
240 /// To pass a member function 'f' of an instance 'c' of a class 'C'
241 /// as callback you have to 'bind' it, i.e. call:
242 /// bbAddOutputObserver ( "Out", boost::bind( &C::f , c, _1, _2, _3 ) );
243 /// The convenience macro BBTK_BIND_OUTPUT_OBSERVER ( c, C::f ) does it for you
244 void bbAddOutputObserver(const std::string& output_name,
245 OutputChangeCallbackType f);
247 /// Removes the function f from the list of functions to call when
248 /// the output changes (TO WRITE)
249 void bbRemoveOutputObserver(const std::string& output_name,
250 OutputChangeCallbackType f);
251 //==================================================================
254 //==================================================================
255 /// Signals that the BlackBox outputs have been modified
256 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
257 /// This method should be used by widgets in response
258 /// to user interaction when **ALL** outputs have been modified
259 /// (after the outputs has been updated !).
260 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
261 /// ** USER INTENDED **
262 virtual void bbSignalOutputModification(bool reaction = true);
263 /// Signals that the BlackBox output "output_name" has been modified
264 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
265 /// This method should be used by widgets in response to user interaction
266 /// only when **ONE** output has been modified
267 /// (after the output has been updated !)
268 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
269 /// ** USER INTENDED **
270 virtual void bbSignalOutputModification( const std::string& output_name,
271 bool reaction = true);
272 /// Signals that the BlackBox vector of outputs "output_name"
273 /// have been modified.
274 /// Should be used when more than ONE output is modified but not ALL
275 /// (optimization issue).
276 /// (without marking the box as MODIFIED because its output state is ok).
277 /// This method should be used by widgets in response to user interaction
278 /// When more than one output has been changed but not all
279 /// (after the outputs have been updated of course!)
280 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
281 /// ** USER INTENDED **
282 virtual void bbSignalOutputModification( const std::vector<std::string>&
284 bool reaction = true);
285 //==================================================================
293 //==================================================================
294 /// @name Common inputs / outputs to all boxes
296 /// Returns the value of the input 'BoxProcessMode'
297 std::string bbGetInputBoxProcessMode() { return bbmBoxProcessMode; }
298 /// Sets the value of the input 'BoxProcessMode'
299 void bbSetInputBoxProcessMode(std::string a) { bbmBoxProcessMode = a; }
300 /// The possible values of the input 'BoxProcessMode'
311 /// Returns the "decoded" value of the input "BoxProcessMode"
312 BoxProcessModeValue bbGetBoxProcessModeValue() const;
313 /// Returns true iff the input 'BoxProcessMode' is set to 'Reactive' (or a synonym)
314 virtual bool bbBoxProcessModeIsReactive() const;
315 /// Returns true iff the input 'BoxProcessMode' is set to 'Always' (or a synonym)
316 virtual bool bbBoxProcessModeIsAlways() const;
317 /// Returns true iff the input 'BoxProcessMode' is set to 'Manual' (or a synonym)
318 virtual bool bbBoxProcessModeIsManual() const;
320 /// Returns the value of the input 'BoxExecute'
321 Void bbGetInputBoxExecute() { return Void(); }
322 /// Sets the value of the input 'BoxExecute'
323 void bbSetInputBoxExecute(Void = 0) { }
325 /// Returns the value of the output 'BoxChange'
326 Void bbGetOutputBoxChange() { return Void(); }
327 /// Sets the value of the output 'BoxChange'
328 void bbSetOutputBoxChange(Void = 0) { }
330 //==================================================================
332 virtual void bbPrintHelp(BlackBox::Pointer parentblackbox,
333 int detail, int level
336 /// Does nothing here : overloaded in ComplexBlackBox
337 void bbInsertHTMLGraph( std::ofstream& s,
341 const std::string& output_dir,
346 //==================================================================
347 /// @name Window related methods
349 virtual void bbSetShown(bool) {}
350 virtual bool bbIsShown() { return false; }
352 //==================================================================
354 //JCP changed to public 09-06-09
355 //==================================================================
356 /// @name Manage the execution
358 static bool bbGlobalGetSomeBoxExecuting();
359 static void bbGlobalSetSomeBoxExecuting(bool b);
361 static void bbGlobalSetFreezeExecution(bool b);
362 static bool bbGlobalGetFreezeExecution();
364 static void bbGlobalAddToExecutionList( BlackBox::Pointer b );
365 static void bbGlobalProcessExecutionList();
372 //==================================================================
373 /// @name User redefinable methods
374 /// Virtual methods which can be redefined by inherited classes
377 //==================================================================
378 /// User can redefine this method to set
379 /// the default values of the box inputs and outputs
380 /// (it is called in the box constructor)
381 virtual void bbUserSetDefaultValues() {}
383 /// User can redefine this method to initialize what must be
384 /// initialized for the box to work, for example allocate dynamic data.
385 /// It is called once and only once before any call to bbUserCreateWidget
386 /// or bbUserProcess.
387 /// What has been allocated here must be desalocated in
388 /// bbFinalizeProcessing
389 virtual void bbUserInitializeProcessing() {}
391 /// User must redefine this method to uninitialize what has been
392 /// initialized in bbUserInitializeProcessing,
393 /// typically desallocate memory that has been allocated dynamically.
394 /// It is called in the box destructor if and only if (iff)
395 /// bbUserInitializeProcessing has been called previously.
396 virtual void bbUserFinalizeProcessing() {}
398 virtual void bbUserOnShow() {}
400 //==================================================================
402 //==================================================================
405 //==================================================================
407 /// Write Graphviz-dot description in file.
408 /// Here dumps a single box description (i/o) but overloaded
409 /// in ComplexBlackBox to dump the internal pipeline representation
410 /// recursing into internal boxes descriptions if level>0.
411 /// detail = 1 : draw inputs and outputs (do not draw otherwise)
412 /// instanceOrtype = true : draw inputs and outputs VALUES
413 /// (uses bbGetInputAsString / bbGetOutputAsString which use adaptors)
414 /// If relative_link is true then creates relative hrefs
415 virtual void bbWriteDotFileBlackBox(FILE *ff,
416 BlackBox::Pointer parentblackbox,
417 int detail, int level,
419 bool relative_link );
420 /// Auxiliary method for bbWriteDotFileBlackBox
421 virtual void bbWriteDotInputOutputName(FILE *ff,
423 int detail, int level);
425 virtual BlackBox::Pointer bbFindBlackBox(const std::string &blackboxname)
426 { return BlackBox::Pointer();}
428 virtual void Check(bool recursive = true);
430 //==================================================================
431 // PROTECTED PART : ACCESSIBLE TO THE BlackBox DEVELOPER
432 // (IN INHERITED CLASSES)
433 /// Constructor that take the BlackBox's name
434 BlackBox(const std::string &name);
435 /// Constructor from an existing box (copy) with a new name
436 BlackBox(BlackBox& from, const std::string &name);
437 //==================================================================
441 //==================================================================
442 /// @name Pipeline processing methods
443 /// Methods which participate to pipeline processing.
445 //==================================================================
446 /// Recursive execution method
448 /// \param caller : The connection which invoked the method; null if called by bbExecute
449 virtual void bbRecursiveExecute(Connection::Pointer caller);
450 //==================================================================
452 //==================================================================
453 /// Updates the BlackBox inputs
454 /// Calls RecursiveExecute on all BlackBoxInputConnector
455 /// \returns The maximum of final IOStatus after each input update
456 IOStatus bbUpdateInputs();
457 //==================================================================
460 //==================================================================
461 /// Actual CreateWindow method (vitual)
462 /// Overloaded in AtomicBlacBox and descendants
463 virtual void bbCreateWindow()
465 // bbtkError("BlackBox::bbCreateWidget called : how can this happen ?");
467 //==================================================================
469 //==================================================================
470 /// Actual ShowWindow method (vitual)
471 /// Overloaded in AtomicBlacBox and descendants
472 virtual void bbShowWindow()
474 // bbtkError("BlackBox::bbShowWidget called : how can this happen ?");
476 //==================================================================
479 //==================================================================
480 /// Actual processing method (vitual)
481 /// Overloaded in AtomicBlacBox and descendants
482 virtual void bbProcess()
484 bbtkError("BlackBox::bbProcess called : how can this happen ?");
485 // this->bbUserProcess();
487 //==================================================================
489 //==================================================================
490 /// Computes the final IOStatus of inputs and outputs after processing
491 virtual void bbComputePostProcessStatus();
493 //==================================================================
496 //==================================================================
497 /// Signals that the input whose connector is c has changed
498 /// and propagates the info downward
499 /// ** NOT USER INTENDED **
500 virtual void bbSetStatusAndPropagate(BlackBoxInputConnector* c,
502 //==================================================================
506 //==================================================================
507 /// @name Box con(des)struction / initi(fin)alization methods
510 //==================================================================
511 /// Allocates the i/o connectors of the black box
512 virtual void bbAllocateConnectors();
513 /// Desallocates the i/o connectors of the black box
514 virtual void bbDesallocateConnectors();
515 /// Copies the values of the inputs/output from the BlackBox from
516 virtual void bbCopyIOValues(BlackBox& from);
517 //==================================================================
519 //==================================================================
520 /// Initializes processing IF NEEDED.
521 /// Calls bbRecursiveInitializeProcessing if the box is in
522 /// "uninitialized" state and put it in "initialized" state.
523 /// On construction, boxes are "uninitialized".
524 /// See also bbFinalizeProcessing
525 void bbInitializeProcessing();
527 /// Finalizes processing IF NEEDED.
528 /// Calls bbRecursiveFinalizeProcessing if the box is in
529 /// "initialized" state and put it in "uninitialized" state.
530 /// On construction, boxes are "uninitialized".
531 /// See also bbInitializeProcessing
532 void bbFinalizeProcessing();
534 /// Abstract prototype of the method which
535 /// Recursively calls itself for the parent black box and then
536 /// calls bbUserInitializeProcessing for its own class.
537 /// It is redefined in each black box descendant.
538 /// Allows to call bbUserInitializeProcessing for all inherited classes
539 /// (like a constructor does)
540 virtual void bbRecursiveInitializeProcessing() {}
543 /// Abstract prototype of the method which
544 /// calls bbUserFinalizeProcessing for its own class and then
545 /// recursively calls itself for the parent black box.
546 /// It is redefined in each black box descendant.
547 /// Allows to call bbUserFinalizeProcessing for all inherited classes
548 /// (like a destructor does)
549 virtual void bbRecursiveFinalizeProcessing() {}
550 //==================================================================
553 //==================================================================
556 //==================================================================
557 friend class Connection;
558 friend class ComplexBlackBox;
560 /// Sets the parent of the BlackBox
561 void bbSetParent(BlackBox::Pointer p) { bbmParent = p; }
563 //==================================================================
564 /// @name Input/output connection/disconnection
565 /// INTERNAL METHODS used by a Connection to connect/disconnect
566 /// itself to the i/o connectors of the box
569 /// Connects the input <name> to the connection c
570 virtual void bbConnectInput( const std::string& name, Connection* c);
571 /// Connects the output <name> to the connection c
572 virtual void bbConnectOutput( const std::string& name, Connection* c);
573 /// Disconnects the input <name> from the connection c
574 virtual void bbDisconnectInput( const std::string& name, Connection* c);
575 /// Disconnects the output <name> from the connection c
576 virtual void bbDisconnectOutput( const std::string& name, Connection* c);
578 //==================================================================
580 /// Returns true if the box can "react",
581 /// which means execute in response to an input change
582 virtual bool bbCanReact() const;
584 /// Returns true iff the box is executing
585 bool bbGetExecuting() const { return bbmExecuting; }
586 /// Sets the bbmExecuting bool returned by bbGetExecuting
587 void bbSetExecuting(bool b) { bbmExecuting = b; }
589 //==================================================================
593 //==================================================================
594 /// Black box objects have a special deleter
595 /// which must take care of releasing the descriptor
596 /// **AFTER** the box is deleted
597 /// (Releasing it in the destructor may cause dl close and crash)
598 /// Black box deleter
599 /// 1) Calls the user overloadable bbDelete method
600 /// 2) Releases the box descriptor
601 struct BBTK_EXPORT Deleter : public Object::Deleter
604 int Delete(Object* p);
606 //==================================================================
608 //==================================================================
609 /// Like Object::MakePointer but returns a boost::shared_pointer which uses a BlackBox::Deleter to delete the object instead of the default Object::Deleter
611 static boost::shared_ptr<U> MakeBlackBoxPointer(U* s, bool lock = false)
613 return MakePointer(s,BlackBox::Deleter(),lock);
615 //==================================================================
617 //==================================================================
618 /// Effective deletion method called by the Deleter.
619 /// The default implementation is to issue 'delete this'
620 /// 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.).
621 /// \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...
623 //JCP 21-09-20 09 delete this throws and exception change due to compiler version changing and boost version
624 virtual int bbDelete() { delete this;
626 //==================================================================
629 //==================================================================
631 //==================================================================
633 //==================================================================
635 /// Is the box initialized ?
637 /// Is the box executing ?
639 /// The name of the black-box
641 /// The name of the package to which it belongs
642 std::string bbmPackageName;
643 /// The box processing mode
644 /// 0 : "Pipeline" mode
645 /// 1 : "Always" mode
646 /// 2 : "Reactive" mode
647 /// 3 : "Manual" mode
648 std::string bbmBoxProcessMode;
649 /// The parent of the black box in the ComplexBlackBox hierarchy
650 BlackBox::WeakPointer bbmParent;
651 //==================================================================
654 //==================================================================
656 /// Map that contains the output connectors of the black box
657 OutputConnectorMapType mOutputConnectorMap;
658 /// Map that contains the input connectors of the black box
659 InputConnectorMapType mInputConnectorMap;
660 //==================================================================
663 bool bbLetRecursiveExecuteManualMode;
668 /// Convenient macro to create output observer callbacks (freehand functions) from object and method pointer (see samples/SampleOutputObserver)
669 #define BBTK_MAKE_OUTPUT_OBSERVER(OBJECT,METHOD) \
670 boost::bind( METHOD, OBJECT, _1, _2, _3)