Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "ComboBox.hxx"
31 : : #include "property.hxx"
32 : : #include "property.hrc"
33 : : #include "services.hxx"
34 : :
35 : : #include "frm_resource.hxx"
36 : : #include "frm_resource.hrc"
37 : : #include "BaseListBox.hxx"
38 : :
39 : : #include <com/sun/star/sdb/SQLErrorEvent.hpp>
40 : : #include <com/sun/star/sdbc/XRowSet.hpp>
41 : : #include <com/sun/star/sdbc/DataType.hpp>
42 : : #include <com/sun/star/container/XIndexAccess.hpp>
43 : : #include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
44 : : #include <com/sun/star/sdb/XQueriesSupplier.hpp>
45 : : #include <com/sun/star/util/NumberFormat.hpp>
46 : : #include <com/sun/star/sdbc/XConnection.hpp>
47 : : #include <com/sun/star/sdb/SQLContext.hpp>
48 : : #include <com/sun/star/sdb/CommandType.hpp>
49 : :
50 : : #include <comphelper/numbers.hxx>
51 : : #include <comphelper/basicio.hxx>
52 : : #include <connectivity/dbtools.hxx>
53 : : #include <connectivity/dbconversion.hxx>
54 : : #include <cppuhelper/queryinterface.hxx>
55 : : #include <rtl/ustrbuf.hxx>
56 : : #include <tools/debug.hxx>
57 : : #include <tools/diagnose_ex.h>
58 : : #include <unotools/sharedunocomponent.hxx>
59 : :
60 : : #include <limits.h>
61 : :
62 : : using namespace dbtools;
63 : :
64 : : //.........................................................................
65 : : namespace frm
66 : : {
67 : : using namespace ::com::sun::star::uno;
68 : : using namespace ::com::sun::star::sdb;
69 : : using namespace ::com::sun::star::sdbc;
70 : : using namespace ::com::sun::star::sdbcx;
71 : : using namespace ::com::sun::star::beans;
72 : : using namespace ::com::sun::star::container;
73 : : using namespace ::com::sun::star::form;
74 : : using namespace ::com::sun::star::awt;
75 : : using namespace ::com::sun::star::io;
76 : : using namespace ::com::sun::star::lang;
77 : : using namespace ::com::sun::star::util;
78 : : using namespace ::com::sun::star::form::binding;
79 : :
80 : : //========================================================================
81 : : // class OComboBoxModel
82 : : //========================================================================
83 : : //------------------------------------------------------------------
84 : 19 : InterfaceRef SAL_CALL OComboBoxModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) throw (RuntimeException)
85 : : {
86 [ + - ]: 19 : return (*new OComboBoxModel(_rxFactory));
87 : : }
88 : :
89 : : //------------------------------------------------------------------------------
90 : 4 : Sequence<Type> OComboBoxModel::_getTypes()
91 : : {
92 : : return ::comphelper::concatSequences(
93 : : OBoundControlModel::_getTypes(),
94 : : OEntryListHelper::getTypes(),
95 : : OErrorBroadcaster::getTypes()
96 [ + - ][ + - ]: 4 : );
[ + - ][ + - ]
[ + - ]
97 : : }
98 : :
99 : : // XServiceInfo
100 : : //------------------------------------------------------------------------------
101 : 16 : StringSequence SAL_CALL OComboBoxModel::getSupportedServiceNames() throw(RuntimeException)
102 : : {
103 : 16 : StringSequence aSupported = OBoundControlModel::getSupportedServiceNames();
104 : :
105 : 16 : sal_Int32 nOldLen = aSupported.getLength();
106 [ + - ]: 16 : aSupported.realloc( nOldLen + 8 );
107 [ + - ]: 16 : ::rtl::OUString* pStoreTo = aSupported.getArray() + nOldLen;
108 : :
109 [ + - ]: 16 : *pStoreTo++ = BINDABLE_CONTROL_MODEL;
110 [ + - ]: 16 : *pStoreTo++ = DATA_AWARE_CONTROL_MODEL;
111 [ + - ]: 16 : *pStoreTo++ = VALIDATABLE_CONTROL_MODEL;
112 : :
113 [ + - ]: 16 : *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL;
114 [ + - ]: 16 : *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL;
115 : :
116 [ + - ]: 16 : *pStoreTo++ = FRM_SUN_COMPONENT_COMBOBOX;
117 [ + - ]: 16 : *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_COMBOBOX;
118 [ + - ]: 16 : *pStoreTo++ = BINDABLE_DATABASE_COMBO_BOX;
119 : :
120 : 16 : return aSupported;
121 : : }
122 : :
123 : : //------------------------------------------------------------------------------
124 : 12770 : Any SAL_CALL OComboBoxModel::queryAggregation(const Type& _rType) throw (RuntimeException)
125 : : {
126 : 12770 : Any aReturn = OBoundControlModel::queryAggregation( _rType );
127 [ + + ]: 12770 : if ( !aReturn.hasValue() )
128 [ + - ]: 245 : aReturn = OEntryListHelper::queryInterface( _rType );
129 [ + + ]: 12770 : if ( !aReturn.hasValue() )
130 [ + - ]: 177 : aReturn = OErrorBroadcaster::queryInterface( _rType );
131 : 12770 : return aReturn;
132 : : }
133 : :
134 : : //------------------------------------------------------------------
135 : : DBG_NAME( OComboBoxModel )
136 : : //------------------------------------------------------------------
137 : 19 : OComboBoxModel::OComboBoxModel(const Reference<XMultiServiceFactory>& _rxFactory)
138 : : :OBoundControlModel( _rxFactory, VCL_CONTROLMODEL_COMBOBOX, FRM_SUN_CONTROL_COMBOBOX, sal_True, sal_True, sal_True )
139 : : // use the old control name for compytibility reasons
140 : : ,OEntryListHelper( (OControlModel&)*this )
141 : : ,OErrorBroadcaster( OComponentHelper::rBHelper )
142 : 19 : ,m_aListRowSet( getContext() )
143 : : ,m_eListSourceType(ListSourceType_TABLE)
144 [ + - ][ + - ]: 38 : ,m_bEmptyIsNull(sal_True)
[ + - ]
[ + - + - ]
[ + - ]
145 : : {
146 : : DBG_CTOR( OComboBoxModel, NULL );
147 : :
148 : 19 : m_nClassId = FormComponentType::COMBOBOX;
149 [ + - ][ + - ]: 19 : initValueProperty( PROPERTY_TEXT, PROPERTY_ID_TEXT );
150 : 19 : }
151 : :
152 : : //------------------------------------------------------------------
153 : 2 : OComboBoxModel::OComboBoxModel( const OComboBoxModel* _pOriginal, const Reference<XMultiServiceFactory>& _rxFactory )
154 : : :OBoundControlModel( _pOriginal, _rxFactory )
155 : : ,OEntryListHelper( *_pOriginal, (OControlModel&)*this )
156 : : ,OErrorBroadcaster( OComponentHelper::rBHelper )
157 : 2 : ,m_aListRowSet( getContext() )
158 : : ,m_aListSource( _pOriginal->m_aListSource )
159 : : ,m_aDefaultText( _pOriginal->m_aDefaultText )
160 : : ,m_eListSourceType( _pOriginal->m_eListSourceType )
161 [ + - ]: 4 : ,m_bEmptyIsNull( _pOriginal->m_bEmptyIsNull )
[ + - + - ]
[ + - ]
162 : : {
163 : : DBG_CTOR( OComboBoxModel, NULL );
164 : 2 : }
165 : :
166 : : //------------------------------------------------------------------
167 [ + - ][ + - ]: 21 : OComboBoxModel::~OComboBoxModel()
[ + - ][ + - ]
[ + - ]
168 : : {
169 [ - + ]: 21 : if (!OComponentHelper::rBHelper.bDisposed)
170 : : {
171 : 0 : acquire();
172 [ # # ]: 0 : dispose();
173 : : }
174 : :
175 : : DBG_DTOR( OComboBoxModel, NULL );
176 [ - + ]: 42 : }
177 : :
178 : : // XCloneable
179 : : //------------------------------------------------------------------------------
180 [ + - ][ + - ]: 2 : IMPLEMENT_DEFAULT_CLONING( OComboBoxModel )
181 : :
182 : : //------------------------------------------------------------------------------
183 : 21 : void OComboBoxModel::disposing()
184 : : {
185 : 21 : OBoundControlModel::disposing();
186 : 21 : OEntryListHelper::disposing();
187 : 21 : OErrorBroadcaster::disposing();
188 : 21 : m_xFormatter = NULL;
189 : 21 : }
190 : :
191 : : //------------------------------------------------------------------------------
192 : 8598 : void OComboBoxModel::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
193 : : {
194 [ + + + + : 8598 : switch (_nHandle)
+ + ]
195 : : {
196 : : case PROPERTY_ID_LISTSOURCETYPE:
197 : 178 : _rValue <<= m_eListSourceType;
198 : 178 : break;
199 : :
200 : : case PROPERTY_ID_LISTSOURCE:
201 : 178 : _rValue <<= m_aListSource;
202 : 178 : break;
203 : :
204 : : case PROPERTY_ID_EMPTY_IS_NULL:
205 : 178 : _rValue <<= m_bEmptyIsNull;
206 : 178 : break;
207 : :
208 : : case PROPERTY_ID_DEFAULT_TEXT:
209 : 178 : _rValue <<= m_aDefaultText;
210 : 178 : break;
211 : :
212 : : case PROPERTY_ID_STRINGITEMLIST:
213 : 222 : _rValue <<= getStringItemList();
214 : 222 : break;
215 : :
216 : : default:
217 : 7664 : OBoundControlModel::getFastPropertyValue(_rValue, _nHandle);
218 : : }
219 : 8598 : }
220 : :
221 : : //------------------------------------------------------------------------------
222 : 297 : void OComboBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
223 : : throw (Exception)
224 : : {
225 [ + + + + : 297 : switch (_nHandle)
+ + ]
226 : : {
227 : : case PROPERTY_ID_LISTSOURCETYPE :
228 : : DBG_ASSERT(_rValue.getValueType().equals(::getCppuType(static_cast<ListSourceType*>(0))),
229 : : "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
230 : 22 : _rValue >>= m_eListSourceType;
231 : 22 : break;
232 : :
233 : : case PROPERTY_ID_LISTSOURCE :
234 : : DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_STRING,
235 : : "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
236 : 22 : _rValue >>= m_aListSource;
237 : : // The ListSource has changed -> reload
238 [ + + ]: 22 : if (ListSourceType_VALUELIST != m_eListSourceType)
239 : : {
240 [ - + ][ # # ]: 16 : if ( m_xCursor.is() && !hasField() && !hasExternalListSource() )
[ # # ][ - + ]
241 : : // combo box is already connected to a database, and no external list source
242 : : // data source changed -> refresh
243 : 0 : loadData( false );
244 : : }
245 : 22 : break;
246 : :
247 : : case PROPERTY_ID_EMPTY_IS_NULL :
248 : : DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN,
249 : : "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
250 : 22 : _rValue >>= m_bEmptyIsNull;
251 : 22 : break;
252 : :
253 : : case PROPERTY_ID_DEFAULT_TEXT :
254 : : DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_STRING,
255 : : "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
256 : 22 : _rValue >>= m_aDefaultText;
257 : 22 : resetNoBroadcast();
258 : 22 : break;
259 : :
260 : : case PROPERTY_ID_STRINGITEMLIST:
261 : : {
262 [ + - ]: 34 : ControlModelLock aLock( *this );
263 [ + - ][ + - ]: 34 : setNewStringItemList( _rValue, aLock );
264 : : // TODO: this is bogus. setNewStringItemList expects a guard which has the *only*
265 : : // lock to the mutex, but setFastPropertyValue_NoBroadcast is already called with
266 : : // a lock - so we effectively has two locks here, of which setNewStringItemList can
267 : : // only control one.
268 : : }
269 : 34 : break;
270 : :
271 : : default:
272 : 175 : OBoundControlModel::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
273 : : }
274 : 297 : }
275 : :
276 : : //------------------------------------------------------------------------------
277 : 1287 : sal_Bool OComboBoxModel::convertFastPropertyValue(
278 : : Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
279 : : throw (IllegalArgumentException)
280 : : {
281 : 1287 : sal_Bool bModified(sal_False);
282 [ + + + + : 1287 : switch (_nHandle)
+ + ]
283 : : {
284 : : case PROPERTY_ID_LISTSOURCETYPE :
285 : 112 : bModified = tryPropertyValueEnum(_rConvertedValue, _rOldValue, _rValue, m_eListSourceType);
286 : 112 : break;
287 : :
288 : : case PROPERTY_ID_LISTSOURCE :
289 : 112 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aListSource);
290 : 112 : break;
291 : :
292 : : case PROPERTY_ID_EMPTY_IS_NULL :
293 : 112 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bEmptyIsNull);
294 : 112 : break;
295 : :
296 : : case PROPERTY_ID_DEFAULT_TEXT :
297 : 112 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aDefaultText);
298 : 112 : break;
299 : :
300 : : case PROPERTY_ID_STRINGITEMLIST:
301 : 124 : bModified = convertNewListSourceProperty( _rConvertedValue, _rOldValue, _rValue );
302 : 124 : break;
303 : :
304 : : default:
305 : 715 : bModified = OBoundControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
306 : 715 : break;
307 : : }
308 : 1287 : return bModified;
309 : : }
310 : :
311 : : //------------------------------------------------------------------------------
312 : 23 : void OComboBoxModel::describeFixedProperties( Sequence< Property >& _rProps ) const
313 : : {
314 : 23 : BEGIN_DESCRIBE_PROPERTIES( 6, OBoundControlModel )
315 [ + - ]: 23 : DECL_PROP1(TABINDEX, sal_Int16, BOUND);
316 [ + - ]: 23 : DECL_PROP1(LISTSOURCETYPE, ListSourceType, BOUND);
317 [ + - ]: 23 : DECL_PROP1(LISTSOURCE, ::rtl::OUString, BOUND);
318 [ + - ]: 23 : DECL_BOOL_PROP1(EMPTY_IS_NULL, BOUND);
319 [ + - ]: 23 : DECL_PROP1(DEFAULT_TEXT, ::rtl::OUString, BOUND);
320 [ + - ]: 23 : DECL_PROP1(STRINGITEMLIST, Sequence< ::rtl::OUString >,BOUND);
321 : : END_DESCRIBE_PROPERTIES();
322 : 23 : }
323 : :
324 : : //------------------------------------------------------------------------------
325 : 23 : void OComboBoxModel::describeAggregateProperties( Sequence< Property >& _rAggregateProps ) const
326 : : {
327 : 23 : OBoundControlModel::describeAggregateProperties( _rAggregateProps );
328 : :
329 : : // superseded properties:
330 [ + - ]: 23 : RemoveProperty( _rAggregateProps, PROPERTY_STRINGITEMLIST );
331 : 23 : }
332 : :
333 : : //------------------------------------------------------------------------------
334 : 2 : ::rtl::OUString SAL_CALL OComboBoxModel::getServiceName() throw(RuntimeException)
335 : : {
336 : 2 : return FRM_COMPONENT_COMBOBOX; // old (non-sun) name for compatibility !
337 : : }
338 : :
339 : : //------------------------------------------------------------------------------
340 : 2 : void SAL_CALL OComboBoxModel::write(const Reference<stario::XObjectOutputStream>& _rxOutStream)
341 : : throw(stario::IOException, RuntimeException)
342 : : {
343 [ + - ]: 2 : OBoundControlModel::write(_rxOutStream);
344 : :
345 : : // Version
346 : : // Version 0x0002: EmptyIsNull
347 : : // Version 0x0003: ListSource->Seq
348 : : // Version 0x0004: DefaultText
349 : : // Version 0x0005: HelpText
350 [ + - ][ + - ]: 2 : _rxOutStream->writeShort(0x0006);
351 : :
352 : : // Maskierung fuer any
353 : 2 : sal_uInt16 nAnyMask = 0;
354 [ - + ]: 2 : if (m_aBoundColumn.getValueType().getTypeClass() == TypeClass_SHORT)
355 : 0 : nAnyMask |= BOUNDCOLUMN;
356 [ + - ]: 2 : _rxOutStream << nAnyMask;
357 : :
358 [ + - ]: 2 : StringSequence aListSourceSeq(&m_aListSource, 1);
359 [ + - ]: 2 : _rxOutStream << aListSourceSeq;
360 [ + - ]: 2 : _rxOutStream << (sal_Int16)m_eListSourceType;
361 : :
362 [ - + ]: 2 : if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
363 : : {
364 : 0 : sal_Int16 nBoundColumn = 0;
365 : 0 : m_aBoundColumn >>= nBoundColumn;
366 [ # # ]: 0 : _rxOutStream << nBoundColumn;
367 : : }
368 : :
369 [ + - ]: 2 : _rxOutStream << (sal_Bool)m_bEmptyIsNull;
370 [ + - ]: 2 : _rxOutStream << m_aDefaultText;
371 [ + - ]: 2 : writeHelpTextCompatibly(_rxOutStream);
372 : :
373 : : // from version 0x0006 : common properties
374 [ + - ][ + - ]: 2 : writeCommonProperties(_rxOutStream);
375 : 2 : }
376 : :
377 : : //------------------------------------------------------------------------------
378 : 2 : void SAL_CALL OComboBoxModel::read(const Reference<stario::XObjectInputStream>& _rxInStream) throw(stario::IOException, RuntimeException)
379 : : {
380 [ + - ]: 2 : OBoundControlModel::read(_rxInStream);
381 [ + - ]: 2 : ControlModelLock aLock( *this );
382 : :
383 : : // since we are "overwriting" the StringItemList of our aggregate (means we have
384 : : // an own place to store the value, instead of relying on our aggregate storing it),
385 : : // we need to respect what the aggregate just read for the StringItemList property.
386 : : try
387 : : {
388 [ + - ]: 2 : if ( m_xAggregateSet.is() )
389 [ + - ][ + - ]: 2 : setNewStringItemList( m_xAggregateSet->getPropertyValue( PROPERTY_STRINGITEMLIST ), aLock );
[ + - ][ + - ]
[ # # ]
390 : : }
391 [ # # ]: 0 : catch( const Exception& )
392 : : {
393 : : OSL_FAIL( "OComboBoxModel::read: caught an exception while examining the aggregate's string item list!" );
394 : : }
395 : :
396 : : // Version
397 [ + - ][ + - ]: 2 : sal_uInt16 nVersion = _rxInStream->readShort();
398 : : DBG_ASSERT(nVersion > 0, "OComboBoxModel::read : version 0 ? this should never have been written !");
399 : :
400 [ - + ]: 2 : if (nVersion > 0x0006)
401 : : {
402 : : OSL_FAIL("OComboBoxModel::read : invalid (means unknown) version !");
403 : 0 : m_aListSource = ::rtl::OUString();
404 [ # # ]: 0 : m_aBoundColumn <<= (sal_Int16)0;
405 : 0 : m_aDefaultText = ::rtl::OUString();
406 : 0 : m_eListSourceType = ListSourceType_TABLE;
407 : 0 : m_bEmptyIsNull = sal_True;
408 [ # # ]: 0 : defaultCommonProperties();
409 : 2 : return;
410 : : }
411 : :
412 : : // Masking for any
413 : : sal_uInt16 nAnyMask;
414 [ + - ]: 2 : _rxInStream >> nAnyMask;
415 : :
416 : : // ListSource
417 [ - + ]: 2 : if (nVersion < 0x0003)
418 : : {
419 [ # # ]: 0 : _rxInStream >> m_aListSource;
420 : : }
421 : : else // nVersion == 4
422 : : {
423 : 2 : m_aListSource = ::rtl::OUString();
424 [ + - ]: 2 : StringSequence aListSource;
425 [ + - ]: 2 : _rxInStream >> aListSource;
426 : 2 : const ::rtl::OUString* pToken = aListSource.getConstArray();
427 : 2 : sal_Int32 nLen = aListSource.getLength();
428 [ + + ]: 4 : for (sal_Int32 i = 0; i < nLen; ++i, ++pToken)
429 [ + - ]: 4 : m_aListSource += *pToken;
430 : : }
431 : :
432 : : sal_Int16 nListSourceType;
433 [ + - ]: 2 : _rxInStream >> nListSourceType;
434 : 2 : m_eListSourceType = (ListSourceType)nListSourceType;
435 : :
436 [ - + ]: 2 : if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
437 : : {
438 : : sal_Int16 nValue;
439 [ # # ]: 0 : _rxInStream >> nValue;
440 [ # # ]: 0 : m_aBoundColumn <<= nValue;
441 : : }
442 : :
443 [ + - ]: 2 : if (nVersion > 0x0001)
444 : : {
445 : : sal_Bool bNull;
446 [ + - ]: 2 : _rxInStream >> bNull;
447 : 2 : m_bEmptyIsNull = bNull;
448 : : }
449 : :
450 [ + - ]: 2 : if (nVersion > 0x0003) // nVersion == 4
451 [ + - ]: 2 : _rxInStream >> m_aDefaultText;
452 : :
453 : : // StringList must be emptied if a ListSource is set.
454 : : // This can be the case if we save in alive mode.
455 [ - + # # ]: 2 : if ( !m_aListSource.isEmpty()
[ - + ]
456 : 0 : && !hasExternalListSource()
457 : : )
458 : : {
459 [ # # ][ # # ]: 0 : setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( StringSequence() ) );
[ # # ][ # # ]
460 : : }
461 : :
462 [ + - ]: 2 : if (nVersion > 0x0004)
463 [ + - ]: 2 : readHelpTextCompatibly(_rxInStream);
464 : :
465 [ + - ]: 2 : if (nVersion > 0x0005)
466 [ + - ]: 2 : readCommonProperties(_rxInStream);
467 : :
468 : : // After reading in, display the default values
469 [ + - ]: 2 : if ( !getControlSource().isEmpty() )
470 : : {
471 : : // (not if we don't have a control source - the "State" property acts like it is persistent, then
472 [ + - ]: 2 : resetNoBroadcast();
473 [ + - ][ + - ]: 2 : }
474 : : }
475 : :
476 : : //------------------------------------------------------------------------------
477 : 0 : void OComboBoxModel::loadData( bool _bForce )
478 : : {
479 : : DBG_ASSERT(m_eListSourceType != ListSourceType_VALUELIST, "OComboBoxModel::loadData : do not call for a value list !");
480 : : DBG_ASSERT( !hasExternalListSource(), "OComboBoxModel::loadData: cannot load from DB when I have an external list source!" );
481 : :
482 [ # # ]: 0 : if ( hasExternalListSource() )
483 : : return;
484 : :
485 : : // Get Connection
486 [ # # ]: 0 : Reference<XRowSet> xForm(m_xCursor, UNO_QUERY);
487 [ # # ]: 0 : if (!xForm.is())
488 : : return;
489 [ # # ]: 0 : Reference<XConnection> xConnection = getConnection(xForm);
490 [ # # ]: 0 : if (!xConnection.is())
491 : : return;
492 : :
493 [ # # ]: 0 : Reference<XServiceInfo> xServiceInfo(xConnection, UNO_QUERY);
494 [ # # ][ # # ]: 0 : if (!xServiceInfo.is() || !xServiceInfo->supportsService(SRV_SDB_CONNECTION))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
495 : : {
496 : : OSL_FAIL("OComboBoxModel::loadData : invalid connection !");
497 : : return;
498 : : }
499 : :
500 [ # # ][ # # ]: 0 : if (m_aListSource.isEmpty() || m_eListSourceType == ListSourceType_VALUELIST)
[ # # ]
501 : : return;
502 : :
503 [ # # ]: 0 : ::utl::SharedUNOComponent< XResultSet > xListCursor;
504 : : try
505 : : {
506 [ # # ]: 0 : m_aListRowSet.setConnection( xConnection );
507 : :
508 : 0 : bool bExecuteRowSet( false );
509 [ # # # # ]: 0 : switch (m_eListSourceType)
510 : : {
511 : : case ListSourceType_TABLEFIELDS:
512 : : // don't work with a statement here, the fields will be collected below
513 : 0 : break;
514 : : case ListSourceType_TABLE:
515 : : {
516 : : // does the bound field belong to the table ?
517 : : // if we use an alias for the bound field, we won't find it
518 : : // in that case we use the first field of the table
519 : :
520 [ # # ]: 0 : Reference<XNameAccess> xFieldsByName = getTableFields(xConnection, m_aListSource);
521 [ # # ]: 0 : Reference<XIndexAccess> xFieldsByIndex(xFieldsByName, UNO_QUERY);
522 : :
523 : 0 : ::rtl::OUString aFieldName;
524 [ # # ][ # # ]: 0 : if ( xFieldsByName.is() && xFieldsByName->hasByName( getControlSource() ) )
[ # # ][ # # ]
[ # # ]
525 : : {
526 : 0 : aFieldName = getControlSource();
527 : : }
528 : : else
529 : : {
530 : : // otherwise look for the alias
531 [ # # ]: 0 : Reference<XPropertySet> xFormProp(xForm,UNO_QUERY);
532 : 0 : Reference< XColumnsSupplier > xSupplyFields;
533 [ # # ][ # # ]: 0 : xFormProp->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SingleSelectQueryComposer"))) >>= xSupplyFields;
[ # # ][ # # ]
534 : :
535 : : // search the field
536 : : DBG_ASSERT(xSupplyFields.is(), "OComboBoxModel::loadData : invalid query composer !");
537 : :
538 [ # # ][ # # ]: 0 : Reference< XNameAccess > xFieldNames = xSupplyFields->getColumns();
539 [ # # ][ # # ]: 0 : if ( xFieldNames->hasByName( getControlSource() ) )
[ # # ]
540 : : {
541 : 0 : Reference< XPropertySet > xComposerFieldAsSet;
542 [ # # ][ # # ]: 0 : xFieldNames->getByName( getControlSource() ) >>= xComposerFieldAsSet;
[ # # ]
543 [ # # ][ # # ]: 0 : if (hasProperty(PROPERTY_FIELDSOURCE, xComposerFieldAsSet))
[ # # ]
544 [ # # ][ # # ]: 0 : xComposerFieldAsSet->getPropertyValue(PROPERTY_FIELDSOURCE) >>= aFieldName;
[ # # ]
545 : 0 : }
546 : : }
547 : :
548 [ # # ]: 0 : if (aFieldName.isEmpty())
549 : : break;
550 : :
551 [ # # ][ # # ]: 0 : Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
552 : : OSL_ENSURE(xMeta.is(),"No database meta data!");
553 [ # # ]: 0 : if ( xMeta.is() )
554 : : {
555 [ # # ][ # # ]: 0 : ::rtl::OUString aQuote = xMeta->getIdentifierQuoteString();
556 : :
557 : 0 : ::rtl::OUString sCatalog, sSchema, sTable;
558 [ # # ]: 0 : qualifiedNameComponents( xMeta, m_aListSource, sCatalog, sSchema, sTable, eInDataManipulation );
559 : :
560 : 0 : ::rtl::OUStringBuffer aStatement;
561 [ # # ]: 0 : aStatement.appendAscii( "SELECT DISTINCT " );
562 [ # # ][ # # ]: 0 : aStatement.append ( quoteName( aQuote, aFieldName ) );
563 [ # # ]: 0 : aStatement.appendAscii( " FROM " );
564 [ # # ][ # # ]: 0 : aStatement.append ( composeTableNameForSelect( xConnection, sCatalog, sSchema, sTable ) );
565 : :
566 [ # # ]: 0 : m_aListRowSet.setEscapeProcessing( sal_False );
567 [ # # ][ # # ]: 0 : m_aListRowSet.setCommand( aStatement.makeStringAndClear() );
568 : 0 : bExecuteRowSet = true;
569 [ # # ][ # # ]: 0 : }
[ # # ]
570 : 0 : } break;
571 : : case ListSourceType_QUERY:
572 : : {
573 [ # # ]: 0 : m_aListRowSet.setCommandFromQuery( m_aListSource );
574 : 0 : bExecuteRowSet = true;
575 : : }
576 : 0 : break;
577 : :
578 : : default:
579 : : {
580 [ # # ]: 0 : m_aListRowSet.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH != m_eListSourceType );
581 [ # # ]: 0 : m_aListRowSet.setCommand( m_aListSource );
582 : 0 : bExecuteRowSet = true;
583 : : }
584 : : }
585 : :
586 [ # # ]: 0 : if ( bExecuteRowSet )
587 : : {
588 [ # # ][ # # ]: 0 : if ( !_bForce && !m_aListRowSet.isDirty() )
[ # # ][ # # ]
589 : : {
590 : : // if none of the settings of the row set changed, compared to the last
591 : : // invocation of loadData, then don't re-fill the list. Instead, assume
592 : : // the list entries are the same.
593 : : return;
594 : : }
595 [ # # ][ # # ]: 0 : xListCursor.reset( m_aListRowSet.execute() );
596 : : }
597 : : }
598 [ # # # # : 0 : catch(const SQLException& eSQL)
# ]
599 : : {
600 [ # # # # ]: 0 : onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST));
601 : : return;
602 : : }
603 [ # # ]: 0 : catch( const Exception& )
604 : : {
605 : : DBG_UNHANDLED_EXCEPTION();
606 : : return;
607 : : }
608 : :
609 [ # # ]: 0 : ::std::vector< ::rtl::OUString > aStringList;
610 [ # # ]: 0 : aStringList.reserve(16);
611 : : try
612 : : {
613 : : OSL_ENSURE( xListCursor.is() || ( ListSourceType_TABLEFIELDS == m_eListSourceType ),
614 : : "OComboBoxModel::loadData: logic error!" );
615 [ # # ][ # # ]: 0 : if ( !xListCursor.is() && ( ListSourceType_TABLEFIELDS != m_eListSourceType ) )
[ # # ]
616 : : return;
617 : :
618 [ # # # ]: 0 : switch (m_eListSourceType)
619 : : {
620 : : case ListSourceType_SQL:
621 : : case ListSourceType_SQLPASSTHROUGH:
622 : : case ListSourceType_TABLE:
623 : : case ListSourceType_QUERY:
624 : : {
625 : : // The XDatabaseVariant of the first column
626 [ # # ]: 0 : Reference<XColumnsSupplier> xSupplyCols(xListCursor, UNO_QUERY);
627 : : DBG_ASSERT(xSupplyCols.is(), "OComboBoxModel::loadData : cursor supports the row set service but is no column supplier?!");
628 : 0 : Reference<XIndexAccess> xColumns;
629 [ # # ]: 0 : if (xSupplyCols.is())
630 : : {
631 [ # # ][ # # ]: 0 : xColumns = Reference<XIndexAccess>(xSupplyCols->getColumns(), UNO_QUERY);
[ # # ][ # # ]
632 : : DBG_ASSERT(xColumns.is(), "OComboBoxModel::loadData : no columns supplied by the row set !");
633 : : }
634 : 0 : Reference< XPropertySet > xDataField;
635 [ # # ]: 0 : if ( xColumns.is() )
636 [ # # ][ # # ]: 0 : xColumns->getByIndex(0) >>= xDataField;
[ # # ]
637 [ # # ]: 0 : if ( !xDataField.is() )
638 : : return;
639 : :
640 [ # # ]: 0 : ::dbtools::FormattedColumnValue aValueFormatter( getContext(), xForm, xDataField );
641 : :
642 : : // Fill Lists
643 : 0 : sal_Int16 i = 0;
644 : : // At the moment by definition the list cursor is positioned _before_ the first row
645 [ # # ][ # # ]: 0 : while (xListCursor->next() && (i++<SHRT_MAX)) // Set max. count
[ # # ][ # # ]
[ # # ]
646 : : {
647 [ # # ][ # # ]: 0 : aStringList.push_back( aValueFormatter.getFormattedValue() );
648 [ # # ][ # # ]: 0 : }
[ # # ][ # # ]
649 : : }
650 : 0 : break;
651 : : case ListSourceType_TABLEFIELDS:
652 : : {
653 [ # # ]: 0 : Reference<XNameAccess> xFieldNames = getTableFields(xConnection, m_aListSource);
654 [ # # ]: 0 : if (xFieldNames.is())
655 : : {
656 [ # # ][ # # ]: 0 : StringSequence seqNames = xFieldNames->getElementNames();
657 : 0 : sal_Int32 nFieldsCount = seqNames.getLength();
658 : 0 : const ::rtl::OUString* pustrNames = seqNames.getConstArray();
659 : :
660 [ # # ]: 0 : for (sal_Int32 k=0; k<nFieldsCount; ++k)
661 [ # # ][ # # ]: 0 : aStringList.push_back(pustrNames[k]);
662 : 0 : }
663 : : }
664 : 0 : break;
665 : : default:
666 : : OSL_FAIL( "OComboBoxModel::loadData: unreachable!" );
667 : 0 : break;
668 : : }
669 : : }
670 [ # # # # : 0 : catch(const SQLException& eSQL)
# ]
671 : : {
672 [ # # # # ]: 0 : onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST));
673 : : return;
674 : : }
675 [ # # ]: 0 : catch( const Exception& )
676 : : {
677 : : DBG_UNHANDLED_EXCEPTION();
678 : : return;
679 : : }
680 : :
681 : : // Create StringSequence for ListBox
682 [ # # ]: 0 : StringSequence aStringSeq(aStringList.size());
683 [ # # ]: 0 : ::rtl::OUString* pStringAry = aStringSeq.getArray();
684 [ # # ]: 0 : for (sal_Int32 i = 0; i<aStringSeq.getLength(); ++i)
685 : 0 : pStringAry[i] = aStringList[i];
686 : :
687 : : // Set String-Sequence at ListBox
688 [ # # ][ # # ]: 0 : setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( aStringSeq ) );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
689 : : }
690 : :
691 : : //------------------------------------------------------------------------------
692 : 0 : void OComboBoxModel::onConnectedDbColumn( const Reference< XInterface >& _rxForm )
693 : : {
694 : 0 : Reference<XPropertySet> xField = getField();
695 [ # # ]: 0 : if ( xField.is() )
696 [ # # ][ # # ]: 0 : m_pValueFormatter.reset( new ::dbtools::FormattedColumnValue( getContext(), Reference< XRowSet >( _rxForm, UNO_QUERY ), xField ) );
[ # # ]
697 [ # # ][ # # ]: 0 : getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= m_aDesignModeStringItems;
[ # # ]
698 : :
699 : : // Only load data if a ListSource was supplied
700 [ # # ][ # # ]: 0 : if ( !m_aListSource.isEmpty() && m_xCursor.is() && !hasExternalListSource() )
[ # # ][ # # ]
701 [ # # ]: 0 : loadData( false );
702 : 0 : }
703 : :
704 : : //------------------------------------------------------------------------------
705 : 0 : void OComboBoxModel::onDisconnectedDbColumn()
706 : : {
707 : 0 : m_pValueFormatter.reset();
708 : :
709 : : // reset the string item list
710 [ # # ]: 0 : if ( !hasExternalListSource() )
711 [ # # ]: 0 : setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( m_aDesignModeStringItems ) );
712 : :
713 : 0 : m_aListRowSet.dispose();
714 : 0 : }
715 : :
716 : : //------------------------------------------------------------------------------
717 : 0 : void SAL_CALL OComboBoxModel::reloaded( const EventObject& aEvent ) throw(RuntimeException)
718 : : {
719 : 0 : OBoundControlModel::reloaded(aEvent);
720 : :
721 : : // reload data if we have a list source
722 [ # # ][ # # ]: 0 : if ( !m_aListSource.isEmpty() && m_xCursor.is() && !hasExternalListSource() )
[ # # ][ # # ]
723 : 0 : loadData( false );
724 : 0 : }
725 : :
726 : : //------------------------------------------------------------------------------
727 : 28 : void OComboBoxModel::resetNoBroadcast()
728 : : {
729 : 28 : OBoundControlModel::resetNoBroadcast();
730 : 28 : m_aLastKnownValue.clear();
731 : 28 : }
732 : :
733 : : //-----------------------------------------------------------------------------
734 : 0 : sal_Bool OComboBoxModel::commitControlValueToDbColumn( bool _bPostReset )
735 : : {
736 [ # # ][ # # ]: 0 : Any aNewValue( m_xAggregateFastSet->getFastPropertyValue( getValuePropertyAggHandle() ) );
737 : :
738 : 0 : ::rtl::OUString sNewValue;
739 : 0 : aNewValue >>= sNewValue;
740 : :
741 : 0 : bool bModified = ( aNewValue != m_aLastKnownValue );
742 [ # # ]: 0 : if ( bModified )
743 : : {
744 [ # # # # ]: 0 : if ( !aNewValue.hasValue()
[ # # ][ # # ]
745 : 0 : || ( sNewValue.isEmpty() // an empty string
746 : : && m_bEmptyIsNull // which should be interpreted as NULL
747 : : )
748 : : )
749 : : {
750 [ # # ][ # # ]: 0 : m_xColumnUpdate->updateNull();
751 : : }
752 : : else
753 : : {
754 : : try
755 : : {
756 : : OSL_PRECOND( m_pValueFormatter.get(), "OComboBoxModel::commitControlValueToDbColumn: no value formatter!" );
757 [ # # ]: 0 : if ( m_pValueFormatter.get() )
758 : : {
759 [ # # ][ # # ]: 0 : if ( !m_pValueFormatter->setFormattedValue( sNewValue ) )
760 : 0 : return sal_False;
761 : : }
762 : : else
763 [ # # ][ # # ]: 0 : m_xColumnUpdate->updateString( sNewValue );
764 : : }
765 [ # # ]: 0 : catch ( const Exception& )
766 : : {
767 : 0 : return sal_False;
768 : : }
769 : : }
770 : :
771 : 0 : m_aLastKnownValue = aNewValue;
772 : : }
773 : :
774 : : // add the new value to the list
775 [ # # ][ # # ]: 0 : sal_Bool bAddToList = bModified && !_bPostReset;
776 : : // (only if this is not the "commit" triggered by a "reset")
777 : :
778 [ # # ]: 0 : if ( bAddToList )
779 : : {
780 [ # # ]: 0 : StringSequence aStringItemList;
781 [ # # ][ # # ]: 0 : if ( getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aStringItemList )
[ # # ][ # # ]
782 : : {
783 : 0 : const ::rtl::OUString* pStringItems = aStringItemList.getConstArray();
784 : : sal_Int32 i;
785 [ # # ]: 0 : for (i=0; i<aStringItemList.getLength(); ++i, ++pStringItems)
786 : : {
787 [ # # ]: 0 : if ( pStringItems->equals( sNewValue ) )
788 : 0 : break;
789 : : }
790 : :
791 : : // not found -> add
792 [ # # ]: 0 : if (i >= aStringItemList.getLength())
793 : : {
794 : 0 : sal_Int32 nOldLen = aStringItemList.getLength();
795 [ # # ]: 0 : aStringItemList.realloc( nOldLen + 1 );
796 [ # # ]: 0 : aStringItemList.getArray()[ nOldLen ] = sNewValue;
797 : :
798 [ # # ][ # # ]: 0 : setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( aStringItemList ) );
799 : : }
800 [ # # ]: 0 : }
801 : : }
802 : :
803 [ # # ]: 0 : return sal_True;
804 : : }
805 : :
806 : : // XPropertiesChangeListener
807 : : //------------------------------------------------------------------------------
808 : 0 : Any OComboBoxModel::translateDbColumnToControlValue()
809 : : {
810 : : OSL_PRECOND( m_pValueFormatter.get(), "OComboBoxModel::translateDbColumnToControlValue: no value formatter!" );
811 [ # # ]: 0 : if ( m_pValueFormatter.get() )
812 : : {
813 [ # # ]: 0 : ::rtl::OUString sValue( m_pValueFormatter->getFormattedValue() );
814 [ # # # # ]: 0 : if ( sValue.isEmpty()
[ # # ][ # # ]
815 [ # # ]: 0 : && m_pValueFormatter->getColumn().is()
816 [ # # ][ # # ]: 0 : && m_pValueFormatter->getColumn()->wasNull()
[ # # ]
817 : : )
818 : : {
819 : 0 : m_aLastKnownValue.clear();
820 : : }
821 : : else
822 : : {
823 : :
824 [ # # ]: 0 : m_aLastKnownValue <<= sValue;
825 : 0 : }
826 : : }
827 : : else
828 : 0 : m_aLastKnownValue.clear();
829 : :
830 [ # # ][ # # ]: 0 : return m_aLastKnownValue.hasValue() ? m_aLastKnownValue : makeAny( ::rtl::OUString() );
[ # # ][ # # ]
831 : : // (m_aLastKnownValue is alllowed to be VOID, the control value isn't)
832 : : }
833 : :
834 : : //------------------------------------------------------------------------------
835 : 28 : Any OComboBoxModel::getDefaultForReset() const
836 : : {
837 : 28 : return makeAny( m_aDefaultText );
838 : : }
839 : :
840 : : //--------------------------------------------------------------------
841 : 36 : void OComboBoxModel::stringItemListChanged( ControlModelLock& /*_rInstanceLock*/ )
842 : : {
843 [ + - ]: 36 : if ( m_xAggregateSet.is() )
844 [ + - ][ + - ]: 36 : m_xAggregateSet->setPropertyValue( PROPERTY_STRINGITEMLIST, makeAny( getStringItemList() ) );
845 : 36 : }
846 : :
847 : : //--------------------------------------------------------------------
848 : 0 : void OComboBoxModel::connectedExternalListSource( )
849 : : {
850 : : // TODO?
851 : 0 : }
852 : :
853 : : //--------------------------------------------------------------------
854 : 0 : void OComboBoxModel::disconnectedExternalListSource( )
855 : : {
856 : : // TODO?
857 : 0 : }
858 : :
859 : : //--------------------------------------------------------------------
860 : 0 : void OComboBoxModel::refreshInternalEntryList()
861 : : {
862 : : DBG_ASSERT( !hasExternalListSource(), "OComboBoxModel::refreshInternalEntryList: invalid call!" );
863 : :
864 [ # # ]: 0 : if ( !hasExternalListSource( )
[ # # # # ]
[ # # ]
865 : : && ( m_eListSourceType != ListSourceType_VALUELIST )
866 : 0 : && ( m_xCursor.is() )
867 : : )
868 : : {
869 : 0 : loadData( true );
870 : : }
871 : 0 : }
872 : :
873 : : //--------------------------------------------------------------------
874 : 0 : void SAL_CALL OComboBoxModel::disposing( const EventObject& _rSource ) throw ( RuntimeException )
875 : : {
876 [ # # ]: 0 : if ( !OEntryListHelper::handleDisposing( _rSource ) )
877 : 0 : OBoundControlModel::disposing( _rSource );
878 : 0 : }
879 : :
880 : : //========================================================================
881 : : //= OComboBoxControl
882 : : //========================================================================
883 : :
884 : : //------------------------------------------------------------------
885 : 12 : InterfaceRef SAL_CALL OComboBoxControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) throw (RuntimeException)
886 : : {
887 [ + - ]: 12 : return *(new OComboBoxControl(_rxFactory));
888 : : }
889 : :
890 : : //------------------------------------------------------------------------------
891 : 12 : OComboBoxControl::OComboBoxControl(const Reference<XMultiServiceFactory>& _rxFactory)
892 [ + - ]: 12 : :OBoundControl(_rxFactory, VCL_CONTROL_COMBOBOX)
893 : : {
894 : 12 : }
895 : :
896 : : //------------------------------------------------------------------------------
897 : 0 : StringSequence SAL_CALL OComboBoxControl::getSupportedServiceNames() throw(RuntimeException)
898 : : {
899 : 0 : StringSequence aSupported = OBoundControl::getSupportedServiceNames();
900 [ # # ]: 0 : aSupported.realloc(aSupported.getLength() + 1);
901 : :
902 [ # # ]: 0 : ::rtl::OUString* pArray = aSupported.getArray();
903 [ # # ]: 0 : pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_COMBOBOX;
904 : 0 : return aSupported;
905 : : }
906 : :
907 : : //.........................................................................
908 : : }
909 : : //.........................................................................
910 : :
911 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|