0031687: Draw Harness, ViewerTest - extend command vrenderparams with option updating...
[occt.git] / src / XmlMDF / XmlMDF.cxx
1 // Created on: 2001-07-09
2 // Created by: Julia DOROVSKIKH
3 // Copyright (c) 2001-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16
17 #include <Message_Messenger.hxx>
18 #include <Message_ProgressSentry.hxx>
19 #include <Storage_Schema.hxx>
20 #include <TColStd_MapOfTransient.hxx>
21 #include <TDF_Attribute.hxx>
22 #include <TDF_AttributeIterator.hxx>
23 #include <TDF_ChildIterator.hxx>
24 #include <TDF_Data.hxx>
25 #include <TDF_Label.hxx>
26 #include <TDF_TagSource.hxx>
27 #include <TDF_Tool.hxx>
28 #include <XmlMDF.hxx>
29 #include <XmlMDF_ADriver.hxx>
30 #include <XmlMDF_ADriverTable.hxx>
31 #include <XmlMDF_DataMapIteratorOfTypeADriverMap.hxx>
32 #include <XmlMDF_ReferenceDriver.hxx>
33 #include <XmlMDF_TagSourceDriver.hxx>
34 #include <XmlObjMgt_Document.hxx>
35 #include <XmlObjMgt_DOMString.hxx>
36 #include <XmlObjMgt_Persistent.hxx>
37 #include <XmlLDrivers.hxx>
38 #include <TDocStd_Owner.hxx>
39 #include <TDocStd_Document.hxx>
40 #include <Standard_GUID.hxx>
41
42 IMPLEMENT_DOMSTRING (TagString,         "tag")
43 IMPLEMENT_DOMSTRING (LabelString,       "label")
44 #define DATATYPE_MIGRATION
45 //#define DATATYPE_MIGRATION_DEB
46 //=======================================================================
47 //function : UnsuppTypesMap
48 //purpose  : 
49 //=======================================================================
50
51 static TColStd_MapOfTransient& UnsuppTypesMap ()
52 {
53   static TColStd_MapOfTransient anUnsuppTypes;
54   return anUnsuppTypes;
55 }
56
57 //=======================================================================
58 //function : FromTo
59 //purpose  : Paste transient data into DOM_Element
60 //=======================================================================
61 void XmlMDF::FromTo (const Handle(TDF_Data)&             theData,
62                      XmlObjMgt_Element&                  theElement,
63                      XmlObjMgt_SRelocationTable&         theRelocTable,
64                      const Handle(XmlMDF_ADriverTable)&  theDrivers,
65                      const Handle(Message_ProgressIndicator)& theProgress)
66 {
67   UnsuppTypesMap().Clear();
68 //  Standard_Integer count =
69   WriteSubTree(theData->Root(), theElement, theRelocTable, theDrivers, theProgress);
70   UnsuppTypesMap().Clear();
71 }
72
73 //=======================================================================
74 //function : WriteSubTree
75 //purpose  : 
76 //=======================================================================
77 Standard_Integer XmlMDF::WriteSubTree
78                       (const TDF_Label&                    theLabel,
79                        XmlObjMgt_Element&                  theElement,
80                        XmlObjMgt_SRelocationTable&         theRelocTable,
81                        const Handle(XmlMDF_ADriverTable)&  theDrivers,
82                        const Handle(Message_ProgressIndicator)& theProgress)
83 {
84   XmlObjMgt_Document aDoc = theElement.getOwnerDocument();
85
86   // create element "label"
87   XmlObjMgt_Element aLabElem = aDoc.createElement (::LabelString());
88
89   // Extraction of the driver subset.
90   const XmlMDF_TypeADriverMap& aDriverMap = theDrivers->GetDrivers();
91
92   // write attributes
93   Standard_Integer count = 0;
94   TDF_AttributeIterator itr1 (theLabel);
95   for ( ; itr1.More(); itr1.Next())
96   {
97     const Handle(TDF_Attribute)& tAtt = itr1.Value();
98     const Handle(Standard_Type)& aType = tAtt->DynamicType();
99     if (aDriverMap.IsBound (aType))
100     {
101       const Handle(XmlMDF_ADriver)& aDriver = aDriverMap.Find (aType);
102       count++;
103
104       //    Add source to relocation table
105       Standard_Integer anId      = theRelocTable.Add (tAtt);
106
107       //    Create DOM data item
108       XmlObjMgt_Persistent pAtt;
109       // In the document version 8 the attribute TPrsStd_AISPresentation
110       // was replaced by TDataXtd_Presentation. Therefore, for old versions
111       // we write old name of the attribute (TPrsStd_AISPresentation).
112       Standard_CString typeName = aDriver->TypeName().ToCString();
113       if (XmlLDrivers::StorageVersion() < 8 &&
114           strcmp(typeName, "TDataXtd_Presentation") == 0)
115       {
116         typeName = "TPrsStd_AISPresentation";
117       }
118       pAtt.CreateElement (aLabElem, typeName, anId);
119
120       //    Paste
121       aDriver -> Paste (tAtt, pAtt, theRelocTable);
122     }
123 #ifdef OCCT_DEBUG
124     else if (!UnsuppTypesMap().Contains (aType))
125     {
126       std::cout << "attribute driver for type "<< aType -> Name()<< " not found"<< std::endl;
127       UnsuppTypesMap().Add (aType);
128     }
129 #endif
130   }
131
132   // write sub-labels
133   TDF_ChildIterator itr2 (theLabel);
134   Standard_Real child_count = 0;
135   for (; itr2.More(); ++child_count, itr2.Next())
136   {
137   }
138   itr2.Initialize(theLabel);
139   Message_ProgressSentry aPS(theProgress, "Writing sub-tree", 0, child_count, 1);
140   for ( ; itr2.More() && aPS.More(); itr2.Next(), aPS.Next())
141   {
142     const TDF_Label& aChildLab = itr2.Value();
143     count += WriteSubTree(aChildLab, aLabElem, theRelocTable, theDrivers, theProgress);
144   }
145
146   if (count > 0 || TDocStd_Owner::GetDocument(theLabel.Data())->EmptyLabelsSavingMode())
147   {
148     theElement.appendChild(aLabElem);
149
150     // set attribute "tag"
151     aLabElem.setAttribute (::TagString(), theLabel.Tag());
152   }
153   return count;
154 }
155
156 //=======================================================================
157 //function : FromTo
158 //purpose  : Paste data from DOM_Element into transient document
159 //=======================================================================
160 Standard_Boolean XmlMDF::FromTo (const XmlObjMgt_Element&         theElement,
161                                  Handle(TDF_Data)&                theData,
162                                  XmlObjMgt_RRelocationTable&      theRelocTable,
163                                  const Handle(XmlMDF_ADriverTable)& theDrivers, 
164                                  const Handle(Message_ProgressIndicator)& theProgress)
165 {
166   TDF_Label aRootLab = theData->Root();
167   XmlMDF_MapOfDriver aDriverMap;
168   CreateDrvMap (theDrivers, aDriverMap);
169
170   Standard_Integer count = 0;
171
172   LDOM_Node theNode = theElement.getFirstChild();
173   XmlObjMgt_Element anElem = (const XmlObjMgt_Element&)theNode;
174   while ( !anElem.isNull() )
175   {
176     if ( anElem.getNodeName().equals (::LabelString()) )
177     {
178       Standard_Integer subcount =
179         ReadSubTree(anElem, aRootLab, theRelocTable, aDriverMap, theProgress);
180       // check for error
181       if (subcount < 0)
182         return Standard_False;
183       count += subcount;
184     }
185     //anElem = (const XmlObjMgt_Element &) anElem.getNextSibling();
186     LDOM_Node theNode1 = anElem.getNextSibling();
187     anElem = (const XmlObjMgt_Element &) theNode1;
188   }
189
190   return Standard_True;
191 }
192
193 //=======================================================================
194 //function : ReadSubTree
195 //purpose  : 
196 //=======================================================================
197 Standard_Integer XmlMDF::ReadSubTree (const XmlObjMgt_Element&    theElement,
198                                       const TDF_Label&            theLabel,
199                                       XmlObjMgt_RRelocationTable& theRelocTable,
200                                       const XmlMDF_MapOfDriver&   theDriverMap, 
201                                       const Handle(Message_ProgressIndicator)& theProgress)
202 {
203   // Extraction of the driver subset.
204   Standard_Integer count = 0;
205
206   //XmlObjMgt_Element anElem = (const XmlObjMgt_Element &) theElement.getFirstChild();
207   LDOM_Node theNode = theElement.getFirstChild();
208   XmlObjMgt_Element anElem = (const XmlObjMgt_Element &) theNode;
209   Message_ProgressSentry aPS(theProgress, "Reading sub-tree", 0, 2, 1, true);
210   while ( !anElem.isNull() )
211   {
212     if ( anElem.getNodeType() == LDOM_Node::ELEMENT_NODE )
213     {
214       if ( anElem.getNodeName().equals (::LabelString()) )
215       {
216         // read tag
217         Standard_Integer tag;
218         XmlObjMgt_DOMString aTag (anElem.getAttribute(::TagString()));
219         if ( !aTag.GetInteger (tag) ) {
220           TCollection_ExtendedString anErrorMessage =
221             TCollection_ExtendedString ("Wrong Tag value for OCAF Label: ")
222               + aTag;
223           theDriverMap.Find("TDF_TagSource") -> myMessageDriver->Send (anErrorMessage, Message_Fail);
224           return -1;
225         }
226         // create label
227         TDF_Label aLab = theLabel.FindChild(tag, Standard_True);
228
229         // read sub-tree
230         Standard_Integer subcount =
231           ReadSubTree(anElem, aLab, theRelocTable, theDriverMap, theProgress);
232         // check for error
233         if (subcount == -1)
234           return -1;
235         count += subcount;
236       }
237       else
238       {
239         // read attribute
240         XmlObjMgt_DOMString aName = anElem.getNodeName();
241
242 #ifdef DATATYPE_MIGRATION
243         TCollection_AsciiString  newName;       
244         if(Storage_Schema::CheckTypeMigration(aName, newName)) {
245 #ifdef OCCT_DEBUG
246           std::cout << "CheckTypeMigration:OldType = " <<aName.GetString() << " Len = "<<strlen(aName.GetString())<<std::endl;
247           std::cout << "CheckTypeMigration:NewType = " <<newName  << " Len = "<< newName.Length()<<std::endl;
248 #endif
249           aName = newName.ToCString();
250         }
251 #endif  
252        
253         if (theDriverMap.IsBound (aName))
254         {
255           count++;
256           const Handle(XmlMDF_ADriver)& driver = theDriverMap.Find(aName);
257           XmlObjMgt_Persistent pAtt (anElem);
258           Standard_Integer anID = pAtt.Id ();
259           if (anID <= 0) {      // check for ID validity
260             TCollection_ExtendedString anErrorMessage =
261              TCollection_ExtendedString("Wrong ID of OCAF attribute with type ")
262                + aName;
263             driver -> myMessageDriver->Send (anErrorMessage, Message_Fail);
264             return -1;
265           }
266           Handle(TDF_Attribute) tAtt;
267           Standard_Boolean isBound = theRelocTable.IsBound(anID);
268           if (isBound)
269             tAtt = Handle(TDF_Attribute)::DownCast(theRelocTable.Find(anID));
270           else
271             tAtt = driver -> NewEmpty();
272
273           if (tAtt->Label().IsNull())
274           {
275             try
276             {
277               theLabel.AddAttribute (tAtt);
278             }
279             catch (const Standard_DomainError&)
280             {
281               // For attributes that can have arbitrary GUID (e.g. TDataStd_Integer), exception
282               // will be raised in valid case if attribute of that type with default GUID is already
283               // present  on the same label; the reason is that actual GUID will be read later.
284               // To avoid this, set invalid (null) GUID to the newly added attribute (see #29669)
285               static const Standard_GUID fbidGuid;
286               tAtt->SetID (fbidGuid);
287               theLabel.AddAttribute (tAtt);
288             }
289           }
290           else
291             driver->myMessageDriver->Send
292               (TCollection_ExtendedString("XmlDriver warning: ") +
293                "attempt to attach attribute " +
294                aName + " to a second label", Message_Warning);
295
296           if (! driver -> Paste (pAtt, tAtt, theRelocTable))
297           {
298             // error converting persistent to transient
299             driver->myMessageDriver->Send
300               (TCollection_ExtendedString("XmlDriver warning: ") +
301                "failure reading attribute " + aName, Message_Warning);
302           }
303           else if (isBound == Standard_False)
304             theRelocTable.Bind (anID, tAtt);
305         }
306 #ifdef OCCT_DEBUG
307         else
308         {
309           const TCollection_AsciiString anAsciiName = aName;
310           std::cerr << "XmlDriver warning: "
311                << "label contains object of unknown type "<< anAsciiName<< std::endl;
312         }
313 #endif
314       }
315     }
316     //anElem = (const XmlObjMgt_Element &) anElem.getNextSibling();
317     LDOM_Node theNode1 = anElem.getNextSibling();
318     anElem = (const XmlObjMgt_Element &) theNode1;
319
320     if (!aPS.More())
321       return -1;
322     aPS.Next();
323   }
324
325   // AfterRetrieval
326   if (count > 0)
327   {
328   }
329
330   return count;
331 }
332
333 //=======================================================================
334 //function : AddDrivers
335 //purpose  : 
336 //=======================================================================
337 void XmlMDF::AddDrivers (const Handle(XmlMDF_ADriverTable)& aDriverTable,
338                          const Handle(Message_Messenger)&   aMessageDriver)
339 {
340   aDriverTable->AddDriver (new XmlMDF_TagSourceDriver(aMessageDriver)); 
341   aDriverTable->AddDriver (new XmlMDF_ReferenceDriver(aMessageDriver));
342 }
343
344 //=======================================================================
345 //function : CreateDrvMap
346 //purpose  : 
347 //=======================================================================
348
349 void XmlMDF::CreateDrvMap (const Handle(XmlMDF_ADriverTable)& theDrivers,
350                            XmlMDF_MapOfDriver&                theAsciiDriverMap)
351 {
352   const XmlMDF_TypeADriverMap& aDriverMap = theDrivers->GetDrivers();
353   XmlMDF_DataMapIteratorOfTypeADriverMap anIter (aDriverMap);
354   while (anIter.More()) {
355     const Handle(XmlMDF_ADriver)& aDriver = anIter.Value();
356     const TCollection_AsciiString aTypeName = aDriver -> TypeName();
357     if (theAsciiDriverMap.IsBound (aTypeName) == Standard_False)
358       theAsciiDriverMap.Bind (aTypeName, aDriver);
359     else
360       aDriver -> myMessageDriver->Send
361         (TCollection_ExtendedString ("Warning: skipped driver name: \"")
362          + aTypeName + '\"', Message_Warning);
363     anIter.Next();
364   }
365 }