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__
52 #include <boost/bind.hpp>
53 #include <boost/signals2/signal.hpp>
55 #include "bbtkSystem.h"
56 #include "bbtkMessageManager.h"
57 #include "bbtkBlackBoxDescriptor.h"
58 #include "bbtkBlackBoxInputConnector.h"
60 //#include "bbtkBlackBoxOutputConnector.h"
63 // Signal/slot mechanism for output change events
66 #include <boost/bind.hpp>
67 #include <boost/signals2/signal.hpp>
69 #include "bbtkSystem.h"
70 #include "bbtkMessageManager.h"
71 #include "bbtkBlackBoxDescriptor.h"
72 #include "bbtkBlackBoxInputConnector.h"
74 //#include "bbtkBlackBoxOutputConnector.h"
77 // Signal/slot mechanism for output change events
81 #define bbtkBlackBoxMessage(key,level,mess) \
82 bbtkMessage(key,level,"["<<bbGetTypeName()<<":"<<bbGetName()<<"] "<<mess)
83 #define bbtkBlackBoxDebugMessage(key,level,mess) \
84 bbtkDebugMessage(key,level,"["<<bbGetTypeName()<<":"<<bbGetName()<<"] "<<mess)
89 struct Void { Void(int = 0) {} };
93 class BlackBoxOutputConnector;
95 class BBTK_EXPORT BlackBox : public Object
97 BBTK_ABSTRACT_OBJECT_INTERFACE(BlackBox);
102 //==================================================================
104 //==================================================================
105 typedef boost::signals2::trackable OutputChangeObserverType;
106 typedef boost::signals2::signal<void (bbtk::BlackBox::Pointer,
108 IOStatus)> OutputChangeSignalType;
109 typedef OutputChangeSignalType::slot_function_type
110 OutputChangeCallbackType;
112 /// The type of map of output connector pointers
113 typedef std::map<std::string, BlackBoxOutputConnector*>
114 OutputConnectorMapType;
115 /// The type of map of input connector pointers
116 typedef std::map<std::string, BlackBoxInputConnector*>
117 InputConnectorMapType;
118 //==================================================================
121 //==================================================================
122 /// @name Pipeline processing methods
123 /// Methods which participate to pipeline processing.
125 /// Main processing method of the box.
126 virtual void bbExecute(bool force = false);
128 //==================================================================
134 //==================================================================
135 /// Returns a pointer on a clone of the box with name <name>
136 virtual BlackBox::Pointer bbClone(const std::string& name) = 0;
137 //==================================================================
140 //==================================================================
141 /// @name General accessors
142 /// Methods which give access to general informations on the box
145 /// Returns the pointer on the descriptor of the box
146 virtual BlackBoxDescriptor::Pointer bbGetDescriptor() const = 0;
148 /// Returns the Name of the Type of the BlackBox
149 const std::string& bbGetTypeName() const
150 { return bbGetDescriptor()->GetTypeName(); }
153 /// Returns the name of the BlackBox (instance)
154 const std::string& bbGetName() const { return bbmName; }
156 /// Returns the full name of the BlackBox (instance+type)
157 virtual std::string bbGetFullName() const;
159 /// Returns the name with the name of the parent prepended if any
160 virtual std::string bbGetNameWithParent() const;
162 /// Returns the parent of the BlackBox, i.e the BlackBox that contains it (0 if none)
163 BlackBox::Pointer bbGetParent() const { return bbmParent.lock(); }
166 //==================================================================
170 //==================================================================
171 /// @name Inputs/Outputs related methods
172 /// Methods related to the box inputs and outputs
175 /// Returns true iff the BlackBox has an input of name label
176 virtual bool bbHasInput(const std::string& label) const;
177 /// Gets the input type of a given label
178 virtual TypeInfo bbGetInputType( const std::string &label ) const;
179 /// Gets the status of the input called <name>
180 IOStatus bbGetInputStatus( const std::string &name ) const
181 { return mInputConnectorMap.find(name)->second->GetStatus(); }
182 /// Gets the data of the input called <name>
183 virtual Data bbGetInput( const std::string &name ) = 0;
184 /// Gets the data of the input called <name> as a string using an Adaptor if possible (else returns empty string)
185 std::string bbGetInputAsString( const std::string &input);
188 /// Sets the data of the input called <name>.
189 /// If update_time is false then does not update ChangeTime of input
190 virtual void bbSetInput( const std::string &name, Data data,
191 bool update_time = true ) = 0;
192 /// [SYSTEM]: Sets the data of the input called <name> which **MUST* be a pointer
193 virtual void bbBruteForceSetInputPointer( const std::string &name,
195 bool update_time = true) =0;
198 /// Returns true iff the BlackBox has an output of name label
199 virtual bool bbHasOutput(const std::string& label) const;
200 /// Gets the output type of a given label
201 virtual TypeInfo bbGetOutputType( const std::string &label ) const;
202 /// Gets the data of the output called <name>
203 virtual Data bbGetOutput( const std::string &name ) = 0;
204 /// Gets the data of the output called <name> as a string using an Adaptor if possible (else returns empty string)
205 std::string bbGetOutputAsString( const std::string &output ); //,Factory *factory);
207 /// Sets the data of the output called <name>
208 virtual void bbSetOutput( const std::string &name, Data data) = 0;
211 /// Returns the input connectors map
212 InputConnectorMapType& bbGetInputConnectorMap()
213 { return mInputConnectorMap; }
214 /// Returns the input connectors map (const)
215 const InputConnectorMapType& bbGetInputConnectorMap() const
216 { return mInputConnectorMap; }
217 /// Returns the input connector
218 BlackBoxInputConnector& bbGetInputConnector(const std::string& n)
219 { return *(mInputConnectorMap.find(n)->second); }
220 /// Returns the input connector (const)
221 const BlackBoxInputConnector& bbGetInputConnector(const std::string& n) const
222 { return *(mInputConnectorMap.find(n)->second); }
225 /// Returns the output connectors map
226 OutputConnectorMapType& bbGetOutputConnectorMap()
227 { return mOutputConnectorMap; }
228 /// Returns the output connectors map (const)
229 const OutputConnectorMapType& bbGetOutputConnectorMap() const
230 { return mOutputConnectorMap; }
231 /// Returns the output connector
232 BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n)
233 { return *(mOutputConnectorMap.find(n)->second); }
234 /// Returns the output connector (const)
235 const BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n) const
236 { return *(mOutputConnectorMap.find(n)->second); }
239 //==================================================================
241 /// Prints the Help on the BlackBox type
242 virtual void bbGetHelp(bool full=true) const;
246 //==================================================================
247 /// @name Output signals / observers related methods
248 /// Methods related to signals emitted by outputs and the
251 //==================================================================
252 /// Adds the function f to the list of functions to call when
253 /// the output changes.
254 /// f is of type ChangeCallbackType which is basically:
255 /// void (*ChangeCallbackType)(bbtk::BlackBox::Pointer,
256 /// const std::string&,
258 /// To pass a member function 'f' of an instance 'c' of a class 'C'
259 /// as callback you have to 'bind' it, i.e. call:
260 /// bbAddOutputObserver ( "Out", boost::bind( &C::f , c, _1, _2, _3 ) );
261 /// The convenience macro BBTK_BIND_OUTPUT_OBSERVER ( c, C::f ) does it for you
262 void bbAddOutputObserver(const std::string& output_name,
263 OutputChangeCallbackType f);
265 /// Removes the function f from the list of functions to call when
266 /// the output changes (TO WRITE)
267 void bbRemoveOutputObserver(const std::string& output_name,
268 OutputChangeCallbackType f);
269 //==================================================================
272 //==================================================================
273 /// Signals that the BlackBox outputs have been modified
274 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
275 /// This method should be used by widgets in response
276 /// to user interaction when **ALL** outputs have been modified
277 /// (after the outputs has been updated !).
278 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
279 /// ** USER INTENDED **
280 virtual void bbSignalOutputModification(bool reaction = true);
281 /// Signals that the BlackBox output "output_name" has been modified
282 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
283 /// This method should be used by widgets in response to user interaction
284 /// only when **ONE** output has been modified
285 /// (after the output has been updated !)
286 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
287 /// ** USER INTENDED **
288 virtual void bbSignalOutputModification( const std::string& output_name,
289 bool reaction = true);
290 /// Signals that the BlackBox vector of outputs "output_name"
291 /// have been modified.
292 /// Should be used when more than ONE output is modified but not ALL
293 /// (optimization issue).
294 /// (without marking the box as MODIFIED because its output state is ok).
295 /// This method should be used by widgets in response to user interaction
296 /// When more than one output has been changed but not all
297 /// (after the outputs have been updated of course!)
298 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
299 /// ** USER INTENDED **
300 virtual void bbSignalOutputModification( const std::vector<std::string>&
302 bool reaction = true);
303 //==================================================================
311 //==================================================================
312 /// @name Common inputs / outputs to all boxes
314 /// Returns the value of the input 'BoxProcessMode'
315 std::string bbGetInputBoxProcessMode() { return bbmBoxProcessMode; }
316 /// Sets the value of the input 'BoxProcessMode'
317 void bbSetInputBoxProcessMode(std::string a) { bbmBoxProcessMode = a; }
318 /// The possible values of the input 'BoxProcessMode'
329 /// Returns the "decoded" value of the input "BoxProcessMode"
330 BoxProcessModeValue bbGetBoxProcessModeValue() const;
331 /// Returns true iff the input 'BoxProcessMode' is set to 'Reactive' (or a synonym)
332 virtual bool bbBoxProcessModeIsReactive() const;
333 /// Returns true iff the input 'BoxProcessMode' is set to 'Always' (or a synonym)
334 virtual bool bbBoxProcessModeIsAlways() const;
335 /// Returns true iff the input 'BoxProcessMode' is set to 'Manual' (or a synonym)
336 virtual bool bbBoxProcessModeIsManual() const;
338 /// Returns the value of the input 'BoxExecute'
339 Void bbGetInputBoxExecute() { return Void(); }
340 /// Sets the value of the input 'BoxExecute'
341 void bbSetInputBoxExecute(Void = 0) { }
343 /// Returns the value of the output 'BoxChange'
344 Void bbGetOutputBoxChange() { return Void(); }
345 /// Sets the value of the output 'BoxChange'
346 void bbSetOutputBoxChange(Void = 0) { }
348 //==================================================================
350 virtual void bbPrintHelp(BlackBox::Pointer parentblackbox,
351 int detail, int level
354 /// Does nothing here : overloaded in ComplexBlackBox
355 void bbInsertHTMLGraph( std::ofstream& s,
359 const std::string& output_dir,
364 //==================================================================
365 /// @name Window related methods
367 virtual void bbSetShown(bool) {}
368 virtual bool bbIsShown() { return false; }
370 //==================================================================
372 //JCP changed to public 09-06-09
373 //==================================================================
374 /// @name Manage the execution
376 static bool bbGlobalGetSomeBoxExecuting();
377 static void bbGlobalSetSomeBoxExecuting(bool b);
379 static void bbGlobalSetFreezeExecution(bool b);
380 static bool bbGlobalGetFreezeExecution();
382 static void bbGlobalAddToExecutionList( BlackBox::Pointer b );
383 static void bbGlobalProcessExecutionList();
390 //==================================================================
391 /// @name User redefinable methods
392 /// Virtual methods which can be redefined by inherited classes
395 //==================================================================
396 /// User can redefine this method to set
397 /// the default values of the box inputs and outputs
398 /// (it is called in the box constructor)
399 virtual void bbUserSetDefaultValues() {}
401 /// User can redefine this method to initialize what must be
402 /// initialized for the box to work, for example allocate dynamic data.
403 /// It is called once and only once before any call to bbUserCreateWidget
404 /// or bbUserProcess.
405 /// What has been allocated here must be desalocated in
406 /// bbFinalizeProcessing
407 virtual void bbUserInitializeProcessing() {}
409 /// User must redefine this method to uninitialize what has been
410 /// initialized in bbUserInitializeProcessing,
411 /// typically desallocate memory that has been allocated dynamically.
412 /// It is called in the box destructor if and only if (iff)
413 /// bbUserInitializeProcessing has been called previously.
414 virtual void bbUserFinalizeProcessing() {}
416 virtual void bbUserOnShow() {}
418 //==================================================================
420 //==================================================================
423 //==================================================================
425 /// Write Graphviz-dot description in file.
426 /// Here dumps a single box description (i/o) but overloaded
427 /// in ComplexBlackBox to dump the internal pipeline representation
428 /// recursing into internal boxes descriptions if level>0.
429 /// detail = 1 : draw inputs and outputs (do not draw otherwise)
430 /// instanceOrtype = true : draw inputs and outputs VALUES
431 /// (uses bbGetInputAsString / bbGetOutputAsString which use adaptors)
432 /// If relative_link is true then creates relative hrefs
433 virtual void bbWriteDotFileBlackBox(FILE *ff,
434 BlackBox::Pointer parentblackbox,
435 int detail, int level,
437 bool relative_link );
438 /// Auxiliary method for bbWriteDotFileBlackBox
439 virtual void bbWriteDotInputOutputName(FILE *ff,
441 int detail, int level);
443 virtual BlackBox::Pointer bbFindBlackBox(const std::string &blackboxname)
444 { return BlackBox::Pointer();}
446 virtual void Check(bool recursive = true);
448 //==================================================================
449 // PROTECTED PART : ACCESSIBLE TO THE BlackBox DEVELOPER
450 // (IN INHERITED CLASSES)
451 /// Constructor that take the BlackBox's name
452 BlackBox(const std::string &name);
453 /// Constructor from an existing box (copy) with a new name
454 BlackBox(BlackBox& from, const std::string &name);
455 //==================================================================
459 //==================================================================
460 /// @name Pipeline processing methods
461 /// Methods which participate to pipeline processing.
463 //==================================================================
464 /// Recursive execution method
466 /// \param caller : The connection which invoked the method; null if called by bbExecute
467 virtual void bbRecursiveExecute(Connection::Pointer caller);
468 //==================================================================
470 //==================================================================
471 /// Updates the BlackBox inputs
472 /// Calls RecursiveExecute on all BlackBoxInputConnector
473 /// \returns The maximum of final IOStatus after each input update
474 IOStatus bbUpdateInputs();
475 //==================================================================
478 //==================================================================
479 /// Actual CreateWindow method (vitual)
480 /// Overloaded in AtomicBlacBox and descendants
481 virtual void bbCreateWindow()
483 // bbtkError("BlackBox::bbCreateWidget called : how can this happen ?");
485 //==================================================================
487 //==================================================================
488 /// Actual ShowWindow method (vitual)
489 /// Overloaded in AtomicBlacBox and descendants
490 virtual void bbShowWindow()
492 // bbtkError("BlackBox::bbShowWidget called : how can this happen ?");
494 //==================================================================
497 //==================================================================
498 /// Actual processing method (vitual)
499 /// Overloaded in AtomicBlacBox and descendants
500 virtual void bbProcess()
502 bbtkError("BlackBox::bbProcess called : how can this happen ?");
503 // this->bbUserProcess();
505 //==================================================================
507 //==================================================================
508 /// Computes the final IOStatus of inputs and outputs after processing
509 virtual void bbComputePostProcessStatus();
511 //==================================================================
514 //==================================================================
515 /// Signals that the input whose connector is c has changed
516 /// and propagates the info downward
517 /// ** NOT USER INTENDED **
518 virtual void bbSetStatusAndPropagate(BlackBoxInputConnector* c,
520 //==================================================================
524 //==================================================================
525 /// @name Box con(des)struction / initi(fin)alization methods
528 //==================================================================
529 /// Allocates the i/o connectors of the black box
530 virtual void bbAllocateConnectors();
531 /// Desallocates the i/o connectors of the black box
532 virtual void bbDesallocateConnectors();
533 /// Copies the values of the inputs/output from the BlackBox from
534 virtual void bbCopyIOValues(BlackBox& from);
535 //==================================================================
537 //==================================================================
538 /// Initializes processing IF NEEDED.
539 /// Calls bbRecursiveInitializeProcessing if the box is in
540 /// "uninitialized" state and put it in "initialized" state.
541 /// On construction, boxes are "uninitialized".
542 /// See also bbFinalizeProcessing
543 void bbInitializeProcessing();
545 /// Finalizes processing IF NEEDED.
546 /// Calls bbRecursiveFinalizeProcessing if the box is in
547 /// "initialized" state and put it in "uninitialized" state.
548 /// On construction, boxes are "uninitialized".
549 /// See also bbInitializeProcessing
550 void bbFinalizeProcessing();
552 /// Abstract prototype of the method which
553 /// Recursively calls itself for the parent black box and then
554 /// calls bbUserInitializeProcessing for its own class.
555 /// It is redefined in each black box descendant.
556 /// Allows to call bbUserInitializeProcessing for all inherited classes
557 /// (like a constructor does)
558 virtual void bbRecursiveInitializeProcessing() {}
561 /// Abstract prototype of the method which
562 /// calls bbUserFinalizeProcessing for its own class and then
563 /// recursively calls itself for the parent black box.
564 /// It is redefined in each black box descendant.
565 /// Allows to call bbUserFinalizeProcessing for all inherited classes
566 /// (like a destructor does)
567 virtual void bbRecursiveFinalizeProcessing() {}
568 //==================================================================
571 //==================================================================
574 //==================================================================
575 friend class Connection;
576 friend class ComplexBlackBox;
578 /// Sets the parent of the BlackBox
579 void bbSetParent(BlackBox::Pointer p) { bbmParent = p; }
581 //==================================================================
582 /// @name Input/output connection/disconnection
583 /// INTERNAL METHODS used by a Connection to connect/disconnect
584 /// itself to the i/o connectors of the box
587 /// Connects the input <name> to the connection c
588 virtual void bbConnectInput( const std::string& name, Connection* c);
589 /// Connects the output <name> to the connection c
590 virtual void bbConnectOutput( const std::string& name, Connection* c);
591 /// Disconnects the input <name> from the connection c
592 virtual void bbDisconnectInput( const std::string& name, Connection* c);
593 /// Disconnects the output <name> from the connection c
594 virtual void bbDisconnectOutput( const std::string& name, Connection* c);
596 //==================================================================
598 /// Returns true if the box can "react",
599 /// which means execute in response to an input change
600 virtual bool bbCanReact() const;
602 /// Returns true iff the box is executing
603 bool bbGetExecuting() const { return bbmExecuting; }
604 /// Sets the bbmExecuting bool returned by bbGetExecuting
605 void bbSetExecuting(bool b) { bbmExecuting = b; }
607 //==================================================================
611 //==================================================================
612 /// Black box objects have a special deleter
613 /// which must take care of releasing the descriptor
614 /// **AFTER** the box is deleted
615 /// (Releasing it in the destructor may cause dl close and crash)
616 /// Black box deleter
617 /// 1) Calls the user overloadable bbDelete method
618 /// 2) Releases the box descriptor
619 struct BBTK_EXPORT Deleter : public Object::Deleter
622 int Delete(Object* p);
624 //==================================================================
626 //==================================================================
627 /// Like Object::MakePointer but returns a boost::shared_pointer which uses a BlackBox::Deleter to delete the object instead of the default Object::Deleter
629 static boost::shared_ptr<U> MakeBlackBoxPointer(U* s, bool lock = false)
631 return MakePointer(s,BlackBox::Deleter(),lock);
633 //==================================================================
635 //==================================================================
636 /// Effective deletion method called by the Deleter.
637 /// The default implementation is to issue 'delete this'
638 /// 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.).
639 /// \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...
641 //JCP 21-09-20 09 delete this throws and exception change due to compiler version changing and boost version
642 virtual int bbDelete() { delete this;
644 //==================================================================
647 //==================================================================
649 //==================================================================
651 //==================================================================
653 /// Is the box initialized ?
655 /// Is the box executing ?
657 /// The name of the black-box
659 /// The name of the package to which it belongs
660 std::string bbmPackageName;
661 /// The box processing mode
662 /// 0 : "Pipeline" mode
663 /// 1 : "Always" mode
664 /// 2 : "Reactive" mode
665 /// 3 : "Manual" mode
666 std::string bbmBoxProcessMode;
667 /// The parent of the black box in the ComplexBlackBox hierarchy
668 BlackBox::WeakPointer bbmParent;
669 //==================================================================
672 //==================================================================
674 /// Map that contains the output connectors of the black box
675 OutputConnectorMapType mOutputConnectorMap;
676 /// Map that contains the input connectors of the black box
677 InputConnectorMapType mInputConnectorMap;
678 //==================================================================
681 bool bbLetRecursiveExecuteManualMode;
686 /// Convenient macro to create output observer callbacks (freehand functions) from object and method pointer (see samples/SampleOutputObserver)
687 #define BBTK_MAKE_OUTPUT_OBSERVER(OBJECT,METHOD) \
688 boost::bind( METHOD, OBJECT, _1, _2, _3)