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