1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "EditBase.hxx"
21 #include <property.hxx>
22 #include <tools/debug.hxx>
23 #include <comphelper/basicio.hxx>
24 #include <comphelper/property.hxx>
25 #include <comphelper/types.hxx>
26 #include <tools/time.hxx>
27 #include <tools/date.hxx>
28 #include <com/sun/star/io/XMarkableStream.hpp>
29 #include <com/sun/star/util/Time.hpp>
30 #include <com/sun/star/util/Date.hpp>
31 
32 
33 namespace frm
34 {
35 using namespace ::com::sun::star;
36 using namespace ::com::sun::star::uno;
37 using namespace ::com::sun::star::sdb;
38 using namespace ::com::sun::star::sdbc;
39 using namespace ::com::sun::star::beans;
40 using namespace ::com::sun::star::container;
41 using namespace ::com::sun::star::form;
42 using namespace ::com::sun::star::awt;
43 using namespace ::com::sun::star::io;
44 using namespace ::com::sun::star::lang;
45 using namespace ::com::sun::star::util;
46 
47 namespace
48 {
49     const sal_uInt16 DEFAULT_LONG    =  0x0001;
50     const sal_uInt16 DEFAULT_DOUBLE  =  0x0002;
51     const sal_uInt16 FILTERPROPOSAL  =  0x0004;
52     const sal_uInt16 DEFAULT_TIME    =  0x0008;
53     const sal_uInt16 DEFAULT_DATE    =  0x0010;
54 }
55 
56 
OEditBaseModel(const Reference<XComponentContext> & _rxFactory,const OUString & rUnoControlModelName,const OUString & rDefault,const bool _bSupportExternalBinding,const bool _bSupportsValidation)57 OEditBaseModel::OEditBaseModel( const Reference< XComponentContext >& _rxFactory, const OUString& rUnoControlModelName,
58         const OUString& rDefault, const bool _bSupportExternalBinding, const bool _bSupportsValidation )
59     :OBoundControlModel( _rxFactory, rUnoControlModelName, rDefault, true, _bSupportExternalBinding, _bSupportsValidation )
60     ,m_nLastReadVersion(0)
61     ,m_bEmptyIsNull(true)
62     ,m_bFilterProposal(false)
63 {
64 }
65 
66 
OEditBaseModel(const OEditBaseModel * _pOriginal,const Reference<XComponentContext> & _rxFactory)67 OEditBaseModel::OEditBaseModel( const OEditBaseModel* _pOriginal, const Reference< XComponentContext >& _rxFactory )
68      :OBoundControlModel( _pOriginal, _rxFactory )
69      ,m_nLastReadVersion(0)
70 {
71 
72     m_bFilterProposal = _pOriginal->m_bFilterProposal;
73     m_bEmptyIsNull = _pOriginal->m_bEmptyIsNull;
74     m_aDefault = _pOriginal->m_aDefault;
75     m_aDefaultText = _pOriginal->m_aDefaultText;
76 }
77 
78 
~OEditBaseModel()79 OEditBaseModel::~OEditBaseModel( )
80 {
81 }
82 
83 // XPersist
84 
write(const Reference<XObjectOutputStream> & _rxOutStream)85 void OEditBaseModel::write(const Reference<XObjectOutputStream>& _rxOutStream)
86 {
87     OBoundControlModel::write(_rxOutStream);
88 
89     // Version
90     sal_uInt16 nVersionId = 0x0006;
91     DBG_ASSERT((getPersistenceFlags() & ~PF_SPECIAL_FLAGS) == 0,
92         "OEditBaseModel::write : invalid special version flags !");
93         // please don't use other flags, older versions can't interpret them !
94 
95     nVersionId |= getPersistenceFlags();
96     _rxOutStream->writeShort(nVersionId);
97 
98     // Name
99     _rxOutStream->writeShort(0);    // obsolete
100     _rxOutStream << m_aDefaultText;
101 
102     // Masking for any
103     sal_uInt16 nAnyMask = 0;
104     if (m_aDefault.getValueType().getTypeClass() == TypeClass_LONG)
105         nAnyMask |= DEFAULT_LONG;
106     else if (m_aDefault.getValueType().getTypeClass() == TypeClass_DOUBLE)
107         nAnyMask |= DEFAULT_DOUBLE;
108     else if (m_aDefault.getValueType() == cppu::UnoType<util::Time>::get())
109         nAnyMask |= DEFAULT_TIME;
110     else if (m_aDefault.getValueType() == cppu::UnoType<util::Date>::get())
111         nAnyMask |= DEFAULT_DATE;
112 
113     if (m_bFilterProposal)  // Don't save a value, because it's boolean
114         nAnyMask |= FILTERPROPOSAL;
115 
116     _rxOutStream->writeBoolean(m_bEmptyIsNull);
117     _rxOutStream->writeShort(nAnyMask);
118 
119     if ((nAnyMask & DEFAULT_LONG) == DEFAULT_LONG)
120         _rxOutStream->writeLong(getINT32(m_aDefault));
121     else if ((nAnyMask & DEFAULT_DOUBLE) == DEFAULT_DOUBLE)
122         _rxOutStream->writeDouble(getDouble(m_aDefault));
123     else if ((nAnyMask & DEFAULT_TIME) == DEFAULT_TIME)
124     {
125         util::Time aTime;
126         OSL_VERIFY(m_aDefault >>= aTime);
127         _rxOutStream->writeHyper(::tools::Time(aTime).GetTime());
128     }
129     else if ((nAnyMask & DEFAULT_DATE) == DEFAULT_DATE)
130     {
131         util::Date aDate;
132         OSL_VERIFY(m_aDefault >>= aDate);
133         _rxOutStream->writeLong(::Date(aDate).GetDate());
134     }
135 
136     // since version 5 we write the help text
137     writeHelpTextCompatibly(_rxOutStream);
138     // (that's potentially bad : at the time I added the above line we had two derived classes : OEditModel and
139     // OFormattedModel. The first one does not have an own version handling, so it can't write the help text itself,
140     // the second one does its own writing (reading) after calling our method, so normally we shouldn't write any
141     // additional members as this is not compatible to older office versions.
142     // We decided to place the writing of the help text here as it seems the less worse alternative. There is no delivered
143     // office version including formatted controls (and thus the OFormattedModel), and the OFormattedModel::read seems
144     // robust against this change (as it will read a wrong and unknown file version and thus set its members to defaults).
145 
146     if ((nVersionId & PF_HANDLE_COMMON_PROPS) != 0)
147         writeCommonEditProperties(_rxOutStream);
148 
149     // !!! properties common to all OEditBaseModel derived classes should be written in writeCommonEditProperties !!!
150 }
151 
152 
getPersistenceFlags() const153 sal_uInt16 OEditBaseModel::getPersistenceFlags() const
154 {
155     return PF_HANDLE_COMMON_PROPS;
156 }
157 
158 
read(const Reference<XObjectInputStream> & _rxInStream)159 void OEditBaseModel::read(const Reference<XObjectInputStream>& _rxInStream)
160 {
161     OBoundControlModel::read(_rxInStream);
162     ::osl::MutexGuard aGuard(m_aMutex);
163 
164     // Version's own version number
165     sal_uInt16 nVersion = _rxInStream->readShort();
166     m_nLastReadVersion = nVersion;
167 
168     bool bHandleCommonProps = (nVersion & PF_HANDLE_COMMON_PROPS) != 0;
169     nVersion = nVersion & ~PF_SPECIAL_FLAGS;
170 
171     // obsolete
172     _rxInStream->readShort();
173 
174     _rxInStream >> m_aDefaultText;
175 
176     if (nVersion >= 0x0003)
177     {
178         m_bEmptyIsNull = _rxInStream->readBoolean();
179 
180         sal_uInt16 nAnyMask = _rxInStream->readShort();
181         if ((nAnyMask & DEFAULT_LONG) == DEFAULT_LONG)
182         {
183             sal_Int32 nValue = _rxInStream->readLong();
184             m_aDefault <<= nValue;
185         }
186         else if ((nAnyMask & DEFAULT_DOUBLE) == DEFAULT_DOUBLE)
187         {
188             double fValue = _rxInStream->readDouble();
189             m_aDefault <<= fValue;
190         }
191         else if ((nAnyMask & DEFAULT_TIME) == DEFAULT_TIME)
192         {
193             m_aDefault <<= ::tools::Time(_rxInStream->readHyper()).GetUNOTime();
194         }
195         else if ((nAnyMask & DEFAULT_DATE) == DEFAULT_DATE)
196         {
197             m_aDefault <<= ::Date(_rxInStream->readLong()).GetUNODate();
198         }
199 
200         if ((nAnyMask & FILTERPROPOSAL) == FILTERPROPOSAL)
201             m_bFilterProposal = true;
202     }
203 
204     if (nVersion > 4)
205         readHelpTextCompatibly(_rxInStream);
206 
207     if (bHandleCommonProps)
208         readCommonEditProperties(_rxInStream);
209 
210     // After reading, display default values
211     if ( !getControlSource().isEmpty() )
212         // (not if we don't have a control source - the "State" property acts like it is persistent, then)
213         resetNoBroadcast();
214 };
215 
216 
defaultCommonEditProperties()217 void OEditBaseModel::defaultCommonEditProperties()
218 {
219     OBoundControlModel::defaultCommonProperties();
220     // no own common properties at the moment
221 }
222 
223 
readCommonEditProperties(const Reference<XObjectInputStream> & _rxInStream)224 void OEditBaseModel::readCommonEditProperties(const Reference<XObjectInputStream>& _rxInStream)
225 {
226     sal_Int32 nLen = _rxInStream->readLong();
227 
228     Reference<XMarkableStream>  xMark(_rxInStream, UNO_QUERY);
229     DBG_ASSERT(xMark.is(), "OBoundControlModel::readCommonProperties : can only work with markable streams !");
230     sal_Int32 nMark = xMark->createMark();
231 
232     // read properties common to all OBoundControlModels
233     OBoundControlModel::readCommonProperties(_rxInStream);
234 
235     // read properties common to all OEditBaseModels
236 
237     // skip the remaining bytes
238     xMark->jumpToMark(nMark);
239     _rxInStream->skipBytes(nLen);
240     xMark->deleteMark(nMark);
241 }
242 
243 
writeCommonEditProperties(const Reference<XObjectOutputStream> & _rxOutStream)244 void OEditBaseModel::writeCommonEditProperties(const Reference<XObjectOutputStream>& _rxOutStream)
245 {
246     Reference<XMarkableStream>  xMark(_rxOutStream, UNO_QUERY);
247     DBG_ASSERT(xMark.is(), "OEditBaseModel::writeCommonProperties : can only work with markable streams !");
248     sal_Int32 nMark = xMark->createMark();
249 
250     // a placeholder where we will write the overall length (later in this method)
251     sal_Int32 nLen = 0;
252     _rxOutStream->writeLong(nLen);
253 
254     // write properties common to all OBoundControlModels
255     OBoundControlModel::writeCommonProperties(_rxOutStream);
256 
257     // write properties common to all OEditBaseModels
258 
259     // close the block - write the correct length at the beginning
260     nLen = xMark->offsetToMark(nMark) - sizeof(nLen);
261     xMark->jumpToMark(nMark);
262     _rxOutStream->writeLong(nLen);
263     xMark->jumpToFurthest();
264     xMark->deleteMark(nMark);
265 }
266 
267 
getFastPropertyValue(Any & rValue,sal_Int32 nHandle) const268 void OEditBaseModel::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
269 {
270     switch (nHandle)
271     {
272         case PROPERTY_ID_EMPTY_IS_NULL:
273             rValue <<= m_bEmptyIsNull;
274             break;
275         case PROPERTY_ID_FILTERPROPOSAL:
276             rValue <<= m_bFilterProposal;
277             break;
278         case PROPERTY_ID_DEFAULT_TEXT:
279             rValue <<= m_aDefaultText;
280             break;
281         case PROPERTY_ID_DEFAULT_VALUE:
282         case PROPERTY_ID_DEFAULT_DATE:
283         case PROPERTY_ID_DEFAULT_TIME:
284             rValue = m_aDefault;
285             break;
286         default:
287             OBoundControlModel::getFastPropertyValue(rValue, nHandle);
288     }
289 }
290 
convertFastPropertyValue(Any & rConvertedValue,Any & rOldValue,sal_Int32 nHandle,const Any & rValue)291 sal_Bool OEditBaseModel::convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue,
292                                             sal_Int32 nHandle, const Any& rValue )
293 {
294     bool bModified(false);
295     switch (nHandle)
296     {
297         case PROPERTY_ID_EMPTY_IS_NULL:
298             bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bEmptyIsNull);
299             break;
300         case PROPERTY_ID_FILTERPROPOSAL:
301             bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bFilterProposal);
302             break;
303         case PROPERTY_ID_DEFAULT_TEXT:
304             bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aDefaultText);
305             break;
306         case PROPERTY_ID_DEFAULT_VALUE:
307             bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aDefault, cppu::UnoType<double>::get());
308             break;
309         case PROPERTY_ID_DEFAULT_DATE:
310             bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aDefault, cppu::UnoType<util::Date>::get());
311             break;
312         case PROPERTY_ID_DEFAULT_TIME:
313             bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aDefault, cppu::UnoType<util::Time>::get());
314             break;
315         default:
316             bModified = OBoundControlModel::convertFastPropertyValue(
317                                             rConvertedValue,
318                                             rOldValue,
319                                             nHandle,
320                                             rValue);
321     }
322     return bModified;
323 }
324 
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any & rValue)325 void OEditBaseModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
326 {
327     switch (nHandle)
328     {
329         case PROPERTY_ID_EMPTY_IS_NULL:
330             DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN, "invalid type" );
331             m_bEmptyIsNull = getBOOL(rValue);
332             break;
333         case PROPERTY_ID_FILTERPROPOSAL:
334             DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN, "invalid type" );
335             m_bFilterProposal = getBOOL(rValue);
336             break;
337         // Changing the default values causes a reset
338         case PROPERTY_ID_DEFAULT_TEXT:
339             DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_STRING, "invalid type" );
340             rValue >>= m_aDefaultText;
341             resetNoBroadcast();
342             break;
343         case PROPERTY_ID_DEFAULT_VALUE:
344         case PROPERTY_ID_DEFAULT_DATE:
345         case PROPERTY_ID_DEFAULT_TIME:
346             m_aDefault = rValue;
347             resetNoBroadcast();
348             break;
349         default:
350             OBoundControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue );
351     }
352 }
353 
354 // XPropertyState
355 
getPropertyDefaultByHandle(sal_Int32 nHandle) const356 Any OEditBaseModel::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
357 {
358     switch (nHandle)
359     {
360         case PROPERTY_ID_DEFAULT_TEXT:
361             return makeAny(OUString());
362         case PROPERTY_ID_FILTERPROPOSAL:
363             return makeAny(false);
364         case PROPERTY_ID_DEFAULT_VALUE:
365         case PROPERTY_ID_DEFAULT_DATE:
366         case PROPERTY_ID_DEFAULT_TIME:
367             return Any();
368         default:
369             return OBoundControlModel::getPropertyDefaultByHandle(nHandle);
370     }
371 }
372 
373 
374 }
375 
376 
377 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
378