]> Creatis software - bbtk.git/blob - kernel/src/bbtkExecuter.cxx
3c7b04cf704b7f803921ee9dcfc8be9e693718b0
[bbtk.git] / kernel / src / bbtkExecuter.cxx
1 /*=========================================================================
2          
3   Program:   bbtk
4   Module:    $RCSfile: bbtkExecuter.cxx,v $ $
5   Language:  C++
6   Date:      $Date: 2008/04/08 06:59:30 $
7   Version:   $Revision: 1.16 $
8
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/bbtk/License.html for details.
12
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16
17 =========================================================================*/
18 /**
19  *  \file 
20  *  \brief class Executer: level 0 of script execution (code)
21  */
22
23 #include "bbtkExecuter.h"
24 #include "bbtkMessageManager.h"
25 #include "bbtkFactory.h"
26 #include "bbtkUtilities.h"
27 #include <fstream>
28
29 #ifdef _USE_WXWIDGETS_
30 #include <wx/textdlg.h>
31 #endif
32
33 #include "bbtkWxBlackBox.h"
34
35 #include "bbtkConfigurationFile.h"
36
37 namespace bbtk
38 {
39   //=======================================================================
40   Executer::Executer()
41     : 
42     mFactory(0),
43     mRootPackage(0),
44     mRootCBB(0),
45     mNoExecMode(false),
46     mDialogMode(NoDialog)
47   {
48     bbtkDebugMessageInc("Kernel",9,"Executer::Executer()" <<std::endl);
49     mFactory = new Factory;
50     mFactory->SetExecuter(this);
51     Reset();
52     bbtkDebugDecTab("Kernel",9);
53   }
54   //=======================================================================
55
56   //=======================================================================
57   Executer::~Executer()
58   {
59      bbtkDebugMessageInc("Kernel",9,"Executer::~Executer()" <<std::endl);
60      if (mRootCBB) 
61      {
62         mRootPackage->UnRegisterBlackBox("workspace");
63         delete mRootCBB;
64      }
65      if (mRootPackage)
66      {
67         GetFactory()->UnLoadPackage("user");
68      }
69      delete mFactory;
70
71      bbtkDebugDecTab("Kernel",9);
72   }
73   //=======================================================================
74
75   //=======================================================================
76    /// Loads a package
77     void Executer::LoadPackage(const std::string &name )
78    {
79      GetFactory()->LoadPackage(name);
80    }
81   //=======================================================================
82
83   //=======================================================================
84     /// Unloads a package
85     void Executer::UnLoadPackage(const std::string &name )
86     {
87       GetFactory()->UnLoadPackage(name);
88     }
89   //=======================================================================
90
91   //=======================================================================
92   void Executer::Reset()
93   {
94     bbtkDebugMessageInc("Kernel",9,"Executer::Reset()" <<std::endl);
95
96     // The 'user' package must be closed before all other 
97     // because box destructors must not be unloaded when bb are deleted!
98     // Similarly, the 'workspace' CBB must be destroyed before 
99     // all user defined CBB otherwise any instance 
100     // of a user CBB that is in the 'workspace' would try to 
101     // access a user CBB descriptor which has been previously freed
102     if (mRootCBB)
103     {
104        mRootPackage->UnRegisterBlackBox(mRootCBB->GetTypeName());
105        delete mRootCBB;
106     }
107     if (mRootPackage)
108     {
109        GetFactory()->UnLoadPackage("user");
110     }
111     GetFactory()->Reset();
112
113     // Create user package
114     mRootPackage = new Package("user","internal to bbi",
115                            "User defined black boxes",
116                            "",
117                            BBTK_STRINGIFY_SYMBOL(BBTK_VERSION));
118     // Create user workspace
119     mRootCBB = new ComplexBlackBoxDescriptor("workspace"); //,f);
120     mRootCBB->SetFactory(GetFactory());
121     mRootCBB->AddToAuthor("bbi (internal)");
122     mRootCBB->AddToDescription("User's workspace");
123     mOpenDefinition.push_back(CBBDefinition(mRootCBB,"user"));
124     // Register it into the user package
125     mRootPackage->RegisterBlackBox(mRootCBB);
126     // Insert the user package in the factory
127     GetFactory()->InsertPackage(mRootPackage);
128     // And in the list of open packages
129     mOpenPackage.push_back(mRootPackage);
130
131     bbtkDebugDecTab("Kernel",9);
132   }
133   //=======================================================================
134
135   //=======================================================================
136   /// changes the workspace name
137   void Executer::SetWorkspaceName( const std::string& n )
138   {
139     mRootPackage->ChangeBlackBoxName( mRootCBB->GetTypeName(), n );
140   }
141   //=======================================================================
142
143   //=======================================================================
144   void Executer::BeginPackage (const std::string &name)
145   {
146      bbtkDebugMessageInc("Kernel",9,"Executer::BeginPackage(\""<<name<<"\")"
147                         <<std::endl);
148      Package* p;
149      try 
150       {
151          p = GetFactory()->GetPackage(name);
152       }
153     catch (Exception e)
154       {
155          p = new Package(name,
156                          "",
157                          "",
158                          "",
159                          BBTK_STRINGIFY_SYMBOL(BBTK_VERSION));
160          GetFactory()->InsertPackage(p);
161       }
162      mOpenPackage.push_back(p);
163   }
164   //=======================================================================
165
166   //=======================================================================
167   void Executer::EndPackage()
168   {
169     if (mOpenPackage.size()>1) mOpenPackage.pop_back();
170   }
171   //=======================================================================
172
173   //=======================================================================
174   void Executer::Define (const std::string &name,
175                          const std::string &pack,
176                          const std::string &scriptfilename)
177   {
178     bbtkDebugMessageInc("Kernel",9,"Executer::Define(\""<<name<<
179                         ","<<pack<<"\")"
180                         <<std::endl);
181
182     ComplexBlackBoxDescriptor* b = new ComplexBlackBoxDescriptor(name);
183     b->SetFactory(GetFactory());
184     b->SetScriptFileName(scriptfilename);
185     mOpenDefinition.push_back( CBBDefinition( b, pack ) );
186     
187     bbtkDebugDecTab("Kernel",9);
188   }
189   //=======================================================================
190
191   //=======================================================================
192   /// Sets the file name to use for the current definition
193   /// (Used to set it after the Define command)
194   void Executer::SetCurrentFileName (const std::string &name )
195   {
196     mOpenDefinition.back().box->SetScriptFileName(name);
197   }
198   //=======================================================================
199
200   //=======================================================================
201   void Executer::EndDefine ()
202   {
203     bbtkDebugMessageInc("Kernel",9,"Executer::EndDefine(\""
204                         <<Current()->GetTypeName()<<"\")" 
205                         <<std::endl);
206     // Does current package exist ?
207     Package* p;
208     std::string pname(mOpenDefinition.back().package);
209     if (pname.size()>0)
210       {
211         try
212           {
213             p = GetFactory()->GetPackage(pname);
214           }
215         catch (Exception e)
216           {
217             p = new Package(pname,
218                             "",
219                             "",
220                             "",
221                             BBTK_STRINGIFY_SYMBOL(BBTK_VERSION));
222             GetFactory()->InsertPackage(p);
223           }
224       }
225     else
226       {
227         p = mOpenPackage.back();
228       }
229     p->RegisterBlackBox(Current());
230     
231     mOpenDefinition.pop_back();
232   }
233   //======================================================================= 
234
235   //=======================================================================  
236   void Executer::Kind(const std::string& kind)
237   {
238     if (kind=="ADAPTOR")
239       {
240         Current()->AddToCategory("adaptor");
241         Current()->SetKind(bbtk::BlackBoxDescriptor::ADAPTOR);
242       }
243     else if (kind=="DEFAULT_ADAPTOR")
244       {
245         Current()->AddToCategory("adaptor");
246         Current()->SetKind(bbtk::BlackBoxDescriptor::DEFAULT_ADAPTOR);
247       }
248     if (kind=="WIDGET_ADAPTOR")
249       {
250         Current()->AddToCategory("adaptor");
251         Current()->SetKind(bbtk::BlackBoxDescriptor::WIDGET_ADAPTOR);
252       }
253     else if (kind=="DEFAULT_WIDGET_ADAPTOR")
254       {
255         Current()->AddToCategory("adaptor");
256         Current()->SetKind(bbtk::BlackBoxDescriptor::DEFAULT_WIDGET_ADAPTOR);
257       }
258     else
259       {
260         bbtkError("Unknown box kind : '"<<kind<<"'. "
261                   <<"Valid kinds are 'ADAPTOR','DEFAULT_ADAPTOR',"
262                   <<"'WIDGET_ADAPTOR','DEFAULT_WIDGET_ADAPTOR'");
263       }
264   }
265   //=======================================================================
266
267   //=======================================================================
268   void Executer::Create ( const std::string& nodeType, 
269                           const std::string& nodeName)
270   {
271      Current()->Add(nodeType,nodeName);
272   }
273   //=======================================================================
274
275   //=======================================================================
276   void Executer::Destroy(const std::string &boxName)
277   {
278     bbtkError("Executer::Destroy : NOT IMPLEMENTED !");
279   }
280   //=======================================================================
281
282   //=======================================================================
283   void Executer::Connect (const std::string &nodeFrom,
284                           const std::string &outputLabel,
285                           const std::string &nodeTo, 
286                           const std::string &inputLabel)
287   {
288     Current()->Connect(nodeFrom, outputLabel, nodeTo, inputLabel);
289   }
290   //=======================================================================
291
292   //=======================================================================
293   void Executer::Execute (const std::string &nodeName) 
294   {
295     // if in root
296      if (Current()==mRootCBB) 
297      {
298         if (!mNoExecMode) 
299         {
300            Current()->GetPrototype()->bbGetBlackBox(nodeName)->bbExecute(true);
301         }
302      }
303      else 
304      {
305         Current()->AddToExecutionList(nodeName) ;
306      }
307   }
308   //=======================================================================
309
310   //=======================================================================
311   void Executer::DefineInput ( const std::string &name,
312                                const std::string &box,
313                                const std::string &input,
314                                const std::string& help)
315   {
316     // If the input is defined in the Root box
317     if (Current()==mRootCBB) 
318       {
319       // If the dialog mode is set to NoDialog
320       // and the user passed the name in the Inputs map 
321       // then the associated value is set to the box.input
322       // This is the way command line parameters are passed to the Root box
323          if (mDialogMode == NoDialog) 
324          {
325          // find if name is in mInputs
326             std::map<std::string,std::string>::iterator i;
327             i = mInputs.find(name);
328             if (i!=mInputs.end()) {
329                Set(box,input,(*i).second);
330             }
331          }
332         // If the dialog mode is set to TextDialog
333         // The user is prompted for the value
334         else if (mDialogMode == TextDialog) 
335         {
336            std::cout << name << "=";
337            std::string ans;
338            std::cin >> ans;
339            Set(box,input,ans);
340         }
341 #ifdef _USE_WXWIDGETS_
342        // If the dialog mode is set to GraphicalDialog
343        // A dialog box is pop up
344        else if (mDialogMode == GraphicalDialog) 
345        {
346           std::string mess("Enter the value of '");
347           mess += name;
348           mess += "' (";
349           mess += help;
350           mess += ")";
351           std::string title(name);
352           title += " ?";
353           std::string ans = wx2std ( wxGetTextFromUser( std2wx (mess), std2wx(title)));
354           Set(box,input,ans); 
355        }
356 #endif
357     }
358
359     Current()->DefineInput(name,box,input,help);
360
361   }
362   //=======================================================================
363
364   //=======================================================================
365    void Executer::DefineOutput ( const std::string &name,
366                                  const std::string &box,
367                                  const std::string &output,
368                                  const std::string& help)
369   {
370     Current()->DefineOutput(name,box,output,help);
371   }
372   //=======================================================================
373
374   //=======================================================================
375   void Executer::Set (const std::string &box,
376                       const std::string &input,
377                       const std::string &value)
378   {
379     BlackBox* b = Current()->GetPrototype()->bbGetBlackBox(box);
380     // Looks for the adaptor
381
382     if ( b->bbGetInputType(input) !=  typeid(std::string) ) 
383       {
384          BlackBox* a =
385            GetFactory()->NewAdaptor(typeid(std::string),
386                                     b->bbGetInputType(input),
387                                     "tmp");
388          if (!a) 
389            {
390              bbtkError("No <"<<
391                        TypeName(b->bbGetInputType(input))
392                        <<"> to <std::string> found");
393            }
394          std::string v(value);
395          a->bbSetInput("In",v);
396          a->bbExecute();
397          b->bbSetInput(input,a->bbGetOutput("Out"));
398          a->bbDelete();
399       }
400     else 
401       {
402       std::string v(value);
403       b->bbSetInput(input,v);
404       }
405   }
406   //=======================================================================
407
408   //=======================================================================
409   std::string Executer::Get(const std::string &box,
410                             const std::string &output)
411   {
412     BlackBox* b = Current()->GetPrototype()->bbGetBlackBox(box);
413     // Looks for the adaptor
414     if (b->bbGetOutputType(output) != typeid(std::string)) 
415       {
416         BlackBox* a =
417           GetFactory()->NewAdaptor(
418                                    b->bbGetOutputType(output),
419                                    typeid(std::string),
420                                    "tmp");
421         if (!a) 
422           {
423             bbtkError("No <"<<
424                       TypeName(b->bbGetOutputType(output))
425                       <<"> to <std::string> found");
426           }
427         b->bbExecute();
428         
429         a->bbSetInput("In",b->bbGetOutput(output));
430         a->bbExecute();
431         std::string r = a->bbGetOutput("Out").unsafe_get<std::string>();
432         //std::string v = *((std::string*)a->bbGetOutput("Out")) ;
433         //   std::cout << a->bbGetOutput("Out").unsafe_get<std::string>() 
434         //             << std::endl;
435         //std::string v(value);
436         //b->bbSetInput(input,a->bbGetOutput("Out"));
437         a->bbDelete();
438         return r;
439       }
440     else
441       {
442         b->bbExecute();
443         return b->bbGetOutput(output).unsafe_get<std::string>();
444         // std::string v = *((std::string*)b->bbGetOutput(output)) ;
445         // std::cout << b->bbGetOutput("Out").unsafe_get<std::string>() 
446         //   << std::endl;
447         // b->bbSetInput(input,&v);
448       }
449   }
450   //=======================================================================
451
452   //=======================================================================
453   void Executer::Author(const std::string &authorName)
454   {
455     Current()->AddToAuthor(authorName,Current()==mRootCBB);
456   }
457   //=======================================================================
458
459   //=======================================================================
460   void Executer::Category(const std::string &category)
461   {
462     Current()->AddToCategory(category,Current()==mRootCBB);
463   }
464   //=======================================================================
465
466   //=======================================================================
467   void Executer::Description(const std::string &d)
468   {
469     Current()->AddToDescription(d,Current()==mRootCBB);
470   }
471   //=======================================================================
472
473   //=======================================================================
474   /// prints the list of the boxes of the current descriptor
475   void Executer::PrintBoxes()
476   {
477     bbtkMessageInc("Help",1,"The black box descriptor \""
478                    <<Current()->GetTypeName()<<"\" contains : "<<std::endl);
479     Current()->PrintBlackBoxes();
480     bbtkDecTab("Help",1);
481  }
482   //=======================================================================
483
484   //=======================================================================
485   std::string Executer::ShowGraph(const std::string &nameblackbox, 
486                                   const std::string &detailStr, 
487                                   const std::string &levelStr,
488                                   const std::string &output_html,
489                                   const std::string &custom_header,
490                                   const std::string &custom_title,
491                                   bool system_display )
492   {
493     int detail  =       atoi(detailStr.c_str());
494     int level   =       atoi(levelStr.c_str());
495
496     std::string filename_rootHtml (output_html) ;
497     std::string simplefilename_rootHtml ( Utilities::get_file_name(output_html));
498
499     bool relative_link = true;
500
501     // No output provided : automatic generation
502     if (output_html.length() == 0)
503       {
504         // Don't pollute the file store with  "temp_dir" directories ...    
505         std::string default_doc_dir = ConfigurationFile::GetInstance().Get_default_temp_dir();
506         
507         char c = default_doc_dir.c_str()[strlen(default_doc_dir.c_str())-1];
508         
509         std::string directory = default_doc_dir; 
510         if (c != '/' && c !='\\') directory = directory + "/";
511         directory = directory +  "temp_dir";    
512         
513         filename_rootHtml = directory + "/" + "User.html";
514         simplefilename_rootHtml = "User.html" ;
515
516         // Creating directory
517         std::string command0("mkdir \"" +directory + "\"");
518         system( command0.c_str() );
519
520         relative_link = false;
521       }
522
523     Package* p;
524     try
525     {
526        p = GetFactory()->GetPackage(nameblackbox);
527     }
528     catch (Exception e)
529     {
530        p = mRootPackage;
531     }
532     // Generating documentation-help of workspace
533     p->SetDocURL(filename_rootHtml);
534     p->SetDocRelativeURL(simplefilename_rootHtml);
535
536     p->CreateHtmlPage(filename_rootHtml,"bbi","user package",custom_header,custom_title,detail,level,relative_link);
537
538     std::string page = filename_rootHtml;
539     /*
540     try 
541     {
542        ShowGraphTypes(nameblackbox);
543     }
544     catch (bbtk::Exception a)
545     {
546        std::cout <<"EXC"<<std::endl;
547        page = ShowGraphInstances(nameblackbox,detail,level,system_display);
548     }
549     */
550     return page;
551   }
552   //=======================================================================
553
554   //=======================================================================
555   /// Generate a png file with the actual pipeline (Graphviz-dot needed)
556   std::string Executer::ShowGraphInstances(const std::string &nameblackbox, int detail, int level,
557                                            bool system_display)
558   {
559
560     BlackBox* blackbox=NULL;
561     if (nameblackbox==".")
562     {
563        blackbox=Current()->GetPrototype();
564     }
565     else
566     {
567        blackbox = Current()->GetPrototype()->bbFindBlackBox(nameblackbox);
568     }
569     
570     std::string page;
571
572     if (blackbox)
573       {      
574         // Don't pollute the file store with  "temp_dir" directories ...
575         std::string default_doc_dir = ConfigurationFile::GetInstance().Get_default_temp_dir();
576         char c = default_doc_dir.c_str()[strlen(default_doc_dir.c_str())-1];
577
578         std::string directory = default_doc_dir; 
579         if (c != '/' && c !='\\') directory = directory + "/";
580
581         directory = directory +  "temp_dir";
582         //std::string directory("temp_dir");
583         std::string filename(directory + "/" + "bbtk_graph_pipeline");
584         std::string filename_html(filename+".html");
585         std::string command0("mkdir \""+directory + "\"");
586
587 #if defined(_WIN32)
588         std::string command2("start ");
589 #else 
590         std::string command2("gnome-open ");
591 #endif
592
593         command2=command2+filename_html;
594         page = filename_html;
595         // 1. Generate Html Diagram
596         std::ofstream s;
597         s.open(filename_html.c_str());
598         if (s.good()) 
599           {
600             s << "<html><head><title>BBtk graph diagram</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"></head>\n";
601             s << "<body bgcolor=\"#FFFFFF\" text=\"#000000\"> \n\n";
602             if ( blackbox->bbGetName()=="workspacePrototype" )
603               {
604                 s << "<center>Current workspace</center>";
605               } else {
606               s << "<center>" << blackbox->bbGetName()<< "</center>";
607             } 
608
609             blackbox->bbInsertHTMLGraph( s, detail, level, true, directory, false );
610             s << "</body></html>\n";
611           }
612         s.close();
613         
614         // 2. Starting Browser
615         if (system_display) system( command2.c_str() );      
616       } 
617     else 
618       {
619         bbtkMessageInc("Help",1,"No black box: \""
620                        <<nameblackbox<<"\" " <<std::endl);
621       }
622     return page;
623   }
624   //=======================================================================
625
626   //=======================================================================
627   void Executer::ShowRelations(const std::string &nameblackbox, 
628                                const std::string &detailStr, 
629                                const std::string &levelStr)
630   {
631     bool found=false;
632     
633     int detail = atoi(detailStr.c_str());
634     int level  = atoi(levelStr.c_str());
635     BlackBox* blackbox=NULL;
636     if (nameblackbox.compare(".")==0)
637       {
638         blackbox=Current()->GetPrototype();
639       } 
640     else 
641       {
642         blackbox = Current()->GetPrototype()->bbFindBlackBox(nameblackbox);
643       }
644     
645     if (blackbox)
646       {
647         found=true;
648         blackbox->bbShowRelations(blackbox,detail,level); //,mFactory);
649       }
650     
651     if (!found) 
652       {
653         bbtkError("Blackbox Name not found.. <"  <<nameblackbox<<">");
654       }
655   }
656   //=======================================================================
657
658   //=======================================================================
659   /// sets the level of message
660   void Executer::SetMessageLevel(const std::string &kind,
661                                  int level)
662   {
663     bbtk::MessageManager::SetMessageLevel(kind,level);
664   }
665   //=======================================================================
666
667   //=======================================================================
668   /// Prints help on the messages
669   void  Executer::HelpMessages()
670   {
671     bbtk::MessageManager::PrintInfo();
672   }
673   //=======================================================================
674
675   //=======================================================================
676   ///
677   void Executer::Print(const std::string &str)
678   {  
679     if (GetNoExecMode() &&  (Current()==mRootCBB) ) return;
680     if (Current()!=mRootCBB) return;
681
682     bbtkDebugMessageInc("Interpreter",9,"Interpreter::Print(\""<<str<<"\")"<<std::endl);
683
684  // TO DO :
685  // InterpretLine ("load std")
686  // InterpretLine("new ConcatStrings _C_ ") -> trouver un nom unique : # commande 
687  // InterpretLine("new Print _P_") 
688  // InterpretLine("connect _C_.Out _P_.In")
689  // int num = 1
690  
691
692     std::vector<std::string> chains;
693     std::string delimiters("$");
694
695     // Skip delimiters at beginning.
696     std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
697     bool is_text = true;
698     if (lastPos>0) is_text = false;
699
700     // Find first delimiter.
701     std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
702
703     while (std::string::npos != pos || std::string::npos != lastPos)
704     {
705        if (is_text) 
706        {
707           // Found a text token, add it to the vector.
708           chains.push_back(str.substr(lastPos, pos - lastPos));
709  // std::string token = str.substr(lastPos, pos - lastPos)
710  // InterpretLine("set _C_.In%num% %token%")
711  
712        }
713        else 
714        {
715
716        // is an output (between $$) : decode 
717          std::string tok,box,output;
718          tok = str.substr(lastPos, pos - lastPos);
719          Utilities::SplitAroundFirstDot(tok,box,output);
720          chains.push_back( Get(box,output) );
721
722 // InterpretLine("connect %tok% _C_.In%num%") 
723
724        }
725         // Skip delimiters.  Note the "not_of"
726        lastPos = str.find_first_not_of(delimiters, pos);
727         // Find next delimiter
728        pos = str.find_first_of(delimiters, lastPos);
729     //
730        is_text = !is_text;
731 // num ++;
732      }
733 // InterpretLine("exec _P_")
734 // if (IS_IN_WORKSPACE) InterpretLine("delete _C_; delete _P_");
735
736     std::vector<std::string>::iterator i;
737     for (i= chains.begin(); i!=chains.end(); ++i) 
738       {
739         //  bbtkMessage("Echo",1,*i);
740         Utilities::SubsBackslashN(*i);
741         bbtkMessage("Output",1,*i);
742       }
743     bbtkMessage("Output",1,std::endl);
744   }
745
746 }//namespace