1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/uno/Reference.h>
32 
33 #include <rtl/ustring.hxx>
34 #include <tools/debug.hxx>
35 #include "XMLPropertyBackpatcher.hxx"
36 #include <xmloff/txtimp.hxx>	// XMLTextImportHelper partially implemented here
37 
38 
39 using ::rtl::OUString;
40 using ::std::vector;
41 using ::std::map;
42 using ::com::sun::star::uno::Reference;
43 using ::com::sun::star::uno::Any;
44 using ::com::sun::star::beans::XPropertySet;
45 
46 
47 template<class A>
48 XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
49 	const ::rtl::OUString& sPropName)
50 :	sPropertyName(sPropName)
51 ,	bDefaultHandling(sal_False)
52 ,	bPreserveProperty(sal_False)
53 ,	sPreservePropertyName()
54 {
55 }
56 
57 template<class A>
58 XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
59 	const OUString& sPropName,
60 	const OUString& sPreserveName,
61 	sal_Bool bDefault,
62 	A aDef)
63 :	sPropertyName(sPropName)
64 ,	bDefaultHandling(bDefault)
65 ,	bPreserveProperty(sPreserveName.getLength()>0)
66 ,	sPreservePropertyName(sPreserveName)
67 ,	aDefault(aDef)
68 {
69 }
70 
71 template<class A>
72 XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
73 	const sal_Char* pPropName)
74 :	bDefaultHandling(sal_False)
75 ,	bPreserveProperty(sal_False)
76 {
77 	DBG_ASSERT(pPropName != NULL, "need property name");
78 	sPropertyName = OUString::createFromAscii(pPropName);
79 }
80 
81 template<class A>
82 XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
83 	const sal_Char* pPropName,
84 	const sal_Char* pPreservePropName,
85 	sal_Bool bDefault,
86 	A aDef)
87 :	bDefaultHandling(bDefault)
88 ,	bPreserveProperty(pPreservePropName != NULL)
89 ,	aDefault(aDef)
90 {
91 	DBG_ASSERT(pPropName != NULL, "need property name");
92 	sPropertyName = OUString::createFromAscii(pPropName);
93 	if (pPreservePropName != NULL)
94 	{
95 		sPreservePropertyName = OUString::createFromAscii(pPreservePropName);
96 	}
97 }
98 
99 template<class A>
100 XMLPropertyBackpatcher<A>::~XMLPropertyBackpatcher()
101 {
102 	SetDefault();
103 }
104 
105 
106 template<class A>
107 void XMLPropertyBackpatcher<A>::ResolveId(
108 	const OUString& sName,
109 	A aValue)
110 {
111 	// insert ID into ID map
112 	aIDMap[sName] = aValue;
113 
114 	// backpatch old references, if backpatch list exists
115 	if (aBackpatchListMap.count(sName))
116 	{
117 		// aah, we have a backpatch list!
118 		BackpatchListType* pList =
119 			(BackpatchListType*)aBackpatchListMap[sName];
120 
121 		// a) remove list from list map
122 		aBackpatchListMap.erase(sName);
123 
124 		// b) for every item, set SequenceNumber
125 		//    (and preserve Property, if appropriate)
126 		Any aAny;
127 		aAny <<= aValue;
128 		if (bPreserveProperty)
129 		{
130 			// preserve version
131 			for(BackpatchListType::iterator aIter = pList->begin();
132 				aIter != pList->end();
133 				aIter++)
134 			{
135 				Reference<XPropertySet> xProp = (*aIter);
136 				Any aPres = xProp->getPropertyValue(sPreservePropertyName);
137 				xProp->setPropertyValue(sPropertyName, aAny);
138 				xProp->setPropertyValue(sPreservePropertyName, aPres);
139 			}
140 		}
141 		else
142 		{
143 			// without preserve
144 			for(BackpatchListType::iterator aIter = pList->begin();
145 				aIter != pList->end();
146 				aIter++)
147 			{
148 				(*aIter)->setPropertyValue(sPropertyName, aAny);
149 			}
150 		}
151 
152 		// c) delete list
153 		delete pList;
154 	}
155 	// else: no backpatch list -> then we're finished
156 }
157 
158 template<class A>
159 void XMLPropertyBackpatcher<A>::SetProperty(
160 	const Reference<XPropertySet> & xPropSet,
161 	const OUString& sName)
162 {
163 	Reference<XPropertySet> xNonConstPropSet(xPropSet);
164 	SetProperty(xNonConstPropSet, sName);
165 }
166 
167 template<class A>
168 void XMLPropertyBackpatcher<A>::SetProperty(
169 	Reference<XPropertySet> & xPropSet,
170 	const OUString& sName)
171 {
172 	if (aIDMap.count(sName))
173 	{
174 		// we know this ID -> set property
175 		Any aAny;
176 		aAny <<= aIDMap[sName];
177 		xPropSet->setPropertyValue(sPropertyName, aAny);
178 	}
179 	else
180 	{
181 		// ID unknown -> into backpatch list for later fixup
182 		if (! aBackpatchListMap.count(sName))
183 		{
184 			// create backpatch list for this name
185 			BackpatchListType* pTmp = new BackpatchListType() ;
186 			aBackpatchListMap[sName] = (void*)pTmp;
187 		}
188 
189 		// insert footnote
190 		((BackpatchListType*)aBackpatchListMap[sName])->push_back(xPropSet);
191 	}
192 }
193 
194 template<class A>
195 void XMLPropertyBackpatcher<A>::SetDefault()
196 {
197 	if (bDefaultHandling)
198 	{
199 		// not implemented yet
200 	}
201 }
202 
203 // force instantiation of templates
204 template class XMLPropertyBackpatcher<sal_Int16>;
205 template class XMLPropertyBackpatcher<OUString>;
206 
207 struct SAL_DLLPRIVATE XMLTextImportHelper::BackpatcherImpl
208 {
209     /// backpatcher for references to footnotes and endnotes
210     ::std::auto_ptr< XMLPropertyBackpatcher<sal_Int16> >
211         m_pFootnoteBackpatcher;
212 
213     /// backpatchers for references to sequences
214     ::std::auto_ptr< XMLPropertyBackpatcher<sal_Int16> >
215         m_pSequenceIdBackpatcher;
216 
217     ::std::auto_ptr< XMLPropertyBackpatcher< ::rtl::OUString> >
218         m_pSequenceNameBackpatcher;
219 
220 };
221 
222 ::boost::shared_ptr<XMLTextImportHelper::BackpatcherImpl>
223 XMLTextImportHelper::MakeBackpatcherImpl()
224 {
225     // n.b.: the shared_ptr stores the dtor!
226     return ::boost::shared_ptr<BackpatcherImpl>(new BackpatcherImpl);
227 }
228 
229 static ::rtl::OUString const& GetSequenceNumber()
230 {
231     static ::rtl::OUString s_SequenceNumber(
232         RTL_CONSTASCII_USTRINGPARAM("SequenceNumber"));
233     return s_SequenceNumber;
234 }
235 
236 //
237 // XMLTextImportHelper
238 //
239 // Code from XMLTextImportHelper using the XMLPropertyBackpatcher is
240 // implemented here. The reason is that in the unxsols2 environment,
241 // all templates are instatiated as file local (switch
242 // -instances=static), and thus are not accessible from the outside.
243 //
244 // The previous solution was to force additional instantiation of
245 // XMLPropertyBackpatcher in txtimp.cxx. This solution combines all
246 // usage of the XMLPropertyBackpatcher in XMLPropertyBackpatcher.cxx
247 // instead.
248 //
249 
250 XMLPropertyBackpatcher<sal_Int16>& XMLTextImportHelper::GetFootnoteBP()
251 {
252     if (!m_pBackpatcherImpl->m_pFootnoteBackpatcher.get())
253     {
254         m_pBackpatcherImpl->m_pFootnoteBackpatcher.reset(
255             new XMLPropertyBackpatcher<sal_Int16>(GetSequenceNumber()));
256     }
257     return *m_pBackpatcherImpl->m_pFootnoteBackpatcher;
258 }
259 
260 XMLPropertyBackpatcher<sal_Int16>& XMLTextImportHelper::GetSequenceIdBP()
261 {
262     if (!m_pBackpatcherImpl->m_pSequenceIdBackpatcher.get())
263     {
264         m_pBackpatcherImpl->m_pSequenceIdBackpatcher.reset(
265             new XMLPropertyBackpatcher<sal_Int16>(GetSequenceNumber()));
266     }
267     return *m_pBackpatcherImpl->m_pSequenceIdBackpatcher;
268 }
269 
270 XMLPropertyBackpatcher<OUString>& XMLTextImportHelper::GetSequenceNameBP()
271 {
272     static ::rtl::OUString s_SourceName(
273         RTL_CONSTASCII_USTRINGPARAM("SourceName"));
274     if (!m_pBackpatcherImpl->m_pSequenceNameBackpatcher.get())
275     {
276         m_pBackpatcherImpl->m_pSequenceNameBackpatcher.reset(
277             new XMLPropertyBackpatcher<OUString>(s_SourceName));
278     }
279     return *m_pBackpatcherImpl->m_pSequenceNameBackpatcher;
280 }
281 
282 void XMLTextImportHelper::InsertFootnoteID(
283 	const OUString& sXMLId,
284 	sal_Int16 nAPIId)
285 {
286 	GetFootnoteBP().ResolveId(sXMLId, nAPIId);
287 }
288 
289 void XMLTextImportHelper::ProcessFootnoteReference(
290 	const OUString& sXMLId,
291 	const Reference<XPropertySet> & xPropSet)
292 {
293 	GetFootnoteBP().SetProperty(xPropSet, sXMLId);
294 }
295 
296 void XMLTextImportHelper::InsertSequenceID(
297 	const OUString& sXMLId,
298 	const OUString& sName,
299 	sal_Int16 nAPIId)
300 {
301 	GetSequenceIdBP().ResolveId(sXMLId, nAPIId);
302 	GetSequenceNameBP().ResolveId(sXMLId, sName);
303 }
304 
305 void XMLTextImportHelper::ProcessSequenceReference(
306 	const OUString& sXMLId,
307 	const Reference<XPropertySet> & xPropSet)
308 {
309 	GetSequenceIdBP().SetProperty(xPropSet, sXMLId);
310 	GetSequenceNameBP().SetProperty(xPropSet, sXMLId);
311 }
312 
313