]> Creatis software - crea.git/blob - lib/creaDevManagerLib/modelCDMAppli.cpp
Feature #1711 CreaDevManager application implementation
[crea.git] / lib / creaDevManagerLib / modelCDMAppli.cpp
1 /*
2 # ---------------------------------------------------------------------
3 #
4 # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image
5 #                        pour la Sant�)
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
9 #
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.
16 #
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
21 #  liability.
22 #
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 # ------------------------------------------------------------------------
26  */
27
28 /*
29  * modelCDMAppli.cpp
30  *
31  *  Created on: Nov 23, 2012
32  *      Author: Daniel Felipe Gonzalez Obando
33  */
34
35 #include "modelCDMAppli.h"
36
37 #include <iostream>
38 #include <fstream>
39 #include <sstream>
40 #include <algorithm>
41
42 #include "CDMUtilities.h"
43 #include "creaWx.h"
44 #include "wx/dir.h"
45
46 modelCDMAppli::modelCDMAppli()
47 {
48 }
49
50 modelCDMAppli::modelCDMAppli(modelCDMIProjectTreeNode* parent, const std::string& path, const std::string& name, const int& level)
51 {
52   std::cout << "creating appli\n";
53   this->parent = parent;
54   this->type = wxDIR_DIRS;
55   this->name = name;
56   this->level = level;
57   this->path = path;
58
59
60
61   this->path = CDMUtilities::fixPath(path);
62   std::string pathFixed(CDMUtilities::fixPath(path));
63
64   this->applications.clear();
65   wxDir dir(crea::std2wx((pathFixed).c_str()));
66   if (dir.IsOpened())
67     {
68       wxString fileName;
69       bool cont = dir.GetFirst(&fileName, wxEmptyString, wxDIR_DIRS);
70       while (cont)
71         {
72           std::string stdfileName = crea::wx2std(fileName);
73
74           if(stdfileName != "template_appli" && stdfileName != "template_wx_appli")
75             {
76               modelCDMApplication* application = new modelCDMApplication(this, pathFixed + CDMUtilities::SLASH + stdfileName, stdfileName, this->level + 1);
77               this->applications.push_back(application);
78               this->children.push_back(application);
79             }
80           else
81             {
82               modelCDMFolder* folder = new modelCDMFolder(this, pathFixed + CDMUtilities::SLASH + stdfileName, stdfileName, this->level + 1);
83               this->children.push_back(folder);
84             }
85
86           cont = dir.GetNext(&fileName);
87         }
88       //files
89       cont = dir.GetFirst(&fileName, wxEmptyString, wxDIR_FILES);
90       while (cont)
91         {
92           std::string stdfileName = crea::wx2std(fileName);
93           std::size_t fileTypePos = stdfileName.find_last_of(".");
94           std::string fileType;
95           if(fileTypePos != std::string::npos)
96             fileType = stdfileName.substr(fileTypePos);
97           else
98             fileType = "";
99
100           //if CMakeLists, create CMakeLists
101           if(stdfileName == "CMakeLists.txt")
102             {
103               this->CMakeLists = new modelCDMCMakeListsFile(this, pathFixed + CDMUtilities::SLASH + stdfileName, stdfileName, this->level + 1);
104               this->children.push_back(this->CMakeLists);
105             }
106           //if is a code file, create modelCDMCodeFile
107           else if(
108               fileType == ".c" ||
109               fileType == ".cxx" ||
110               fileType == ".h" ||
111               fileType == ".cpp" ||
112               fileType == ".txx" ||
113               fileType == ".cmake" )
114             {
115               this->children.push_back(new modelCDMCodeFile(this, pathFixed + CDMUtilities::SLASH + stdfileName, stdfileName, this->level + 1));
116             }
117           //if is an unknown file, create file
118           else
119             {
120               this->children.push_back(new modelCDMFile(this, pathFixed + CDMUtilities::SLASH + stdfileName, stdfileName, this->level + 1));
121             }
122
123           cont = dir.GetNext(&fileName);
124         }
125
126     }
127   this->SortChildren();
128   std::sort(this->applications.begin(), this->applications.end(), CompareNodeItem);
129 }
130
131 modelCDMAppli::~modelCDMAppli()
132 {
133 }
134
135 const std::vector<modelCDMApplication*>& modelCDMAppli::GetApplications() const
136 {
137   return this->applications;
138 }
139
140 modelCDMApplication* modelCDMAppli::CreateApplication(
141     const std::string& namein,
142     const int& type,
143     std::string*& result
144 )
145 {
146   std::vector<std::string> words;
147   CDMUtilities::splitter::split(words,namein," '/\\*\"%",CDMUtilities::splitter::no_empties);
148   std::string name;
149   for (int i = 0; i < (int)(words.size()); i++)
150     {
151       name += words[i];
152     }
153   if (name == "")
154     {
155       result = new std::string("The given name is not valid:  '/\\*\"% are forbidden.");
156       return NULL;
157     }
158
159   if (type == 0)
160     {
161       //copy template application folder with new name
162 #ifdef _WIN32
163       std::string copyCommand = "xcopy \"" + this->path + CDMUtilities::SLASH + "template_appli\" \"" + this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "\" /Y";
164 #else
165       std::string copyCommand = "cp -r \"" + this->path + CDMUtilities::SLASH + "template_appli\" \"" + this->path + CDMUtilities::SLASH + name + "\"";
166 #endif
167
168       if(system(copyCommand.c_str()))
169         {
170           result = new std::string("An error occurred while running '" + copyCommand + "'.");
171           return NULL;
172         }
173       //set name of library in CMakeLists inside copied folder
174       std::string line;
175       std::ifstream in((this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt").c_str());
176       if( !in.is_open())
177         {
178           result = new std::string("CMakeLists.txt file failed to open.");
179           return NULL;
180         }
181       std::ofstream out((this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt.tmp").c_str());
182       while (getline(in, line))
183         {
184           if(line == "SET ( EXE_NAME   MyExe  )")
185             line = "SET ( EXE_NAME   " + name + "  )";
186           out << line << std::endl;
187         }
188       in.close();
189       out.close();
190       //delete old file and rename new file
191 #ifdef _WIN32
192       std::string renameCommand = "move /Y \"" + this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt.tmp\" \"" + this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt\"";
193 #else
194       std::string renameCommand = "mv \"" + this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt.tmp\" \"" + this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt\"";
195 #endif
196
197       if(system(renameCommand.c_str()))
198         {
199           result = new std::string("An error occurred while running '" + renameCommand + "'.");
200           return NULL;
201         }
202
203       //add application to appli CMakeLists
204       std::fstream out1((this->path + CDMUtilities::SLASH + "CMakeLists.txt").c_str(), std::fstream::in | std::fstream::out | std::fstream::app);
205       if (out1.is_open())
206         {
207           out1 << "ADD_SUBDIRECTORY(" << name << ")" << std::endl;
208           out1.close();
209         }
210
211       //add application to model
212       modelCDMApplication* application = new modelCDMApplication(this, this->path + CDMUtilities::SLASH + name, name, this->level + 1);
213       this->applications.push_back(application);
214       this->children.push_back(application);
215
216       this->SortChildren();
217
218       result = new std::string(this->path + CDMUtilities::SLASH + name);
219       return application;
220     }
221   else if(type == 1)
222     {
223       //copy template application folder with new name
224 #ifdef _WIN32
225       std::string copyCommand = "xcopy \"" + this->path + CDMUtilities::SLASH + "template_wx_appli\" \"" + this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "\" /Y";
226 #else
227       std::string copyCommand = "cp -r \"" + this->path + CDMUtilities::SLASH + "template_wx_appli\" \"" + this->path + CDMUtilities::SLASH + name + "\"";
228 #endif
229
230       if(system(copyCommand.c_str()))
231         {
232           result = new std::string("An error occurred while running '" + copyCommand + "'.");
233           return NULL;
234         }
235       //set name of library in CMakeLists inside copied folder
236       std::string line;
237       std::ifstream in((this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt").c_str());
238       if( !in.is_open())
239         {
240           result = new std::string("CMakeLists.txt file failed to open.");
241           return NULL;
242         }
243       std::ofstream out((this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt.tmp").c_str());
244       while (getline(in, line))
245         {
246           if(line == "SET ( EXE_NAME   MyExeWx  )")
247             line = "SET ( EXE_NAME   " + name + "  )";
248           out << line << std::endl;
249         }
250       in.close();
251       out.close();
252       //delete old file and rename new file
253 #ifdef _WIN32
254       std::string renameCommand = "move /Y \"" + this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt.tmp\" \"" + this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt\"";
255 #else
256       std::string renameCommand = "mv \"" + this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt.tmp\" \"" + this->path + CDMUtilities::SLASH + name + CDMUtilities::SLASH + "CMakeLists.txt\"";
257 #endif
258
259       if(system(renameCommand.c_str()))
260         {
261           result = new std::string("An error occurred while running '" + renameCommand + "'.");
262           return NULL;
263         }
264
265       //add application to appli CMakeLists
266       std::fstream out1((this->path + CDMUtilities::SLASH + "CMakeLists.txt").c_str(), std::fstream::in | std::fstream::out | std::fstream::app);
267       if (out1.is_open())
268         {
269           out1 << "ADD_SUBDIRECTORY(" << name << ")" << std::endl;
270           out1.close();
271         }
272
273       //add application to model
274       modelCDMApplication* application = new modelCDMApplication(this, this->path + CDMUtilities::SLASH + name, name, this->level + 1);
275       this->applications.push_back(application);
276       this->children.push_back(application);
277
278       this->SortChildren();
279
280       result = new std::string(this->path + CDMUtilities::SLASH + name);
281       return application;
282     }
283   else
284     {
285       std::string res = "Invalid application type: ";
286       res += type;
287       res += std::string(".\n0:Console application.\n1:GUI Application (wxWidgets).");
288       result = new std::string(res);
289
290       return NULL;
291     }
292 }
293
294 const bool modelCDMAppli::Refresh(std::string*& result)
295 {
296   std::cout << "refreshing appli" << std::endl;
297   this->type = wxDIR_DIRS;
298
299   std::vector<bool> checked(this->children.size(), false);
300   std::vector<bool> checkedApplications(this->applications.size(), false);
301
302   //check all folders
303   wxDir dir(crea::std2wx((this->path).c_str()));
304   if (dir.IsOpened())
305     {
306       wxString fileName;
307       bool cont = dir.GetFirst(&fileName, wxEmptyString, wxDIR_DIRS);
308       while (cont)
309         {
310           std::string stdfileName = crea::wx2std(fileName);
311
312           if(stdfileName != "template_appli" && stdfileName != "template_wx_appli")
313             {
314               std::string applicationName = stdfileName;
315               //check if application already exist
316               bool found = false;
317               for (int i = 0; !found && i < (int)(this->applications.size()); i++)
318                 {
319                   if (this->applications[i]->GetName() == applicationName)
320                     {
321                       found = true;
322                       int pos = std::find(this->children.begin(), this->children.end(), this->applications[i]) - this->children.begin();
323                       checked[pos] = true;
324                       checkedApplications[i] = true;
325                       if(!this->applications[i]->Refresh(result))
326                         return false;
327                     }
328                 }
329               if(!found)
330                 {
331                   modelCDMApplication* application= new modelCDMApplication(this, this->path + CDMUtilities::SLASH + stdfileName, stdfileName, this->level + 1);
332                   this->applications.push_back(application);
333                   this->children.push_back(application);
334                 }
335             }
336           else
337             {
338               //check if folder already exist
339               bool found = false;
340               for (int i = 0; !found && i < (int)(this->children.size()); i++)
341                 {
342                   if (this->children[i]->GetName() == stdfileName)
343                     {
344                       found = true;
345                       checked[i] = true;
346
347                       if(!this->children[i]->Refresh(result))
348                         return false;
349                     }
350                 }
351               if(!found)
352                 {
353                   modelCDMFolder* folder= new modelCDMFolder(this, this->path + CDMUtilities::SLASH + stdfileName, stdfileName, this->level + 1);
354                   this->children.push_back(folder);
355                 }
356             }
357           cont = dir.GetNext(&fileName);
358         }
359
360       cont = dir.GetFirst(&fileName, wxEmptyString, wxDIR_FILES);
361       while (cont)
362         {
363           std::string stdfileName = crea::wx2std(fileName);
364           std::size_t fileTypePos = stdfileName.find_last_of(".");
365           std::string fileType;
366           if(fileTypePos != std::string::npos)
367             fileType = stdfileName.substr(fileTypePos);
368           else
369             fileType = "";
370
371           //if CMakeLists, create CMakeLists
372           if(stdfileName == "CMakeLists.txt")
373             {
374               if (this->CMakeLists == NULL)
375                 {
376                   this->CMakeLists = new modelCDMCMakeListsFile(this, this->path + CDMUtilities::SLASH + stdfileName, stdfileName, this->level + 1);
377                   this->children.push_back(this->CMakeLists);
378                 }
379               else
380                 {
381                   int pos = std::find(this->children.begin(), this->children.end(), this->CMakeLists) - this->children.begin();
382                   checked[pos] = true;
383                   if(!this->CMakeLists->Refresh(result))
384                     return false;
385                 }
386             }
387           //if is a code file, create modelCDMCodeFile
388           //if is an unknown file, create file
389           else
390             {
391               bool found = false;
392               for (int i = 0; !found && i < (int)(this->children.size()); i++)
393                 {
394                   if (this->children[i]->GetName() == stdfileName)
395                     {
396                       found = true;
397                       checked[i] = true;
398                       if(!this->children[i]->Refresh(result))
399                         return false;
400                     }
401                 }
402
403               if(!found)
404                 {
405                   if(
406                     fileType == ".c" ||
407                     fileType == ".cxx" ||
408                     fileType == ".h" ||
409                     fileType == ".cpp" ||
410                     fileType == ".txx" ||
411                     fileType == ".cmake" )
412                     {
413                       this->children.push_back(new modelCDMCodeFile(this, this->path + CDMUtilities::SLASH + stdfileName, stdfileName, this->level + 1));
414                     }
415                   else
416                     {
417                       modelCDMFile* file = new modelCDMFile(this, this->path + CDMUtilities::SLASH + stdfileName, stdfileName, this->level + 1);
418                       this->children.push_back(file);
419                     }
420                 }
421             }
422
423           cont = dir.GetNext(&fileName);
424         }
425     }
426
427   for (int i = 0; i < (int)(checkedApplications.size()); i++)
428     {
429       if(!checkedApplications[i])
430         {
431           this->applications.erase(this->applications.begin()+i);
432           checkedApplications.erase(checkedApplications.begin()+i);
433           i--;
434         }
435     }
436   for (int i = 0; i < (int)(checked.size()); i++)
437     {
438       if(!checked[i])
439         {
440           delete this->children[i];
441           this->children.erase(this->children.begin()+i);
442           checked.erase(checked.begin()+i);
443           i--;
444         }
445     }
446   this->SortChildren();
447   std::sort(this->applications.begin(), this->applications.end(), CompareNodeItem);
448   return true;
449 }
450
451 void modelCDMAppli::CheckStructure(std::map<std::string, bool>& properties)
452 {
453   //check cmake exist
454   if(this->CMakeLists != NULL)
455     {
456       //set properties parameters based on model
457       for (int i = 0; i < (int)(this->applications.size()); i++)
458         properties["appli add " + this->applications[i]->GetName()] = false;
459
460       //open cmakelists
461       std::ifstream confFile;
462       confFile.open((this->CMakeLists->GetPath()).c_str());
463
464       //take everything that is not commented
465       std::string fileContent;
466
467       std::string word;
468       std::vector<std::string> words;
469       while(confFile.is_open() && !confFile.eof())
470         {
471           std::getline(confFile,word, '\n');
472           if(word[0] != '#')
473             {
474               CDMUtilities::splitter::split(words, word, "#", CDMUtilities::splitter::empties_ok);
475               if (words.size() > 0)
476                 {
477                   word = words[0];
478                   CDMUtilities::splitter::split(words, word, " ", CDMUtilities::splitter::empties_ok);
479                   for (int i = 0; i < (int)(words.size()); i++)
480                     {
481                       if(words[i].substr(0,2) == "//")
482                         break;
483                       fileContent += words[i] + " ";
484                     }
485                 }
486             }
487         }
488
489       //check every instruction
490       std::stringstream ss(fileContent);
491       while(!ss.eof())
492         {
493           std::getline(ss,word, '(');
494
495           //check instruction name
496           CDMUtilities::splitter::split(words, word, " ", CDMUtilities::splitter::no_empties);
497
498           //add instructions
499           if (words.size() > 0 && words[words.size()-1] == "ADD_SUBDIRECTORY")
500             {
501               std::getline(ss,word, ')');
502               //std::cout << word << std::endl;
503               CDMUtilities::splitter::split(words, word, " ", CDMUtilities::splitter::no_empties);
504
505               if (words.size() > 0)
506                 {
507                   {
508                     properties["appli add " + words[0]] = true;
509                   }
510                 }
511             }
512         }
513
514     }
515
516   //check libraries' structure
517   for (int i = 0; i < (int)(this->applications.size()); i++)
518     {
519       properties["application " + this->applications[i]->GetName()] = true;
520       this->applications[i]->CheckStructure(properties);
521     }
522 }
523
524 bool modelCDMAppli::IsApplicationIncluded(const std::string& application_name)
525 {
526   if (this->HasCMakeLists())
527       {
528         CDMUtilities::CMLFile cmlFile = CDMUtilities::readCMLFile(this->CMakeLists->GetPath().c_str());
529         for (int i = 0; i < cmlFile.size(); ++i)
530           {
531             if (cmlFile[i].first=="command" && cmlFile[i].second[0] == "ADD_SUBDIRECTORY")
532               {
533                 int pos = 1;
534                 while (pos < cmlFile[i].second.size())
535                   {
536                     if (!isspace(cmlFile[i].second[pos][0]) && cmlFile[i].second[pos][0] != '(' && cmlFile[i].second[pos][0] != '#')
537                       {
538                         if (application_name == cmlFile[i].second[pos])
539                           return true;
540                         break;
541                       }
542                     pos++;
543                   }
544               }
545           }
546       }
547     return false;
548 }
549
550 bool modelCDMAppli::SetApplicationInclude(const std::string& application_name, const bool& toInclude)
551 {
552   if (this->HasCMakeLists())
553     {
554       CDMUtilities::CMLFile cmlFile = CDMUtilities::readCMLFile(this->CMakeLists->GetPath().c_str());
555
556       bool found = false;
557
558       for (int i = 0; i < cmlFile.size(); ++i)
559         {
560           if(toInclude && cmlFile[i].first == "comment")
561             {
562               std::vector<std::string> segments;
563               std::string line = cmlFile[i].second[0];
564               while(line[0] == '#')
565                 line.erase(0,1);
566
567               CDMUtilities::splitter::split(segments, line, " ()", CDMUtilities::splitter::no_empties);
568               if (segments.size() > 1 && segments[0] == "ADD_SUBDIRECTORY" && segments[1] == application_name)
569                 {
570                   found = true;
571                   while(cmlFile[i].second[0][0] == '#')
572                     cmlFile[i].second[0].erase(0,1);
573                 }
574             }
575           else if(cmlFile[i].first == "command" && cmlFile[i].second[0] == "ADD_SUBDIRECTORY")
576             {
577               int pos = 1;
578               while (pos < cmlFile[i].second.size())
579                 {
580                   if (!isspace(cmlFile[i].second[pos][0]) && cmlFile[i].second[pos][0] != '(' && cmlFile[i].second[pos][0] != '#')
581                     {
582                       if (application_name == cmlFile[i].second[pos])
583                         {
584                           found = true;
585                           if (!toInclude)
586                             {
587                               cmlFile[i].first = "comment";
588                               cmlFile[i].second[0] = "#" + cmlFile[i].second[0];
589                               while (cmlFile[i].second.size() > 1)
590                                 {
591                                   cmlFile[i].second[0] += cmlFile[i].second[1];
592                                   cmlFile[i].second.erase(cmlFile[i].second.begin()+1);
593                                 }
594
595                             }
596                         }
597                       break;
598                     }
599                   pos++;
600                 }
601             }
602         }
603       if (!found && toInclude)
604         {
605           CDMUtilities::syntaxElement element;
606           element.first = "command";
607           element.second.push_back("ADD_SUBDIRECTORY(" + application_name + ")");
608           cmlFile.push_back(element);
609         }
610
611       return CDMUtilities::writeCMLFile(this->CMakeLists->GetPath().c_str(),cmlFile);
612     }
613   return false;
614 }