0030773: Application Framework - To allow to inherit existing attributes to reuse...
[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   // write attributes
90   Standard_Integer count = 0;
91   TDF_AttributeIterator itr1 (theLabel);
92   for ( ; itr1.More(); itr1.Next())
93   {
94     const Handle(TDF_Attribute)& tAtt = itr1.Value();
95     const Handle(Standard_Type)& aType = tAtt->DynamicType();
96     Handle(XmlMDF_ADriver) aDriver;
97     if (theDrivers->GetDriver(aType, aDriver))
98     {
99       count++;
100
101       //    Add source to relocation table
102       Standard_Integer anId      = theRelocTable.Add (tAtt);
103
104       //    Create DOM data item
105       XmlObjMgt_Persistent pAtt;
106       // In the document version 8 the attribute TPrsStd_AISPresentation
107       // was replaced by TDataXtd_Presentation. Therefore, for old versions
108       // we write old name of the attribute (TPrsStd_AISPresentation).
109       Standard_CString typeName = aDriver->TypeName().ToCString();
110       if (XmlLDrivers::StorageVersion() < 8 &&
111           strcmp(typeName, "TDataXtd_Presentation") == 0)
112       {
113         typeName = "TPrsStd_AISPresentation";
114       }
115       pAtt.CreateElement (aLabElem, typeName, anId);
116
117       //    Paste
118       aDriver -> Paste (tAtt, pAtt, theRelocTable);
119     }
120 #ifdef OCCT_DEBUG
121     else if (!UnsuppTypesMap().Contains (aType))
122     {
123       std::cout << "attribute driver for type "<< aType -> Name()<< " not found"<< std::endl;
124       UnsuppTypesMap().Add (aType);
125     }
126 #endif
127   }
128
129   // write sub-labels
130   TDF_ChildIterator itr2 (theLabel);
131   Standard_Real child_count = 0;
132   for (; itr2.More(); ++child_count, itr2.Next())
133   {
134   }
135   itr2.Initialize(theLabel);
136   Message_ProgressSentry aPS(theProgress, "Writing sub-tree", 0, child_count, 1);
137   for ( ; itr2.More() && aPS.More(); itr2.Next(), aPS.Next())
138   {
139     const TDF_Label& aChildLab = itr2.Value();
140     count += WriteSubTree(aChildLab, aLabElem, theRelocTable, theDrivers, theProgress);
141   }
142
143   if (count > 0 || TDocStd_Owner::GetDocument(theLabel.Data())->EmptyLabelsSavingMode())
144   {
145     theElement.appendChild(aLabElem);
146
147     // set attribute "tag"
148     aLabElem.setAttribute (::TagString(), theLabel.Tag());
149   }
150   return count;
151 }
152
153 //=======================================================================
154 //function : FromTo
155 //purpose  : Paste data from DOM_Element into transient document
156 //=======================================================================
157 Standard_Boolean XmlMDF::FromTo (const XmlObjMgt_Element&         theElement,
158                                  Handle(TDF_Data)&                theData,
159                                  XmlObjMgt_RRelocationTable&      theRelocTable,
160                                  const Handle(XmlMDF_ADriverTable)& theDrivers, 
161                                  const Handle(Message_ProgressIndicator)& theProgress)
162 {
163   TDF_Label aRootLab = theData->Root();
164   XmlMDF_MapOfDriver aDriverMap;
165   theDrivers->CreateDrvMap (aDriverMap);
166
167   Standard_Integer count = 0;
168
169   LDOM_Node theNode = theElement.getFirstChild();
170   XmlObjMgt_Element anElem = (const XmlObjMgt_Element&)theNode;
171   while ( !anElem.isNull() )
172   {
173     if ( anElem.getNodeName().equals (::LabelString()) )
174     {
175       Standard_Integer subcount =
176         ReadSubTree(anElem, aRootLab, theRelocTable, aDriverMap, theProgress);
177       // check for error
178       if (subcount < 0)
179         return Standard_False;
180       count += subcount;
181     }
182     //anElem = (const XmlObjMgt_Element &) anElem.getNextSibling();
183     LDOM_Node theNode1 = anElem.getNextSibling();
184     anElem = (const XmlObjMgt_Element &) theNode1;
185   }
186
187   return Standard_True;
188 }
189
190 //=======================================================================
191 //function : ReadSubTree
192 //purpose  : 
193 //=======================================================================
194 Standard_Integer XmlMDF::ReadSubTree (const XmlObjMgt_Element&    theElement,
195                                       const TDF_Label&            theLabel,
196                                       XmlObjMgt_RRelocationTable& theRelocTable,
197                                       const XmlMDF_MapOfDriver&   theDriverMap, 
198                                       const Handle(Message_ProgressIndicator)& theProgress)
199 {
200   // Extraction of the driver subset.
201   Standard_Integer count = 0;
202
203   //XmlObjMgt_Element anElem = (const XmlObjMgt_Element &) theElement.getFirstChild();
204   LDOM_Node theNode = theElement.getFirstChild();
205   XmlObjMgt_Element anElem = (const XmlObjMgt_Element &) theNode;
206   Message_ProgressSentry aPS(theProgress, "Reading sub-tree", 0, 2, 1, true);
207   while ( !anElem.isNull() )
208   {
209     if ( anElem.getNodeType() == LDOM_Node::ELEMENT_NODE )
210     {
211       if ( anElem.getNodeName().equals (::LabelString()) )
212       {
213         // read tag
214         Standard_Integer tag;
215         XmlObjMgt_DOMString aTag (anElem.getAttribute(::TagString()));
216         if ( !aTag.GetInteger (tag) ) {
217           TCollection_ExtendedString anErrorMessage =
218             TCollection_ExtendedString ("Wrong Tag value for OCAF Label: ")
219               + aTag;
220           theDriverMap.Find("TDF_TagSource") -> myMessageDriver->Send (anErrorMessage, Message_Fail);
221           return -1;
222         }
223         // create label
224         TDF_Label aLab = theLabel.FindChild(tag, Standard_True);
225
226         // read sub-tree
227         Standard_Integer subcount =
228           ReadSubTree(anElem, aLab, theRelocTable, theDriverMap, theProgress);
229         // check for error
230         if (subcount == -1)
231           return -1;
232         count += subcount;
233       }
234       else
235       {
236         // read attribute
237         XmlObjMgt_DOMString aName = anElem.getNodeName();
238
239 #ifdef DATATYPE_MIGRATION
240         TCollection_AsciiString  newName;       
241         if(Storage_Schema::CheckTypeMigration(aName, newName)) {
242 #ifdef OCCT_DEBUG
243           std::cout << "CheckTypeMigration:OldType = " <<aName.GetString() << " Len = "<<strlen(aName.GetString())<<std::endl;
244           std::cout << "CheckTypeMigration:NewType = " <<newName  << " Len = "<< newName.Length()<<std::endl;
245 #endif
246           aName = newName.ToCString();
247         }
248 #endif  
249        
250         if (theDriverMap.IsBound (aName))
251         {
252           count++;
253           const Handle(XmlMDF_ADriver)& driver = theDriverMap.Find(aName);
254           XmlObjMgt_Persistent pAtt (anElem);
255           Standard_Integer anID = pAtt.Id ();
256           if (anID <= 0) {      // check for ID validity
257             TCollection_ExtendedString anErrorMessage =
258              TCollection_ExtendedString("Wrong ID of OCAF attribute with type ")
259                + aName;
260             driver -> myMessageDriver->Send (anErrorMessage, Message_Fail);
261             return -1;
262           }
263           Handle(TDF_Attribute) tAtt;
264           Standard_Boolean isBound = theRelocTable.IsBound(anID);
265           if (isBound)
266             tAtt = Handle(TDF_Attribute)::DownCast(theRelocTable.Find(anID));
267           else
268             tAtt = driver -> NewEmpty();
269
270           if (tAtt->Label().IsNull())
271           {
272             try
273             {
274               theLabel.AddAttribute (tAtt);
275             }
276             catch (const Standard_DomainError&)
277             {
278               // For attributes that can have arbitrary GUID (e.g. TDataStd_Integer), exception
279               // will be raised in valid case if attribute of that type with default GUID is already
280               // present  on the same label; the reason is that actual GUID will be read later.
281               // To avoid this, set invalid (null) GUID to the newly added attribute (see #29669)
282               static const Standard_GUID fbidGuid;
283               tAtt->SetID (fbidGuid);
284               theLabel.AddAttribute (tAtt);
285             }
286           }
287           else
288             driver->myMessageDriver->Send
289               (TCollection_ExtendedString("XmlDriver warning: ") +
290                "attempt to attach attribute " +
291                aName + " to a second label", Message_Warning);
292
293           if (! driver -> Paste (pAtt, tAtt, theRelocTable))
294           {
295             // error converting persistent to transient
296             driver->myMessageDriver->Send
297               (TCollection_ExtendedString("XmlDriver warning: ") +
298                "failure reading attribute " + aName, Message_Warning);
299           }
300           else if (isBound == Standard_False)
301             theRelocTable.Bind (anID, tAtt);
302         }
303 #ifdef OCCT_DEBUG
304         else
305         {
306           const TCollection_AsciiString anAsciiName = aName;
307           std::cerr << "XmlDriver warning: "
308                << "label contains object of unknown type "<< anAsciiName<< std::endl;
309         }
310 #endif
311       }
312     }
313     //anElem = (const XmlObjMgt_Element &) anElem.getNextSibling();
314     LDOM_Node theNode1 = anElem.getNextSibling();
315     anElem = (const XmlObjMgt_Element &) theNode1;
316
317     if (!aPS.More())
318       return -1;
319     aPS.Next();
320   }
321
322   // AfterRetrieval
323   if (count > 0)
324   {
325   }
326
327   return count;
328 }
329
330 //=======================================================================
331 //function : AddDrivers
332 //purpose  : 
333 //=======================================================================
334 void XmlMDF::AddDrivers (const Handle(XmlMDF_ADriverTable)& aDriverTable,
335                          const Handle(Message_Messenger)&   aMessageDriver)
336 {
337   aDriverTable->AddDriver (new XmlMDF_TagSourceDriver(aMessageDriver)); 
338   aDriverTable->AddDriver (new XmlMDF_ReferenceDriver(aMessageDriver));
339 }