1 /**
2  * @file    RenderLayoutPlugin.cpp
3  * @brief   Implementation of RenderLayoutPlugin, the plugin class of
4  *          the fbc package for the Model element.
5  * @author  Frank T. Bergmann
6  *
7  *<!---------------------------------------------------------------------------
8  * This file is part of libSBML.  Please visit http://sbml.org for more
9  * information about SBML, and the latest version of libSBML.
10  *
11  * Copyright (C) 2020 jointly by the following organizations:
12  *     1. California Institute of Technology, Pasadena, CA, USA
13  *     2. University of Heidelberg, Heidelberg, Germany
14  *     3. University College London, London, UK
15  *
16  * Copyright (C) 2019 jointly by the following organizations:
17  *     1. California Institute of Technology, Pasadena, CA, USA
18  *     2. University of Heidelberg, Heidelberg, Germany
19  *
20  * Copyright (C) 2013-2018 jointly by the following organizations:
21  *     1. California Institute of Technology, Pasadena, CA, USA
22  *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
23  *     3. University of Heidelberg, Heidelberg, Germany
24  *
25  * Copyright (C) 2009-2013 jointly by the following organizations:
26  *     1. California Institute of Technology, Pasadena, CA, USA
27  *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
28  *
29  * This library is free software; you can redistribute it and/or modify it
30  * under the terms of the GNU Lesser General Public License as published by
31  * the Free Software Foundation.  A copy of the license agreement is provided
32  * in the file named "LICENSE.txt" included with this software distribution
33  * and also available online as http://sbml.org/software/libsbml/license.html
34  *------------------------------------------------------------------------- -->
35  */
36 
37 #include <sbml/packages/render/extension/RenderExtension.h>
38 #include <sbml/packages/render/extension/RenderLayoutPlugin.h>
39 #include <sbml/packages/render/common/RenderExtensionTypes.h>
40 #include <sbml/packages/render/util/RenderUtilities.h>
41 
42 
43 #include <sbml/packages/layout/sbml/Layout.h>
44 
45 #include <sbml/util/ElementFilter.h>
46 
47 #include <iostream>
48 using namespace std;
49 
50 
51 #ifdef __cplusplus
52 
53 LIBSBML_CPP_NAMESPACE_BEGIN
54 
55 
56 
57   /*
58   * Constructor
59   */
RenderLayoutPlugin(const std::string & uri,const std::string & prefix,RenderPkgNamespaces * renderns)60   RenderLayoutPlugin::RenderLayoutPlugin (const std::string &uri,
61   const std::string &prefix,
62   RenderPkgNamespaces *renderns)
63   : SBasePlugin(uri,prefix, renderns)
64   , mLocalRenderInformation(renderns)
65 {
66 }
67 
68 
69 /*
70 * Copy constructor. Creates a copy of this SBase object.
71 */
RenderLayoutPlugin(const RenderLayoutPlugin & orig)72 RenderLayoutPlugin::RenderLayoutPlugin(const RenderLayoutPlugin& orig)
73   : SBasePlugin(orig)
74   , mLocalRenderInformation(orig.mLocalRenderInformation)
75 {
76 }
77 
78 
79 /*
80 * Destroy this object.
81 */
~RenderLayoutPlugin()82 RenderLayoutPlugin::~RenderLayoutPlugin () {}
83 
84 /*
85 * Assignment operator for RenderLayoutPlugin.
86 */
87 RenderLayoutPlugin&
operator =(const RenderLayoutPlugin & orig)88   RenderLayoutPlugin::operator=(const RenderLayoutPlugin& orig)
89 {
90   if(&orig!=this)
91   {
92     this->SBasePlugin::operator =(orig);
93   }
94   return *this;
95 }
96 
97 
98 /*
99 * Creates and returns a deep copy of this RenderLayoutPlugin object.
100 *
101 * @return a (deep) copy of this RenderLayoutPlugin object
102 */
103 RenderLayoutPlugin*
clone() const104   RenderLayoutPlugin::clone () const
105 {
106   return new RenderLayoutPlugin(*this);
107 }
108 
109 
110 List*
getAllElements(ElementFilter * filter)111 RenderLayoutPlugin::getAllElements(ElementFilter* filter)
112 {
113   List* ret = new List();
114   List* sublist = NULL;
115 
116   ADD_FILTERED_LIST(ret, sublist, mLocalRenderInformation, filter);
117 
118   return ret;
119 }
120 
121 
122 /** @cond doxygenLibsbmlInternal */
123 SBase*
createObject(XMLInputStream & stream)124   RenderLayoutPlugin::createObject(XMLInputStream& stream)
125 {
126   SBase*        object = 0;
127 
128   const std::string&   name   = stream.peek().getName();
129   const XMLNamespaces& xmlns  = stream.peek().getNamespaces();
130   const std::string&   prefix = stream.peek().getPrefix();
131 
132   const std::string& targetPrefix = (xmlns.hasURI(mURI)) ? xmlns.getPrefix(mURI) : mPrefix;
133 
134   if (prefix == targetPrefix)
135   {
136     if ( name == "listOfRenderInformation" )
137     {
138       //cout << "[DEBUG] LayoutModelPlugin::createObject create listOfLayouts" << endl;
139       object = &mLocalRenderInformation;
140 
141       if (targetPrefix.empty())
142       {
143         //
144         // prefix is empty when writing elements in layout extension.
145         //
146         mLocalRenderInformation.getSBMLDocument()->enableDefaultNS(mURI,true);
147       }
148     }
149   }
150 
151   return object;
152 }
153 /** @endcond */
154 
155 /** @cond doxygenLibsbmlInternal */
156 void
writeAttributes(XMLOutputStream & stream) const157 RenderLayoutPlugin::writeAttributes (XMLOutputStream& stream) const
158 {
159   //
160   // This function is used only for SBML Level 2.
161   //
162   if ( getURI() != RenderExtension::getXmlnsL2() ) return;
163 
164   SBase *parent = const_cast<SBase*>(getParentSBMLObject());
165   if (parent == NULL)
166     return;
167 
168   // when called this will serialize the annotation
169   parent->getAnnotation();
170 }
171 /** @endcond */
172 
173 /** @cond doxygenLibsbmlInternal */
174 void
writeElements(XMLOutputStream & stream) const175   RenderLayoutPlugin::writeElements (XMLOutputStream& stream) const
176 {
177   if ( getURI() == RenderExtension::getXmlnsL2() ) return;
178   if (mLocalRenderInformation.size() > 0 || mLocalRenderInformation.isSetDefaultValues())
179     mLocalRenderInformation.write(stream);
180 }
181 /** @endcond */
182 
183 /** @cond doxygenLibsbmlInternal */
184 
185 /*
186  * Parse L2 annotation if supported
187  *
188  */
189 void
parseAnnotation(SBase * parentObject,XMLNode * annotation)190 RenderLayoutPlugin::parseAnnotation(SBase *parentObject, XMLNode *annotation)
191 {
192   mLocalRenderInformation.setSBMLDocument(mSBML);
193   parseLocalRenderAnnotation(annotation,(Layout*)parentObject);
194 }
195 /** @endcond */
196 
197 
198 /** @cond doxygenLibsbmlInternal */
199 /*
200  * Synchronizes the annotation of this SBML object.
201  */
202 void
syncAnnotation(SBase * parentObject,XMLNode * pAnnotation)203 RenderLayoutPlugin::syncAnnotation (SBase *parentObject, XMLNode *pAnnotation)
204 {
205   if(pAnnotation && pAnnotation->getNumChildren() > 0)
206   {
207       parentObject->removeTopLevelAnnotationElement("listOfRenderInformation", "", false);
208   }
209 
210   // only do this for L1 and L2 documents
211   if(getLevel() >= 3)
212     return;
213 
214 
215   if (mLocalRenderInformation.size() == 0)
216     return;
217 
218   XMLNode * render = parseLocalRenderInformation((Layout*)parentObject);
219   if (render == NULL)
220     return;
221 
222 
223   if (pAnnotation == NULL)
224   {
225     // cannot happen, as syncAnnotation is called with a valid Annotation
226     // (possibly empty)
227     return;
228   }
229   else
230   {
231       if (pAnnotation->isEnd())
232       {
233           pAnnotation->unsetEnd();
234       }
235       pAnnotation->addChild(render->getChild(0));
236       delete render;
237   }
238 
239 
240 
241 }
242 /** @endcond */
243 
244 
245 /** @cond doxygenLibsbmlInternal */
246 /*
247  * Subclasses should override this method to read (and store) XHTML,
248  * MathML, etc. directly from the XMLInputStream.
249  *
250  * @return @c true if the subclass read from the stream, false otherwise.
251  */
252 bool
readOtherXML(SBase * parentObject,XMLInputStream & stream)253 RenderLayoutPlugin::readOtherXML (SBase* parentObject, XMLInputStream& stream)
254 {
255   // L2 render parsed by the annotation API
256   // @see parseAnnotation / syncAnnotation
257   return false;
258 }
259 /** @endcond */
260 
261 
262 /** @cond doxygenLibsbmlInternal */
263 /* default for components that have no required elements */
264 bool
hasRequiredElements() const265   RenderLayoutPlugin::hasRequiredElements() const
266 {
267   bool allPresent = true;
268 
269   return allPresent;
270 }
271 /** @endcond */
272 
273 
274 
275 /*
276 *
277 *  (EXTENSION) Additional public functions
278 *
279 */
280 
281 
282 
283 /** @cond doxygenLibsbmlInternal */
284 /*
285 * Sets the parent SBMLDocument of this SBML object.
286 *
287 * @param d the SBMLDocument object to use
288 */
289 void
setSBMLDocument(SBMLDocument * d)290   RenderLayoutPlugin::setSBMLDocument (SBMLDocument* d)
291 {
292   SBasePlugin::setSBMLDocument(d);
293   mLocalRenderInformation.setSBMLDocument(d);
294   if (mLocalRenderInformation.isSetDefaultValues())
295   {
296     mLocalRenderInformation.getDefaultValues()->setSBMLDocument(d);
297   }
298 }
299 /** @endcond */
300 
301 
302 /** @cond doxygenLibsbmlInternal */
303 /*
304 * Sets the parent SBML object of this plugin object to
305 * this object and child elements (if any).
306 * (Creates a child-parent relationship by this plugin object)
307 */
308 void
connectToParent(SBase * sbase)309   RenderLayoutPlugin::connectToParent (SBase* sbase)
310 {
311   SBasePlugin::connectToParent(sbase);
312   mLocalRenderInformation.connectToParent(sbase);
313 }
314 /** @endcond */
315 
316 
317 /** @cond doxygenLibsbmlInternal */
318 /*
319 * Enables/Disables the given package with child elements in this plugin
320 * object (if any).
321 */
322 void
enablePackageInternal(const std::string & pkgURI,const std::string & pkgPrefix,bool flag)323   RenderLayoutPlugin::enablePackageInternal(const std::string& pkgURI,
324   const std::string& pkgPrefix, bool flag)
325 {
326   mLocalRenderInformation.enablePackageInternal(pkgURI, pkgPrefix, flag);
327 }
328 /** @endcond */
329 
330 
331 /*
332  * Returns a pointer to the list object that contains local render information.
333  */
getListOfLocalRenderInformation()334 ListOfLocalRenderInformation* RenderLayoutPlugin::getListOfLocalRenderInformation()
335 {
336     return &mLocalRenderInformation;
337 }
338 
339 /*
340  * Returns a const pointer to the list object that contains local render information.
341  */
getListOfLocalRenderInformation() const342 const ListOfLocalRenderInformation* RenderLayoutPlugin::getListOfLocalRenderInformation() const
343 {
344     return &mLocalRenderInformation;
345 }
346 
347 
348 /*
349  * Returns the number of local render information objects.
350  */
getNumLocalRenderInformationObjects() const351 unsigned int RenderLayoutPlugin::getNumLocalRenderInformationObjects() const
352 {
353     return mLocalRenderInformation.size();
354 }
355 
356 /*
357  * Returns a pointer to the local render information object with the given
358  * index.
359  * If the index is invalid, @c NULL is returned.
360  */
getRenderInformation(unsigned int index)361 LocalRenderInformation* RenderLayoutPlugin::getRenderInformation(unsigned int index)
362 {
363     if(index < mLocalRenderInformation.size())
364     {
365          return static_cast<LocalRenderInformation*>(mLocalRenderInformation.get(index));
366     }
367     else
368     {
369         return NULL;
370     }
371 }
372 
373 /*
374  * Returns a const pointer to the local render information object with the given
375  * index.
376  * If the index is invalid, @c NULL is returned.
377  */
getRenderInformation(unsigned int index) const378 const LocalRenderInformation* RenderLayoutPlugin::getRenderInformation(unsigned int index) const
379 {
380   if(index < mLocalRenderInformation.size())
381     {
382          return static_cast<const LocalRenderInformation*>(mLocalRenderInformation.get(index));
383     }
384     else
385     {
386         return NULL;
387     }
388 }
389 
390 /*
391  * Returns a pointer to the local render information object with the given
392  * id.
393  * If no object with the given @p id exists, @c NULL is returned.
394  */
getRenderInformation(const std::string & id)395 LocalRenderInformation* RenderLayoutPlugin::getRenderInformation(const std::string& id)
396 {
397     LocalRenderInformation* pResult=NULL;
398     unsigned int i=0,iMax=mLocalRenderInformation.size();
399     while(i<iMax)
400     {
401         if(mLocalRenderInformation.get(i)->getId()==id)
402         {
403             pResult=static_cast<LocalRenderInformation*>(mLocalRenderInformation.get(i));
404             break;
405         }
406         ++i;
407     }
408     return pResult;
409 }
410 
411 /*
412  * Returns a const pointer to the local render information object with the given
413  * id.
414  * If no object with the given @p id exists, @c NULL is returned.
415  */
getRenderInformation(const std::string & id) const416 const LocalRenderInformation* RenderLayoutPlugin::getRenderInformation(const std::string& id) const
417 {
418     const LocalRenderInformation* pResult=NULL;
419     unsigned int i=0,iMax=mLocalRenderInformation.size();
420     while(i<iMax)
421     {
422         if(mLocalRenderInformation.get(i)->getId()==id)
423         {
424             pResult=static_cast<const LocalRenderInformation*>(mLocalRenderInformation.get(i));
425             break;
426         }
427         ++i;
428     }
429     return pResult;
430 }
431 
432 /*
433  * Adds a copy of the given local render information object to the list of
434  * local render information objects.
435  */
addLocalRenderInformation(const LocalRenderInformation * pLRI)436 void RenderLayoutPlugin::addLocalRenderInformation(const LocalRenderInformation* pLRI)
437 {
438 
439   mLocalRenderInformation.appendAndOwn(new LocalRenderInformation(*pLRI));
440 }
441 
442 /*
443  * Creates a new local render information object and adds it to the list.
444  * The created object does not have a id and it is the responsibility of
445  * the calling code to ensure that it gets one.
446  * For constraints on the id, please consult the render information document.
447  */
createLocalRenderInformation()448 LocalRenderInformation* RenderLayoutPlugin::createLocalRenderInformation()
449 {
450     RENDER_CREATE_NS(renderns, getSBMLNamespaces());
451     LocalRenderInformation* pGRI=new LocalRenderInformation(renderns);
452 
453     mLocalRenderInformation.appendAndOwn(pGRI);
454     delete renderns;
455     return pGRI;
456 }
457 
458 /*
459  * Removed the render information with the given index from the list.
460  * The removed object is returned. It is the responsibility of the calling
461  * code to delete the object.
462  * If the index is not valid, @c NULL is returned.
463  */
removeLocalRenderInformation(unsigned int index)464 LocalRenderInformation* RenderLayoutPlugin::removeLocalRenderInformation(unsigned int index)
465 {
466     if(index < mLocalRenderInformation.size())
467     {
468         return static_cast<LocalRenderInformation*>(mLocalRenderInformation.remove(index));
469     }
470     else
471     {
472         return NULL;
473     }
474 }
475 
476 /*
477  * Removed the render information with the given @p id from the list.
478  * The removed object is returned. It is the responsibility of the calling
479  * code to delete the object.
480  * If an object with the given @p id does not exist, @c NULL is returned.
481  */
removeLocalRenderInformation(const std::string & id)482 LocalRenderInformation* RenderLayoutPlugin::removeLocalRenderInformation(const std::string& id)
483 {
484     unsigned int i=0,iMax=mLocalRenderInformation.size();
485     while(i<iMax)
486     {
487         if(mLocalRenderInformation.get(i)->isSetId() && mLocalRenderInformation.get(i)->getId()==id)
488         {
489             break;
490         }
491         ++i;
492     }
493     if(i!=iMax)
494     {
495         return removeLocalRenderInformation(i);
496     }
497     else
498     {
499         return NULL;
500     }
501 }
502 
503 /** @cond doxygenLibsbmlInternal */
504 
505 bool
accept(SBMLVisitor & v) const506 RenderLayoutPlugin::accept (SBMLVisitor& v) const
507 {
508   return true;
509 }
510 
511 /** @endcond */
512 
513 
514 
515 
516 #ifdef ANNOTATION
517 
518 /** @cond doxygenLibsbmlInternal */
519 /*
520  * Subclasses should override this method to read (and store) XHTML,
521  * MathML, etc. directly from the XMLInputStream.
522  *
523  * @return @c true if the subclass read from the stream, false otherwise.
524  */
525 bool
readOtherXML(XMLInputStream & stream)526 RenderLayoutPlugin::readOtherXML (XMLInputStream& stream)
527 {
528   bool          read = false;
529   const std::string& name = stream.peek().getName();
530 
531   // This has to do additional work for reading annotations, so the code
532 
533   if (name == "annotation")
534   {
535     if (mAnnotation)
536     {
537       if (getLevel() < 3)
538       {
539         logError(NotSchemaConformant, getLevel(), getVersion(),
540           "Only one <annotation> element is permitted inside a "
541           "particular containing element.");
542       }
543       else
544       {
545         logError(MultipleAnnotations, getLevel(), getVersion());
546       }
547     }
548 
549     delete mAnnotation;
550     mAnnotation = new XMLNode(stream);
551     checkAnnotation();
552     // only parse layout from annotations for Level 2 and below
553     if(getLevel() < 3)
554     {
555       mLocalRenderInformation.setSBMLDocument(mSBML);
556       parseLocalRenderAnnotation(mAnnotation,this);
557     }
558 
559     read = true;
560   }
561 
562   return read;
563 }
564 /** @endcond */
565 
566 /*
567  * Sets the annotation of this SBML object to a copy of annotation.
568  */
569 int
setAnnotation(const XMLNode * annotation)570 RenderLayoutPlugin::setAnnotation (const XMLNode* annotation)
571 {
572   int success = SBase::setAnnotation(annotation);
573   if(success == LIBSBML_OPERATION_SUCCESS && getLevel() < 3)
574   {
575       for(unsigned int i=0; i < mLocalRenderInformation.size(); i++)
576       {
577           LocalRenderInformation* lr = static_cast<LocalRenderInformation*>(mLocalRenderInformation.remove(0));
578           delete lr;
579       }
580 
581       if(mAnnotation)
582       {
583           // parse mAnnotation (if any) and set mLayouts
584           mLocalRenderInformation.setSBMLDocument(mSBML);
585           parseLocalRenderAnnotation(mAnnotation,this);
586       }
587   }
588   return success;
589 }
590 
591 
592 /*
593  * Appends annotation to the existing annotations.
594  * This allows other annotations to be preserved whilst
595  * adding additional information.
596  */
597 int
appendAnnotation(const XMLNode * annotation)598 RenderLayoutPlugin::appendAnnotation (const XMLNode* annotation)
599 {
600   int success = LIBSBML_OPERATION_FAILED;
601   if(!annotation) return LIBSBML_OPERATION_SUCCESS;
602 
603   XMLNode* new_annotation = NULL;
604   const std::string&  name = annotation->getName();
605 
606   // check for annotation tags and add if necessary
607   if (name != "annotation")
608   {
609     XMLToken ann_t = XMLToken(XMLTriple("annotation", "", ""), XMLAttributes());
610     new_annotation = new XMLNode(ann_t);
611     new_annotation->addChild(*annotation);
612   }
613   else
614   {
615     new_annotation = annotation->clone();
616   }
617 
618   if(getLevel() < 3)
619   {
620     // parse new_annotation and add mLayouts
621     mLocalRenderInformation.setSBMLDocument(mSBML);
622     parseLocalRenderAnnotation(new_annotation,this);
623 
624   }
625 
626   success = SBase::appendAnnotation(new_annotation);
627   delete new_annotation;
628 
629   return success;
630 }
631 
632 
633 /** @cond doxygenLibsbmlInternal */
634 /*
635  * Synchronizes the annotation of this SBML object.
636  */
637 void
syncAnnotation()638 RenderLayoutPlugin::syncAnnotation ()
639 {
640   SBase::syncAnnotation();
641   // only write the render information to an annotation
642   // if we are in a L1 or L2 document
643   if(getLevel() < 3)
644   {
645       if(mAnnotation)
646       {
647           XMLNode* new_annotation = deleteLocalRenderAnnotation(mAnnotation);
648           delete mAnnotation;
649           mAnnotation = new_annotation;
650       }
651       if (getListOfLocalRenderInformation()->size()!=0)
652       {
653           XMLNode * render = parseLocalRenderInformation(this);
654 
655           if (render)
656           {
657               if (!mAnnotation)
658               {
659                   mAnnotation = render;
660               }
661               else
662               {
663                   if (mAnnotation->isEnd())
664                   {
665                       mAnnotation->unsetEnd();
666                   }
667                   mAnnotation->addChild(render->getChild(0));
668                   delete render;
669               }
670           }
671       }
672   }
673 }
674 /** @endcond */
675 #endif
676 
677 LIBSBML_CPP_NAMESPACE_END
678 
679 #endif  /* __cplusplus */
680