| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #include "precompiled_xmloff.hxx" |
| |
| #include "property_description.hxx" |
| #include "forms/form_handler_factory.hxx" |
| #include "strings.hxx" |
| #include "xmloff/xmltoken.hxx" |
| #include "xmloff/xmlnmspe.hxx" |
| |
| #include <tools/diagnose_ex.h> |
| #include <tools/debug.hxx> |
| |
| #include <hash_map> |
| |
| //...................................................................................................................... |
| namespace xmloff { namespace metadata |
| { |
| //...................................................................................................................... |
| |
| using namespace ::xmloff::token; |
| |
| #define FORM_SINGLE_PROPERTY( id, att ) \ |
| PropertyDescription( PROPERTY_##id, XML_NAMESPACE_FORM, att, &FormHandlerFactory::getFormPropertyHandler, PID_##id, NO_GROUP ) |
| |
| //================================================================================================================== |
| //= property meta data |
| //================================================================================================================== |
| //------------------------------------------------------------------------------------------------------------------ |
| namespace |
| { |
| const PropertyDescription* lcl_getPropertyMetaData() |
| { |
| static const PropertyDescription s_propertyMetaData[] = |
| { |
| FORM_SINGLE_PROPERTY( DATE_MIN, XML_MIN_VALUE ), |
| FORM_SINGLE_PROPERTY( DATE_MAX, XML_MAX_VALUE ), |
| FORM_SINGLE_PROPERTY( DEFAULT_DATE, XML_VALUE ), |
| FORM_SINGLE_PROPERTY( DATE, XML_CURRENT_VALUE ), |
| FORM_SINGLE_PROPERTY( TIME_MIN, XML_MIN_VALUE ), |
| FORM_SINGLE_PROPERTY( TIME_MAX, XML_MAX_VALUE ), |
| FORM_SINGLE_PROPERTY( DEFAULT_TIME, XML_VALUE ), |
| FORM_SINGLE_PROPERTY( TIME, XML_CURRENT_VALUE ), |
| |
| PropertyDescription() |
| }; |
| return s_propertyMetaData; |
| } |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| namespace |
| { |
| // TODO: instead of having all of the below static, it should be some per-instance data. This way, the |
| // approach used here would scale much better. |
| // That is, if you have multiple "meta data instances", which manage a small, but closed set of properties, |
| // then looking looking through those multiple instances would probably be faster than searching within |
| // one big instance, since in this case, every instance can quickly decide whether it is responsible |
| // for some attribute or property, and otherwise delegate to the next instance. |
| |
| //.............................................................................................................. |
| typedef ::std::hash_map< ::rtl::OUString, const PropertyDescription*, ::rtl::OUStringHash > DescriptionsByName; |
| |
| //.............................................................................................................. |
| const DescriptionsByName& lcl_getPropertyDescriptions() |
| { |
| DBG_TESTSOLARMUTEX(); |
| static DescriptionsByName s_propertyDescriptionsByName; |
| if ( s_propertyDescriptionsByName.empty() ) |
| { |
| const PropertyDescription* desc = lcl_getPropertyMetaData(); |
| while ( desc->propertyName.getLength() != 0 ) |
| { |
| s_propertyDescriptionsByName[ desc->propertyName ] = desc; |
| ++desc; |
| } |
| } |
| return s_propertyDescriptionsByName; |
| } |
| |
| //.............................................................................................................. |
| typedef ::std::map< PropertyGroup, PropertyDescriptionList > IndexedPropertyGroups; |
| |
| //.............................................................................................................. |
| const IndexedPropertyGroups& lcl_getIndexedPropertyGroups() |
| { |
| DBG_TESTSOLARMUTEX(); |
| static IndexedPropertyGroups s_indexedPropertyGroups; |
| if ( s_indexedPropertyGroups.empty() ) |
| { |
| const PropertyDescription* desc = lcl_getPropertyMetaData(); |
| while ( desc->propertyName.getLength() != 0 ) |
| { |
| if ( desc->propertyGroup != NO_GROUP ) |
| s_indexedPropertyGroups[ desc->propertyGroup ].push_back( desc ); |
| ++desc; |
| } |
| } |
| return s_indexedPropertyGroups; |
| } |
| |
| //.............................................................................................................. |
| typedef ::std::hash_map< ::rtl::OUString, XMLTokenEnum, ::rtl::OUStringHash > ReverseTokenLookup; |
| |
| //.............................................................................................................. |
| const ReverseTokenLookup& getReverseTokenLookup() |
| { |
| DBG_TESTSOLARMUTEX(); |
| static ReverseTokenLookup s_reverseTokenLookup; |
| if ( s_reverseTokenLookup.empty() ) |
| { |
| const PropertyDescription* desc = lcl_getPropertyMetaData(); |
| while ( desc->propertyName.getLength() != 0 ) |
| { |
| s_reverseTokenLookup[ token::GetXMLToken( desc->attribute.attributeToken ) ] = desc->attribute.attributeToken; |
| ++desc; |
| } |
| } |
| return s_reverseTokenLookup; |
| } |
| |
| //.............................................................................................................. |
| struct AttributeHash : public ::std::unary_function< AttributeDescription, size_t > |
| { |
| size_t operator()( const AttributeDescription& i_attribute ) const |
| { |
| return size_t( i_attribute.attributeToken * 100 ) + size_t( i_attribute.namespacePrefix ); |
| } |
| }; |
| |
| //.............................................................................................................. |
| typedef ::std::hash_multimap< AttributeDescription, PropertyGroup, AttributeHash > AttributeGroups; |
| |
| //.............................................................................................................. |
| const AttributeGroups& lcl_getAttributeGroups() |
| { |
| DBG_TESTSOLARMUTEX(); |
| static AttributeGroups s_attributeGroups; |
| if ( s_attributeGroups.empty() ) |
| { |
| const PropertyDescription* desc = lcl_getPropertyMetaData(); |
| while ( desc->propertyName.getLength() != 0 ) |
| { |
| if ( desc->propertyGroup != NO_GROUP ) |
| s_attributeGroups.insert( AttributeGroups::value_type( desc->attribute, desc->propertyGroup ) ); |
| ++desc; |
| } |
| } |
| return s_attributeGroups; |
| } |
| |
| //.............................................................................................................. |
| typedef ::std::hash_map< AttributeDescription, PropertyGroups, AttributeHash > AttributesWithoutGroup; |
| |
| //.............................................................................................................. |
| const AttributesWithoutGroup& lcl_getAttributesWithoutGroups() |
| { |
| DBG_TESTSOLARMUTEX(); |
| static AttributesWithoutGroup s_attributesWithoutGroup; |
| if ( s_attributesWithoutGroup.empty() ) |
| { |
| const PropertyDescription* desc = lcl_getPropertyMetaData(); |
| while ( desc->propertyName.getLength() != 0 ) |
| { |
| if ( desc->propertyGroup == NO_GROUP ) |
| { |
| PropertyDescriptionList singleElementList; |
| singleElementList.push_back( desc ); |
| |
| s_attributesWithoutGroup[ desc->attribute ].push_back( singleElementList ); |
| } |
| ++desc; |
| } |
| } |
| return s_attributesWithoutGroup; |
| } |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| const PropertyDescription* getPropertyDescription( const ::rtl::OUString& i_propertyName ) |
| { |
| const DescriptionsByName& rAllDescriptions( lcl_getPropertyDescriptions() ); |
| DescriptionsByName::const_iterator pos = rAllDescriptions.find( i_propertyName ); |
| if ( pos != rAllDescriptions.end() ) |
| return pos->second; |
| return NULL; |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void getPropertyGroup( const PropertyGroup i_propertyGroup, PropertyDescriptionList& o_propertyDescriptions ) |
| { |
| OSL_ENSURE( i_propertyGroup != NO_GROUP, "xmloff::metadata::getPropertyGroup: illegal group!" ); |
| |
| const IndexedPropertyGroups& rPropertyGroups( lcl_getIndexedPropertyGroups() ); |
| const IndexedPropertyGroups::const_iterator pos = rPropertyGroups.find( i_propertyGroup ); |
| if ( pos != rPropertyGroups.end() ) |
| o_propertyDescriptions = pos->second; |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| void getPropertyGroupList( const AttributeDescription& i_attribute, PropertyGroups& o_propertyGroups ) |
| { |
| const AttributeGroups& rAttributeGroups = lcl_getAttributeGroups(); |
| |
| ::std::pair< AttributeGroups::const_iterator, AttributeGroups::const_iterator > |
| range = rAttributeGroups.equal_range( i_attribute ); |
| |
| if ( range.first == range.second ) |
| { |
| // the attribute is not used for any non-trivial group, which means it is mapped directly to |
| // a single property |
| const AttributesWithoutGroup& attributesWithoutGroups( lcl_getAttributesWithoutGroups() ); |
| const AttributesWithoutGroup::const_iterator pos = attributesWithoutGroups.find( i_attribute ); |
| if ( pos != attributesWithoutGroups.end() ) |
| o_propertyGroups = pos->second; |
| } |
| else |
| { |
| const IndexedPropertyGroups& rPropertyGroups = lcl_getIndexedPropertyGroups(); |
| for ( AttributeGroups::const_iterator group = range.first; group != range.second; ++group ) |
| { |
| const PropertyGroup propGroup = group->second; |
| const IndexedPropertyGroups::const_iterator groupPos = rPropertyGroups.find( propGroup ); |
| ENSURE_OR_CONTINUE( groupPos != rPropertyGroups.end(), "getPropertyGroupList: inconsistency!" ); |
| o_propertyGroups.push_back( groupPos->second ); |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| AttributeDescription getAttributeDescription( const sal_uInt16 i_namespacePrefix, const ::rtl::OUString& i_attributeName ) |
| { |
| AttributeDescription attribute; |
| const ReverseTokenLookup& rTokenLookup( getReverseTokenLookup() ); |
| const ReverseTokenLookup::const_iterator pos = rTokenLookup.find( i_attributeName ); |
| if ( pos != rTokenLookup.end() ) |
| { |
| attribute.namespacePrefix = i_namespacePrefix; |
| attribute.attributeToken = pos->second; |
| } |
| return attribute; |
| } |
| |
| //...................................................................................................................... |
| } } // namespace xmloff::metadata |
| //...................................................................................................................... |