1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "DDS_Dictionary.h"
25 #include "DDS_KeyWords.h"
27 #include <Basics_OCCTVersion.hxx>
29 #include <LDOMString.hxx>
30 #include <LDOMParser.hxx>
32 #include <UnitsAPI.hxx>
34 #include <TColStd_SequenceOfInteger.hxx>
35 #include <TColStd_SequenceOfAsciiString.hxx>
36 #include <TColStd_SequenceOfExtendedString.hxx>
38 #include <NCollection_Map.hxx>
40 #include <Standard_Failure.hxx>
41 #include <Standard_ErrorHandler.hxx>
43 IMPLEMENT_STANDARD_HANDLE(DDS_Dictionary, MMgt_TShared)
44 IMPLEMENT_STANDARD_RTTIEXT(DDS_Dictionary, MMgt_TShared)
46 Handle(DDS_Dictionary) DDS_Dictionary::myDictionary = Handle(DDS_Dictionary)();
50 \brief This class provides an information about used datums,
51 reading them from XML file.
53 There is the only instance of the class DDS_Dictionary in the application
54 which can be retrieved by method Get().
56 Datum is a set of parameters describing a phisical characteristic.
57 These parameters are loaded from the XML file which has the following format:
61 <COMPONENT COMPONENT_NAME="component_name">
63 <UNIT_SYSTEM UNIT_SYSTEM_NAME="[system_internal_name]" UNIT_SYSTEM_LABEL="[system_label]">
64 <UNIT_SYSTEM UNIT_SYSTEM_NAME="[system_internal_name]" UNIT_SYSTEM_LABEL="[system_label]">
66 <UNIT_SYSTEM UNIT_SYSTEM_NAME="[system_internal_name]" UNIT_SYSTEM_LABEL="[system_label]">
69 <DATUM DATUM_UNITS="[base_system_internal_name]" DATUM_FORMAT="[sprintf_format_specification]"
70 DATUM_ID="[datum_id]" DATUM_LABEL="[datum_label]" DATUM_REQUIRED="[requred_value]"
71 DATUM_FILTER="[string_regular_expression]">
73 <VALUE_DESCR VD_DEFV="[default_value]" VD_MAXV="[max_value]" VD_MINV="[min_value]" VD_TYPE="[value_type]"/>
74 <VALUE_LIST_REF VLR_LIST="[referenced_list_id]"/>
77 <SHORT_D>[brief_desription_text]</SHORT_D>
78 <LONG_D>[full_description_text]</LONG_D>
81 <OPTION OPTION_NAME="[option_name_1]">[option_value_1]</OPTION>
82 <OPTION OPTION_NAME="[option_name_2]">[option_value_2]</OPTION>
84 <OPTION OPTION_NAME="[option_name_n]">[option_value_n]</OPTION>
90 <VALUE_LIST VALUE_LIST_ID="[list_id]" VALUE_LIST_NAME="[list_name]">
91 <VALUE_LIST_VALUE VALUE_LIST_VALUEID="[list_element_id]" VALUE_LIST_VALUEICON="[list_element_icon_file]">[list_element_name]</VALUE_LIST_VALUE>
92 <VALUE_LIST_VALUE VALUE_LIST_VALUEID="[list_element_id]" VALUE_LIST_VALUEICON="[list_element_icon_file]">[list_element_name]</VALUE_LIST_VALUE>
94 <VALUE_LIST_VALUE VALUE_LIST_VALUEID="[list_element_id]" VALUE_LIST_VALUEICON="[list_element_icon_file]">[list_element_name]</VALUE_LIST_VALUE>
104 In above description of the datum XML file format internal keys are used as XML tags
105 and attributes names. Real XML keywords are defined by DDS_KeyWords class.
107 XML file should have one main tag named "dictionary" (key "D_URI"). This tag
108 should contain one or several components.
109 Component is an independent set of datums and units systems.
110 Components are defined by XML tag named "component" (key "COMPONENT") with
111 attribute "name" (key COMPONENT_NAME).
112 Component name is used as component identifier and should be unique.
114 Component tag can contain:
116 - Tag "unit_systems" (key UNIT_SYSTEMS) defines a set of used units systems.
117 At least one unit system named SI ("System International") should exist.
118 If this system does not exist, it will be created automatically.
119 Each units system is defined by XML tag "unit system" (key UNIT_SYSTEM) under
120 the tag "unit_systems" with attributes "name" (key UNIT_SYSTEM_NAME)
121 and "label" (key UNIT_SYSTEM_LABEL). Name is an identifier of the units system and
122 label is its human readable description.
124 - One or several tags "datum" (key DATUM). For this tag the following attributes
126 -# Identifier (key DATUM_ID) specifies the unique id string for the datum.
127 -# Label (key DATUM_LABEL) specifies human readable name of the datum.
128 -# Measure units (key DATUM_UNITS) for the given units system. Attribute name
129 defines a name of units system and a keyword got from DDS_KeyWords by key DATUM_UNITS.
130 For example, for "SI" units system and default keyword the attribute name is "SIunits".
131 This attribute should be specified for each declared units system.
132 Value of this attribute should be a string describing measure units.
133 For possible designations for measure units and their multiple prefixes
134 please refer to the UnitsAPI package of the OpenCascade library
135 (files Units.dat and Lexi_Expr.dat). Measure units are used for numerical
136 values conversion from one units system to another one.
137 -# Format (key DATUM_FORMAT) specifies the format string which will be used
138 during initial formatting of the value. This string should be specified
140 -# Filter (key DATUM_FILTER) specifies the regualr expression. The value (string)
141 entered by the user will be checked up to match to this regular expression
142 (if it defined). Non matched strings will be rejected.
143 -# Required value (key DATUM_REQUIRED). If this attributed si defined and its value
144 is \c true then user can't leave an input non-filled - parameter must be explicitly
145 entered by the user).
147 - One or several tags "list definition" (key VALUE_LIST). Each such tag defines
148 the list of items for enumerable data. Attribute "list id" (key VALUE_LIST_ID)
149 specifies the identifier string for the list and attribute "list name"
150 (key VALUE_LIST_NAME) defines a list name string. Each list item is described
151 by tag "list value" (key VALUE_LIST_VALUE) under the tag "list definition".
152 Each this tag contains item string text and have the following attributes:
153 -# "list item id" (key VALUE_LIST_VALUEID) - integer numerical identifier for
155 -# "list item icon" (key VALUE_LIST_VALUEICON) - icon file name for the item
157 Tag "datum" can have child subtags "description" and "options".
159 - Tag "description" (key DESCR) contains two sub tags:
160 -# "short description" (key SHORT_D) specifies a brief datum description text
161 -# "long description" (key LONG_D) specifies a detailed description text
163 - Tag "options" (key OPTIONS) contains one or more sub tags "option" (key OPTION).
164 Each of these XML elements should contain text option value and attribute
165 "name" (key OPTION_NAME) which specifies option name.
167 Each tag "datum" defines most common parameters of phisical characteristic.
168 These parameters are placed in two groups:
169 -# Domain parameters under the tag "domain" (key DY_DOMAIN). This tag can
170 contain value description tag (key VALUE_DESCR) for descrete data which is
171 described by following parameters:
172 - default value (key VD_DEFV)
173 - maximum value (key VD_MAXV)
174 - minimum value (key VD_MINV)
175 - type of value (key VD_TYPE), possible values are String, Integer, Float, List
176 -# list reference tag (key VALUE_LIST_REF) for enumerable data described by
177 "list reference" attribute (key VLR_LIST) which references to the list
178 (see "list definition" tag) by list id.
180 Below is an example of the XML file using default keywords.
183 <datadictionary version="1.0">
184 <component name="My Component">
186 <!-- specify two unit systems -->
189 <system name="SI" label="System international">
190 <system name="AS" label="Anglo - sacson system">
193 <!-- specify datum -->
194 <!-- units of measure for SI - meters (m), for AS - inches (in) -->
195 <datum SIunits="m" ASunits="in" format="%.25f" id="X" label="X coordinate" required="">
197 <!-- default value not specified -->
198 <valueDescr default="" max="999999999.999" min="0.000" type="Float"/>
201 <shortDescr>X coordinate for object</shortDescr>
202 <longDescr>X multiplier of object coordinates. Describe position of object in direction of X axis</longDescr>
206 <datum SIunits="m" ASunits="in" format="%.25f" id="Y" label="Y coordinate" required="">
208 <valueDescr default="" max="999999999.999" min="0.000" type="Float"/>
211 <shortDescr>Y coordinate for object</shortDescr>
212 <longDescr>Y multiplier of object coordinates. Describe position of object in direction of Y axis</longDescr>
216 <!-- datum for object name with filter which not allow to input more that 8 letters,
217 numbers or unerscores with first letter only -->
218 <datum format="%.8us" id="ObjectName" label="Name" required="yes"
219 filter="^([A-Z]+)([A-Z,0-9,_]*)$">
221 <!-- limits and default not specified, type is string -->
222 <valueDescr default="" max="" min="" type="String" />
225 <!-- long description not specified -->
226 <shortDescr>Name of object</shortDescr>
231 <!-- datum for enumeration of side -->
232 <datum format="" id="Side" label="Side" required="">
234 <!-- default list item is item with id 0 -->
235 <valueDescr default="0" type="List"/>
236 <!-- list reference on list named "side_list" -->
237 <listRef list="side_list"/>
240 <shortDescr>Side of object</shortDescr>
244 <!-- list definition for enumeration of side -->
245 <valueList listid="side_list" name="Side">
246 <value id="1">left</value>
247 <value id="2">right</value>
248 <value id="3">top</value>
249 <value id="4">bottom</value>
250 <value id="0">undefined</value>
261 Create an instance of the dictionary. Can not be used directly.
262 Use Get() method instead.
264 DDS_Dictionary::DDS_Dictionary()
270 \brief Copy constructor (put in private section to prevent object copying).
272 DDS_Dictionary::DDS_Dictionary( const DDS_Dictionary& )
277 \brief Assignment operator (put in private section to prevent object copying).
279 void DDS_Dictionary::operator=( const DDS_Dictionary& )
284 \brief Get the names of defined units systems from all components.
285 \param theSystems returning sequence of units systems names.
287 void DDS_Dictionary::GetUnitSystems( TColStd_SequenceOfAsciiString& theSystems ) const
291 NCollection_Map<TCollection_AsciiString> aMap;
292 for ( Standard_Integer i = 1; i <= myGroupMap.Extent(); i++ )
294 TColStd_SequenceOfAsciiString theSeq;
295 myGroupMap.FindFromIndex( i )->GetUnitSystems( theSeq );
296 for ( Standard_Integer s = 1; s <= theSeq.Length(); s++ )
298 if ( aMap.Contains( theSeq.Value( s ) ) )
301 theSystems.Append( theSeq.Value( s ) );
302 aMap.Add( theSeq.Value( s ) );
309 \brief Get the names of defined units systems from the specified component
312 If component is not found, empty list is returned.
314 \param theSystems returning sequence of units systems names.
315 \param theComponent component name
317 void DDS_Dictionary::GetUnitSystems( TColStd_SequenceOfAsciiString& theSystems,
318 const TCollection_AsciiString& theComponent ) const
321 if ( myGroupMap.Contains( theComponent ) )
322 myGroupMap.FindFromKey( theComponent )->GetUnitSystems( theSystems );
326 \brief Get the label of the units system \a theSystem.
328 Searches the given units system in all components. If units system is not found
329 in any component, empty string is returned.
331 \param theSystem units system
332 \return units system label
334 TCollection_ExtendedString DDS_Dictionary::GetUnitSystemLabel( const TCollection_AsciiString& theSystem ) const
336 TCollection_ExtendedString aLabel;
337 for ( Standard_Integer i = 1; i <= myGroupMap.Extent() && !aLabel.Length(); i++ )
338 aLabel = myGroupMap.FindFromIndex( i )->GetUnitSystemLabel( theSystem );
343 \brief Get the label of the units system \a theSystem from the
344 component \a theComponent.
346 Searches the specified units system in the specified component only.
347 If units system is not found, empty string is returned.
349 \param theSystem units system
350 \param theComponent component name
351 \return units system label
353 TCollection_ExtendedString DDS_Dictionary::GetUnitSystemLabel( const TCollection_AsciiString& theSystem,
354 const TCollection_AsciiString& theComponent ) const
356 TCollection_ExtendedString aLabel;
357 if ( myGroupMap.Contains( theComponent ) )
358 aLabel = myGroupMap.FindFromKey( theComponent )->GetUnitSystemLabel( theSystem );
363 \brief Get the name of active units system from the first found component.
365 If at least one component exists, then its active units system name
366 is returned. Otherwise, empty string is returned.
368 \return active units system name
370 TCollection_AsciiString DDS_Dictionary::GetActiveUnitSystem() const
372 TCollection_AsciiString aSystem;
373 if ( myGroupMap.Extent() )
374 aSystem = myGroupMap.FindFromIndex( 1 )->GetActiveUnitSystem();
379 \brief Get the name of active units system from the component \a theComponent.
381 If this component exists, its active units system name is returned.
382 Otherwise, empty string is returned.
384 \param theComponent component name
385 \return active units system name
387 TCollection_AsciiString DDS_Dictionary::GetActiveUnitSystem( const TCollection_AsciiString& theComponent ) const
389 TCollection_AsciiString aSystem;
390 if ( myGroupMap.Contains( theComponent ) )
391 aSystem = myGroupMap.FindFromKey( theComponent )->GetActiveUnitSystem();
396 \brief Set the active units system.
398 This units system will be activated in each existing component,
399 if it component has this units system.
401 \param theSystem units system to be made active
403 void DDS_Dictionary::SetActiveUnitSystem( const TCollection_AsciiString& theSystem )
405 for ( Standard_Integer i = 1; i <= myGroupMap.Extent(); i++ )
406 myGroupMap.FindFromIndex( i )->SetActiveUnitSystem( theSystem );
410 \brief Set the active units system for the component \a theComponent.
412 If specified units system doesn't exist in the component, nothing happens.
414 \param theSystem units system to be made active
415 \param theComponent component name
417 void DDS_Dictionary::SetActiveUnitSystem( const TCollection_AsciiString& theSystem,
418 const TCollection_AsciiString& theComponent )
420 if ( myGroupMap.Contains( theComponent ) )
421 myGroupMap.FindFromKey( theComponent )->SetActiveUnitSystem( theSystem );
425 \brief Get the only instance of the data dictionary.
426 \return the only instance of the data dictionary
428 Handle_DDS_Dictionary DDS_Dictionary::Get()
430 if ( myDictionary.IsNull() )
431 myDictionary = new DDS_Dictionary();
437 \brief Load datum definitions in the dictionary from the XML file
439 \param theFileName XML file name
440 \return \c true if loading is succeded or \c false otherwise.
442 Standard_Boolean DDS_Dictionary::Load( const TCollection_AsciiString theFileName )
444 static NCollection_Map<TCollection_AsciiString> _LoadMap;
446 if ( _LoadMap.Contains( theFileName ) )
447 return Standard_True;
449 Handle(DDS_Dictionary) aDic = Get();
451 return Standard_False;
454 if ( aParser.parse( theFileName.ToCString() ) )
455 return Standard_False;
457 LDOM_Document aDoc = aParser.getDocument();
458 LDOM_Element aDocElement = aDoc.getDocumentElement();
459 if ( !aDocElement.isNull() )
460 aDic->FillDataMap( aDocElement );
462 _LoadMap.Add( theFileName );
464 return Standard_True;
468 \brief Get XML keyword as LDOMString by specified \a key.
470 If key doesn't exist, empty string is returned.
471 This function is provided for convenience.
473 \param key keyword name
474 \return keyword value
476 LDOMString DDS_Dictionary::KeyWord( const TCollection_AsciiString& key )
479 Handle(DDS_KeyWords) aKeyWords = DDS_KeyWords::Get();
480 if ( !aKeyWords.IsNull() )
482 TCollection_AsciiString aStr = aKeyWords->GetKeyWord( key );
484 keyWord = LDOMString( aStr.ToCString() );
490 \brief Get the data dictionary item by specified identifier \a theID
491 from the component \a theComponent.
493 If the component or item is not found, null handle is returned.
494 \param theID data dictionary item ID
495 \param theComponent component name
496 \return handle to the data dictionary item
498 Handle_DDS_DicItem DDS_Dictionary::GetDicItem( const TCollection_AsciiString& theID,
499 const TCollection_AsciiString& theComponent ) const
501 Handle(DDS_DicItem) aDicItem;
502 Handle(DDS_DicGroup) aDicGroup;
503 if ( myGroupMap.Contains( theComponent ) )
504 aDicGroup = myGroupMap.FindFromKey( theComponent );
505 if ( !aDicGroup.IsNull() )
506 aDicItem = aDicGroup->GetDicItem( theID );
511 \brief Get the data dictionary item by specified identifier \a theID.
513 Function searches the item in all components. If item is not found
514 in all components, null handle is returned.
516 \param theID data dictionary item ID
517 \return handle to the data dictionary item
519 Handle_DDS_DicItem DDS_Dictionary::GetDicItem( const TCollection_AsciiString& theID ) const
521 Handle(DDS_DicItem) aDicItem;
522 for ( Standard_Integer i = 1; i <= myGroupMap.Extent() && aDicItem.IsNull(); i++ )
523 aDicItem = myGroupMap.FindFromIndex( i )->GetDicItem( theID );
528 \brief Fill the internal data structures from the XML node.
529 \param theDocElement document XML node
531 void DDS_Dictionary::FillDataMap( const LDOM_Element& theDocElement )
533 for ( LDOM_Element aComponentElem = theDocElement.GetChildByTagName( KeyWord( "COMPONENT" ) );
534 !aComponentElem.isNull(); aComponentElem = aComponentElem.GetSiblingByTagName() )
536 TCollection_AsciiString aCompName = aComponentElem.getAttribute( KeyWord( "COMPONENT_NAME" ) );
537 if ( !myGroupMap.Contains( aCompName ) )
538 myGroupMap.Add( aCompName, CreateGroup( aCompName ) );
539 Handle(DDS_DicGroup) aDicGroup = myGroupMap.FindFromKey( aCompName );
540 aDicGroup->FillDataMap( aComponentElem, theDocElement );
541 myGroupMap.Add( aCompName, aDicGroup );
546 \brief Convert numeric value \a theValue from specified measure units
547 \a theUnits to "SI" measure units (mm for Length, radians for Angles, etc).
548 \param theValue value being converted
549 \param theUnits measure units
550 \return converted value
552 Standard_Real DDS_Dictionary::ToSI( const Standard_Real theValue, const Standard_CString theUnits )
554 Standard_Real aRetValue = theValue;
555 if ( theUnits && *theUnits && strcmp( theUnits, "%" ) )
559 aRetValue = UnitsAPI::AnyToSI( theValue, theUnits );
561 catch( Standard_Failure ) {
564 else if ( theUnits && *theUnits )
565 aRetValue = theValue / 100.0;
571 \brief Convert numeric value \a theValue to specified measure units
572 \a theUnits from "SI" measure units (mm for Length, radians for Angles, etc).
573 \param theValue value being converted
574 \param theUnits measure units
575 \return converted value
577 Standard_Real DDS_Dictionary::FromSI( const Standard_Real theValue, const Standard_CString theUnits )
579 Standard_Real aRetValue = theValue;
580 if ( theUnits && *theUnits && strcmp( theUnits, "%" ) )
584 aRetValue = UnitsAPI::AnyFromSI( theValue, theUnits );
586 catch( Standard_Failure ) {
589 else if ( theUnits && *theUnits )
590 aRetValue = theValue * 100.0;
596 \brief Fill given string container \a seq with keys belonging to group with name \a theComponent
597 \param theComponent name of group whose keys should be stored in the container
598 \param seq returned string container with keys belonging to group; it is not cleared before filling
600 void DDS_Dictionary::GetKeys( const TCollection_AsciiString& theComponent, TColStd_SequenceOfAsciiString& seq ) const
602 Handle( DDS_DicGroup ) aDicGroup;
603 if( myGroupMap.Contains( theComponent ) )
604 aDicGroup = myGroupMap.FindFromKey( theComponent );
606 if( !aDicGroup.IsNull() )
607 aDicGroup->GetKeys( seq );
611 \brief Create instance of a dictionary group. This method can
612 be used for customization data dictionary by specific
614 \return New dictionary group instance.
616 Handle(DDS_DicGroup) DDS_Dictionary::CreateGroup( const TCollection_AsciiString& theCompName ) const
618 return new DDS_DicGroup( theCompName );
622 \brief Set instance of dictionary. This method might be used in descendant classes to initialize
623 custom dictionary and replace the default implementation.
624 This method overrides static handle on dictionary that is available
627 void DDS_Dictionary::SetDictionary( const Handle(DDS_Dictionary)& theDict )
629 myDictionary = theDict;