]> SALOME platform Git repositories - modules/gui.git/blob - src/DDS/DDS_Dictionary.cxx
Salome HOME
dd741872fb06cee80f2e880d4d1f76cf23cffca4
[modules/gui.git] / src / DDS / DDS_Dictionary.cxx
1 // Copyright (C) 2005  CEA/DEN, EDF R&D, OPEN CASCADE, PRINCIPIA R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library 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 GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 #include "DDS_Dictionary.h"
20
21 #include "DDS_KeyWords.h"
22
23 #include <LDOMString.hxx>
24 #include <LDOMParser.hxx>
25
26 #include <UnitsAPI.hxx>
27
28 #include <TColStd_SequenceOfInteger.hxx>
29 #include <TColStd_SequenceOfAsciiString.hxx>
30 #include <TColStd_SequenceOfExtendedString.hxx>
31
32 #include <NCollection_Map.hxx>
33
34 #include <Standard_Failure.hxx>
35 #include <Standard_ErrorHandler.hxx>
36
37 IMPLEMENT_STANDARD_HANDLE(DDS_Dictionary, MMgt_TShared)
38 IMPLEMENT_STANDARD_RTTIEXT(DDS_Dictionary, MMgt_TShared)
39
40 /*!
41   \class DDS_Dictionary
42   
43   This class to provide information about used datums, reading them from 'xml' file
44
45   Datum is the set of parameters described a phisical characteristic. These parameters loaded from
46   special XML which has following format:
47
48   \hr
49
50   <D_URI>
51   <COMPONENT COMPONENT_NAME="component_name">
52     <UNIT_SYSTEMS>
53       <UNIT_SYSTEM UNIT_SYSTEM_NAME="[system_internal_name]" UNIT_SYSTEM_LABEL="[system_label]">
54       <UNIT_SYSTEM UNIT_SYSTEM_NAME="[system_internal_name]" UNIT_SYSTEM_LABEL="[system_label]">
55       ...
56       <UNIT_SYSTEM UNIT_SYSTEM_NAME="[system_internal_name]" UNIT_SYSTEM_LABEL="[system_label]">
57     </UNIT_SYSTEMS>
58
59     <DATUM DATUM_UNITS="[base_system_internal_name]" DATUM_FORMAT="[sprintf_format_specification]"
60            DATUM_ID="[datum_id]" DATUM_LABEL="[datum_label]" DATUM_REQUIRED="[requred_value]"
61            DATUM_FILTER="[string_regular_expression]">
62       <DY_DOMAIN>
63         <VALUE_DESCR VD_DEFV="[default_value]" VD_MAXV="[max_value]" VD_MINV="[min_value]" VD_TYPE="[value_type]"/>
64         <VALUE_LIST_REF VLR_LIST="[referenced_list_id]"/>
65       </DY_DOMAIN>
66       <DESCR>
67         <SHORT_D>[brief_desription_text]</SHORT_D>
68         <LONG_D>[full_description_text]</LONG_D>
69       </DESCR>
70       <OPTIONS>
71         <OPTION OPTION_NAME="[option_name_1]">[option_value_1]</OPTION>
72         <OPTION OPTION_NAME="[option_name_2]">[option_value_2]</OPTION>
73         ...
74         <OPTION OPTION_NAME="[option_name_n]">[option_value_n]</OPTION>
75       </OPTIONS>
76     </DATUM>
77
78     ...
79
80     <VALUE_LIST VALUE_LIST_ID="[list_id]" VALUE_LIST_NAME="[list_name]">
81       <VALUE_LIST_VALUE VALUE_LIST_VALUEID="[list_element_id]" VALUE_LIST_VALUEICON="[list_element_icon_file]">[list_element_name]</VALUE_LIST_VALUE>
82       <VALUE_LIST_VALUE VALUE_LIST_VALUEID="[list_element_id]" VALUE_LIST_VALUEICON="[list_element_icon_file]">[list_element_name]</VALUE_LIST_VALUE>
83       ...
84       <VALUE_LIST_VALUE VALUE_LIST_VALUEID="[list_element_id]" VALUE_LIST_VALUEICON="[list_element_icon_file]">[list_element_name]</VALUE_LIST_VALUE>
85     </VALUE_LIST>
86
87     ...
88
89     </COMPONENT>
90   </D_URI>
91
92   \hr
93
94   In description of datum file format used internal keys as XML tag and attributes names.
95   Concrete XML keywords defined by DDS_KeyWords class.
96
97   Describe datum file format more detailed. XML file should have one main tag named as "dictionary" (key "D_URI").
98   This tag should contains one or several components. Component is a independent set of datums and unit systems.
99   Components defined as XML tag named "component" (key "COMPONENT") with attribute "name" (key COMPONENT_NAME).
100   Component name used as component identifier and should be unique. Component tag can contains:
101
102   \li Tag "unit_systems" (key UNIT_SYSTEMS) defines set of used unit systems. Should exist at least one unit
103   system named SI ("System International"). If this system not exist then it will be defined automatically.
104   Each unit system defined by XML tag "unit system" (key UNIT_SYSTEM) under tag "unit_systems" with attributes
105   "name" (key UNIT_SYSTEM_NAME) and "label" (key UNIT_SYSTEM_LABEL). Name is identifier of unit system. Label is
106   human readable description.
107
108   \li One or several tag "datum" (key DATUM). For this tag can be defined following attributes:
109
110       \lo Identifier (key DATUM_ID) specify the unique id string for the datum.
111       \lo Label (key DATUM_LABEL) specify human readable name of the datum.
112       \lo Units of measure (key DATUM_UNITS) for given unit system. Attribute name consist of a name
113           of unit system and a keyword got from DDS_KeyWords by key DATUM_UNITS. For example for unit system
114           named SI and default keyword attribute name will be "SIunits". This attribute should be specified
115           for each deaclared unit system. Value of this attribute should be string describs units of measure.
116           Possible designations for units of measure and their multiple prefixes see in package UnitsAPI of
117           library OpenCascade (files Units.dat and Lexi_Expr.dat). Units of measure will be used for numeric
118           value conversion from one unit system to another one.
119       \lo Format (key DATUM_FORMAT) specify the format string which will be used during initial formatting
120           of value. This string should be specified in sprintf() format.
121       \lo Filter (key DATUM_FILTER) specify the regualr expression. Each user entered string will be checked up
122           on matching to this expression (if it defined). Non matched strings will be rejected.
123       \lo Required value (key DATUM_REQUIRED). If this attributed defined and value is true then user can't
124           leave a input filed blank (parameter must be always entered).
125
126       Tag "description" (key DESCR) can be defined under the tag "datum". This tag contains two sub tags:
127          \lo "short description" (key SHORT_D) specify a brief datum description text
128          \lo "long description" (key LONG_D) specify a detailed description text
129
130       Tag "options" (key OPTIONS) can be defined under the tag "datum". This tag contains one or more sub
131       tags "option" (key OPTION). Each of these XML elements should contain text option value and attribute
132       "name" (key OPTION_NAME) which specified option name.
133
134       Each tag "datum" define most common parameters of phisical characteristic.
135       This parameters placed in two groups:
136       \lo Domain parameters under tag "domain" (key DY_DOMAIN). This tag can contains value description tag
137           (key VALUE_DESCR) for discrete data or list reference tag (key VALUE_LIST_REF) for enumerable data.
138           Discrete data described following parameters:
139             default value (key VD_DEFV)
140             maximum value (key VD_MAXV)
141             minimum value (key VD_MINV)
142             type of value (key VD_TYPE) - possible values: String, Integer, Float, List
143           Enumerable data described by "list reference" attribute (key VLR_LIST) which reference on
144           list (see "list definition" tag) by list id.
145
146   \li One or several tag "list definition" (key VALUE_LIST). This tag define the list of items for enumerable
147       data. Attribute "list id" (key VALUE_LIST_ID) specify the identifier string for the list and attribute
148       "list name" (key VALUE_LIST_NAME) define a list name string. Each list item described by tag "list value"
149       (key VALUE_LIST_VALUE) under tag "list definition". Each this tag contains item string text and have
150       following attributes:
151         \lo "list item id" (key VALUE_LIST_VALUEID) - integer numerical identifier for item
152         \lo "list item icon" (key VALUE_LIST_VALUEICON) - icon file name for item
153
154   Below the example of a XML file with use default keywords.
155
156   <datadictionary version="1.0">
157     <component name="My Component">
158
159       <!-- specify two unit systems -->
160
161       <unitSystems>
162         <system name="SI" label="System international">
163         <system name="AS" label="Anglo - sacson system">
164       </unitSystems>
165
166       <!-- specify datum -->
167       <!-- units of measure for SI - meters (m), for AS - inches (in) -->
168       <datum SIunits="m" ASunits="in" format="%.25f" id="X" label="X coordinate" required="">
169         <domain>
170           <!-- default value not specified -->
171           <valueDescr default="" max="999999999.999" min="0.000" type="Float"/>
172         </domain>
173         <description>
174           <shortDescr>X coordinate for object</shortDescr>
175           <longDescr>X multiplier of object coordinates. Describe position of object in direction of X axis</longDescr>
176         </description>
177       </datum>
178
179       <datum SIunits="m" ASunits="in" format="%.25f" id="Y" label="Y coordinate" required="">
180         <domain>
181           <valueDescr default="" max="999999999.999" min="0.000" type="Float"/>
182         </domain>
183         <description>
184           <shortDescr>Y coordinate for object</shortDescr>
185           <longDescr>Y multiplier of object coordinates. Describe position of object in direction of Y axis</longDescr>
186         </description>
187       </datum>
188
189       <!-- datum for object name with filter which not allow to input more that 8 letters,
190            numbers or unerscores with first letter only -->
191       <datum format="%.8us" id="ObjectName" label="Name" required="yes"
192              filter="^([A-Z]+)([A-Z,0-9,_]*)$">
193         <domain>
194           <!-- limits and default not specified, type is string -->
195           <valueDescr default="" max="" min="" type="String" />
196         </domain>
197         <description>
198           <!-- long description not specified -->
199           <shortDescr>Name of object</shortDescr>
200         </description>
201       </datum>
202
203
204       <!-- datum for enumeration of side -->
205       <datum format="" id="Side" label="Side" required="">
206         <domain>
207           <!-- default list item is item with id 0 -->
208           <valueDescr default="0" type="List"/>
209           <!-- list reference on list named "side_list" -->
210           <listRef list="side_list"/>
211         </domain>
212         <description>
213           <shortDescr>Side of object</shortDescr>
214         </description>
215       </datum>
216
217       <!-- list definition for enumeration of side -->
218       <valueList listid="side_list" name="Side">
219         <value id="1">left</value>
220         <value id="2">right</value>
221         <value id="3">top</value>
222         <value id="4">bottom</value>
223         <value id="0">undefined</value>
224       </valueList>
225
226     </component>
227   </datadictionary>
228
229
230 */
231
232 /*!
233   Constructor. Creates the instance of dictionary. Private method. Use DDS_Dictionary::Get() instead.
234 */
235 DDS_Dictionary::DDS_Dictionary()
236 : MMgt_TShared()
237 {
238 }
239
240 /*!
241   Copy constructor. Internal.
242 */
243 DDS_Dictionary::DDS_Dictionary( const DDS_Dictionary& )
244 {
245 }
246
247 /*!
248   Assigment operator. Internal.
249 */
250 void DDS_Dictionary::operator=( const DDS_Dictionary& )
251 {
252 }
253
254 /*!
255   Returns the names list of defined unit systems from all components.
256   Parameter \atheSystems will contains the sequence of string names.
257 */
258 void DDS_Dictionary::GetUnitSystems( TColStd_SequenceOfAsciiString& theSystems ) const
259 {
260   theSystems.Clear();
261
262   NCollection_Map<TCollection_AsciiString> aMap;
263   for ( Standard_Integer i = 1; i <= myGroupMap.Extent(); i++ )
264   {
265     TColStd_SequenceOfAsciiString theSeq;
266     myGroupMap.FindFromIndex( i )->GetUnitSystems( theSeq );
267     for ( Standard_Integer s = 1; s <= theSeq.Length(); s++ )
268     {
269       if ( aMap.Contains( theSeq.Value( s ) ) )
270         continue;
271
272       theSystems.Append( theSeq.Value( s ) );
273       aMap.Add( theSeq.Value( s ) );
274     }
275   }
276
277 }
278
279 /*!
280   Returns the names list of defined unit systems from the specified component \atheComponent.
281   Parameter \atheSystems will contains the sequence of string names. If component not found then
282   empty list returned.
283 */
284 void DDS_Dictionary::GetUnitSystems( TColStd_SequenceOfAsciiString& theSystems,
285                                      const TCollection_AsciiString& theComponent ) const
286 {
287   theSystems.Clear();
288   if ( myGroupMap.Contains( theComponent ) )
289     myGroupMap.FindFromKey( theComponent )->GetUnitSystems( theSystems );
290 }
291
292 /*!
293   Returns the label of unit system \atheSystem. Function find the given unit system in
294   all components. If unit system not found in any component then empty string returned.
295 */
296 TCollection_ExtendedString DDS_Dictionary::GetUnitSystemLabel( const TCollection_AsciiString& theSystem ) const
297 {
298   TCollection_ExtendedString aLabel;
299   for ( Standard_Integer i = 1; i <= myGroupMap.Extent() && !aLabel.Length(); i++ )
300     aLabel = myGroupMap.FindFromIndex( i )->GetUnitSystemLabel( theSystem );
301   return aLabel;
302 }
303
304 /*!
305   Returns the label of unit system \atheSystem from component \atheComponent. Function find
306   the given unit system in the specified component only. If unit system not found in the
307   component then empty string returned.
308 */
309 TCollection_ExtendedString DDS_Dictionary::GetUnitSystemLabel( const TCollection_AsciiString& theSystem,
310                                                                const TCollection_AsciiString& theComponent ) const
311 {
312   TCollection_ExtendedString aLabel;
313   if ( myGroupMap.Contains( theComponent ) )
314     aLabel = myGroupMap.FindFromKey( theComponent )->GetUnitSystemLabel( theSystem );
315   return aLabel;
316 }
317
318 /*!
319   Gets the name of active unit system from first got component. If any component exist then
320   active unit system name returned or empty string otherwise.
321 */
322 TCollection_AsciiString DDS_Dictionary::GetActiveUnitSystem() const
323 {
324   TCollection_AsciiString aSystem;
325   if ( myGroupMap.Extent() )
326     aSystem = myGroupMap.FindFromIndex( 1 )->GetActiveUnitSystem();
327   return aSystem;
328 }
329
330 /*!
331   Gets the name of active unit system from component \atheComponent. If this component exist
332   active unit system name returned or empty string otherwise.
333 */
334 TCollection_AsciiString DDS_Dictionary::GetActiveUnitSystem( const TCollection_AsciiString& theComponent ) const
335 {
336   TCollection_AsciiString aSystem;
337   if ( myGroupMap.Contains( theComponent ) )
338     aSystem = myGroupMap.FindFromKey( theComponent )->GetActiveUnitSystem();
339   return aSystem;
340 }
341
342 /*!
343   Sets the active unit system named \atheSystem. This unit system will be activated in all
344   existing components if component have it.
345 */
346 void DDS_Dictionary::SetActiveUnitSystem( const TCollection_AsciiString& theSystem )
347 {
348   for ( Standard_Integer i = 1; i <= myGroupMap.Extent(); i++ )
349     myGroupMap.FindFromIndex( i )->SetActiveUnitSystem( theSystem );
350 }
351
352 /*!
353   Sets the active unit system named \atheSystem for component \atheComponent. If specified unit
354   system doesn't exist in the component then function do nothing.
355 */
356 void DDS_Dictionary::SetActiveUnitSystem( const TCollection_AsciiString& theSystem,
357                                           const TCollection_AsciiString& theComponent )
358 {
359   if ( myGroupMap.Contains( theComponent ) )
360     myGroupMap.FindFromKey( theComponent )->SetActiveUnitSystem( theSystem );
361 }
362
363 /*!
364   Returns the instance of dictionary. Create instance if it is NULL.
365 */
366 Handle(DDS_Dictionary) DDS_Dictionary::Get()
367 {
368   static Handle(DDS_Dictionary) sDictionary;
369
370   if ( sDictionary.IsNull() )
371     sDictionary = new DDS_Dictionary();
372
373   return sDictionary;
374 }
375
376 /*!
377   Load datum definitions in the dictionary from XML file \atheFileName. Returns true if load
378   successed or false otherwise.
379 */
380 Standard_Boolean DDS_Dictionary::Load( const TCollection_AsciiString theFileName )
381 {
382   static NCollection_Map<TCollection_AsciiString> _LoadMap;
383
384   if ( _LoadMap.Contains( theFileName ) )
385     return Standard_True;
386
387   Handle(DDS_Dictionary) aDic = Get();
388   if ( aDic.IsNull() )
389     return Standard_False;
390
391   LDOMParser aParser;
392   if ( aParser.parse( theFileName.ToCString() ) )
393     return Standard_False;
394
395   LDOM_Document aDoc = aParser.getDocument();
396   LDOM_Element aDocElement = aDoc.getDocumentElement();
397   for ( LDOM_Element aComponentElem = aDocElement.GetChildByTagName( KeyWord( "COMPONENT" ) );
398         !aComponentElem.isNull(); aComponentElem = aComponentElem.GetSiblingByTagName() )
399     aDic->FillDataMap( aComponentElem, aDocElement );
400
401   _LoadMap.Add( theFileName );
402
403   return Standard_True;
404 }
405
406 /*!
407   Gets XML keyword as LDOMString by specified \akey. If key doesn't exist then empty string
408   returned. This function provided for convenience.
409 */
410 LDOMString DDS_Dictionary::KeyWord( const TCollection_AsciiString& key )
411 {
412   LDOMString keyWord;
413   Handle(DDS_KeyWords) aKeyWords = DDS_KeyWords::Get();
414   if ( !aKeyWords.IsNull() )
415   {
416     TCollection_AsciiString aStr = aKeyWords->GetKeyWord( key );
417     if ( aStr.Length() )
418       keyWord = LDOMString( aStr.ToCString() );
419   }
420   return keyWord;
421 }
422
423 /*!
424   Gets dictionary item with specified identifier \atheID from specified component \atheComponent.
425   If component or item not found then null handle returned.
426 */
427 Handle(DDS_DicItem) DDS_Dictionary::GetDicItem( const TCollection_AsciiString& theID,
428                                                 const TCollection_AsciiString& theComponent ) const
429 {
430   Handle(DDS_DicItem) aDicItem;
431   Handle(DDS_DicGroup) aDicGroup;
432   if ( myGroupMap.Contains( theComponent ) )
433     aDicGroup = myGroupMap.FindFromKey( theComponent );
434   if ( !aDicGroup.IsNull() )
435     aDicItem = aDicGroup->GetDicItem( theID );
436   return aDicItem;
437 }
438
439 /*!
440   Gets dictionary item with specified identifier \atheID. Function find the item in all components.
441   If item not found in any component then null handle returned.
442 */
443 Handle(DDS_DicItem) DDS_Dictionary::GetDicItem( const TCollection_AsciiString& theID ) const
444 {
445   Handle(DDS_DicItem) aDicItem;
446   for ( Standard_Integer i = 1; i <= myGroupMap.Extent() && aDicItem.IsNull(); i++ )
447     aDicItem = myGroupMap.FindFromIndex( i )->GetDicItem( theID );
448   return aDicItem;
449 }
450
451 /*!
452   Fill the internal data structures from XML parsed structures. Internal.
453 */
454 void DDS_Dictionary::FillDataMap( const LDOM_Element& theComponentData, const LDOM_Element& theDocElement )
455 {
456   TCollection_AsciiString aCompName = theComponentData.getAttribute( KeyWord( "COMPONENT_NAME" ) );
457   if ( !myGroupMap.Contains( aCompName ) )
458     myGroupMap.Add( aCompName, new DDS_DicGroup( aCompName ) );
459   Handle(DDS_DicGroup) aDicGroup = myGroupMap.FindFromKey( aCompName );
460   aDicGroup->FillDataMap( theComponentData, theDocElement );
461   myGroupMap.Add( aCompName, aDicGroup );
462 }
463
464 /*!
465   Convert numeric value \atheValue from specified unit of measure \atheUnits to SI unit of measure
466   (mm for Length, radians for Angles, etc). Converted value returned.
467 */
468 Standard_Real DDS_Dictionary::ToSI( const Standard_Real theValue, const Standard_CString theUnits )
469 {
470   Standard_Real aRetValue = theValue;
471   if ( theUnits && *theUnits && strcmp( theUnits, "%" ) )
472   {
473     try {
474 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
475       OCC_CATCH_SIGNALS;
476 #endif
477       aRetValue = UnitsAPI::AnyToSI( theValue, theUnits );
478     }
479     catch( Standard_Failure ) {
480     }
481   }
482   else if ( theUnits && *theUnits )
483     aRetValue = theValue / 100.0;
484
485   return aRetValue;
486 }
487
488 /*!
489   Convert numeric value \atheValue to specified unit of measure \atheUnits from SI unit of measure
490   (mm for Length, radians for Angles, etc). Converted value returned.
491 */
492 Standard_Real DDS_Dictionary::FromSI( const Standard_Real theValue, const Standard_CString theUnits )
493 {
494   Standard_Real aRetValue = theValue;
495   if ( theUnits && *theUnits && strcmp( theUnits, "%" ) )
496   {
497     try {
498 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
499       OCC_CATCH_SIGNALS;
500 #endif
501       aRetValue = UnitsAPI::AnyFromSI( theValue, theUnits );
502     }
503     catch( Standard_Failure ) {
504     }
505   }
506   else if ( theUnits && *theUnits )
507     aRetValue = theValue * 100.0;
508
509   return aRetValue;
510 }