1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_forms.hxx"
26 #include "limitedformats.hxx"
27 #include "services.hxx"
28 #include <osl/diagnose.h>
29 #include <comphelper/types.hxx>
30 #include <comphelper/extract.hxx>
31 #include <com/sun/star/form/FormComponentType.hpp>
32 
33 //.........................................................................
34 namespace frm
35 {
36 //.........................................................................
37 
38 	using namespace ::com::sun::star::uno;
39 	using namespace ::com::sun::star::util;
40 	using namespace ::com::sun::star::lang;
41 	using namespace ::com::sun::star::form;
42 	using namespace ::com::sun::star::beans;
43 
44 	sal_Int32								OLimitedFormats::s_nInstanceCount(0);
45 	::osl::Mutex							OLimitedFormats::s_aMutex;
46 	Reference< XNumberFormatsSupplier >		OLimitedFormats::s_xStandardFormats;
47 
48 	//=====================================================================
49 	//=
50 	//=====================================================================
51 	//---------------------------------------------------------------------
52 	enum LocaleType
53 	{
54 		ltEnglishUS,
55 		ltGerman,
56 		ltSystem
57 	};
58 
59 	//---------------------------------------------------------------------
getLocale(LocaleType _eType)60 	static const Locale& getLocale(LocaleType _eType)
61 	{
62 		static const Locale s_aEnglishUS( ::rtl::OUString::createFromAscii("en"), ::rtl::OUString::createFromAscii("us"), ::rtl::OUString() );
63 		static const Locale s_aGerman( ::rtl::OUString::createFromAscii("de"), ::rtl::OUString::createFromAscii("DE"), ::rtl::OUString() );
64 		static const ::rtl::OUString s_sEmptyString;
65 		static const Locale s_aSystem( s_sEmptyString, s_sEmptyString, s_sEmptyString );
66 
67 		switch (_eType)
68 		{
69 			case ltEnglishUS:
70 				return s_aEnglishUS;
71 
72 			case ltGerman:
73 				return s_aGerman;
74 
75 			case ltSystem:
76 				return s_aSystem;
77 		}
78 
79 		OSL_ENSURE(sal_False, "getLocale: invalid enum value!");
80 		return s_aSystem;
81 	}
82 
83 	//---------------------------------------------------------------------
84 	struct FormatEntry
85 	{
86 		const sal_Char* pDescription;
87 		sal_Int32		nKey;
88 		LocaleType		eLocale;
89 	};
90 
91 	//---------------------------------------------------------------------
lcl_getFormatTable(sal_Int16 nTableId)92 	static const FormatEntry* lcl_getFormatTable(sal_Int16 nTableId)
93 	{
94 		switch (nTableId)
95 		{
96 			case FormComponentType::TIMEFIELD:
97 			{
98 				static FormatEntry s_aFormats[] = {
99 					{ "HH:MM", -1, ltEnglishUS },
100 					{ "HH:MM:SS", -1, ltEnglishUS },
101 					{ "HH:MM AM/PM", -1, ltEnglishUS },
102 					{ "HH:MM:SS AM/PM", -1, ltEnglishUS },
103 					{ NULL, -1, ltSystem }
104 				};
105 				// don't switch this table here to const. The compiler could be tempted to really place this
106 				// in a non-writeable segment, but we want to fill in the format keys later ....
107 				return s_aFormats;
108 			}
109 			case FormComponentType::DATEFIELD:
110 			{
111 				static FormatEntry s_aFormats[] = {
112 					{ "T-M-JJ", -1, ltGerman },
113 					{ "TT-MM-JJ", -1, ltGerman },
114 					{ "TT-MM-JJJJ", -1, ltGerman },
115 					{ "NNNNT. MMMM JJJJ", -1, ltGerman },
116 
117 					{ "DD/MM/YY", -1, ltEnglishUS },
118 					{ "MM/DD/YY", -1, ltEnglishUS },
119 					{ "YY/MM/DD", -1, ltEnglishUS },
120 					{ "DD/MM/YYYY", -1, ltEnglishUS },
121 					{ "MM/DD/YYYY", -1, ltEnglishUS },
122 					{ "YYYY/MM/DD", -1, ltEnglishUS },
123 
124 					{ "JJ-MM-TT", -1, ltGerman },
125 					{ "JJJJ-MM-TT", -1, ltGerman },
126 
127 					{ NULL, -1, ltSystem }
128 				};
129 				return s_aFormats;
130 			}
131 		}
132 
133 		OSL_ENSURE(sal_False, "lcl_getFormatTable: invalid id!");
134 		return NULL;
135 	}
136 
137 	//=====================================================================
138 	//= OLimitedFormats
139 	//=====================================================================
140 	//---------------------------------------------------------------------
OLimitedFormats(const Reference<XMultiServiceFactory> & _rxORB,const sal_Int16 _nClassId)141 	OLimitedFormats::OLimitedFormats(const Reference< XMultiServiceFactory >& _rxORB, const sal_Int16 _nClassId)
142 		:m_nFormatEnumPropertyHandle(-1)
143         ,m_nTableId(_nClassId)
144 	{
145 		OSL_ENSURE(_rxORB.is(), "OLimitedFormats::OLimitedFormats: invalid service factory!");
146 		acquireSupplier(_rxORB);
147 		ensureTableInitialized(m_nTableId);
148 	}
149 
150 	//---------------------------------------------------------------------
~OLimitedFormats()151 	OLimitedFormats::~OLimitedFormats()
152 	{
153 		releaseSupplier();
154 	}
155 
156 	//---------------------------------------------------------------------
ensureTableInitialized(const sal_Int16 _nTableId)157 	void OLimitedFormats::ensureTableInitialized(const sal_Int16 _nTableId)
158 	{
159 		const FormatEntry* pFormatTable = lcl_getFormatTable(_nTableId);
160 		if (-1 == pFormatTable->nKey)
161 		{
162 			::osl::MutexGuard aGuard(s_aMutex);
163 			if (-1 == pFormatTable->nKey)
164 			{
165 				// initialize the keys
166 				Reference<XNumberFormats> xStandardFormats;
167 				if (s_xStandardFormats.is())
168 					xStandardFormats = s_xStandardFormats->getNumberFormats();
169 				OSL_ENSURE(xStandardFormats.is(), "OLimitedFormats::ensureTableInitialized: don't have a formats supplier!");
170 
171 				if (xStandardFormats.is())
172 				{
173 					// loop through the table
174 					FormatEntry* pLoopFormats = const_cast<FormatEntry*>(pFormatTable);
175 					while (pLoopFormats->pDescription)
176 					{
177 						// get the key for the description
178 						pLoopFormats->nKey = xStandardFormats->queryKey(
179 							::rtl::OUString::createFromAscii(pLoopFormats->pDescription),
180 							getLocale(pLoopFormats->eLocale),
181 							sal_False
182 						);
183 
184 						if (-1 == pLoopFormats->nKey)
185 						{
186 							pLoopFormats->nKey = xStandardFormats->addNew(
187 								::rtl::OUString::createFromAscii(pLoopFormats->pDescription),
188 								getLocale(pLoopFormats->eLocale)
189 							);
190 #ifdef DBG_UTIL
191 							try
192 							{
193 								xStandardFormats->getByKey(pLoopFormats->nKey);
194 							}
195 							catch(const Exception&)
196 							{
197 								OSL_ENSURE(sal_False, "OLimitedFormats::ensureTableInitialized: adding the key to the formats collection failed!");
198 							}
199 #endif
200 						}
201 
202 						// next
203 						++pLoopFormats;
204 					}
205 				}
206 			}
207 		}
208 	}
209 
210 	//---------------------------------------------------------------------
clearTable(const sal_Int16 _nTableId)211 	void OLimitedFormats::clearTable(const sal_Int16 _nTableId)
212 	{
213 		::osl::MutexGuard aGuard(s_aMutex);
214 		const FormatEntry* pFormats = lcl_getFormatTable(_nTableId);
215 		FormatEntry* pResetLoop = const_cast<FormatEntry*>(pFormats);
216 		while (pResetLoop->pDescription)
217 		{
218 			pResetLoop->nKey = -1;
219 			++pResetLoop;
220 		}
221 	}
222 
223 	//---------------------------------------------------------------------
setAggregateSet(const Reference<XFastPropertySet> & _rxAggregate,sal_Int32 _nOriginalPropertyHandle)224 	void OLimitedFormats::setAggregateSet(const Reference< XFastPropertySet >& _rxAggregate, sal_Int32 _nOriginalPropertyHandle)
225 	{
226 		// changes (NULL -> not NULL) and (not NULL -> NULL) are allowed
227 		OSL_ENSURE(!m_xAggregate.is() || !_rxAggregate.is(), "OLimitedFormats::setAggregateSet: already have an aggregate!");
228 		OSL_ENSURE(_rxAggregate.is() || m_xAggregate.is(), "OLimitedFormats::setAggregateSet: invalid new aggregate!");
229 
230 		m_xAggregate = _rxAggregate;
231 		m_nFormatEnumPropertyHandle = _nOriginalPropertyHandle;
232 #ifdef DBG_UTIL
233 		if (m_xAggregate.is())
234 		{
235 			try
236 			{
237 				m_xAggregate->getFastPropertyValue(m_nFormatEnumPropertyHandle);
238 			}
239 			catch(const Exception&)
240 			{
241 				OSL_ENSURE(sal_False, "OLimitedFormats::setAggregateSet: invalid handle!");
242 			}
243 		}
244 #endif
245 	}
246 
247 	//---------------------------------------------------------------------
getFormatKeyPropertyValue(Any & _rValue) const248 	void OLimitedFormats::getFormatKeyPropertyValue( Any& _rValue ) const
249 	{
250 		_rValue.clear();
251 
252 		OSL_ENSURE(m_xAggregate.is() && (-1 != m_nFormatEnumPropertyHandle), "OLimitedFormats::getFormatKeyPropertyValue: not initialized!");
253 		if (m_xAggregate.is())
254 		{
255 			// get the aggregate's enum property value
256 			Any aEnumPropertyValue = m_xAggregate->getFastPropertyValue(m_nFormatEnumPropertyHandle);
257 			sal_Int32 nValue = -1;
258 			::cppu::enum2int(nValue, aEnumPropertyValue);
259 
260 			// get the translation table
261 			const FormatEntry* pFormats = lcl_getFormatTable(m_nTableId);
262 
263 			// seek to the nValue'th entry
264 			sal_Int32 nLookup = 0;
265 			for	(	;
266 					(NULL != pFormats->pDescription) && (nLookup < nValue);
267 					++pFormats, ++nLookup
268 				)
269 				;
270 			OSL_ENSURE(NULL != pFormats->pDescription, "OLimitedFormats::getFormatKeyPropertyValue: did not find the value!");
271 			if (pFormats->pDescription)
272 				_rValue <<= pFormats->nKey;
273 		}
274 
275 		// TODO: should use a standard format for the control type we're working for
276 	}
277 
278 	//---------------------------------------------------------------------
convertFormatKeyPropertyValue(Any & _rConvertedValue,Any & _rOldValue,const Any & _rNewValue)279 	sal_Bool OLimitedFormats::convertFormatKeyPropertyValue(Any& _rConvertedValue, Any& _rOldValue, const Any& _rNewValue)
280 	{
281 		OSL_ENSURE(m_xAggregate.is() && (-1 != m_nFormatEnumPropertyHandle), "OLimitedFormats::convertFormatKeyPropertyValue: not initialized!");
282 
283 		if (m_xAggregate.is())
284 		{
285 			// the new format key to set
286 			sal_Int32 nNewFormat = 0;
287 			if (!(_rNewValue >>= nNewFormat))
288 				throw IllegalArgumentException();
289 
290 			// get the old (enum) value from the aggregate
291 			Any aEnumPropertyValue = m_xAggregate->getFastPropertyValue(m_nFormatEnumPropertyHandle);
292 			sal_Int32 nOldEnumValue = -1;
293 			::cppu::enum2int(nOldEnumValue, aEnumPropertyValue);
294 
295 			// get the translation table
296 			const FormatEntry* pFormats = lcl_getFormatTable(m_nTableId);
297 
298 			_rOldValue.clear();
299 			_rConvertedValue.clear();
300 
301 			// look for the entry with the given format key
302 			sal_Int32 nTablePosition = 0;
303 			for	(	;
304 					(NULL != pFormats->pDescription) && (nNewFormat != pFormats->nKey);
305 					++pFormats, ++nTablePosition
306 				)
307 			{
308 				if (nTablePosition == nOldEnumValue)
309 					_rOldValue <<= pFormats->nKey;
310 			}
311 
312 			sal_Bool bFoundIt = (NULL != pFormats->pDescription);
313 			sal_Bool bModified = sal_False;
314 			if (bFoundIt)
315 			{
316 				_rConvertedValue <<= (sal_Int16)nTablePosition;
317 				bModified = nTablePosition != nOldEnumValue;
318 			}
319 
320 			if (!_rOldValue.hasValue())
321 			{	// did not reach the end of the table (means we found nNewFormat)
322 				// -> go to the end to ensure that _rOldValue is set
323 				while (pFormats->pDescription)
324 				{
325 					if (nTablePosition == nOldEnumValue)
326 					{
327 						_rOldValue <<= pFormats->nKey;
328 						break;
329 					}
330 
331 					++pFormats;
332 					++nTablePosition;
333 				}
334 			}
335 
336 			OSL_ENSURE(_rOldValue.hasValue(), "OLimitedFormats::convertFormatKeyPropertyValue: did not find the old enum value in the table!");
337 
338 			if (!bFoundIt)
339 			{	// somebody gave us an format which we can't translate
340 				::rtl::OUString sMessage = ::rtl::OUString::createFromAscii("This control supports only a very limited number of formats.");
341 				throw IllegalArgumentException(sMessage, NULL, 2);
342 			}
343 
344 			return bModified;
345 		}
346 
347 		return sal_False;
348 	}
349 
350 	//---------------------------------------------------------------------
setFormatKeyPropertyValue(const Any & _rNewValue)351 	void OLimitedFormats::setFormatKeyPropertyValue( const Any& _rNewValue )
352 	{
353 		OSL_ENSURE(m_xAggregate.is() && (-1 != m_nFormatEnumPropertyHandle), "OLimitedFormats::setFormatKeyPropertyValue: not initialized!");
354 
355 		if (m_xAggregate.is())
356 		{	// this is to be called after convertFormatKeyPropertyValue, where
357 			// we translated the format key into a enum value.
358 			// So now we can simply forward this enum value to our aggreate
359 			m_xAggregate->setFastPropertyValue(m_nFormatEnumPropertyHandle, _rNewValue);
360 		}
361 	}
362 
363 	//---------------------------------------------------------------------
acquireSupplier(const Reference<XMultiServiceFactory> & _rxORB)364 	void OLimitedFormats::acquireSupplier(const Reference< XMultiServiceFactory >& _rxORB)
365 	{
366 		::osl::MutexGuard aGuard(s_aMutex);
367 		if ((1 == ++s_nInstanceCount) && _rxORB.is())
368 		{	// create the standard formatter
369 
370 			Sequence< Any > aInit(1);
371 			aInit[0] <<= getLocale(ltEnglishUS);
372 
373 			Reference< XInterface > xSupplier = _rxORB->createInstanceWithArguments(FRM_NUMBER_FORMATS_SUPPLIER, aInit);
374 			OSL_ENSURE(xSupplier.is(), "OLimitedFormats::OLimitedFormats: could not create a formats supplier!");
375 
376 			s_xStandardFormats = Reference< XNumberFormatsSupplier >(xSupplier, UNO_QUERY);
377 			OSL_ENSURE(s_xStandardFormats.is() || !xSupplier.is(), "OLimitedFormats::OLimitedFormats: missing an interface!");
378 		}
379 	}
380 
381 	//---------------------------------------------------------------------
releaseSupplier()382 	void OLimitedFormats::releaseSupplier()
383 	{
384 		::osl::MutexGuard aGuard(s_aMutex);
385 		if (0 == --s_nInstanceCount)
386 		{
387 			::comphelper::disposeComponent(s_xStandardFormats);
388 			s_xStandardFormats = NULL;
389 
390 			clearTable(FormComponentType::TIMEFIELD);
391 			clearTable(FormComponentType::DATEFIELD);
392 		}
393 	}
394 
395 //.........................................................................
396 }	// namespace frm
397 //.........................................................................
398 
399