OSDN Git Service

[denncoCreator] Implement plugin cell edit feature. The work is in progress.
[dennco/denncoCreator.git] / Source / dccontainer.cpp
1 //  Copyright (c) 2012 Dennco Project
2 //
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16 //
17 //  Created by tkawata on Sep-30, 2012.
18 //
19 #include "dccontainer.h"
20
21 #include "dccell.h"
22 #include "dccellcode.h"
23 #include "dcaxon.h"
24 #include "dcaxonterminal.h"
25 #include "dcreceptor.h"
26 #include "dcscene.h"
27 #include "dccontent.h"
28 #include "dccreator.h"
29 #include "dcvpagecomponent.h"
30 #include "utils/dccomponentutil.h"
31 #include "dctreeviewwidget.h"
32
33 #include "DNFileList.h"
34 #include "DNDirectory.h"
35 #include "utils/dcutil.h"
36
37 #include <QMutexLocker>
38 #include <QDir>
39 #include <QDirIterator>
40
41
42 //static
43 TKContainer* TKContainer::createContainer()
44 {
45     TKContainer *container = new DCContainer();
46     container->init();
47     return container;
48 }
49
50 DCContainer::DCContainer() : d_content(NULL), d_factoryCachedLocation("")
51 {
52     d_scene = new DCScene(this);
53
54     d_workDirRoot = QDir::homePath() + "/.denncoCreator/work";
55     d_workDirCellRoot = d_workDirRoot + "/cells";
56     d_workDirCellCodeRoot = d_workDirRoot + "/cellcodes";
57
58 }
59
60 DCContainer::~DCContainer()
61 {
62     if (d_scene)
63     {
64         delete d_scene;
65         d_scene = NULL;
66     }
67 }
68
69 bool DCContainer::getIsModified() const
70 {
71     if (d_scene)
72     {
73         return d_scene->getIsModified();
74     }
75     else
76     {
77         return false;
78     }
79 }
80
81 bool DCContainer::isScriptableCell(DCCell *cell) const
82 {
83     bool    noScript = false;
84
85     std::string type = cell->getType().toStdString();
86
87     if (type == CELLTYPE_JSBASIC || type.length() == 0)
88     {
89         noScript = false;
90     }
91     else if (type == CELLTYPE_IN)
92     {
93         noScript = true;
94     }
95     else if (type == CELLTYPE_OUT)
96     {
97         noScript = true;
98     }
99     else if (type == CELLTYPE_BASICSTORAGE)
100     {
101         noScript = false;
102     }
103     else if (type == CELLTYPE_PLUGIN_IN)
104     {
105         noScript = false;
106     }
107     else if (type == CELLTYPE_PLUGIN_OUT)
108     {
109         noScript = false;
110     }
111     else
112     {
113         Q_ASSERT(0);
114     }
115     return !noScript;
116 }
117
118 void DCContainer::setContent(DCContent *content)
119 {
120     d_content = content;
121 }
122
123 void DCContainer::unselectCellObjectAll()
124 {
125     for ( TKCellMap::iterator it = mCells.begin(); it != mCells.end(); ++it ) {
126         DCCell *cell = dynamic_cast<DCCell*>(it->second);
127         if (cell)
128             cell->getVComponent()->setSelected(false,true);
129     }
130 }
131
132 QList<DCVComponent*> DCContainer::getSelectedCellObjects() const
133 {
134     QList<DCVComponent*> list;
135
136     for ( TKCellMap::const_iterator it = mCells.begin(); it != mCells.end(); ++it ) {
137         DCCell *cell = dynamic_cast<DCCell*>(it->second);
138         if (cell)
139         {
140             DCVComponent *object = NULL;
141
142             object = cell->getVComponent();
143             if (object && object->getIsSelected())
144             {
145                 list.push_back(object);
146             }
147
148             //axon
149             DCAxon *axon = cell->getAxon();
150             object = axon->getVComponent();
151             if (object && object->getIsSelected())
152             {
153                 list.push_back(object);
154             }
155
156             //terminals
157             int n = axon->getNumberOfTerminals();
158             for (int i = 0; i < n; i++)
159             {
160                 object = axon->getTerminalAt(i)->getVComponent();
161                 if (object && object->getIsSelected())
162                 {
163                     list.push_back(object);
164                 }
165             }
166
167             //receptors
168             const TKReceptorMap *receptors = cell->getReceptors();
169             TKReceptorMap::const_iterator it = receptors->begin();
170             while( it != receptors->end())
171             {
172                 object = ((DCReceptor*)(*it).second)->getVComponent();
173                 if (object && object->getIsSelected())
174                 {
175                     list.push_back(object);
176                 }
177                 ++it;
178             }
179         }
180     }
181
182     return list;
183 }
184
185 TKCell* DCContainer::addCell(std::string theLocation, std::string theName, std::string type, std::string customScript)
186 {
187     QMutexLocker lock(d_scene->getSceneLock());
188
189     DCCell *cell = dynamic_cast<DCCell*>(TKContainer::addCell(theLocation, theName, type, customScript));
190
191     saveCustomScriptToWorkFile(cell, customScript);
192
193     return cell;
194 }
195
196 TKCell*  DCContainer::addCell(std::string theLocation, std::string theName, TKCellCode *cellCode, std::string customScript)
197 {
198     QMutexLocker lock(d_scene->getSceneLock());
199
200     DCCell *cell = dynamic_cast<DCCell*>(TKContainer::addCell(theLocation, theName, cellCode, customScript));
201
202     saveCustomScriptToWorkFile(cell, customScript);
203
204     return cell;
205 }
206
207 TKCellCode* DCContainer::addCellCode(std::string theName, std::string theAPIType, std::string code)
208 {
209     QMutexLocker lock(d_scene->getSceneLock());
210
211     DCCellCode *cellCode = dynamic_cast<DCCellCode*>(TKContainer::addCellCode(theName, theAPIType, code));
212
213     saveClassScriptToWorkFile(cellCode, code);
214
215     return cellCode;
216 }
217
218 TKCell* DCContainer::cellFactory(std::string location, std::string name, std::string type, bool canInterfaceIn, bool canInterfaceOut)
219 {
220     if (location != d_factoryCachedLocation || d_factoryCachedPageObject.ref() == NULL)
221     {
222         d_factoryCachedPageObject.assign(d_scene->getPage(location));
223         if (d_factoryCachedPageObject.ref() == NULL)
224         {
225             d_factoryCachedPageObject.assign(d_scene->addPage(location));
226         }
227     }
228     d_factoryCachedLocation = location;
229
230     TKCell *cell = DCComponentUtil::createCell(this, dynamic_cast<DCVCPage*>(d_factoryCachedPageObject.ref()), location, name, type, canInterfaceIn, canInterfaceOut);
231     cell->init();
232
233     return cell;
234 }
235
236 TKCell* DCContainer::pluginCellFactory(std::string location, std::string fullName, std::string type, std::string pluginName, std::string pluginValue, bool canInterfaceIn, bool canInterfaceOut)
237 {
238     return cellFactory(location, fullName, type, canInterfaceIn, canInterfaceOut );
239 }
240
241
242 TKAxon* DCContainer::axonFactory(TKCell *theOwner)
243 {
244     return DCComponentUtil::createAxon((DCCell*)theOwner);
245 }
246
247 TKReceptor* DCContainer::receptorFactory(TKCell *theOwner)
248 {
249     return DCComponentUtil::createReceptor((DCCell*)theOwner);
250 }
251
252 TKAxonTerminal* DCContainer::axonTerminalFactory(TKAxon *theOwner)
253 {
254     return DCComponentUtil::createAxonTerminal((DCAxon*)theOwner);
255 }
256
257 TKCellCode* DCContainer::cellCodeFactory(std::string name, std::string cellapi, std::string code)
258 {
259     DCVCPage *page = NULL;
260     if (name != TKContainer::CELLCODENAME_EMPTY)
261     {
262         std::string location = name;
263         if (location.find("#") != std::string::npos)
264         {
265             location = location.substr(0, location.find("#"));
266         }
267         if (location != d_factoryCachedLocation || d_factoryCachedPageObject.ref() == NULL)
268         {
269             d_factoryCachedPageObject.assign(d_scene->getPage(location));
270             if (d_factoryCachedPageObject.ref() == NULL)
271             {
272                 d_factoryCachedPageObject.assign(d_scene->addPage(location));
273             }
274         }
275         d_factoryCachedLocation = location;
276         page = dynamic_cast<DCVCPage*>(d_factoryCachedPageObject.ref());
277     }
278     return DCComponentUtil::createCellCode(this, page, name, cellapi);
279 }
280
281 void DCContainer::beganParsePage(const char *docRoot, const char *path)
282 {
283     (void)docRoot;
284
285     QDir workCellDir(d_workDirCellRoot + QString::fromLocal8Bit(path));
286     QDir workCellCodeDir(d_workDirCellCodeRoot + QString::fromLocal8Bit(path));
287     if (!workCellDir.exists())
288     {
289         workCellDir.mkpath(workCellDir.absolutePath());
290     }
291     if (!workCellCodeDir.exists())
292     {
293         workCellCodeDir.mkpath(workCellCodeDir.absolutePath());
294     }
295
296     std::string location = path;
297     d_factoryCachedPageObject.assign(d_scene->getPage(location));
298     if (d_factoryCachedPageObject.ref() == NULL)
299     {
300         d_factoryCachedPageObject.assign(d_scene->addPage(location));
301     }
302     d_factoryCachedLocation = location;
303 }
304
305 void DCContainer::endedParsePage(const char *docRoot, const char *path)
306 {
307     (void)docRoot; (void)path;
308 }
309
310
311 void DCContainer::beganBuildContainer()
312 {
313     DCUtil::removeDirRecursive(d_workDirRoot);
314 }
315
316 void DCContainer::endedBuildContainer()
317 {
318
319
320 }
321
322 bool DCContainer::removeCellCode(DCCellCode *cellcode)
323 {
324     for ( TKCellMap::iterator it = mCells.begin(); it != mCells.end(); ++it )
325     {
326         DCCell *cell = dynamic_cast<DCCell*>(it->second);
327         if (cell->getCellCode() == cellcode)
328         {
329             cell->setCellCode(mEmptyCellClass, cell->getCustomScript().toLocal8Bit().data());
330         }
331     }
332
333     bool found = false;
334     for ( TKCellCodeMap::iterator it = mCellCodes.begin(); it != mCellCodes.end(); ++it )
335     {
336         if (it->second == cellcode)
337         {
338             mCellCodes.erase(it);
339             found = true;
340             break;
341         }
342     }
343
344     if (cellcode->getPageBelonging())
345     {
346         cellcode->getPageBelonging()->unregisterCellCodeClass(cellcode->getVComponent());
347     }
348     delete cellcode;
349
350     return found;
351 }
352
353 bool DCContainer::removeCell(DCCell *cell)
354 {
355     for ( TKCellMap::iterator it = mCells.begin(); it != mCells.end(); ++it )
356     {
357         if (it->second == cell)
358         {
359             mCells.erase(it++);
360             if (cell->getPageBelonging())
361             {
362                 cell->getPageBelonging()->unregisterCell(cell->getVComponent());
363             }
364             delete cell;
365             return true;
366         }
367     }
368     return false;
369 }
370
371 bool DCContainer::saveCustomScriptToWorkFile(const DCCell *cell, std::string customScript)
372 {
373     QFile workfile(getWorkFilePathForCustomScript(cell));
374     QFileInfo fileInfo(workfile);
375     if (!fileInfo.absoluteDir().exists())
376     {
377         QDir dir;
378         dir.mkpath(fileInfo.absolutePath());
379     }
380
381     workfile.open(QIODevice::WriteOnly);
382     QTextStream out(&workfile);
383     out << QString::fromStdString(customScript);
384     workfile.close();
385     return true;
386 }
387
388 bool DCContainer::saveClassScriptToWorkFile(const DCCellCode *cellCode, std::string code)
389 {
390     QString qNamePath = QString::fromStdString(cellCode->getFQNName());
391     QString name = DCUtil::getNameFromFQNPath(qNamePath);
392
393     if (name.length() == 0)
394         return false;
395
396     QFile workfile(getWorkFilePathForCellCode(cellCode));
397     QFileInfo fileInfo(workfile);
398     if (!fileInfo.absoluteDir().exists())
399     {
400         QDir dir;
401         dir.mkpath(fileInfo.absolutePath());
402     }
403     workfile.open(QIODevice::WriteOnly);
404     QTextStream out(&workfile);
405     out << QString::fromStdString(code);
406     workfile.close();
407     return true;
408 }
409
410 QString DCContainer::readCustomScriptFromWorkFile(const DCCell *cell)
411 {
412     QFile file(getWorkFilePathForCustomScript(cell));
413
414     if (!file.exists())
415     {
416         return "";
417     }
418
419     file.open(QIODevice::ReadOnly);
420     QTextStream in(&file);
421     QString out = in.readAll();
422     file.close();
423
424     return out;
425 }
426
427 QString DCContainer::readCellCodeScriptFromFile(const DCCellCode *cellCode)
428 {
429     QString qNamePath = QString::fromStdString(cellCode->getFQNName());
430     QString name = DCUtil::getNameFromFQNPath(qNamePath);
431
432     if (name.length() == 0)
433         return false;
434
435     QFile file(getWorkFilePathForCellCode(cellCode));
436     if (!file.exists())
437     {
438         return "";
439     }
440
441     file.open(QIODevice::ReadOnly);
442     QTextStream in(&file);
443     QString out = in.readAll();
444     file.close();
445
446     return out;
447 }
448
449 QString DCContainer::sysFilePathToContainerBasedPath(const QString &sysFilePath)
450 {
451     QString containerPath = QString::fromStdString(getContainerRootPath());
452     return "/" + QDir(containerPath).relativeFilePath(sysFilePath);
453 }
454
455 QString DCContainer::containerBasedPathToSysFilePath(const QString &containerBasedPath)
456 {
457     QString containerPath = QString::fromStdString(getContainerRootPath());
458     return containerPath + containerBasedPath;
459 }
460
461 bool DCContainer::renameCell(DCCell *cell, const QString &newName)
462 {
463     QString oldFqnName = DCUtil::getFQNPath(cell->getLocation(), cell->getName());
464     QString oldName = QString::fromStdString(cell->getName());
465
466     if (oldName == newName)
467         return true;
468
469     QString customScript = readCustomScriptFromWorkFile(cell);
470     QFile workFileOld(getWorkFilePathForCustomScript(cell));
471
472     cell->changeName(newName);
473     if (!saveCustomScriptToWorkFile(cell, customScript.toStdString()))
474     {
475         cell->changeName(oldName);
476         return false;
477     }
478     workFileOld.remove();
479     mCells.erase(oldFqnName.toStdString());
480
481     QString newFqnName = DCUtil::getFQNPath(cell->getLocation(), cell->getName());
482     std::pair<TKCellMap::iterator, bool> r = mCells.insert(TKCellMap::value_type(newFqnName.toStdString(), cell));
483
484     return r.second;
485 }
486
487 bool DCContainer::moveCell(DCCell *cell, const QString& pageNewContainerBasedPathName)
488 {
489     QString oldFqnName = DCUtil::getFQNPath(cell->getLocation(), cell->getName());
490     QString oldContainerPath = QString::fromStdString(cell->getLocation());
491
492     if (oldContainerPath == pageNewContainerBasedPathName)
493         return true;
494
495     QString customScript = readCustomScriptFromWorkFile(cell);
496     QFile workFileOld(getWorkFilePathForCustomScript(cell));
497
498     cell->changePath(pageNewContainerBasedPathName);
499     if (!saveCustomScriptToWorkFile(cell, customScript.toStdString()))
500     {
501         cell->changePath(oldContainerPath);
502         return false;
503     }
504     workFileOld.remove();
505     mCells.erase(oldFqnName.toStdString());
506
507     QString newFqnName = DCUtil::getFQNPath(pageNewContainerBasedPathName.toStdString(), cell->getName());
508     std::pair<TKCellMap::iterator, bool> r = mCells.insert(TKCellMap::value_type(newFqnName.toStdString(), cell));
509     return r.second;
510 }
511
512 bool DCContainer::renameCellCodeClass(DCCellCode *cellcode, const QString &newName)
513 {
514     QString oldFqnName = QString::fromStdString(cellcode->getFQNName());
515     QString oldPath = DCUtil::getContainerBasedPathFromFQNPath(oldFqnName);
516     QString oldName = DCUtil::getNameFromFQNPath(oldFqnName);
517
518     if (oldName == newName)
519         return true;
520
521     QFile oldFile(getWorkFilePathForCellCode(cellcode));
522     QString script = readCellCodeScriptFromFile(cellcode);
523
524     cellcode->changeName(newName);
525     if (!saveClassScriptToWorkFile(cellcode, script.toStdString()))
526     {
527         cellcode->changeName(oldName);
528         return false;
529     }
530     oldFile.remove();
531     mCellCodes.erase(oldFqnName.toStdString());
532
533     std::pair<TKCellCodeMap::iterator, bool> r = mCellCodes.insert(TKCellCodeMap::value_type(cellcode->getFQNName(), cellcode));
534
535     return r.second;
536 }
537
538 bool DCContainer::moveCellCodeClass(DCCellCode *cellcode, const QString& pageNewContainerBasedPathName)
539 {
540     QString oldFqnName = QString::fromStdString(cellcode->getFQNName());
541     QString oldPath = DCUtil::getContainerBasedPathFromFQNPath(oldFqnName);
542     QString oldName = DCUtil::getNameFromFQNPath(oldFqnName);
543
544     if (oldPath == pageNewContainerBasedPathName)
545         return true;
546
547     QFile oldFile(getWorkFilePathForCellCode(cellcode));
548     QString script = readCellCodeScriptFromFile(cellcode);
549
550     cellcode->changePath(pageNewContainerBasedPathName);
551     if (!saveClassScriptToWorkFile(cellcode, script.toStdString()))
552     {
553         cellcode->changePath(oldPath);
554         return false;
555     }
556     oldFile.remove();
557     mCellCodes.erase(oldFqnName.toStdString());
558
559     std::pair<TKCellCodeMap::iterator, bool> r = mCellCodes.insert(TKCellCodeMap::value_type(cellcode->getFQNName(), cellcode));
560
561     return r.second;
562 }
563
564 DCVCPage* DCContainer::movePage(const QString &oldContainerBasedPathName, const QString &newContainerBasedPathName)
565 {
566     bool r = false;
567     DCVCPage *newPage = NULL;
568     DCScene *scene = getScene();
569     if (scene)
570     {
571         DCVCPage *oldPage = getScene()->getPage(oldContainerBasedPathName.toStdString());
572         newPage = getScene()->addPage(newContainerBasedPathName.toStdString());
573
574         if (oldPage && newPage)
575         {
576             r = oldPage->moveComponentsTo(newPage);
577         }
578         if (r)
579         {
580             QString sysOldFilePath = containerBasedPathToSysFilePath(oldContainerBasedPathName);
581             QString sceneSettingFilePath = scene->getSceneSettingFilePathForPage(oldPage);
582             if (!DCTreeViewWidget::removeFile(sysOldFilePath))
583             {
584                 r = false;
585             }
586             QDir dir;
587             dir.remove(sceneSettingFilePath);
588
589             if (!scene->removePage(oldPage))
590             {
591                 r = false;
592             }
593         }
594     }
595
596     return r ? newPage : NULL;
597 }
598
599
600 QList<QString> DCContainer::getAvailableCellTypes() const
601 {
602     QList<QString> list;
603
604     list.append(QString::fromStdString(TKContainer::CELLTYPE_JSBASIC));
605     list.append(QString::fromStdString(TKContainer::CELLTYPE_BASICSTORAGE));
606     list.append(QString::fromStdString(TKContainer::CELLTYPE_IN));
607     list.append(QString::fromStdString(TKContainer::CELLTYPE_OUT));
608     list.append(QString::fromStdString(TKContainer::CELLTYPE_PLUGIN_IN));
609     list.append(QString::fromStdString(TKContainer::CELLTYPE_PLUGIN_OUT));
610
611     return list;
612 }
613
614 QList<QString> DCContainer::getAvailableScriptableCellTypes() const
615 {
616     QList<QString> list;
617
618     list.append(QString::fromStdString(TKContainer::CELLTYPE_JSBASIC));
619     list.append(QString::fromStdString(TKContainer::CELLTYPE_BASICSTORAGE));
620
621     return list;
622 }
623
624 bool DCContainer::getIsScriptable(const QString& type) const
625 {
626     std::string t = type.toStdString();
627
628     if (t == TKContainer::CELLTYPE_JSBASIC)
629     {
630         return true;
631     }
632     else if (t == TKContainer::CELLTYPE_BASICSTORAGE)
633     {
634         return true;
635     }
636     else if (t == TKContainer::CELLTYPE_IN)
637     {
638         return false;
639     }
640     else if (t == TKContainer::CELLTYPE_OUT)
641     {
642         return false;
643     }
644     else if (t == TKContainer::CELLTYPE_PLUGIN_IN)
645     {
646         return false;
647     }
648     else if (t == TKContainer::CELLTYPE_PLUGIN_OUT)
649     {
650         return false;
651     }
652
653     return false;
654 }
655
656
657 bool DCContainer::getIsReceptorAvailable(const QString& type) const
658 {
659     std::string t = type.toStdString();
660
661     if (t == TKContainer::CELLTYPE_JSBASIC)
662     {
663         return true;
664     }
665     else if (t == TKContainer::CELLTYPE_BASICSTORAGE)
666     {
667         return true;
668     }
669     else if (t == TKContainer::CELLTYPE_IN)
670     {
671         return false;
672     }
673     else if (t == TKContainer::CELLTYPE_OUT)
674     {
675         return true;
676     }
677     else if (t == TKContainer::CELLTYPE_PLUGIN_IN)
678     {
679         return false;
680     }
681     else if (t == TKContainer::CELLTYPE_PLUGIN_OUT)
682     {
683         return true;
684     }
685
686     return false;
687 }
688
689 QString DCContainer::getWorkFilePathForCustomScript(const DCCell *cell) const
690 {
691     QDir workdir(d_workDirCellRoot + QString::fromStdString(cell->getLocation()));
692     return workdir.absoluteFilePath(QString::fromStdString(cell->getName()) + ".js");
693 }
694
695 QString DCContainer::getWorkFilePathForCellCode(const DCCellCode *cellCode) const
696 {
697     QString qNamePath = QString::fromStdString(cellCode->getFQNName());
698     QString path = DCUtil::getContainerBasedPathFromFQNPath(qNamePath);
699     QString name = DCUtil::getNameFromFQNPath(qNamePath);
700
701     QDir workdir(d_workDirCellCodeRoot + path);
702     return workdir.absoluteFilePath(name + ".js");
703 }
704
705 bool DCContainer::getIsPluginType(const QString &type) const
706 {
707     std::string t = type.toStdString();
708
709     if (t == TKContainer::CELLTYPE_PLUGIN_IN)
710     {
711         return true;
712     }
713     else if (t == TKContainer::CELLTYPE_PLUGIN_OUT)
714     {
715         return true;
716     }
717
718     return false;
719 }
720
721 QList<QString> DCContainer::getAvailablePluginLibraries() const
722 {
723     QList<QString> list;
724     return list;
725 }
726
727 QList<QString> DCContainer::getPreDefinedPluginVariablesForPlugin(const QString& libraryName) const
728 {
729     QList<QString> list;
730     return list;
731 }
732
733 QString DCContainer::createPluginCellName(const QString &name, const QString& type, const QString &libraryName)
734 {
735     QString cellName = name;
736
737     if (type == QString::fromStdString(TKContainer::CELLTYPE_PLUGIN_IN))
738     {
739         cellName += "@@";
740         cellName += libraryName;
741     }
742     else if (type == QString::fromStdString(TKContainer::CELLTYPE_PLUGIN_OUT))
743     {
744         cellName += "@";
745         cellName += libraryName;
746     }
747     return cellName;
748 }