xref: /trunk/main/forms/source/misc/limitedformats.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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