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