1 /*=========================================================================
3 Module: $RCSfile: bbtkBlackBox.h,v $
5 Date: $Date: 2009/04/30 14:31:31 $
6 Version: $Revision: 1.24 $
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;
68 class BBTK_EXPORT BlackBox : public Object
70 BBTK_ABSTRACT_OBJECT_INTERFACE(BlackBox);
72 //==================================================================
74 //==================================================================
75 typedef boost::signals::trackable OutputChangeObserverType;
76 typedef boost::signal<void (bbtk::BlackBox::Pointer,
78 IOStatus)> OutputChangeSignalType;
79 typedef OutputChangeSignalType::slot_function_type
80 OutputChangeCallbackType;
82 /// The type of map of output connector pointers
83 typedef std::map<std::string, BlackBoxOutputConnector*>
84 OutputConnectorMapType;
85 /// The type of map of input connector pointers
86 typedef std::map<std::string, BlackBoxInputConnector*>
87 InputConnectorMapType;
89 /// Returns the pointer on the descriptor of the box
90 virtual BlackBoxDescriptor::Pointer bbGetDescriptor() const = 0;
92 /// Returns a pointer on a clone of the box with name <name>
93 virtual BlackBox::Pointer bbClone(const std::string& name) = 0;
95 /// User overloadable destruction method of a black box
96 virtual void bbUserDelete();
98 /// Returns the Name of the Type of the BlackBox
99 const std::string& bbGetTypeName() const
100 { return bbGetDescriptor()->GetTypeName(); }
103 /// Returns the name of the BlackBox (instance)
104 const std::string& bbGetName() const { return bbmName; }
106 /// Returns the full name of the BlackBox (instance+type)
107 virtual std::string bbGetFullName() const;
109 /// Returns the name with the name of the parent prepended if any
110 virtual std::string bbGetNameWithParent() const;
112 /// Returns the parent of the BlackBox, i.e the BlackBox that contains it (0 if none)
113 BlackBox::Pointer bbGetParent() const { return bbmParent.lock(); }
116 /// Main processing method of the box.
117 virtual void bbExecute(bool force = false);
121 //==================================================================
122 /// System callback which calls bbUserConstructor for all its ancestors
123 /// and the box itself
124 virtual void bbConstructor() {}
125 /// System callback which calls bbUserDestructor for all its ancestors
126 /// and the box itself
127 virtual void bbDestructor() {}
128 //==================================================================
132 /// Returns true iff the BlackBox has an input of name label
133 virtual bool bbHasInput(const std::string& label) const;
134 /// Returns true iff the BlackBox has an output of name label
135 virtual bool bbHasOutput(const std::string& label) const;
137 /// Gets the input type of a given label
138 virtual TypeInfo bbGetInputType( const std::string &label ) const;
139 /// Gets the output type of a given label
140 virtual TypeInfo bbGetOutputType( const std::string &label ) const;
142 /// Gets the data of the input called <name>
143 virtual Data bbGetInput( const std::string &name ) = 0;
144 /// Gets the data of the output called <name>
145 virtual Data bbGetOutput( const std::string &name ) = 0;
147 /// Sets the data of the input called <name>.
148 /// If update_time is false then does not update ChangeTime of input
149 virtual void bbSetInput( const std::string &name, Data data,
150 bool update_time = true ) = 0;
151 virtual void bbBruteForceSetInputPointer( const std::string &name,
153 bool update_time = true) =0;
154 /// Sets the data of the output called <name>
155 virtual void bbSetOutput( const std::string &name, Data data) = 0;
158 /// Gets the status of the input called <name>
159 IOStatus bbGetInputStatus( const std::string &name ) const
160 { return mInputConnectorMap.find(name)->second->GetStatus(); }
162 /// Returns the input connectors map
163 InputConnectorMapType& bbGetInputConnectorMap()
164 { return mInputConnectorMap; }
165 /// Returns the output connectors map
166 OutputConnectorMapType& bbGetOutputConnectorMap()
167 { return mOutputConnectorMap; }
168 /// Returns the input connectors map (const)
169 const InputConnectorMapType& bbGetInputConnectorMap() const
170 { return mInputConnectorMap; }
171 /// Returns the output connectors map (const)
172 const OutputConnectorMapType& bbGetOutputConnectorMap() const
173 { return mOutputConnectorMap; }
175 /// Returns the input connector
176 BlackBoxInputConnector& bbGetInputConnector(const std::string& n)
177 { return *(mInputConnectorMap.find(n)->second); }
178 /// Returns the output connector
179 BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n)
180 { return *(mOutputConnectorMap.find(n)->second); }
181 /// Returns the input connector (const)
182 const BlackBoxInputConnector& bbGetInputConnector(const std::string& n) const
183 { return *(mInputConnectorMap.find(n)->second); }
184 /// Returns the output connector (const)
185 const BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n) const
186 { return *(mOutputConnectorMap.find(n)->second); }
191 /// Prints the Help on the BlackBox type
192 virtual void bbGetHelp(bool full=true) const;
194 //==================================================================
195 /// Adds the function f to the list of functions to call when
196 /// the output changes.
197 /// f is of type ChangeCallbackType which is basically:
198 /// void (*ChangeCallbackType)(bbtk::BlackBox::Pointer,
199 /// const std::string&,
201 /// To pass a member function 'f' of an instance 'c' of a class 'C'
202 /// as callback you have to 'bind' it, i.e. call:
203 /// bbAddOutputObserver ( "Out", boost::bind( &C::f , c, _1, _2, _3 ) );
204 /// The convenience macro BBTK_BIND_OUTPUT_OBSERVER ( c, C::f ) does it for you
205 void bbAddOutputObserver(const std::string& output_name,
206 OutputChangeCallbackType f);
208 /// Removes the function f from the list of functions to call when
209 /// the output changes (TO WRITE)
210 void bbRemoveOutputObserver(const std::string& output_name,
211 OutputChangeCallbackType f);
212 //==================================================================
215 //==================================================================
216 /// Signals that the BlackBox outputs have been modified
217 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
218 /// This method should be used by widgets in response
219 /// to user interaction when **ALL** outputs have been modified
220 /// (after the outputs has been updated !).
221 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
222 /// ** USER INTENDED **
223 virtual void bbSignalOutputModification(bool reaction = true);
224 /// Signals that the BlackBox output "output_name" has been modified
225 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
226 /// This method should be used by widgets in response to user interaction
227 /// only when **ONE** output has been modified
228 /// (after the output has been updated !)
229 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
230 /// ** USER INTENDED **
231 virtual void bbSignalOutputModification( const std::string& output_name,
232 bool reaction = true);
233 /// Signals that the BlackBox vector of outputs "output_name"
234 /// have been modified.
235 /// Should be used when more than ONE output is modified but not ALL
236 /// (optimization issue).
237 /// (without marking the box as MODIFIED because its output state is ok).
238 /// This method should be used by widgets in response to user interaction
239 /// When more than one output has been changed but not all
240 /// (after the outputs have been updated of course!)
241 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
242 /// ** USER INTENDED **
243 virtual void bbSignalOutputModification( const std::vector<std::string>&
245 bool reaction = true);
246 //==================================================================
250 //==================================================================
251 // Common inputs / outputs to all boxes
252 /// Returns the value of the input "BoxProcessMode"
253 std::string bbGetInputBoxProcessMode() { return bbmBoxProcessMode; }
254 /// Sets the value of the input "BoxProcessMode"
255 void bbSetInputBoxProcessMode(std::string a) { bbmBoxProcessMode = a; }
263 /// Returns the "decoded" value of the input "BoxProcessMode"
264 BoxProcessModeValue bbGetBoxProcessModeValue() const;
266 virtual bool bbBoxProcessModeIsReactive() const;
268 virtual bool bbBoxProcessModeIsAlways() const;
270 /// Returns the value of the input "Execute"
271 Void bbGetInputBoxExecute() { return Void(); }
272 /// Sets the value of the input "Execute"
273 void bbSetInputBoxExecute(Void = 0) {}
275 /// Returns the value of the output "Change"
276 Void bbGetOutputBoxChange() { return Void(); }
277 /// Sets the value of the output "Change" : signal a modification
278 void bbSetOutputBoxChange(Void = 0) { } //bbSetModifiedStatus(); }
280 //==================================================================
283 //==================================================================
285 /// Does nothing here : overloaded in ComplexBlackBox
286 void bbInsertHTMLGraph( std::ofstream& s,
290 const std::string& output_dir,
294 /// Write Graphviz-dot description in file.
295 /// Here dumps a single box description (i/o) but overloaded
296 /// in ComplexBlackBox to dump the internal pipeline representation
297 /// recursing into internal boxes descriptions if level>0.
298 /// detail = 1 : draw inputs and outputs (do not draw otherwise)
299 /// instanceOrtype = true : draw inputs and outputs VALUES
300 /// (uses bbGetInputAsString / bbGetOutputAsString which use adaptors)
301 /// If relative_link is true then creates relative hrefs
302 virtual void bbWriteDotFileBlackBox(FILE *ff,
303 BlackBox::Pointer parentblackbox,
304 int detail, int level,
306 bool relative_link );
307 /// Auxiliary method for bbWriteDotFileBlackBox
308 virtual void bbWriteDotInputOutputName(FILE *ff,
310 int detail, int level);
313 virtual void bbShowRelations(BlackBox::Pointer parentblackbox,
314 int detail, int level
317 std::string bbGetOutputAsString( const std::string &output ); //,Factory *factory);
318 std::string bbGetInputAsString( const std::string &input); //,Factory *factory);
319 virtual BlackBox::Pointer bbFindBlackBox(const std::string &blackboxname)
320 { return BlackBox::Pointer();}
322 virtual void Check(bool recursive = true);
324 virtual void bbUserOnShow() { }
325 void bbUserOnShowWidget(std::string nameInput);
328 //==================================================================
329 // PROTECTED PART : ACCESSIBLE TO THE BlackBox DEVELOPER
330 // (IN INHERITED CLASSES)
331 /// Constructor that take the BlackBox's name
332 BlackBox(const std::string &name);
333 /// Constructor from an existing box (copy) with a new name
334 BlackBox(BlackBox& from, const std::string &name);
335 //==================================================================
338 //==================================================================
339 /// Signals that the input whose connector is c has changed
340 /// and propagates the info downward
341 /// ** NOT USER INTENDED **
342 virtual void bbSetStatusAndPropagate(BlackBoxInputConnector* c,
344 //==================================================================
347 //==================================================================
348 friend class Connection;
349 friend class ComplexBlackBox;
351 /// Sets the parent of the BlackBox
352 void bbSetParent(BlackBox::Pointer p) { bbmParent = p; }
355 /// Connects the input <name> to the connection c
356 virtual void bbConnectInput( const std::string& name,
358 /// Connects the output <name> to the connection c
359 virtual void bbConnectOutput( const std::string& name,
361 /// Disconnects the input <name> from the connection c
362 virtual void bbDisconnectInput( const std::string& name,
364 /// Disconnects the output <name> from the connection c
365 virtual void bbDisconnectOutput( const std::string& name,
368 //==================================================================
370 /// @name Pipeline processing methods
371 /// Methods which participate to pipeline processing.
375 //==================================================================
376 /// Recursive execution method
378 /// \param caller : The connection which invoked the method; null if called by bbExecute
379 virtual void bbRecursiveExecute(Connection::Pointer caller);
380 //==================================================================
382 //==================================================================
383 /// Updates the BlackBox inputs
384 /// Calls RecursiveExecute on all BlackBoxInputConnector
385 /// \returns The maximum of final IOStatus after each input update
386 IOStatus bbUpdateInputs();
387 //==================================================================
390 //==================================================================
391 /// Actual CreateWindow method (vitual)
392 /// Overloaded in AtomicBlacBox and descendants
393 virtual void bbCreateWindow()
395 // bbtkError("BlackBox::bbCreateWidget called : how can this happen ?");
397 //==================================================================
399 //==================================================================
400 /// Actual ShowWindow method (vitual)
401 /// Overloaded in AtomicBlacBox and descendants
402 virtual void bbShowWindow()
404 // bbtkError("BlackBox::bbShowWidget called : how can this happen ?");
406 //==================================================================
409 //==================================================================
410 /// Actual processing method (vitual)
411 /// Overloaded in AtomicBlacBox and descendants
412 virtual void bbProcess()
414 bbtkError("BlackBox::bbProcess called : how can this happen ?");
415 // this->bbUserProcess();
417 //==================================================================
419 //==================================================================
420 /// Computes the final IOStatus of inputs and outputs after processing
421 void bbComputePostProcessStatus();
422 //==================================================================
425 //==================================================================
426 /// Specific methods for window creation during pipeline execution
427 /// Creates the window associated to the box (called after bbUpdateInputs)
428 /// Does nothing here. Overloaded in WxBlackBox.
429 // virtual void bbCreateWindow() { }
430 /// Shows the window associated to the box
431 /// (called after bbProcess during bbExecute)
432 /// Does nothing here but overloaded in WxBlackBox and WxContainerBlackBox
433 // virtual void bbShowWindow(Connection::Pointer caller) { }
434 // virtual void bbHideWindow() {}
435 // virtual void bbCloseWindow() { }
436 //==================================================================
441 static bool bbGlobalGetSomeBoxExecuting();
442 static void bbGlobalSetSomeBoxExecuting(bool b);
444 static void bbGlobalSetFreezeExecution(bool b);
445 static bool bbGlobalGetFreezeExecution();
447 /// Returns true if the box can "react",
448 /// which means execute in response to an input change
449 virtual bool bbCanReact() const;
451 /// Returns true iff the box is executing
452 bool bbGetExecuting() const { return bbmExecuting; }
455 static void bbGlobalAddToExecutionList( BlackBox::Pointer b );
456 static void bbGlobalProcessExecutionList();
457 /// Sets the bbmExecuting bool returned by bbGetExecuting
458 void bbSetExecuting(bool b) { bbmExecuting = b; }
460 //==================================================================
462 //==================================================================
463 /// Allocates the i/o connectors of the black box
464 virtual void bbAllocateConnectors();
465 /// Desallocates the i/o connectors of the black box
466 virtual void bbDesallocateConnectors();
467 /// Copies the values of the inputs/output from the BlackBox from
468 virtual void bbCopyIOValues(BlackBox& from);
469 //==================================================================
471 //==================================================================
472 // Black box objects have a special deleter
473 // which must take care of releasing the descriptor
474 // **AFTER** the box is deleted
475 // (Releasing it in the destructor may cause dl close and crash)
476 /// Black box deleter
477 /// 1) Calls the user overloadable bbDelete method
478 /// 2) Releases the box descriptor
479 struct BBTK_EXPORT Deleter : public Object::Deleter
482 int Delete(Object* p);
484 //==================================================================
486 //==================================================================
488 static boost::shared_ptr<U> MakeBlackBoxPointer(U* s, bool lock = false)
490 return MakePointer(s,BlackBox::Deleter(),lock);
492 //==================================================================
494 //==================================================================
495 virtual int bbDelete() { delete this; return 0; }
496 //==================================================================
499 //==================================================================
501 //==================================================================
503 //==================================================================
505 /// Is the box "constructed" ? (initialized)
507 /// Is the box executing ?
509 /// The name of the black-box
511 /// The name of the package to which it belongs
512 std::string bbmPackageName;
513 /// The box processing mode
514 /// 0 : "Pipeline" mode
515 /// 1 : "Always" mode
516 /// 2 : "Reactive" mode
517 std::string bbmBoxProcessMode;
518 /// The parent of the black box in the ComplexBlackBox hierarchy
519 BlackBox::WeakPointer bbmParent;
520 //==================================================================
523 //==================================================================
525 /// Map that contains the output connectors of the black box
526 OutputConnectorMapType mOutputConnectorMap;
527 /// Map that contains the input connectors of the black box
528 InputConnectorMapType mInputConnectorMap;
529 //==================================================================
537 /// Convenient macro to create output observer callbacks (freehand functions) from object and method pointer (see samples/SampleOutputObserver)
538 #define BBTK_MAKE_OUTPUT_OBSERVER(OBJECT,METHOD) \
539 boost::bind( METHOD, OBJECT, _1, _2, _3)