1 /*=========================================================================
3 Module: $RCSfile: bbtkBlackBox.h,v $
5 Date: $Date: 2012/07/26 08:28:31 $
6 Version: $Revision: 1.33 $
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 "bbtkMessageManager.h"
48 #include "bbtkBlackBoxDescriptor.h"
49 #include "bbtkBlackBoxInputConnector.h"
50 //#include "bbtkBlackBoxOutputConnector.h"
53 // Signal/slot mechanism for output change events
54 #include <boost/signal.hpp>
55 #include <boost/bind.hpp>
58 #define bbtkBlackBoxMessage(key,level,mess) \
59 bbtkMessage(key,level,"["<<bbGetName()<<"] "<<mess)
60 #define bbtkBlackBoxDebugMessage(key,level,mess) \
61 bbtkDebugMessage(key,level,"["<<bbGetName()<<"] "<<mess)
66 struct Void { Void(int = 0) {} };
70 class BlackBoxOutputConnector;
72 class BBTK_EXPORT BlackBox : public Object
74 BBTK_ABSTRACT_OBJECT_INTERFACE(BlackBox);
79 //==================================================================
81 //==================================================================
82 typedef boost::signals::trackable OutputChangeObserverType;
83 typedef boost::signal<void (bbtk::BlackBox::Pointer,
85 IOStatus)> OutputChangeSignalType;
86 typedef OutputChangeSignalType::slot_function_type
87 OutputChangeCallbackType;
89 /// The type of map of output connector pointers
90 typedef std::map<std::string, BlackBoxOutputConnector*>
91 OutputConnectorMapType;
92 /// The type of map of input connector pointers
93 typedef std::map<std::string, BlackBoxInputConnector*>
94 InputConnectorMapType;
95 //==================================================================
98 //==================================================================
99 /// @name Pipeline processing methods
100 /// Methods which participate to pipeline processing.
102 /// Main processing method of the box.
103 virtual void bbExecute(bool force = false);
105 //==================================================================
111 //==================================================================
112 /// Returns a pointer on a clone of the box with name <name>
113 virtual BlackBox::Pointer bbClone(const std::string& name) = 0;
114 //==================================================================
117 //==================================================================
118 /// @name General accessors
119 /// Methods which give access to general informations on the box
122 /// Returns the pointer on the descriptor of the box
123 virtual BlackBoxDescriptor::Pointer bbGetDescriptor() const = 0;
125 /// Returns the Name of the Type of the BlackBox
126 const std::string& bbGetTypeName() const
127 { return bbGetDescriptor()->GetTypeName(); }
130 /// Returns the name of the BlackBox (instance)
131 const std::string& bbGetName() const { return bbmName; }
133 /// Returns the full name of the BlackBox (instance+type)
134 virtual std::string bbGetFullName() const;
136 /// Returns the name with the name of the parent prepended if any
137 virtual std::string bbGetNameWithParent() const;
139 /// Returns the parent of the BlackBox, i.e the BlackBox that contains it (0 if none)
140 BlackBox::Pointer bbGetParent() const { return bbmParent.lock(); }
143 //==================================================================
147 //==================================================================
148 /// @name Inputs/Outputs related methods
149 /// Methods related to the box inputs and outputs
152 /// Returns true iff the BlackBox has an input of name label
153 virtual bool bbHasInput(const std::string& label) const;
154 /// Gets the input type of a given label
155 virtual TypeInfo bbGetInputType( const std::string &label ) const;
156 /// Gets the status of the input called <name>
157 IOStatus bbGetInputStatus( const std::string &name ) const
158 { return mInputConnectorMap.find(name)->second->GetStatus(); }
159 /// Gets the data of the input called <name>
160 virtual Data bbGetInput( const std::string &name ) = 0;
161 /// Gets the data of the input called <name> as a string using an Adaptor if possible (else returns empty string)
162 std::string bbGetInputAsString( const std::string &input);
165 /// Sets the data of the input called <name>.
166 /// If update_time is false then does not update ChangeTime of input
167 virtual void bbSetInput( const std::string &name, Data data,
168 bool update_time = true ) = 0;
169 /// [SYSTEM]: Sets the data of the input called <name> which **MUST* be a pointer
170 virtual void bbBruteForceSetInputPointer( const std::string &name,
172 bool update_time = true) =0;
175 /// Returns true iff the BlackBox has an output of name label
176 virtual bool bbHasOutput(const std::string& label) const;
177 /// Gets the output type of a given label
178 virtual TypeInfo bbGetOutputType( const std::string &label ) const;
179 /// Gets the data of the output called <name>
180 virtual Data bbGetOutput( const std::string &name ) = 0;
181 /// Gets the data of the output called <name> as a string using an Adaptor if possible (else returns empty string)
182 std::string bbGetOutputAsString( const std::string &output ); //,Factory *factory);
184 /// Sets the data of the output called <name>
185 virtual void bbSetOutput( const std::string &name, Data data) = 0;
188 /// Returns the input connectors map
189 InputConnectorMapType& bbGetInputConnectorMap()
190 { return mInputConnectorMap; }
191 /// Returns the input connectors map (const)
192 const InputConnectorMapType& bbGetInputConnectorMap() const
193 { return mInputConnectorMap; }
194 /// Returns the input connector
195 BlackBoxInputConnector& bbGetInputConnector(const std::string& n)
196 { return *(mInputConnectorMap.find(n)->second); }
197 /// Returns the input connector (const)
198 const BlackBoxInputConnector& bbGetInputConnector(const std::string& n) const
199 { return *(mInputConnectorMap.find(n)->second); }
202 /// Returns the output connectors map
203 OutputConnectorMapType& bbGetOutputConnectorMap()
204 { return mOutputConnectorMap; }
205 /// Returns the output connectors map (const)
206 const OutputConnectorMapType& bbGetOutputConnectorMap() const
207 { return mOutputConnectorMap; }
208 /// Returns the output connector
209 BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n)
210 { return *(mOutputConnectorMap.find(n)->second); }
211 /// Returns the output connector (const)
212 const BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n) const
213 { return *(mOutputConnectorMap.find(n)->second); }
216 //==================================================================
218 /// Prints the Help on the BlackBox type
219 virtual void bbGetHelp(bool full=true) const;
223 //==================================================================
224 /// @name Output signals / observers related methods
225 /// Methods related to signals emitted by outputs and the
228 //==================================================================
229 /// Adds the function f to the list of functions to call when
230 /// the output changes.
231 /// f is of type ChangeCallbackType which is basically:
232 /// void (*ChangeCallbackType)(bbtk::BlackBox::Pointer,
233 /// const std::string&,
235 /// To pass a member function 'f' of an instance 'c' of a class 'C'
236 /// as callback you have to 'bind' it, i.e. call:
237 /// bbAddOutputObserver ( "Out", boost::bind( &C::f , c, _1, _2, _3 ) );
238 /// The convenience macro BBTK_BIND_OUTPUT_OBSERVER ( c, C::f ) does it for you
239 void bbAddOutputObserver(const std::string& output_name,
240 OutputChangeCallbackType f);
242 /// Removes the function f from the list of functions to call when
243 /// the output changes (TO WRITE)
244 void bbRemoveOutputObserver(const std::string& output_name,
245 OutputChangeCallbackType f);
246 //==================================================================
249 //==================================================================
250 /// Signals that the BlackBox outputs have been modified
251 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
252 /// This method should be used by widgets in response
253 /// to user interaction when **ALL** outputs have been modified
254 /// (after the outputs has been updated !).
255 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
256 /// ** USER INTENDED **
257 virtual void bbSignalOutputModification(bool reaction = true);
258 /// Signals that the BlackBox output "output_name" has been modified
259 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
260 /// This method should be used by widgets in response to user interaction
261 /// only when **ONE** output has been modified
262 /// (after the output has been updated !)
263 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
264 /// ** USER INTENDED **
265 virtual void bbSignalOutputModification( const std::string& output_name,
266 bool reaction = true);
267 /// Signals that the BlackBox vector of outputs "output_name"
268 /// have been modified.
269 /// Should be used when more than ONE output is modified but not ALL
270 /// (optimization issue).
271 /// (without marking the box as MODIFIED because its output state is ok).
272 /// This method should be used by widgets in response to user interaction
273 /// When more than one output has been changed but not all
274 /// (after the outputs have been updated of course!)
275 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
276 /// ** USER INTENDED **
277 virtual void bbSignalOutputModification( const std::vector<std::string>&
279 bool reaction = true);
280 //==================================================================
288 //==================================================================
289 /// @name Common inputs / outputs to all boxes
291 /// Returns the value of the input 'BoxProcessMode'
292 std::string bbGetInputBoxProcessMode() { return bbmBoxProcessMode; }
293 /// Sets the value of the input 'BoxProcessMode'
294 void bbSetInputBoxProcessMode(std::string a) { bbmBoxProcessMode = a; }
295 /// The possible values of the input 'BoxProcessMode'
306 /// Returns the "decoded" value of the input "BoxProcessMode"
307 BoxProcessModeValue bbGetBoxProcessModeValue() const;
308 /// Returns true iff the input 'BoxProcessMode' is set to 'Reactive' (or a synonym)
309 virtual bool bbBoxProcessModeIsReactive() const;
310 /// Returns true iff the input 'BoxProcessMode' is set to 'Always' (or a synonym)
311 virtual bool bbBoxProcessModeIsAlways() const;
312 /// Returns true iff the input 'BoxProcessMode' is set to 'Manual' (or a synonym)
313 virtual bool bbBoxProcessModeIsManual() const;
315 /// Returns the value of the input 'BoxExecute'
316 Void bbGetInputBoxExecute() { return Void(); }
317 /// Sets the value of the input 'BoxExecute'
318 void bbSetInputBoxExecute(Void = 0) { }
320 /// Returns the value of the output 'BoxChange'
321 Void bbGetOutputBoxChange() { return Void(); }
322 /// Sets the value of the output 'BoxChange'
323 void bbSetOutputBoxChange(Void = 0) { }
325 //==================================================================
327 virtual void bbPrintHelp(BlackBox::Pointer parentblackbox,
328 int detail, int level
331 /// Does nothing here : overloaded in ComplexBlackBox
332 void bbInsertHTMLGraph( std::ofstream& s,
336 const std::string& output_dir,
341 //==================================================================
342 /// @name Window related methods
344 virtual void bbSetShown(bool) {}
345 virtual bool bbIsShown() { return false; }
347 //==================================================================
349 //JCP changed to public 09-06-09
350 //==================================================================
351 /// @name Manage the execution
353 static bool bbGlobalGetSomeBoxExecuting();
354 static void bbGlobalSetSomeBoxExecuting(bool b);
356 static void bbGlobalSetFreezeExecution(bool b);
357 static bool bbGlobalGetFreezeExecution();
359 static void bbGlobalAddToExecutionList( BlackBox::Pointer b );
360 static void bbGlobalProcessExecutionList();
367 //==================================================================
368 /// @name User redefinable methods
369 /// Virtual methods which can be redefined by inherited classes
372 //==================================================================
373 /// User can redefine this method to set
374 /// the default values of the box inputs and outputs
375 /// (it is called in the box constructor)
376 virtual void bbUserSetDefaultValues() {}
378 /// User can redefine this method to initialize what must be
379 /// initialized for the box to work, for example allocate dynamic data.
380 /// It is called once and only once before any call to bbUserCreateWidget
381 /// or bbUserProcess.
382 /// What has been allocated here must be desalocated in
383 /// bbFinalizeProcessing
384 virtual void bbUserInitializeProcessing() {}
386 /// User must redefine this method to uninitialize what has been
387 /// initialized in bbUserInitializeProcessing,
388 /// typically desallocate memory that has been allocated dynamically.
389 /// It is called in the box destructor if and only if (iff)
390 /// bbUserInitializeProcessing has been called previously.
391 virtual void bbUserFinalizeProcessing() {}
393 virtual void bbUserOnShow() {}
395 //==================================================================
397 //==================================================================
400 //==================================================================
402 /// Write Graphviz-dot description in file.
403 /// Here dumps a single box description (i/o) but overloaded
404 /// in ComplexBlackBox to dump the internal pipeline representation
405 /// recursing into internal boxes descriptions if level>0.
406 /// detail = 1 : draw inputs and outputs (do not draw otherwise)
407 /// instanceOrtype = true : draw inputs and outputs VALUES
408 /// (uses bbGetInputAsString / bbGetOutputAsString which use adaptors)
409 /// If relative_link is true then creates relative hrefs
410 virtual void bbWriteDotFileBlackBox(FILE *ff,
411 BlackBox::Pointer parentblackbox,
412 int detail, int level,
414 bool relative_link );
415 /// Auxiliary method for bbWriteDotFileBlackBox
416 virtual void bbWriteDotInputOutputName(FILE *ff,
418 int detail, int level);
420 virtual BlackBox::Pointer bbFindBlackBox(const std::string &blackboxname)
421 { return BlackBox::Pointer();}
423 virtual void Check(bool recursive = true);
425 //==================================================================
426 // PROTECTED PART : ACCESSIBLE TO THE BlackBox DEVELOPER
427 // (IN INHERITED CLASSES)
428 /// Constructor that take the BlackBox's name
429 BlackBox(const std::string &name);
430 /// Constructor from an existing box (copy) with a new name
431 BlackBox(BlackBox& from, const std::string &name);
432 //==================================================================
436 //==================================================================
437 /// @name Pipeline processing methods
438 /// Methods which participate to pipeline processing.
440 //==================================================================
441 /// Recursive execution method
443 /// \param caller : The connection which invoked the method; null if called by bbExecute
444 virtual void bbRecursiveExecute(Connection::Pointer caller);
445 //==================================================================
447 //==================================================================
448 /// Updates the BlackBox inputs
449 /// Calls RecursiveExecute on all BlackBoxInputConnector
450 /// \returns The maximum of final IOStatus after each input update
451 IOStatus bbUpdateInputs();
452 //==================================================================
455 //==================================================================
456 /// Actual CreateWindow method (vitual)
457 /// Overloaded in AtomicBlacBox and descendants
458 virtual void bbCreateWindow()
460 // bbtkError("BlackBox::bbCreateWidget called : how can this happen ?");
462 //==================================================================
464 //==================================================================
465 /// Actual ShowWindow method (vitual)
466 /// Overloaded in AtomicBlacBox and descendants
467 virtual void bbShowWindow()
469 // bbtkError("BlackBox::bbShowWidget called : how can this happen ?");
471 //==================================================================
474 //==================================================================
475 /// Actual processing method (vitual)
476 /// Overloaded in AtomicBlacBox and descendants
477 virtual void bbProcess()
479 bbtkError("BlackBox::bbProcess called : how can this happen ?");
480 // this->bbUserProcess();
482 //==================================================================
484 //==================================================================
485 /// Computes the final IOStatus of inputs and outputs after processing
486 void bbComputePostProcessStatus();
488 //==================================================================
491 //==================================================================
492 /// Signals that the input whose connector is c has changed
493 /// and propagates the info downward
494 /// ** NOT USER INTENDED **
495 virtual void bbSetStatusAndPropagate(BlackBoxInputConnector* c,
497 //==================================================================
501 //==================================================================
502 /// @name Box con(des)struction / initi(fin)alization methods
505 //==================================================================
506 /// Allocates the i/o connectors of the black box
507 virtual void bbAllocateConnectors();
508 /// Desallocates the i/o connectors of the black box
509 virtual void bbDesallocateConnectors();
510 /// Copies the values of the inputs/output from the BlackBox from
511 virtual void bbCopyIOValues(BlackBox& from);
512 //==================================================================
514 //==================================================================
515 /// Initializes processing IF NEEDED.
516 /// Calls bbRecursiveInitializeProcessing if the box is in
517 /// "uninitialized" state and put it in "initialized" state.
518 /// On construction, boxes are "uninitialized".
519 /// See also bbFinalizeProcessing
520 void bbInitializeProcessing();
522 /// Finalizes processing IF NEEDED.
523 /// Calls bbRecursiveFinalizeProcessing if the box is in
524 /// "initialized" state and put it in "uninitialized" state.
525 /// On construction, boxes are "uninitialized".
526 /// See also bbInitializeProcessing
527 void bbFinalizeProcessing();
529 /// Abstract prototype of the method which
530 /// Recursively calls itself for the parent black box and then
531 /// calls bbUserInitializeProcessing for its own class.
532 /// It is redefined in each black box descendant.
533 /// Allows to call bbUserInitializeProcessing for all inherited classes
534 /// (like a constructor does)
535 virtual void bbRecursiveInitializeProcessing() {}
538 /// Abstract prototype of the method which
539 /// calls bbUserFinalizeProcessing for its own class and then
540 /// recursively calls itself for the parent black box.
541 /// It is redefined in each black box descendant.
542 /// Allows to call bbUserFinalizeProcessing for all inherited classes
543 /// (like a destructor does)
544 virtual void bbRecursiveFinalizeProcessing() {}
545 //==================================================================
548 //==================================================================
551 //==================================================================
552 friend class Connection;
553 friend class ComplexBlackBox;
555 /// Sets the parent of the BlackBox
556 void bbSetParent(BlackBox::Pointer p) { bbmParent = p; }
558 //==================================================================
559 /// @name Input/output connection/disconnection
560 /// INTERNAL METHODS used by a Connection to connect/disconnect
561 /// itself to the i/o connectors of the box
564 /// Connects the input <name> to the connection c
565 virtual void bbConnectInput( const std::string& name,
567 /// Connects the output <name> to the connection c
568 virtual void bbConnectOutput( const std::string& name,
570 /// Disconnects the input <name> from the connection c
571 virtual void bbDisconnectInput( const std::string& name,
573 /// Disconnects the output <name> from the connection c
574 virtual void bbDisconnectOutput( const std::string& name,
577 //==================================================================
579 /// Returns true if the box can "react",
580 /// which means execute in response to an input change
581 virtual bool bbCanReact() const;
583 /// Returns true iff the box is executing
584 bool bbGetExecuting() const { return bbmExecuting; }
585 /// Sets the bbmExecuting bool returned by bbGetExecuting
586 void bbSetExecuting(bool b) { bbmExecuting = b; }
590 //==================================================================
594 //==================================================================
595 /// Black box objects have a special deleter
596 /// which must take care of releasing the descriptor
597 /// **AFTER** the box is deleted
598 /// (Releasing it in the destructor may cause dl close and crash)
599 /// Black box deleter
600 /// 1) Calls the user overloadable bbDelete method
601 /// 2) Releases the box descriptor
602 struct BBTK_EXPORT Deleter : public Object::Deleter
605 int Delete(Object* p);
607 //==================================================================
609 //==================================================================
610 /// Like Object::MakePointer but returns a boost::shared_pointer which uses a BlackBox::Deleter to delete the object instead of the default Object::Deleter
612 static boost::shared_ptr<U> MakeBlackBoxPointer(U* s, bool lock = false)
614 return MakePointer(s,BlackBox::Deleter(),lock);
616 //==================================================================
618 //==================================================================
619 /// Effective deletion method called by the Deleter.
620 /// The default implementation is to issue 'delete this'
621 /// 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.).
622 /// \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...
624 //JCP 21-09-20 09 delete this throws and exception change due to compiler version changing and boost version
625 virtual int bbDelete() { delete this;
627 //==================================================================
630 //==================================================================
632 //==================================================================
634 //==================================================================
636 /// Is the box initialized ?
638 /// Is the box executing ?
640 /// The name of the black-box
642 /// The name of the package to which it belongs
643 std::string bbmPackageName;
644 /// The box processing mode
645 /// 0 : "Pipeline" mode
646 /// 1 : "Always" mode
647 /// 2 : "Reactive" mode
648 /// 3 : "Manual" mode
649 std::string bbmBoxProcessMode;
650 /// The parent of the black box in the ComplexBlackBox hierarchy
651 BlackBox::WeakPointer bbmParent;
652 //==================================================================
655 //==================================================================
657 /// Map that contains the output connectors of the black box
658 OutputConnectorMapType mOutputConnectorMap;
659 /// Map that contains the input connectors of the black box
660 InputConnectorMapType mInputConnectorMap;
661 //==================================================================
664 bool bbLetRecursiveExecuteManualMode;
669 /// Convenient macro to create output observer callbacks (freehand functions) from object and method pointer (see samples/SampleOutputObserver)
670 #define BBTK_MAKE_OUTPUT_OBSERVER(OBJECT,METHOD) \
671 boost::bind( METHOD, OBJECT, _1, _2, _3)