1 /*************************************************************************
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * Copyright 2000, 2010 Oracle and/or its affiliates.
5  *
6  * OpenOffice.org - a multi-platform office productivity suite
7  *
8  * This file is part of OpenOffice.org.
9  *
10  * OpenOffice.org is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License version 3
12  * only, as published by the Free Software Foundation.
13  *
14  * OpenOffice.org is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License version 3 for more details
18  * (a copy is included in the LICENSE file that accompanied this code).
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * version 3 along with OpenOffice.org.  If not, see
22  * <http://www.openoffice.org/license.html>
23  * for a copy of the LGPLv3 License.
24  *
25  ************************************************************************/
26 
27 #include "precompiled_xmloff.hxx"
28 
29 #include "property_description.hxx"
30 #include "forms/form_handler_factory.hxx"
31 #include "strings.hxx"
32 #include "xmloff/xmltoken.hxx"
33 #include "xmloff/xmlnmspe.hxx"
34 
35 #include <tools/diagnose_ex.h>
36 #include <tools/debug.hxx>
37 
38 #include <hash_map>
39 
40 //......................................................................................................................
41 namespace xmloff { namespace metadata
42 {
43 //......................................................................................................................
44 
45     using namespace ::xmloff::token;
46 
47 #define FORM_SINGLE_PROPERTY( id, att ) \
48     PropertyDescription( PROPERTY_##id, XML_NAMESPACE_FORM, att, &FormHandlerFactory::getFormPropertyHandler, PID_##id, NO_GROUP )
49 
50     //==================================================================================================================
51 	//= property meta data
52 	//==================================================================================================================
53 	//------------------------------------------------------------------------------------------------------------------
54     namespace
55     {
56         const PropertyDescription* lcl_getPropertyMetaData()
57         {
58             static const PropertyDescription s_propertyMetaData[] =
59             {
60                 FORM_SINGLE_PROPERTY( DATE_MIN,        XML_MIN_VALUE        ),
61                 FORM_SINGLE_PROPERTY( DATE_MAX,        XML_MAX_VALUE        ),
62                 FORM_SINGLE_PROPERTY( DEFAULT_DATE,    XML_VALUE            ),
63                 FORM_SINGLE_PROPERTY( DATE,            XML_CURRENT_VALUE    ),
64                 FORM_SINGLE_PROPERTY( TIME_MIN,        XML_MIN_VALUE        ),
65                 FORM_SINGLE_PROPERTY( TIME_MAX,        XML_MAX_VALUE        ),
66                 FORM_SINGLE_PROPERTY( DEFAULT_TIME,    XML_VALUE            ),
67                 FORM_SINGLE_PROPERTY( TIME,            XML_CURRENT_VALUE    ),
68 
69                 PropertyDescription()
70             };
71             return s_propertyMetaData;
72         }
73     }
74 
75 	//------------------------------------------------------------------------------------------------------------------
76     namespace
77     {
78         // TODO: instead of having all of the below static, it should be some per-instance data. This way, the
79         // approach used here would scale much better.
80         // That is, if you have multiple "meta data instances", which manage a small, but closed set of properties,
81         // then looking looking through those multiple instances would probably be faster than searching within
82         // one big instance, since in this case, every instance can quickly decide whether it is responsible
83         // for some attribute or property, and otherwise delegate to the next instance.
84 
85 	    //..............................................................................................................
86         typedef ::std::hash_map< ::rtl::OUString, const PropertyDescription*, ::rtl::OUStringHash > DescriptionsByName;
87 
88 	    //..............................................................................................................
89         const DescriptionsByName& lcl_getPropertyDescriptions()
90         {
91             DBG_TESTSOLARMUTEX();
92             static DescriptionsByName s_propertyDescriptionsByName;
93             if ( s_propertyDescriptionsByName.empty() )
94             {
95                 const PropertyDescription* desc = lcl_getPropertyMetaData();
96                 while ( desc->propertyName.getLength() != 0 )
97                 {
98                     s_propertyDescriptionsByName[ desc->propertyName ] = desc;
99                     ++desc;
100                 }
101             }
102             return s_propertyDescriptionsByName;
103         }
104 
105         //..............................................................................................................
106         typedef ::std::map< PropertyGroup, PropertyDescriptionList > IndexedPropertyGroups;
107 
108         //..............................................................................................................
109         const IndexedPropertyGroups& lcl_getIndexedPropertyGroups()
110         {
111             DBG_TESTSOLARMUTEX();
112             static IndexedPropertyGroups s_indexedPropertyGroups;
113             if ( s_indexedPropertyGroups.empty() )
114             {
115                 const PropertyDescription* desc = lcl_getPropertyMetaData();
116                 while ( desc->propertyName.getLength() != 0 )
117                 {
118                     if ( desc->propertyGroup != NO_GROUP )
119                         s_indexedPropertyGroups[ desc->propertyGroup ].push_back( desc );
120                     ++desc;
121                 }
122             }
123             return s_indexedPropertyGroups;
124         }
125 
126         //..............................................................................................................
127         typedef ::std::hash_map< ::rtl::OUString, XMLTokenEnum, ::rtl::OUStringHash > ReverseTokenLookup;
128 
129         //..............................................................................................................
130         const ReverseTokenLookup& getReverseTokenLookup()
131         {
132             DBG_TESTSOLARMUTEX();
133             static ReverseTokenLookup s_reverseTokenLookup;
134             if ( s_reverseTokenLookup.empty() )
135             {
136                 const PropertyDescription* desc = lcl_getPropertyMetaData();
137                 while ( desc->propertyName.getLength() != 0 )
138                 {
139                     s_reverseTokenLookup[ token::GetXMLToken( desc->attribute.attributeToken ) ] = desc->attribute.attributeToken;
140                     ++desc;
141                 }
142             }
143             return s_reverseTokenLookup;
144         }
145 
146         //..............................................................................................................
147         struct AttributeHash : public ::std::unary_function< AttributeDescription, size_t >
148         {
149             size_t operator()( const AttributeDescription& i_attribute ) const
150             {
151                 return size_t( i_attribute.attributeToken * 100 ) + size_t( i_attribute.namespacePrefix );
152             }
153         };
154 
155         //..............................................................................................................
156         typedef ::std::hash_multimap< AttributeDescription, PropertyGroup, AttributeHash > AttributeGroups;
157 
158         //..............................................................................................................
159         const AttributeGroups& lcl_getAttributeGroups()
160         {
161             DBG_TESTSOLARMUTEX();
162             static AttributeGroups s_attributeGroups;
163             if ( s_attributeGroups.empty() )
164             {
165                 const PropertyDescription* desc = lcl_getPropertyMetaData();
166                 while ( desc->propertyName.getLength() != 0 )
167                 {
168                     if ( desc->propertyGroup != NO_GROUP )
169                         s_attributeGroups.insert( AttributeGroups::value_type( desc->attribute, desc->propertyGroup ) );
170                     ++desc;
171                 }
172             }
173             return s_attributeGroups;
174         }
175 
176         //..............................................................................................................
177         typedef ::std::hash_map< AttributeDescription, PropertyGroups, AttributeHash > AttributesWithoutGroup;
178 
179         //..............................................................................................................
180         const AttributesWithoutGroup& lcl_getAttributesWithoutGroups()
181         {
182             DBG_TESTSOLARMUTEX();
183             static AttributesWithoutGroup s_attributesWithoutGroup;
184             if ( s_attributesWithoutGroup.empty() )
185             {
186                 const PropertyDescription* desc = lcl_getPropertyMetaData();
187                 while ( desc->propertyName.getLength() != 0 )
188                 {
189                     if ( desc->propertyGroup == NO_GROUP )
190                     {
191                         PropertyDescriptionList singleElementList;
192                         singleElementList.push_back( desc );
193 
194                         s_attributesWithoutGroup[ desc->attribute ].push_back( singleElementList );
195                     }
196                     ++desc;
197                 }
198             }
199             return s_attributesWithoutGroup;
200         }
201     }
202 
203 	//------------------------------------------------------------------------------------------------------------------
204     const PropertyDescription* getPropertyDescription( const ::rtl::OUString& i_propertyName )
205     {
206         const DescriptionsByName& rAllDescriptions( lcl_getPropertyDescriptions() );
207         DescriptionsByName::const_iterator pos = rAllDescriptions.find( i_propertyName );
208         if ( pos != rAllDescriptions.end() )
209             return pos->second;
210         return NULL;
211     }
212 
213 	//------------------------------------------------------------------------------------------------------------------
214     void getPropertyGroup( const PropertyGroup i_propertyGroup, PropertyDescriptionList& o_propertyDescriptions )
215     {
216         OSL_ENSURE( i_propertyGroup != NO_GROUP, "xmloff::metadata::getPropertyGroup: illegal group!" );
217 
218         const IndexedPropertyGroups& rPropertyGroups( lcl_getIndexedPropertyGroups() );
219         const IndexedPropertyGroups::const_iterator pos = rPropertyGroups.find( i_propertyGroup );
220         if ( pos != rPropertyGroups.end() )
221             o_propertyDescriptions = pos->second;
222     }
223 
224 	//------------------------------------------------------------------------------------------------------------------
225     void getPropertyGroupList( const AttributeDescription& i_attribute, PropertyGroups& o_propertyGroups )
226     {
227         const AttributeGroups& rAttributeGroups = lcl_getAttributeGroups();
228 
229         ::std::pair< AttributeGroups::const_iterator, AttributeGroups::const_iterator >
230             range = rAttributeGroups.equal_range( i_attribute );
231 
232         if ( range.first == range.second )
233         {
234             // the attribute is not used for any non-trivial group, which means it is mapped directly to
235             // a single property
236             const AttributesWithoutGroup& attributesWithoutGroups( lcl_getAttributesWithoutGroups() );
237             const AttributesWithoutGroup::const_iterator pos = attributesWithoutGroups.find( i_attribute );
238             if ( pos != attributesWithoutGroups.end() )
239                 o_propertyGroups = pos->second;
240         }
241         else
242         {
243             const IndexedPropertyGroups& rPropertyGroups = lcl_getIndexedPropertyGroups();
244             for ( AttributeGroups::const_iterator group = range.first; group != range.second; ++group )
245             {
246                 const PropertyGroup propGroup = group->second;
247                 const IndexedPropertyGroups::const_iterator groupPos = rPropertyGroups.find( propGroup );
248                 ENSURE_OR_CONTINUE( groupPos != rPropertyGroups.end(), "getPropertyGroupList: inconsistency!" );
249                 o_propertyGroups.push_back( groupPos->second );
250             }
251         }
252     }
253 
254 	//------------------------------------------------------------------------------------------------------------------
255     AttributeDescription getAttributeDescription( const sal_uInt16 i_namespacePrefix, const ::rtl::OUString& i_attributeName )
256     {
257         AttributeDescription attribute;
258         const ReverseTokenLookup& rTokenLookup( getReverseTokenLookup() );
259         const ReverseTokenLookup::const_iterator pos = rTokenLookup.find( i_attributeName );
260         if ( pos != rTokenLookup.end() )
261         {
262             attribute.namespacePrefix = i_namespacePrefix;
263             attribute.attributeToken = pos->second;
264         }
265         return attribute;
266     }
267 
268 //......................................................................................................................
269 } } // namespace xmloff::metadata
270 //......................................................................................................................
271