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 : #include <config_features.h>
21 :
22 : #include "ListBox.hxx"
23 : #include "property.hxx"
24 : #include "property.hrc"
25 : #include "services.hxx"
26 : #include "frm_resource.hxx"
27 : #include "frm_resource.hrc"
28 : #include "BaseListBox.hxx"
29 : #include "listenercontainers.hxx"
30 : #include "componenttools.hxx"
31 :
32 : #include <com/sun/star/util/XNumberFormatTypes.hpp>
33 : #include <com/sun/star/sdbc/XRowSet.hpp>
34 : #include <com/sun/star/container/XIndexAccess.hpp>
35 : #include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
36 : #include <com/sun/star/sdb/XQueriesSupplier.hpp>
37 : #include <com/sun/star/util/NumberFormat.hpp>
38 : #include <com/sun/star/awt/XWindow.hpp>
39 : #include <com/sun/star/sdbc/XConnection.hpp>
40 : #include <com/sun/star/sdb/CommandType.hpp>
41 :
42 : #include <comphelper/basicio.hxx>
43 : #include <comphelper/container.hxx>
44 : #include <comphelper/numbers.hxx>
45 : #include <comphelper/processfactory.hxx>
46 : #include <comphelper/listenernotification.hxx>
47 : #include <connectivity/dbtools.hxx>
48 : #include <connectivity/formattedcolumnvalue.hxx>
49 : #include <connectivity/dbconversion.hxx>
50 : #include <cppuhelper/queryinterface.hxx>
51 : #include <tools/debug.hxx>
52 : #include <tools/diagnose_ex.h>
53 : #include <unotools/sharedunocomponent.hxx>
54 : #include <vcl/svapp.hxx>
55 :
56 : #include <boost/optional.hpp>
57 :
58 : #include <algorithm>
59 : #include <functional>
60 : #include <iterator>
61 :
62 : namespace frm
63 : {
64 : using namespace ::com::sun::star::uno;
65 : using namespace ::com::sun::star::sdb;
66 : using namespace ::com::sun::star::sdbc;
67 : using namespace ::com::sun::star::sdbcx;
68 : using namespace ::com::sun::star::beans;
69 : using namespace ::com::sun::star::container;
70 : using namespace ::com::sun::star::form;
71 : using namespace ::com::sun::star::awt;
72 : using namespace ::com::sun::star::io;
73 : using namespace ::com::sun::star::lang;
74 : using namespace ::com::sun::star::util;
75 : using namespace ::com::sun::star::form::binding;
76 : using namespace ::dbtools;
77 :
78 : using ::connectivity::ORowSetValue;
79 :
80 46 : const ::connectivity::ORowSetValue OListBoxModel::s_aEmptyValue;
81 46 : const ::connectivity::ORowSetValue OListBoxModel::s_aEmptyStringValue = OUString();
82 :
83 : //= helper
84 :
85 : namespace
86 : {
87 :
88 : struct RowSetValueToString : public ::std::unary_function< ORowSetValue, OUString >
89 : {
90 762 : OUString operator()( const ORowSetValue& _value ) const
91 : {
92 762 : return _value.getString();
93 : }
94 : };
95 :
96 :
97 : struct AppendRowSetValueString : public ::std::unary_function< OUString, void >
98 : {
99 0 : AppendRowSetValueString( OUString& _string )
100 0 : :m_string( _string )
101 : {
102 0 : }
103 :
104 0 : void operator()( const OUString& _append )
105 : {
106 0 : m_string += _append;
107 0 : }
108 :
109 : private:
110 : OUString& m_string;
111 : };
112 :
113 :
114 188 : Sequence< OUString > lcl_convertToStringSequence( const ValueList& _values )
115 : {
116 188 : Sequence< OUString > aStrings( _values.size() );
117 : ::std::transform(
118 : _values.begin(),
119 : _values.end(),
120 : aStrings.getArray(),
121 : RowSetValueToString()
122 188 : );
123 188 : return aStrings;
124 : }
125 : }
126 :
127 :
128 : //= ItemEventDescription
129 :
130 : typedef ::comphelper::EventHolder< ItemEvent > ItemEventDescription;
131 :
132 :
133 : //= OListBoxModel
134 :
135 22 : Sequence< Type> OListBoxModel::_getTypes()
136 : {
137 : return TypeBag(
138 : OBoundControlModel::_getTypes(),
139 : OEntryListHelper::getTypes(),
140 : OErrorBroadcaster::getTypes()
141 22 : ).getTypes();
142 : }
143 :
144 : // stuff common to all constructors
145 19 : void OListBoxModel::init()
146 : {
147 19 : startAggregatePropertyListening( PROPERTY_STRINGITEMLIST );
148 19 : }
149 :
150 :
151 18 : OListBoxModel::OListBoxModel(const Reference<XComponentContext>& _rxFactory)
152 : :OBoundControlModel( _rxFactory, VCL_CONTROLMODEL_LISTBOX, FRM_SUN_CONTROL_LISTBOX, true, true, true )
153 : // use the old control name for compatibility reasons
154 : ,OEntryListHelper( (OControlModel&)*this )
155 : ,OErrorBroadcaster( OComponentHelper::rBHelper )
156 : ,m_aListRowSet()
157 : ,m_nConvertedBoundValuesType(0)
158 : ,m_nNULLPos(-1)
159 18 : ,m_nBoundColumnType( DataType::SQLNULL )
160 : {
161 :
162 18 : m_nClassId = FormComponentType::LISTBOX;
163 18 : m_eListSourceType = ListSourceType_VALUELIST;
164 18 : m_aBoundColumn <<= (sal_Int16)1;
165 18 : initValueProperty( PROPERTY_SELECT_SEQ, PROPERTY_ID_SELECT_SEQ);
166 :
167 18 : init();
168 18 : }
169 :
170 :
171 1 : OListBoxModel::OListBoxModel( const OListBoxModel* _pOriginal, const Reference<XComponentContext>& _rxFactory )
172 : :OBoundControlModel( _pOriginal, _rxFactory )
173 : ,OEntryListHelper( *_pOriginal, (OControlModel&)*this )
174 : ,OErrorBroadcaster( OComponentHelper::rBHelper )
175 : ,m_aListRowSet()
176 : ,m_eListSourceType( _pOriginal->m_eListSourceType )
177 : ,m_aBoundColumn( _pOriginal->m_aBoundColumn )
178 : ,m_aListSourceValues( _pOriginal->m_aListSourceValues )
179 : ,m_aBoundValues( _pOriginal->m_aBoundValues )
180 : ,m_nConvertedBoundValuesType(0)
181 : ,m_aDefaultSelectSeq( _pOriginal->m_aDefaultSelectSeq )
182 : ,m_nNULLPos(-1)
183 1 : ,m_nBoundColumnType( DataType::SQLNULL )
184 : {
185 :
186 1 : init();
187 1 : }
188 :
189 :
190 51 : OListBoxModel::~OListBoxModel()
191 : {
192 17 : if (!OComponentHelper::rBHelper.bDisposed)
193 : {
194 0 : acquire();
195 0 : dispose();
196 : }
197 :
198 34 : }
199 :
200 : // XCloneable
201 :
202 1 : IMPLEMENT_DEFAULT_CLONING( OListBoxModel )
203 :
204 : // XServiceInfo
205 :
206 104 : StringSequence SAL_CALL OListBoxModel::getSupportedServiceNames() throw(RuntimeException, std::exception)
207 : {
208 104 : StringSequence aSupported = OBoundControlModel::getSupportedServiceNames();
209 :
210 104 : sal_Int32 nOldLen = aSupported.getLength();
211 104 : aSupported.realloc( nOldLen + 9 );
212 104 : OUString* pStoreTo = aSupported.getArray() + nOldLen;
213 :
214 104 : *pStoreTo++ = BINDABLE_CONTROL_MODEL;
215 104 : *pStoreTo++ = DATA_AWARE_CONTROL_MODEL;
216 104 : *pStoreTo++ = VALIDATABLE_CONTROL_MODEL;
217 :
218 104 : *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL;
219 104 : *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL;
220 :
221 104 : *pStoreTo++ = FRM_SUN_COMPONENT_LISTBOX;
222 104 : *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_LISTBOX;
223 104 : *pStoreTo++ = BINDABLE_DATABASE_LIST_BOX;
224 :
225 104 : *pStoreTo++ = FRM_COMPONENT_LISTBOX;
226 :
227 104 : return aSupported;
228 : }
229 :
230 :
231 7616 : Any SAL_CALL OListBoxModel::queryAggregation(const Type& _rType) throw (RuntimeException, std::exception)
232 : {
233 7616 : Any aReturn = OBoundControlModel::queryAggregation( _rType );
234 7616 : if ( !aReturn.hasValue() )
235 180 : aReturn = OEntryListHelper::queryInterface( _rType );
236 7616 : if ( !aReturn.hasValue() )
237 148 : aReturn = OErrorBroadcaster::queryInterface( _rType );
238 7616 : return aReturn;
239 : }
240 :
241 : // OComponentHelper
242 :
243 17 : void OListBoxModel::disposing()
244 : {
245 17 : OBoundControlModel::disposing();
246 17 : OEntryListHelper::disposing();
247 17 : OErrorBroadcaster::disposing();
248 17 : }
249 :
250 :
251 4681 : void OListBoxModel::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
252 : {
253 4681 : switch (_nHandle)
254 : {
255 : case PROPERTY_ID_BOUNDCOLUMN:
256 28 : _rValue <<= m_aBoundColumn;
257 28 : break;
258 :
259 : case PROPERTY_ID_LISTSOURCETYPE:
260 91 : _rValue <<= m_eListSourceType;
261 91 : break;
262 :
263 : case PROPERTY_ID_LISTSOURCE:
264 91 : _rValue <<= lcl_convertToStringSequence( m_aListSourceValues );
265 91 : break;
266 :
267 : case PROPERTY_ID_VALUE_SEQ:
268 26 : _rValue <<= lcl_convertToStringSequence( m_aBoundValues );
269 26 : break;
270 :
271 : case PROPERTY_ID_SELECT_VALUE_SEQ:
272 89 : _rValue = getCurrentMultiValue();
273 89 : break;
274 :
275 : case PROPERTY_ID_SELECT_VALUE:
276 31 : _rValue = getCurrentSingleValue();
277 31 : break;
278 :
279 : case PROPERTY_ID_DEFAULT_SELECT_SEQ:
280 93 : _rValue <<= m_aDefaultSelectSeq;
281 93 : break;
282 :
283 : case PROPERTY_ID_STRINGITEMLIST:
284 106 : _rValue <<= getStringItemList();
285 106 : break;
286 :
287 : default:
288 4126 : OBoundControlModel::getFastPropertyValue(_rValue, _nHandle);
289 : }
290 4681 : }
291 :
292 :
293 202 : void OListBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) throw (com::sun::star::uno::Exception, std::exception)
294 : {
295 202 : switch (_nHandle)
296 : {
297 : case PROPERTY_ID_BOUNDCOLUMN :
298 : DBG_ASSERT((_rValue.getValueType().getTypeClass() == TypeClass_SHORT) || (_rValue.getValueType().getTypeClass() == TypeClass_VOID),
299 : "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
300 1 : m_aBoundColumn = _rValue;
301 1 : break;
302 :
303 : case PROPERTY_ID_LISTSOURCETYPE :
304 : DBG_ASSERT(_rValue.getValueType().equals(::cppu::UnoType<ListSourceType>::get()),
305 : "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
306 17 : _rValue >>= m_eListSourceType;
307 17 : break;
308 :
309 : case PROPERTY_ID_LISTSOURCE:
310 : {
311 : // extract
312 17 : Sequence< OUString > aListSource;
313 17 : OSL_VERIFY( _rValue >>= aListSource );
314 :
315 : // copy to member
316 17 : ValueList().swap(m_aListSourceValues);
317 : ::std::copy(
318 : aListSource.getConstArray(),
319 17 : aListSource.getConstArray() + aListSource.getLength(),
320 : ::std::insert_iterator< ValueList >( m_aListSourceValues, m_aListSourceValues.end() )
321 34 : );
322 :
323 : // propagate
324 17 : if ( m_eListSourceType == ListSourceType_VALUELIST )
325 : {
326 8 : setBoundValues(m_aListSourceValues);
327 : }
328 : else
329 : {
330 9 : if ( m_xCursor.is() && !hasField() && !hasExternalListSource() )
331 : // listbox is already connected to a database, and no external list source
332 : // data source changed -> refresh
333 0 : loadData( false );
334 17 : }
335 : }
336 17 : break;
337 :
338 : case PROPERTY_ID_VALUE_SEQ :
339 : SAL_WARN( "forms.component", "ValueItemList is read-only!" );
340 0 : throw PropertyVetoException();
341 :
342 : case PROPERTY_ID_SELECT_VALUE_SEQ :
343 : {
344 9 : Sequence< const Any > v;
345 9 : _rValue >>= v;
346 18 : Any newSelectSeq(translateBindingValuesToControlValue(v));
347 18 : setControlValue( newSelectSeq, eOther );
348 : }
349 9 : break;
350 :
351 : #if HAVE_FEATURE_DBCONNECTIVITY
352 : case PROPERTY_ID_SELECT_VALUE :
353 : {
354 2 : ORowSetValue v;
355 2 : v.fill(_rValue);
356 4 : Any newSelectSeq(translateDbValueToControlValue(v));
357 4 : setControlValue( newSelectSeq, eOther );
358 : }
359 2 : break;
360 : #endif
361 : case PROPERTY_ID_DEFAULT_SELECT_SEQ :
362 : DBG_ASSERT(_rValue.getValueType().equals(cppu::UnoType<Sequence<sal_Int16>>::get()),
363 : "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
364 13 : _rValue >>= m_aDefaultSelectSeq;
365 :
366 : DBG_ASSERT(m_xAggregateFastSet.is(), "OListBoxModel::setFastPropertyValue_NoBroadcast(DEFAULT_SELECT_SEQ) : invalid aggregate !");
367 13 : if ( m_xAggregateFastSet.is() )
368 13 : setControlValue( _rValue, eOther );
369 13 : break;
370 :
371 : case PROPERTY_ID_STRINGITEMLIST:
372 : {
373 26 : ControlModelLock aLock( *this );
374 26 : setNewStringItemList( _rValue, aLock );
375 : // TODO: this is bogus. setNewStringItemList expects a guard which has the *only*
376 : // lock to the mutex, but setFastPropertyValue_NoBroadcast is already called with
377 : // a lock - so we effectively has two locks here, of which setNewStringItemList can
378 : // only control one.
379 : }
380 26 : resetNoBroadcast();
381 26 : break;
382 :
383 : default:
384 117 : OBoundControlModel::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
385 : }
386 202 : }
387 :
388 :
389 826 : sal_Bool OListBoxModel::convertFastPropertyValue(
390 : Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
391 : throw (IllegalArgumentException)
392 : {
393 826 : bool bModified(false);
394 826 : switch (_nHandle)
395 : {
396 : case PROPERTY_ID_BOUNDCOLUMN :
397 8 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aBoundColumn, ::cppu::UnoType<sal_Int16>::get());
398 8 : break;
399 :
400 : case PROPERTY_ID_LISTSOURCETYPE:
401 63 : bModified = tryPropertyValueEnum(_rConvertedValue, _rOldValue, _rValue, m_eListSourceType);
402 63 : break;
403 :
404 : case PROPERTY_ID_LISTSOURCE:
405 70 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, lcl_convertToStringSequence( m_aListSourceValues ) );
406 70 : break;
407 :
408 : case PROPERTY_ID_VALUE_SEQ :
409 : SAL_WARN( "forms.component", "ValueItemList is read-only!" );
410 0 : throw IllegalArgumentException();
411 :
412 : case PROPERTY_ID_SELECT_VALUE_SEQ :
413 56 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, getCurrentMultiValue());
414 56 : break;
415 :
416 : case PROPERTY_ID_SELECT_VALUE :
417 2 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, getCurrentSingleValue());
418 2 : break;
419 :
420 : case PROPERTY_ID_DEFAULT_SELECT_SEQ :
421 66 : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aDefaultSelectSeq);
422 66 : break;
423 :
424 : case PROPERTY_ID_STRINGITEMLIST:
425 72 : bModified = convertNewListSourceProperty( _rConvertedValue, _rOldValue, _rValue );
426 72 : break;
427 :
428 : default:
429 489 : return OBoundControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
430 : }
431 337 : return bModified;
432 : }
433 :
434 :
435 61 : void SAL_CALL OListBoxModel::setPropertyValues( const Sequence< OUString >& _rPropertyNames, const Sequence< Any >& _rValues ) throw(PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException, std::exception)
436 : {
437 : // if both SelectedItems and StringItemList are set, care for this
438 : // #i27024#
439 61 : const Any* pSelectSequenceValue = NULL;
440 :
441 61 : const OUString* pStartPos = _rPropertyNames.getConstArray();
442 61 : const OUString* pEndPos = _rPropertyNames.getConstArray() + _rPropertyNames.getLength();
443 : const OUString* pSelectedItemsPos = ::std::find_if(
444 : pStartPos, pEndPos,
445 : ::std::bind2nd( ::std::equal_to< OUString >(), PROPERTY_SELECT_SEQ )
446 61 : );
447 : const OUString* pStringItemListPos = ::std::find_if(
448 : pStartPos, pEndPos,
449 : ::std::bind2nd( ::std::equal_to< OUString >(), PROPERTY_STRINGITEMLIST )
450 61 : );
451 61 : if ( ( pSelectedItemsPos != pEndPos ) && ( pStringItemListPos != pEndPos ) )
452 : {
453 : // both properties are present
454 : // -> remember the value for the select sequence
455 57 : pSelectSequenceValue = _rValues.getConstArray() + ( pSelectedItemsPos - pStartPos );
456 : }
457 :
458 61 : OBoundControlModel::setPropertyValues( _rPropertyNames, _rValues );
459 :
460 60 : if ( pSelectSequenceValue )
461 : {
462 57 : setPropertyValue( PROPERTY_SELECT_SEQ, *pSelectSequenceValue );
463 : // Note that this is the only reliable way, since one of the properties is implemented
464 : // by ourself, and one is implemented by the aggregate, we cannot rely on any particular
465 : // results when setting them both - too many undocumented behavior in all the involved
466 :
467 : }
468 60 : }
469 :
470 :
471 20 : void OListBoxModel::describeFixedProperties( Sequence< Property >& _rProps ) const
472 : {
473 20 : BEGIN_DESCRIBE_PROPERTIES( 9, OBoundControlModel )
474 20 : DECL_PROP1(TABINDEX, sal_Int16, BOUND);
475 20 : DECL_PROP2(BOUNDCOLUMN, sal_Int16, BOUND, MAYBEVOID);
476 20 : DECL_PROP1(LISTSOURCETYPE, ListSourceType, BOUND);
477 20 : DECL_PROP1(LISTSOURCE, StringSequence, BOUND);
478 20 : DECL_PROP3(VALUE_SEQ, StringSequence, BOUND, READONLY, TRANSIENT);
479 20 : DECL_PROP2(SELECT_VALUE_SEQ, Sequence< Any >, BOUND, TRANSIENT);
480 20 : DECL_PROP2(SELECT_VALUE, Any, BOUND, TRANSIENT);
481 20 : DECL_PROP1(DEFAULT_SELECT_SEQ, Sequence<sal_Int16>, BOUND);
482 20 : DECL_PROP1(STRINGITEMLIST, Sequence< OUString >, BOUND);
483 : END_DESCRIBE_PROPERTIES();
484 20 : }
485 :
486 :
487 60 : void OListBoxModel::_propertyChanged( const PropertyChangeEvent& i_rEvent ) throw ( RuntimeException )
488 : {
489 60 : if ( i_rEvent.PropertyName == PROPERTY_STRINGITEMLIST )
490 : {
491 0 : ControlModelLock aLock( *this );
492 : // SYNCHRONIZED ----->
493 : // our aggregate internally changed its StringItemList property - reflect this in our "overridden"
494 : // version of the property
495 0 : setNewStringItemList( i_rEvent.NewValue, aLock );
496 : // <----- SYNCHRONIZED
497 60 : return;
498 : }
499 60 : OBoundControlModel::_propertyChanged( i_rEvent );
500 : }
501 :
502 :
503 20 : void OListBoxModel::describeAggregateProperties( Sequence< Property >& _rAggregateProps ) const
504 : {
505 20 : OBoundControlModel::describeAggregateProperties( _rAggregateProps );
506 :
507 : // superseded properties:
508 20 : RemoveProperty( _rAggregateProps, PROPERTY_STRINGITEMLIST );
509 20 : }
510 :
511 :
512 2 : OUString SAL_CALL OListBoxModel::getServiceName() throw(RuntimeException, std::exception)
513 : {
514 2 : return OUString(FRM_COMPONENT_LISTBOX); // old (non-sun) name for compatibility !
515 : }
516 :
517 :
518 1 : void SAL_CALL OListBoxModel::write(const Reference<XObjectOutputStream>& _rxOutStream)
519 : throw(IOException, RuntimeException, std::exception)
520 : {
521 1 : OBoundControlModel::write(_rxOutStream);
522 :
523 : // Dummy sequence, to stay compatible if SelectSeq is not saved anymore
524 1 : Sequence<sal_Int16> aDummySeq;
525 :
526 : // Version
527 : // Version 0x0002: ListSource becomes StringSeq
528 1 : _rxOutStream->writeShort(0x0004);
529 :
530 : // Masking for any
531 1 : sal_uInt16 nAnyMask = 0;
532 1 : if (m_aBoundColumn.getValueType().getTypeClass() != TypeClass_VOID)
533 1 : nAnyMask |= BOUNDCOLUMN;
534 :
535 1 : _rxOutStream << nAnyMask;
536 :
537 1 : _rxOutStream << lcl_convertToStringSequence( m_aListSourceValues );
538 1 : _rxOutStream << (sal_Int16)m_eListSourceType;
539 1 : _rxOutStream << aDummySeq;
540 1 : _rxOutStream << m_aDefaultSelectSeq;
541 :
542 1 : if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
543 : {
544 1 : sal_Int16 nBoundColumn = 0;
545 1 : m_aBoundColumn >>= nBoundColumn;
546 1 : _rxOutStream << nBoundColumn;
547 : }
548 1 : writeHelpTextCompatibly(_rxOutStream);
549 :
550 : // from version 0x0004 : common properties
551 1 : writeCommonProperties(_rxOutStream);
552 1 : }
553 :
554 :
555 1 : void SAL_CALL OListBoxModel::read(const Reference<XObjectInputStream>& _rxInStream) throw(IOException, RuntimeException, std::exception)
556 : {
557 : // We need to respect dependencies for certain variables.
558 : // Therefore, we need to set them explicitly via setPropertyValue().
559 :
560 1 : OBoundControlModel::read(_rxInStream);
561 1 : ControlModelLock aLock( *this );
562 :
563 : // since we are "overwriting" the StringItemList of our aggregate (means we have
564 : // an own place to store the value, instead of relying on our aggregate storing it),
565 : // we need to respect what the aggregate just read for the StringItemList property.
566 : try
567 : {
568 1 : if ( m_xAggregateSet.is() )
569 1 : setNewStringItemList( m_xAggregateSet->getPropertyValue( PROPERTY_STRINGITEMLIST ), aLock );
570 : }
571 0 : catch( const Exception& )
572 : {
573 : SAL_WARN( "forms.component", "OComboBoxModel::read: caught an exception while examining the aggregate's string item list!" );
574 : }
575 :
576 : // Version
577 1 : sal_uInt16 nVersion = _rxInStream->readShort();
578 : DBG_ASSERT(nVersion > 0, "OListBoxModel::read : version 0 ? this should never have been written !");
579 :
580 1 : if (nVersion > 0x0004)
581 : {
582 : SAL_WARN( "forms.component", "OListBoxModel::read : invalid (means unknown) version !");
583 0 : ValueList().swap(m_aListSourceValues);
584 0 : m_aBoundColumn <<= (sal_Int16)0;
585 0 : clearBoundValues();
586 0 : m_eListSourceType = ListSourceType_VALUELIST;
587 0 : m_aDefaultSelectSeq.realloc(0);
588 0 : defaultCommonProperties();
589 1 : return;
590 : }
591 :
592 : // Masking for any
593 : sal_uInt16 nAnyMask;
594 1 : _rxInStream >> nAnyMask;
595 :
596 : // ListSourceSeq
597 2 : StringSequence aListSourceSeq;
598 1 : if (nVersion == 0x0001)
599 : {
600 : // Create ListSourceSeq from String
601 0 : OUString sListSource;
602 0 : _rxInStream >> sListSource;
603 :
604 0 : sal_Int32 nTokens = 1;
605 0 : const sal_Unicode* pStr = sListSource.getStr();
606 0 : while ( *pStr )
607 : {
608 0 : if ( *pStr == ';' )
609 0 : nTokens++;
610 0 : pStr++;
611 : }
612 0 : aListSourceSeq.realloc( nTokens );
613 0 : for (sal_Int32 i=0; i<nTokens; ++i)
614 : {
615 0 : sal_Int32 nTmp = 0;
616 0 : aListSourceSeq.getArray()[i] = sListSource.getToken(i,';',nTmp);
617 0 : }
618 : }
619 : else
620 1 : _rxInStream >> aListSourceSeq;
621 :
622 : sal_Int16 nListSourceType;
623 1 : _rxInStream >> nListSourceType;
624 1 : m_eListSourceType = (ListSourceType)nListSourceType;
625 2 : Any aListSourceSeqAny;
626 1 : aListSourceSeqAny <<= aListSourceSeq;
627 :
628 1 : setFastPropertyValue(PROPERTY_ID_LISTSOURCE, aListSourceSeqAny );
629 :
630 : // Dummy sequence, to stay compatible if SelectSeq is not saved anymore
631 2 : Sequence<sal_Int16> aDummySeq;
632 1 : _rxInStream >> aDummySeq;
633 :
634 : // DefaultSelectSeq
635 2 : Sequence<sal_Int16> aDefaultSelectSeq;
636 1 : _rxInStream >> aDefaultSelectSeq;
637 2 : Any aDefaultSelectSeqAny;
638 1 : aDefaultSelectSeqAny <<= aDefaultSelectSeq;
639 1 : setFastPropertyValue(PROPERTY_ID_DEFAULT_SELECT_SEQ, aDefaultSelectSeqAny);
640 :
641 : // BoundColumn
642 1 : if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
643 : {
644 : sal_Int16 nValue;
645 1 : _rxInStream >> nValue;
646 1 : m_aBoundColumn <<= nValue;
647 : }
648 : else // the constructor initialises to 1, so if it is empty,
649 : // we must explicitly set to empty
650 : {
651 0 : m_aBoundColumn = Any();
652 : }
653 :
654 1 : if (nVersion > 2)
655 1 : readHelpTextCompatibly(_rxInStream);
656 :
657 : // if our string list is not filled from the value list, we must empty it
658 : // this can be the case when somebody saves in alive mode
659 2 : if ( ( m_eListSourceType != ListSourceType_VALUELIST )
660 1 : && !hasExternalListSource()
661 : )
662 : {
663 0 : setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( StringSequence() ) );
664 : }
665 :
666 1 : if (nVersion > 3)
667 1 : readCommonProperties(_rxInStream);
668 :
669 : // Display the default values after reading
670 1 : if ( !getControlSource().isEmpty() )
671 : // (not if we don't have a control source - the "State" property acts like it is persistent, then
672 2 : resetNoBroadcast();
673 : }
674 :
675 :
676 0 : void OListBoxModel::loadData( bool _bForce )
677 : {
678 : SAL_INFO( "forms.component", "OListBoxModel::loadData" );
679 : DBG_ASSERT( m_eListSourceType != ListSourceType_VALUELIST, "OListBoxModel::loadData: cannot load value list from DB!" );
680 : DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::loadData: cannot load from DB when I have an external list source!" );
681 :
682 0 : const sal_Int16 nNULLPosBackup( m_nNULLPos );
683 0 : const sal_Int32 nBoundColumnTypeBackup( m_nBoundColumnType );
684 0 : m_nNULLPos = -1;
685 0 : m_nBoundColumnType = DataType::SQLNULL;
686 :
687 : // pre-requisites:
688 : // PRE1: connection
689 0 : Reference< XConnection > xConnection;
690 : // is the active connection of our form
691 0 : Reference< XPropertySet > xFormProps( m_xCursor, UNO_QUERY );
692 0 : if ( xFormProps.is() )
693 0 : xFormProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection;
694 :
695 : // PRE2: list source
696 0 : OUString sListSource;
697 : // if our list source type is no value list, we need to concatenate
698 : // the single list source elements
699 : ::std::for_each(
700 : m_aListSourceValues.begin(),
701 : m_aListSourceValues.end(),
702 : AppendRowSetValueString( sListSource )
703 0 : );
704 :
705 : // outta here if we don't have all pre-requisites
706 0 : if ( !xConnection.is() || sListSource.isEmpty() )
707 : {
708 0 : clearBoundValues();
709 0 : return;
710 : }
711 :
712 0 : ::boost::optional< sal_Int16 > aBoundColumn(boost::none);
713 0 : if ( m_aBoundColumn.getValueType().getTypeClass() == TypeClass_SHORT )
714 : {
715 0 : sal_Int16 nBoundColumn( 0 );
716 0 : m_aBoundColumn >>= nBoundColumn;
717 0 : aBoundColumn.reset( nBoundColumn );
718 : }
719 :
720 0 : ::utl::SharedUNOComponent< XResultSet > xListCursor;
721 : try
722 : {
723 0 : m_aListRowSet.setConnection( xConnection );
724 :
725 0 : bool bExecute = false;
726 0 : switch (m_eListSourceType)
727 : {
728 : case ListSourceType_TABLEFIELDS:
729 : // don't work with a statement here, the fields will be collected below
730 0 : break;
731 :
732 : case ListSourceType_TABLE:
733 : {
734 0 : Reference<XNameAccess> xFieldsByName = getTableFields(xConnection, sListSource);
735 0 : Reference<XIndexAccess> xFieldsByIndex(xFieldsByName, UNO_QUERY);
736 :
737 : // do we have a bound column if yes we have to select it
738 : // and the displayed column is the first column othwhise we act as a combobox
739 0 : OUString aFieldName;
740 0 : OUString aBoundFieldName;
741 :
742 0 : if ( !!aBoundColumn && ( *aBoundColumn >= 0 ) && xFieldsByIndex.is() )
743 : {
744 0 : if ( *aBoundColumn >= xFieldsByIndex->getCount() )
745 0 : break;
746 :
747 0 : Reference<XPropertySet> xFieldAsSet(xFieldsByIndex->getByIndex( *aBoundColumn ),UNO_QUERY);
748 : assert(xFieldAsSet.is());
749 0 : xFieldAsSet->getPropertyValue(PROPERTY_NAME) >>= aBoundFieldName;
750 0 : aBoundColumn.reset( 1 );
751 :
752 0 : xFieldAsSet.set(xFieldsByIndex->getByIndex(0),UNO_QUERY);
753 0 : xFieldAsSet->getPropertyValue(PROPERTY_NAME) >>= aFieldName;
754 : }
755 0 : else if (xFieldsByName.is())
756 : {
757 0 : if ( xFieldsByName->hasByName( getControlSource() ) )
758 0 : aFieldName = getControlSource();
759 : else
760 : {
761 : // otherwise look for the alias
762 0 : Reference< XColumnsSupplier > xSupplyFields;
763 0 : xFormProps->getPropertyValue("SingleSelectQueryComposer") >>= xSupplyFields;
764 :
765 : // search the field
766 : DBG_ASSERT(xSupplyFields.is(), "OListBoxModel::loadData : invalid query composer !");
767 :
768 0 : Reference<XNameAccess> xFieldNames = xSupplyFields->getColumns();
769 0 : if ( xFieldNames->hasByName( getControlSource() ) )
770 : {
771 0 : Reference<XPropertySet> xComposerFieldAsSet;
772 0 : xFieldNames->getByName( getControlSource() ) >>= xComposerFieldAsSet;
773 0 : if (hasProperty(PROPERTY_FIELDSOURCE, xComposerFieldAsSet))
774 0 : xComposerFieldAsSet->getPropertyValue(PROPERTY_FIELDSOURCE) >>= aFieldName;
775 0 : }
776 : }
777 : }
778 0 : if (aFieldName.isEmpty())
779 0 : break;
780 :
781 0 : Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
782 0 : OUString aQuote = xMeta->getIdentifierQuoteString();
783 0 : OUString aStatement("SELECT ");
784 0 : if (aBoundFieldName.isEmpty()) // act like a combobox
785 0 : aStatement += "DISTINCT ";
786 :
787 0 : aStatement += quoteName(aQuote,aFieldName);
788 0 : if (!aBoundFieldName.isEmpty())
789 : {
790 0 : aStatement += ", ";
791 0 : aStatement += quoteName(aQuote, aBoundFieldName);
792 : }
793 0 : aStatement += " FROM ";
794 :
795 0 : OUString sCatalog, sSchema, sTable;
796 0 : qualifiedNameComponents( xMeta, sListSource, sCatalog, sSchema, sTable, eInDataManipulation );
797 0 : aStatement += composeTableNameForSelect( xConnection, sCatalog, sSchema, sTable );
798 :
799 0 : m_aListRowSet.setEscapeProcessing( false );
800 0 : m_aListRowSet.setCommand( aStatement );
801 0 : bExecute = true;
802 : }
803 0 : break;
804 :
805 : case ListSourceType_QUERY:
806 0 : m_aListRowSet.setCommandFromQuery( sListSource );
807 0 : bExecute = true;
808 0 : break;
809 :
810 : default:
811 0 : m_aListRowSet.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH != m_eListSourceType );
812 0 : m_aListRowSet.setCommand( sListSource );
813 0 : bExecute = true;
814 0 : break;
815 : }
816 :
817 0 : if (bExecute)
818 : {
819 0 : if ( !_bForce && !m_aListRowSet.isDirty() )
820 : {
821 : // if none of the settings of the row set changed, compared to the last
822 : // invocation of loadData, then don't re-fill the list. Instead, assume
823 : // the list entries are the same.
824 0 : m_nNULLPos = nNULLPosBackup;
825 0 : m_nBoundColumnType = nBoundColumnTypeBackup;
826 0 : return;
827 : }
828 0 : xListCursor.reset( m_aListRowSet.execute() );
829 : }
830 : }
831 0 : catch(const SQLException& eSQL)
832 : {
833 0 : onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST));
834 0 : return;
835 : }
836 0 : catch(const Exception& eUnknown)
837 : {
838 : (void)eUnknown;
839 0 : return;
840 : }
841 :
842 : // Fill display and value lists
843 0 : ValueList aDisplayList, aValueList;
844 0 : bool bUseNULL = hasField() && !isRequired();
845 :
846 : // empty BoundColumn is treated as BoundColumn==0,
847 0 : if(!aBoundColumn)
848 0 : aBoundColumn = 0;
849 :
850 : try
851 : {
852 : OSL_ENSURE( xListCursor.is() || ( ListSourceType_TABLEFIELDS == m_eListSourceType ),
853 : "OListBoxModel::loadData: logic error!" );
854 0 : if ( !xListCursor.is() && ( ListSourceType_TABLEFIELDS != m_eListSourceType ) )
855 0 : return;
856 :
857 0 : switch (m_eListSourceType)
858 : {
859 : #if HAVE_FEATURE_DBCONNECTIVITY
860 : case ListSourceType_SQL:
861 : case ListSourceType_SQLPASSTHROUGH:
862 : case ListSourceType_TABLE:
863 : case ListSourceType_QUERY:
864 : {
865 : // Get field of the ResultSet's 1st column
866 0 : Reference<XColumnsSupplier> xSupplyCols(xListCursor, UNO_QUERY);
867 : DBG_ASSERT(xSupplyCols.is(), "OListBoxModel::loadData : cursor supports the row set service but is no column supplier?!");
868 0 : Reference<XIndexAccess> xColumns;
869 0 : if (xSupplyCols.is())
870 : {
871 0 : xColumns = Reference<XIndexAccess>(xSupplyCols->getColumns(), UNO_QUERY);
872 : DBG_ASSERT(xColumns.is(), "OListBoxModel::loadData : no columns supplied by the row set !");
873 : }
874 :
875 0 : Reference< XPropertySet > xDataField;
876 0 : if ( xColumns.is() )
877 0 : xColumns->getByIndex(0) >>= xDataField;
878 0 : if ( !xDataField.is() )
879 0 : return;
880 :
881 0 : ::dbtools::FormattedColumnValue aValueFormatter( getContext(), m_xCursor, xDataField );
882 :
883 : // Get the field of BoundColumn of the ResultSet
884 0 : m_nBoundColumnType = DataType::SQLNULL;
885 0 : if ( *aBoundColumn >= 0 )
886 : {
887 : try
888 : {
889 0 : Reference< XPropertySet > xBoundField( xColumns->getByIndex( *aBoundColumn ), UNO_QUERY_THROW );
890 0 : OSL_VERIFY( xBoundField->getPropertyValue("Type") >>= m_nBoundColumnType );
891 : }
892 0 : catch( const Exception& )
893 : {
894 : DBG_UNHANDLED_EXCEPTION();
895 : }
896 : }
897 0 : else if ( *aBoundColumn == -1)
898 0 : m_nBoundColumnType = DataType::SMALLINT;
899 :
900 : // If the LB is bound to a field and empty entries are valid, we remember the position
901 : // for an empty entry
902 : SAL_INFO( "forms.component", "OListBoxModel::loadData: string collection" );
903 0 : OUString aStr;
904 0 : sal_Int16 entryPos = 0;
905 0 : ORowSetValue aBoundValue;
906 0 : Reference< XRow > xCursorRow( xListCursor, UNO_QUERY_THROW );
907 0 : while ( xListCursor->next() && ( entryPos++ < SHRT_MAX ) ) // SHRT_MAX is the maximum number of entries
908 : {
909 0 : aStr = aValueFormatter.getFormattedValue();
910 0 : aDisplayList.push_back( aStr );
911 :
912 0 : if(*aBoundColumn >= 0)
913 0 : aBoundValue.fill( *aBoundColumn + 1, m_nBoundColumnType, xCursorRow );
914 : else
915 : // -1 because getRow() is 1-indexed, but ListBox positions are 0-indexed
916 0 : aBoundValue = static_cast<sal_Int16>(xListCursor->getRow()-1);
917 0 : aValueList.push_back( aBoundValue );
918 :
919 0 : if ( m_nNULLPos == -1 && aBoundValue.isNull() )
920 0 : m_nNULLPos = sal_Int16( aDisplayList.size() - 1 );
921 0 : if ( bUseNULL && ( m_nNULLPos == -1 ) && aStr.isEmpty() )
922 : // There is already a non-NULL entry with empty display string;
923 : // adding another one for NULL would make things confusing,
924 : // so back off.
925 0 : bUseNULL = false;
926 0 : }
927 : }
928 0 : break;
929 : #endif
930 : case ListSourceType_TABLEFIELDS:
931 : {
932 0 : Reference<XNameAccess> xFieldNames = getTableFields(xConnection, sListSource);
933 0 : if (xFieldNames.is())
934 : {
935 0 : StringSequence seqNames = xFieldNames->getElementNames();
936 : ::std::copy(
937 : seqNames.getConstArray(),
938 0 : seqNames.getConstArray() + seqNames.getLength(),
939 : ::std::insert_iterator< ValueList >( aDisplayList, aDisplayList.end() )
940 0 : );
941 0 : if(*aBoundColumn == -1)
942 : {
943 : // the type of i matters! It will be the type of the ORowSetValue pushed to aValueList!
944 0 : for(size_t i=0; i < aDisplayList.size(); ++i)
945 : {
946 0 : aValueList.push_back(ORowSetValue(sal_Int16(i)));
947 : }
948 : }
949 : else
950 : {
951 0 : aValueList = aDisplayList;
952 0 : }
953 0 : }
954 : }
955 0 : break;
956 : default:
957 : SAL_WARN( "forms.component", "OListBoxModel::loadData: unreachable!" );
958 0 : break;
959 : }
960 : }
961 0 : catch(const SQLException& eSQL)
962 : {
963 0 : onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST));
964 0 : return;
965 : }
966 0 : catch( const Exception& )
967 : {
968 : DBG_UNHANDLED_EXCEPTION();
969 0 : return;
970 : }
971 :
972 :
973 : // Create Values sequence
974 : // Add NULL entry
975 0 : if (bUseNULL && m_nNULLPos == -1)
976 : {
977 0 : aValueList.insert( aValueList.begin(), ORowSetValue() );
978 :
979 0 : aDisplayList.insert( aDisplayList.begin(), ORowSetValue( OUString() ) );
980 0 : m_nNULLPos = 0;
981 : }
982 :
983 0 : setBoundValues(aValueList);
984 :
985 0 : setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( lcl_convertToStringSequence( aDisplayList ) ) );
986 : }
987 :
988 :
989 0 : void OListBoxModel::onConnectedDbColumn( const Reference< XInterface >& /*_rxForm*/ )
990 : {
991 : // list boxes which are bound to a db column don't have multi selection
992 : // - this would be unable to reflect in the db column
993 0 : if ( hasField() )
994 : {
995 0 : setFastPropertyValue( PROPERTY_ID_MULTISELECTION, css::uno::Any(false) );
996 : }
997 :
998 0 : if ( !hasExternalListSource() )
999 0 : impl_refreshDbEntryList( false );
1000 0 : }
1001 :
1002 :
1003 0 : void OListBoxModel::onDisconnectedDbColumn()
1004 : {
1005 0 : clearBoundValues();
1006 0 : m_nNULLPos = -1;
1007 0 : m_nBoundColumnType = DataType::SQLNULL;
1008 :
1009 0 : if ( m_eListSourceType != ListSourceType_VALUELIST )
1010 : {
1011 0 : if ( !hasExternalListSource() )
1012 0 : setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( StringSequence() ) );
1013 :
1014 0 : m_aListRowSet.dispose();
1015 : }
1016 0 : }
1017 :
1018 :
1019 8 : void OListBoxModel::setBoundValues(const ValueList &l)
1020 : {
1021 8 : m_aConvertedBoundValues.clear();
1022 8 : m_aBoundValues = l;
1023 8 : }
1024 :
1025 :
1026 0 : void OListBoxModel::clearBoundValues()
1027 : {
1028 0 : ValueList().swap(m_aConvertedBoundValues);
1029 0 : ValueList().swap(m_aBoundValues);
1030 0 : }
1031 :
1032 :
1033 7 : void OListBoxModel::convertBoundValues(const sal_Int32 nFieldType) const
1034 : {
1035 : assert(s_aEmptyValue.isNull());
1036 7 : m_nNULLPos = -1;
1037 7 : m_aConvertedBoundValues.resize(m_aBoundValues.size());
1038 7 : ValueList::const_iterator src = m_aBoundValues.begin();
1039 7 : const ValueList::const_iterator end = m_aBoundValues.end();
1040 7 : ValueList::iterator dst = m_aConvertedBoundValues.begin();
1041 30 : for (; src != end; ++src, ++dst )
1042 : {
1043 69 : if(m_nNULLPos == -1 &&
1044 46 : !isRequired() &&
1045 46 : (*src == s_aEmptyStringValue || *src == s_aEmptyValue || src->isNull()) )
1046 : {
1047 0 : m_nNULLPos = src - m_aBoundValues.begin();
1048 0 : dst->setNull();
1049 : }
1050 : else
1051 : {
1052 23 : *dst = *src;
1053 : }
1054 23 : dst->setTypeKind(nFieldType);
1055 : }
1056 7 : m_nConvertedBoundValuesType = nFieldType;
1057 : OSL_ENSURE(dst == m_aConvertedBoundValues.end(), "OListBoxModel::convertBoundValues expected to have overwritten all of m_aConvertedBoundValues, but did not.");
1058 : assert(dst == m_aConvertedBoundValues.end());
1059 7 : }
1060 :
1061 213 : sal_Int32 OListBoxModel::getValueType() const
1062 : {
1063 213 : return impl_hasBoundComponent() ? m_nBoundColumnType : getFieldType();
1064 : }
1065 :
1066 213 : ValueList OListBoxModel::impl_getValues() const
1067 : {
1068 213 : const sal_Int32 nFieldType = getValueType();
1069 :
1070 213 : if ( !m_aConvertedBoundValues.empty() && m_nConvertedBoundValuesType == nFieldType )
1071 190 : return m_aConvertedBoundValues;
1072 :
1073 23 : if ( !m_aBoundValues.empty() )
1074 : {
1075 7 : convertBoundValues(nFieldType);
1076 7 : return m_aConvertedBoundValues;
1077 : }
1078 :
1079 16 : Sequence< OUString > aStringItems( getStringItemList() );
1080 32 : ValueList aValues( aStringItems.getLength() );
1081 16 : ValueList::iterator dst = aValues.begin();
1082 16 : const OUString *src (aStringItems.getConstArray());
1083 16 : const OUString * const end = src + aStringItems.getLength();
1084 22 : for (; src < end; ++src, ++dst )
1085 : {
1086 6 : *dst = *src;
1087 6 : dst->setTypeKind(nFieldType);
1088 : }
1089 16 : m_nConvertedBoundValuesType = nFieldType;
1090 : OSL_ENSURE(dst == aValues.end(), "OListBoxModel::impl_getValues expected to have set all of aValues, but did not.");
1091 : assert(dst == aValues.end());
1092 32 : return aValues;
1093 : }
1094 :
1095 0 : ORowSetValue OListBoxModel::getFirstSelectedValue() const
1096 : {
1097 : DBG_ASSERT( m_xAggregateFastSet.is(), "OListBoxModel::getFirstSelectedValue: invalid aggregate!" );
1098 0 : if ( !m_xAggregateFastSet.is() )
1099 0 : return s_aEmptyValue;
1100 :
1101 0 : Sequence< sal_Int16 > aSelectedIndices;
1102 0 : OSL_VERIFY( m_xAggregateFastSet->getFastPropertyValue( getValuePropertyAggHandle() ) >>= aSelectedIndices );
1103 0 : if ( !aSelectedIndices.getLength() )
1104 : // nothing selected at all
1105 0 : return s_aEmptyValue;
1106 :
1107 0 : if ( ( m_nNULLPos != -1 ) && ( aSelectedIndices[0] == m_nNULLPos ) )
1108 : // the dedicated "NULL" entry is selected
1109 0 : return s_aEmptyValue;
1110 :
1111 0 : ValueList aValues( impl_getValues() );
1112 :
1113 0 : size_t selectedValue = aSelectedIndices[0];
1114 0 : if ( selectedValue >= aValues.size() )
1115 : {
1116 : SAL_WARN( "forms.component", "OListBoxModel::getFirstSelectedValue: inconsistent selection/valuelist!" );
1117 0 : return s_aEmptyValue;
1118 : }
1119 :
1120 0 : return aValues[ selectedValue ];
1121 : }
1122 :
1123 :
1124 0 : bool OListBoxModel::commitControlValueToDbColumn( bool /*_bPostReset*/ )
1125 : {
1126 : // current selection list
1127 0 : const ORowSetValue aCurrentValue( getFirstSelectedValue() );
1128 0 : if ( aCurrentValue != m_aSaveValue )
1129 : {
1130 0 : if ( aCurrentValue.isNull() )
1131 0 : m_xColumnUpdate->updateNull();
1132 : else
1133 : {
1134 : try
1135 : {
1136 0 : m_xColumnUpdate->updateObject( aCurrentValue.makeAny() );
1137 : }
1138 0 : catch ( const Exception& )
1139 : {
1140 0 : return false;
1141 : }
1142 : }
1143 0 : m_aSaveValue = aCurrentValue;
1144 : }
1145 0 : return true;
1146 : }
1147 :
1148 :
1149 2 : Sequence< sal_Int16 > OListBoxModel::translateDbValueToControlValue(const ORowSetValue &i_aValue) const
1150 : {
1151 2 : Sequence< sal_Int16 > aSelectionIndicies;
1152 :
1153 : // reset selection for NULL values
1154 2 : if ( i_aValue.isNull() )
1155 : {
1156 0 : if ( m_nNULLPos != -1 )
1157 : {
1158 0 : aSelectionIndicies.realloc(1);
1159 0 : aSelectionIndicies[0] = m_nNULLPos;
1160 : }
1161 : }
1162 : else
1163 : {
1164 2 : ValueList aValues( impl_getValues() );
1165 : assert( m_nConvertedBoundValuesType == getValueType());
1166 4 : ORowSetValue v(i_aValue);
1167 2 : v.setTypeKind( m_nConvertedBoundValuesType );
1168 2 : ValueList::const_iterator curValuePos = ::std::find( aValues.begin(), aValues.end(), v );
1169 2 : if ( curValuePos != aValues.end() )
1170 : {
1171 0 : aSelectionIndicies.realloc( 1 );
1172 0 : aSelectionIndicies[0] = curValuePos - aValues.begin();
1173 2 : }
1174 : }
1175 :
1176 2 : return aSelectionIndicies;
1177 : }
1178 :
1179 11 : Sequence< sal_Int16 > OListBoxModel::translateBindingValuesToControlValue(const Sequence< const Any > &i_aValues) const
1180 : {
1181 11 : const ValueList aValues( impl_getValues() );
1182 : assert( m_nConvertedBoundValuesType == getValueType());
1183 11 : Sequence< sal_Int16 > aSelectionIndicies(i_aValues.getLength());
1184 :
1185 11 : sal_Int32 nCount(0);
1186 :
1187 : #if HAVE_FEATURE_DBCONNECTIVITY
1188 11 : sal_Int16 *pIndex = aSelectionIndicies.getArray();
1189 11 : const Any *pValue = i_aValues.getConstArray();
1190 11 : const Any * const pValueEnd = i_aValues.getConstArray() + i_aValues.getLength();
1191 40 : for (;pValue < pValueEnd; ++pValue)
1192 : {
1193 29 : if ( pValue->hasValue() )
1194 : {
1195 29 : ORowSetValue v;
1196 29 : v.fill(*pValue);
1197 29 : v.setTypeKind( m_nConvertedBoundValuesType );
1198 29 : ValueList::const_iterator curValuePos = ::std::find( aValues.begin(), aValues.end(), v );
1199 29 : if ( curValuePos != aValues.end() )
1200 : {
1201 0 : *pIndex = curValuePos - aValues.begin();
1202 0 : ++pIndex;
1203 0 : ++nCount;
1204 29 : }
1205 : }
1206 : else
1207 : {
1208 0 : if ( m_nNULLPos != -1 )
1209 : {
1210 0 : *pIndex = m_nNULLPos;
1211 0 : ++pIndex;
1212 0 : ++nCount;
1213 : }
1214 : }
1215 : }
1216 : assert(aSelectionIndicies.getArray() + nCount == pIndex);
1217 : #endif
1218 11 : aSelectionIndicies.realloc(nCount);
1219 11 : return aSelectionIndicies;
1220 : }
1221 :
1222 0 : Any OListBoxModel::translateDbColumnToControlValue()
1223 : {
1224 : #if HAVE_FEATURE_DBCONNECTIVITY
1225 0 : Reference< XPropertySet > xBoundField( getField() );
1226 0 : if ( !xBoundField.is() )
1227 : {
1228 : SAL_WARN( "forms.component", "OListBoxModel::translateDbColumnToControlValue: no field? How could that happen?!" );
1229 0 : return Any();
1230 : }
1231 :
1232 0 : ORowSetValue aCurrentValue;
1233 0 : aCurrentValue.fill( getValueType(), m_xColumn );
1234 :
1235 0 : m_aSaveValue = aCurrentValue;
1236 :
1237 0 : return makeAny( translateDbValueToControlValue(aCurrentValue) );
1238 : #else
1239 : return Any();
1240 : #endif
1241 : }
1242 :
1243 : // XReset
1244 :
1245 29 : Any OListBoxModel::getDefaultForReset() const
1246 : {
1247 29 : Any aValue;
1248 29 : if (m_aDefaultSelectSeq.getLength())
1249 11 : aValue <<= m_aDefaultSelectSeq;
1250 18 : else if (m_nNULLPos != -1) // bound Listbox
1251 : {
1252 0 : Sequence<sal_Int16> aSeq(1);
1253 0 : aSeq.getArray()[0] = m_nNULLPos;
1254 0 : aValue <<= aSeq;
1255 : }
1256 : else
1257 : {
1258 18 : Sequence<sal_Int16> aSeq;
1259 18 : aValue <<= aSeq;
1260 : }
1261 :
1262 29 : return aValue;
1263 : }
1264 :
1265 :
1266 29 : void OListBoxModel::resetNoBroadcast()
1267 : {
1268 29 : OBoundControlModel::resetNoBroadcast();
1269 29 : m_aSaveValue.setNull();
1270 29 : }
1271 :
1272 :
1273 2 : void SAL_CALL OListBoxModel::disposing( const EventObject& _rSource ) throw ( RuntimeException, std::exception )
1274 : {
1275 2 : if ( !OEntryListHelper::handleDisposing( _rSource ) )
1276 2 : OBoundControlModel::disposing( _rSource );
1277 2 : }
1278 :
1279 :
1280 : namespace
1281 : {
1282 : // The type of how we should transfer our selection to external value bindings
1283 : enum ExchangeType
1284 : {
1285 : eIndexList, /// as list of indexes of selected entries
1286 : eIndex, /// as index of the selected entry
1287 : eEntryList, /// as list of string representations of selected *display* entries
1288 : eEntry, /// as string representation of the selected *display* entry
1289 : eValueList, /// as list of string representations of selected values
1290 : eValue /// as string representation of the selected value
1291 : };
1292 :
1293 :
1294 2 : ExchangeType lcl_getCurrentExchangeType( const Type& _rExchangeType )
1295 : {
1296 2 : switch ( _rExchangeType.getTypeClass() )
1297 : {
1298 : case TypeClass_ANY:
1299 0 : return eValue;
1300 : case TypeClass_STRING:
1301 0 : return eEntry;
1302 : case TypeClass_LONG:
1303 0 : return eIndex;
1304 : case TypeClass_SEQUENCE:
1305 : {
1306 2 : Type aElementType = ::comphelper::getSequenceElementType( _rExchangeType );
1307 2 : switch ( aElementType.getTypeClass() )
1308 : {
1309 : case TypeClass_ANY:
1310 2 : return eValueList;
1311 : case TypeClass_STRING:
1312 0 : return eEntryList;
1313 : case TypeClass_LONG:
1314 0 : return eIndexList;
1315 : default:
1316 0 : break;
1317 0 : }
1318 : }
1319 : default:
1320 0 : break;
1321 : }
1322 : SAL_WARN( "forms.component", "lcl_getCurrentExchangeType: unsupported (unexpected) exchange type!" );
1323 0 : return eEntry;
1324 : }
1325 : }
1326 :
1327 :
1328 2 : Any OListBoxModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const
1329 : {
1330 2 : Sequence< sal_Int16 > aSelectIndexes;
1331 :
1332 2 : switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1333 : {
1334 : case eValueList:
1335 : {
1336 2 : Sequence< const Any > aExternalValues;
1337 2 : OSL_VERIFY( _rExternalValue >>= aExternalValues );
1338 2 : aSelectIndexes = translateBindingValuesToControlValue( aExternalValues );
1339 : }
1340 2 : break;
1341 :
1342 : case eValue:
1343 : #if HAVE_FEATURE_DBCONNECTIVITY
1344 : {
1345 0 : ORowSetValue v;
1346 0 : v.fill(_rExternalValue);
1347 0 : aSelectIndexes = translateDbValueToControlValue(v);
1348 : }
1349 : #endif
1350 0 : break;
1351 :
1352 : case eIndexList:
1353 : {
1354 : // unfortunately, our select sequence is a sequence<short>, while the external binding
1355 : // supplies sequence<int> only -> transform this
1356 0 : Sequence< sal_Int32 > aSelectIndexesPure;
1357 0 : OSL_VERIFY( _rExternalValue >>= aSelectIndexesPure );
1358 0 : aSelectIndexes.realloc( aSelectIndexesPure.getLength() );
1359 : ::std::copy(
1360 : aSelectIndexesPure.getConstArray(),
1361 0 : aSelectIndexesPure.getConstArray() + aSelectIndexesPure.getLength(),
1362 : aSelectIndexes.getArray()
1363 0 : );
1364 : }
1365 0 : break;
1366 :
1367 : case eIndex:
1368 : {
1369 0 : sal_Int32 nSelectIndex = -1;
1370 0 : OSL_VERIFY( _rExternalValue >>= nSelectIndex );
1371 0 : if ( ( nSelectIndex >= 0 ) && ( nSelectIndex < getStringItemList().getLength() ) )
1372 : {
1373 0 : aSelectIndexes.realloc( 1 );
1374 0 : aSelectIndexes[ 0 ] = static_cast< sal_Int16 >( nSelectIndex );
1375 : }
1376 : }
1377 0 : break;
1378 :
1379 : case eEntryList:
1380 : {
1381 : // we can retrieve a string list from the binding for multiple selection
1382 0 : Sequence< OUString > aSelectEntries;
1383 0 : OSL_VERIFY( _rExternalValue >>= aSelectEntries );
1384 :
1385 0 : ::std::set< sal_Int16 > aSelectionSet;
1386 :
1387 : // find the selection entries in our item list
1388 0 : const OUString* pSelectEntries = aSelectEntries.getArray();
1389 0 : const OUString* pSelectEntriesEnd = pSelectEntries + aSelectEntries.getLength();
1390 0 : while ( pSelectEntries != pSelectEntriesEnd )
1391 : {
1392 : // the indexes where the current string appears in our string items
1393 0 : Sequence< sal_Int16 > aThisEntryIndexes;
1394 0 : aThisEntryIndexes = findValue( getStringItemList(), *pSelectEntries++, false );
1395 :
1396 : // insert all the indexes of this entry into our set
1397 : ::std::copy(
1398 : aThisEntryIndexes.getConstArray(),
1399 0 : aThisEntryIndexes.getConstArray() + aThisEntryIndexes.getLength(),
1400 : ::std::insert_iterator< ::std::set< sal_Int16 > >( aSelectionSet, aSelectionSet.begin() )
1401 0 : );
1402 0 : }
1403 :
1404 : // copy the indexes to the sequence
1405 0 : aSelectIndexes.realloc( aSelectionSet.size() );
1406 : ::std::copy(
1407 : aSelectionSet.begin(),
1408 : aSelectionSet.end(),
1409 : aSelectIndexes.getArray()
1410 0 : );
1411 : }
1412 0 : break;
1413 :
1414 : case eEntry:
1415 : {
1416 0 : OUString sStringToSelect;
1417 0 : OSL_VERIFY( _rExternalValue >>= sStringToSelect );
1418 :
1419 0 : aSelectIndexes = findValue( getStringItemList(), sStringToSelect, false );
1420 : }
1421 0 : break;
1422 : }
1423 :
1424 2 : return makeAny( aSelectIndexes );
1425 : }
1426 :
1427 :
1428 : namespace
1429 : {
1430 :
1431 : struct ExtractStringFromSequence_Safe : public ::std::unary_function< sal_Int16, OUString >
1432 : {
1433 : protected:
1434 : const Sequence< OUString >& m_rList;
1435 :
1436 : public:
1437 0 : ExtractStringFromSequence_Safe( const Sequence< OUString >& _rList ) : m_rList( _rList ) { }
1438 :
1439 0 : OUString operator ()( sal_Int16 _nIndex )
1440 : {
1441 : OSL_ENSURE( _nIndex < m_rList.getLength(), "ExtractStringFromSequence_Safe: inconsistence!" );
1442 0 : if ( _nIndex < m_rList.getLength() )
1443 0 : return m_rList[ _nIndex ];
1444 0 : return OUString();
1445 : }
1446 : };
1447 :
1448 :
1449 0 : Any lcl_getSingleSelectedEntry( const Sequence< sal_Int16 >& _rSelectSequence, const Sequence< OUString >& _rStringList )
1450 : {
1451 0 : Any aReturn;
1452 :
1453 : // by definition, multiple selected entries are transferred as NULL if the
1454 : // binding does not support string lists
1455 0 : if ( _rSelectSequence.getLength() <= 1 )
1456 : {
1457 0 : OUString sSelectedEntry;
1458 :
1459 0 : if ( _rSelectSequence.getLength() == 1 )
1460 0 : sSelectedEntry = ExtractStringFromSequence_Safe( _rStringList )( _rSelectSequence[0] );
1461 :
1462 0 : aReturn <<= sSelectedEntry;
1463 : }
1464 :
1465 0 : return aReturn;
1466 : }
1467 :
1468 :
1469 0 : Any lcl_getMultiSelectedEntries( const Sequence< sal_Int16 >& _rSelectSequence, const Sequence< OUString >& _rStringList )
1470 : {
1471 0 : Sequence< OUString > aSelectedEntriesTexts( _rSelectSequence.getLength() );
1472 : ::std::transform(
1473 : _rSelectSequence.getConstArray(),
1474 0 : _rSelectSequence.getConstArray() + _rSelectSequence.getLength(),
1475 : aSelectedEntriesTexts.getArray(),
1476 : ExtractStringFromSequence_Safe( _rStringList )
1477 0 : );
1478 0 : return makeAny( aSelectedEntriesTexts );
1479 : }
1480 :
1481 :
1482 : struct ExtractAnyFromValueList_Safe : public ::std::unary_function< sal_Int16, Any >
1483 : {
1484 : protected:
1485 : const ValueList& m_rList;
1486 :
1487 : public:
1488 161 : ExtractAnyFromValueList_Safe( const ValueList& _rList ) : m_rList( _rList ) { }
1489 :
1490 309 : Any operator ()( sal_Int16 _nIndex )
1491 : {
1492 : OSL_ENSURE( static_cast<ValueList::size_type>(_nIndex) < m_rList.size(), "ExtractAnyFromValueList: inconsistence!" );
1493 309 : if ( static_cast<ValueList::size_type>(_nIndex) < m_rList.size() )
1494 2 : return m_rList[ _nIndex ].makeAny();
1495 307 : return Any();
1496 : }
1497 : };
1498 :
1499 :
1500 47 : Any lcl_getSingleSelectedEntryAny( const Sequence< sal_Int16 >& _rSelectSequence, const ValueList& _rStringList )
1501 : {
1502 47 : Any aReturn;
1503 :
1504 : // by definition, multiple selected entries are transferred as NULL if the
1505 : // binding does not support string lists
1506 47 : if ( _rSelectSequence.getLength() <= 1 )
1507 : {
1508 31 : if ( _rSelectSequence.getLength() == 1 )
1509 8 : aReturn = ExtractAnyFromValueList_Safe( _rStringList )( _rSelectSequence[0] );
1510 : }
1511 :
1512 47 : return aReturn;
1513 : }
1514 :
1515 :
1516 153 : Any lcl_getMultiSelectedEntriesAny( const Sequence< sal_Int16 >& _rSelectSequence, const ValueList& _rStringList )
1517 : {
1518 153 : Sequence< Any > aSelectedEntriesValues( _rSelectSequence.getLength() );
1519 : ::std::transform(
1520 : _rSelectSequence.getConstArray(),
1521 153 : _rSelectSequence.getConstArray() + _rSelectSequence.getLength(),
1522 : aSelectedEntriesValues.getArray(),
1523 : ExtractAnyFromValueList_Safe( _rStringList )
1524 306 : );
1525 153 : return makeAny( aSelectedEntriesValues );
1526 : }
1527 : }
1528 :
1529 :
1530 0 : Any OListBoxModel::translateControlValueToExternalValue( ) const
1531 : {
1532 : OSL_PRECOND( hasExternalValueBinding(), "OListBoxModel::translateControlValueToExternalValue: no binding!" );
1533 :
1534 0 : Sequence< sal_Int16 > aSelectSequence;
1535 0 : OSL_VERIFY( getControlValue() >>= aSelectSequence );
1536 :
1537 0 : Any aReturn;
1538 0 : switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1539 : {
1540 : case eValueList:
1541 0 : aReturn = getCurrentMultiValue();
1542 0 : break;
1543 :
1544 : case eValue:
1545 0 : aReturn = getCurrentSingleValue();
1546 0 : break;
1547 :
1548 : case eIndexList:
1549 : {
1550 : // unfortunately, the select sequence is a sequence<short>, but our binding
1551 : // expects int's
1552 0 : Sequence< sal_Int32 > aTransformed( aSelectSequence.getLength() );
1553 : ::std::copy(
1554 : aSelectSequence.getConstArray(),
1555 0 : aSelectSequence.getConstArray() + aSelectSequence.getLength(),
1556 : aTransformed.getArray()
1557 0 : );
1558 0 : aReturn <<= aTransformed;
1559 : }
1560 0 : break;
1561 :
1562 : case eIndex:
1563 0 : if ( aSelectSequence.getLength() <= 1 )
1564 : {
1565 0 : sal_Int32 nIndex = -1;
1566 :
1567 0 : if ( aSelectSequence.getLength() == 1 )
1568 0 : nIndex = aSelectSequence[0];
1569 :
1570 0 : aReturn <<= nIndex;
1571 : }
1572 0 : break;
1573 :
1574 : case eEntryList:
1575 0 : aReturn = lcl_getMultiSelectedEntries( aSelectSequence, getStringItemList() );
1576 0 : break;
1577 :
1578 : case eEntry:
1579 0 : aReturn = lcl_getSingleSelectedEntry( aSelectSequence, getStringItemList() );
1580 0 : break;
1581 : }
1582 :
1583 0 : return aReturn;
1584 : }
1585 :
1586 :
1587 21 : Any OListBoxModel::translateControlValueToValidatableValue( ) const
1588 : {
1589 : OSL_PRECOND( hasValidator(), "OListBoxModel::translateControlValueToValidatableValue: no validator, so why should I?" );
1590 21 : return getCurrentFormComponentValue();
1591 : }
1592 :
1593 :
1594 47 : Any OListBoxModel::getCurrentSingleValue() const
1595 : {
1596 47 : Any aCurrentValue;
1597 :
1598 : try
1599 : {
1600 47 : Sequence< sal_Int16 > aSelectSequence;
1601 47 : OSL_VERIFY( getControlValue() >>= aSelectSequence );
1602 47 : aCurrentValue = lcl_getSingleSelectedEntryAny( aSelectSequence, impl_getValues() );
1603 : }
1604 0 : catch( const Exception& )
1605 : {
1606 : DBG_UNHANDLED_EXCEPTION();
1607 : }
1608 :
1609 47 : return aCurrentValue;
1610 : }
1611 :
1612 153 : Any OListBoxModel::getCurrentMultiValue() const
1613 : {
1614 153 : Any aCurrentValue;
1615 :
1616 : try
1617 : {
1618 153 : Sequence< sal_Int16 > aSelectSequence;
1619 153 : OSL_VERIFY( getControlValue() >>= aSelectSequence );
1620 153 : aCurrentValue = lcl_getMultiSelectedEntriesAny( aSelectSequence, impl_getValues() );
1621 : }
1622 0 : catch( const Exception& )
1623 : {
1624 : DBG_UNHANDLED_EXCEPTION();
1625 : }
1626 :
1627 153 : return aCurrentValue;
1628 : }
1629 :
1630 22 : Any OListBoxModel::getCurrentFormComponentValue() const
1631 : {
1632 : {
1633 22 : Reference< com::sun::star::form::validation::XValidator > vtor (const_cast<OListBoxModel*>(this)->getValidator());
1634 44 : Reference< XValueBinding > extBinding (const_cast<OListBoxModel*>(this)->getValueBinding());
1635 22 : if ( vtor.is() && vtor == extBinding )
1636 22 : return translateControlValueToExternalValue();
1637 : }
1638 :
1639 22 : Any aCurrentValue;
1640 :
1641 : try
1642 : {
1643 22 : bool bMultiSelection( false );
1644 22 : OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_MULTISELECTION ) >>= bMultiSelection );
1645 :
1646 22 : if ( bMultiSelection )
1647 8 : aCurrentValue = getCurrentMultiValue();
1648 : else
1649 14 : aCurrentValue = getCurrentSingleValue();
1650 : }
1651 0 : catch( const Exception& )
1652 : {
1653 : DBG_UNHANDLED_EXCEPTION();
1654 : }
1655 :
1656 22 : return aCurrentValue;
1657 : }
1658 :
1659 :
1660 4 : Sequence< Type > OListBoxModel::getSupportedBindingTypes()
1661 : {
1662 4 : Sequence< Type > aTypes(6);
1663 4 : aTypes[0] = cppu::UnoType<Sequence< Any >>::get();
1664 4 : aTypes[1] = cppu::UnoType<Any>::get();
1665 4 : aTypes[2] = cppu::UnoType<Sequence< sal_Int32 >>::get();
1666 4 : aTypes[3] = cppu::UnoType<sal_Int32>::get();
1667 4 : aTypes[4] = cppu::UnoType<Sequence< OUString >>::get();
1668 4 : aTypes[5] = cppu::UnoType<OUString>::get();
1669 4 : return aTypes;
1670 : }
1671 :
1672 :
1673 27 : void OListBoxModel::stringItemListChanged( ControlModelLock& _rInstanceLock )
1674 : {
1675 27 : if ( !m_xAggregateSet.is() )
1676 27 : return;
1677 :
1678 27 : suspendValueListening();
1679 : try
1680 : {
1681 27 : m_xAggregateSet->setPropertyValue( PROPERTY_STRINGITEMLIST, makeAny( getStringItemList() ) );
1682 : }
1683 0 : catch( const Exception& )
1684 : {
1685 : DBG_UNHANDLED_EXCEPTION();
1686 : }
1687 27 : resumeValueListening();
1688 :
1689 : // update the selection here
1690 27 : if ( hasExternalValueBinding( ) )
1691 0 : transferExternalValueToControl( _rInstanceLock );
1692 : else
1693 : {
1694 27 : if ( hasField() )
1695 : {
1696 : // TODO: update the selection in case we're bound to a database column
1697 : }
1698 : else
1699 : {
1700 27 : if ( m_aDefaultSelectSeq.getLength() )
1701 11 : setControlValue( makeAny( m_aDefaultSelectSeq ), eOther );
1702 : }
1703 : }
1704 : }
1705 :
1706 :
1707 0 : void OListBoxModel::connectedExternalListSource( )
1708 : {
1709 : // TODO?
1710 0 : }
1711 :
1712 :
1713 0 : void OListBoxModel::disconnectedExternalListSource( )
1714 : {
1715 : // TODO: in case we're part of an already loaded form, we should probably simulate
1716 : // an onConnectedDbColumn, so our list get's filled with the data as indicated
1717 : // by our SQL-binding related properties
1718 0 : }
1719 :
1720 :
1721 0 : void OListBoxModel::impl_refreshDbEntryList( bool _bForce )
1722 : {
1723 : DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::impl_refreshDbEntryList: invalid call!" );
1724 :
1725 0 : if ( !hasExternalListSource( )
1726 0 : && ( m_eListSourceType != ListSourceType_VALUELIST )
1727 0 : && ( m_xCursor.is() )
1728 : )
1729 : {
1730 0 : loadData( _bForce );
1731 : }
1732 0 : }
1733 :
1734 :
1735 0 : void OListBoxModel::refreshInternalEntryList()
1736 : {
1737 0 : impl_refreshDbEntryList( true );
1738 0 : if ( hasField() && m_xCursor.is() )
1739 0 : initFromField( m_xCursor );
1740 0 : }
1741 :
1742 :
1743 : // OListBoxControl
1744 :
1745 24 : Sequence< Type> OListBoxControl::_getTypes()
1746 : {
1747 : return TypeBag(
1748 : OBoundControl::_getTypes(),
1749 : OListBoxControl_BASE::getTypes()
1750 24 : ).getTypes();
1751 : }
1752 :
1753 :
1754 1784 : Any SAL_CALL OListBoxControl::queryAggregation(const Type& _rType) throw (RuntimeException, std::exception)
1755 : {
1756 1784 : Any aReturn = OListBoxControl_BASE::queryInterface( _rType );
1757 :
1758 3568 : if ( !aReturn.hasValue()
1759 1784 : || _rType.equals( cppu::UnoType<XTypeProvider>::get() )
1760 : )
1761 1443 : aReturn = OBoundControl::queryAggregation( _rType );
1762 :
1763 1784 : return aReturn;
1764 : }
1765 :
1766 :
1767 34 : OListBoxControl::OListBoxControl(const Reference<XComponentContext>& _rxFactory)
1768 : :OBoundControl( _rxFactory, VCL_CONTROL_LISTBOX, false )
1769 : ,m_aChangeListeners( m_aMutex )
1770 34 : ,m_aItemListeners( m_aMutex )
1771 : {
1772 :
1773 34 : osl_atomic_increment(&m_refCount);
1774 : {
1775 : // Register as FocusListener
1776 34 : Reference<XWindow> xComp;
1777 34 : if (query_aggregation(m_xAggregate, xComp))
1778 34 : xComp->addFocusListener(this);
1779 :
1780 : // Register as ItemListener
1781 34 : if ( query_aggregation( m_xAggregate, m_xAggregateListBox ) )
1782 34 : m_xAggregateListBox->addItemListener(this);
1783 : }
1784 : // Refcount at 2 for registered Listener
1785 34 : osl_atomic_decrement(&m_refCount);
1786 :
1787 34 : doSetDelegator();
1788 :
1789 34 : m_aChangeIdle.SetPriority(SchedulerPriority::LOWEST);
1790 34 : m_aChangeIdle.SetIdleHdl(LINK(this,OListBoxControl,OnTimeout));
1791 34 : }
1792 :
1793 :
1794 66 : OListBoxControl::~OListBoxControl()
1795 : {
1796 22 : if (!OComponentHelper::rBHelper.bDisposed)
1797 : {
1798 0 : acquire();
1799 0 : dispose();
1800 : }
1801 :
1802 22 : doResetDelegator();
1803 22 : m_xAggregateListBox.clear();
1804 :
1805 44 : }
1806 :
1807 :
1808 1 : StringSequence SAL_CALL OListBoxControl::getSupportedServiceNames() throw(RuntimeException, std::exception)
1809 : {
1810 1 : StringSequence aSupported = OBoundControl::getSupportedServiceNames();
1811 1 : aSupported.realloc(aSupported.getLength() + 2);
1812 :
1813 1 : OUString* pArray = aSupported.getArray();
1814 1 : pArray[aSupported.getLength()-2] = FRM_SUN_CONTROL_LISTBOX;
1815 1 : pArray[aSupported.getLength()-1] = STARDIV_ONE_FORM_CONTROL_LISTBOX;
1816 1 : return aSupported;
1817 : }
1818 :
1819 :
1820 : // XFocusListener
1821 :
1822 0 : void SAL_CALL OListBoxControl::focusGained(const FocusEvent& /*_rEvent*/) throw(RuntimeException, std::exception)
1823 : {
1824 0 : ::osl::MutexGuard aGuard(m_aMutex);
1825 0 : if ( m_aChangeListeners.getLength() ) // only if there are listeners
1826 : {
1827 0 : Reference<XPropertySet> xSet(getModel(), UNO_QUERY);
1828 0 : if (xSet.is())
1829 : {
1830 : // memorize the current selection for posting the change event
1831 0 : m_aCurrentSelection = xSet->getPropertyValue(PROPERTY_SELECT_SEQ);
1832 0 : }
1833 0 : }
1834 0 : }
1835 :
1836 :
1837 0 : void SAL_CALL OListBoxControl::focusLost(const FocusEvent& /*_rEvent*/) throw(RuntimeException, std::exception)
1838 : {
1839 0 : m_aCurrentSelection.clear();
1840 0 : }
1841 :
1842 : // XItemListener
1843 :
1844 0 : void SAL_CALL OListBoxControl::itemStateChanged(const ItemEvent& _rEvent) throw(RuntimeException, std::exception)
1845 : {
1846 : // forward this to our listeners
1847 0 : Reference< XChild > xChild( getModel(), UNO_QUERY );
1848 0 : if ( xChild.is() && xChild->getParent().is() )
1849 : {
1850 0 : ::osl::MutexGuard aGuard( m_aMutex );
1851 0 : if ( m_aItemListeners.getLength() )
1852 : {
1853 0 : if ( !m_pItemBroadcaster.is() )
1854 : {
1855 : m_pItemBroadcaster.set(
1856 0 : new ::comphelper::AsyncEventNotifier("ListBox"));
1857 0 : m_pItemBroadcaster->launch();
1858 : }
1859 0 : m_pItemBroadcaster->addEvent( new ItemEventDescription( _rEvent ), this );
1860 0 : }
1861 : }
1862 : else
1863 0 : m_aItemListeners.notifyEach( &XItemListener::itemStateChanged, _rEvent );
1864 :
1865 : // and do the handling for the ChangeListeners
1866 0 : ::osl::ClearableMutexGuard aGuard(m_aMutex);
1867 0 : if ( m_aChangeIdle.IsActive() )
1868 : {
1869 0 : Reference<XPropertySet> xSet(getModel(), UNO_QUERY);
1870 0 : m_aCurrentSelection = xSet->getPropertyValue(PROPERTY_SELECT_SEQ);
1871 :
1872 0 : m_aChangeIdle.Stop();
1873 0 : m_aChangeIdle.Start();
1874 : }
1875 : else
1876 : {
1877 0 : if ( m_aChangeListeners.getLength() && m_aCurrentSelection.hasValue() )
1878 : {
1879 0 : Reference<XPropertySet> xSet(getModel(), UNO_QUERY);
1880 0 : if (xSet.is())
1881 : {
1882 : // Has the selection been changed?
1883 0 : bool bModified(false);
1884 0 : Any aValue = xSet->getPropertyValue(PROPERTY_SELECT_SEQ);
1885 :
1886 0 : Sequence<sal_Int16> const & rSelection = *static_cast<Sequence<sal_Int16> const *>(aValue.getValue());
1887 0 : Sequence<sal_Int16> const & rOldSelection = *static_cast<Sequence<sal_Int16> const *>(m_aCurrentSelection.getValue());
1888 0 : sal_Int32 nLen = rSelection.getLength();
1889 0 : if (nLen != rOldSelection.getLength())
1890 0 : bModified = true;
1891 : else
1892 : {
1893 0 : const sal_Int16* pVal = rSelection.getConstArray();
1894 0 : const sal_Int16* pCompVal = rOldSelection.getConstArray();
1895 :
1896 0 : while (nLen-- && !bModified)
1897 0 : bModified = pVal[nLen] != pCompVal[nLen];
1898 : }
1899 :
1900 0 : if (bModified)
1901 : {
1902 0 : m_aCurrentSelection = aValue;
1903 0 : m_aChangeIdle.Start();
1904 0 : }
1905 0 : }
1906 : }
1907 0 : else if (m_aCurrentSelection.hasValue())
1908 0 : m_aCurrentSelection.clear();
1909 0 : }
1910 0 : }
1911 :
1912 : // XEventListener
1913 :
1914 82 : void SAL_CALL OListBoxControl::disposing(const EventObject& _rSource) throw (RuntimeException, std::exception)
1915 : {
1916 82 : OBoundControl::disposing(_rSource);
1917 82 : }
1918 :
1919 : // XChangeBroadcaster
1920 :
1921 1 : void SAL_CALL OListBoxControl::addChangeListener(const Reference<XChangeListener>& _rxListener) throw(RuntimeException, std::exception)
1922 : {
1923 1 : m_aChangeListeners.addInterface( _rxListener );
1924 1 : }
1925 :
1926 :
1927 0 : void SAL_CALL OListBoxControl::removeChangeListener(const Reference<XChangeListener>& _rxListener) throw(RuntimeException, std::exception)
1928 : {
1929 0 : m_aChangeListeners.removeInterface( _rxListener );
1930 0 : }
1931 :
1932 : // OComponentHelper
1933 :
1934 23 : void OListBoxControl::disposing()
1935 : {
1936 23 : if (m_aChangeIdle.IsActive())
1937 0 : m_aChangeIdle.Stop();
1938 :
1939 23 : EventObject aEvent( *this );
1940 23 : m_aChangeListeners.disposeAndClear( aEvent );
1941 23 : m_aItemListeners.disposeAndClear( aEvent );
1942 :
1943 46 : rtl::Reference< comphelper::AsyncEventNotifier > t;
1944 : {
1945 23 : ::osl::MutexGuard aGuard( m_aMutex );
1946 23 : if ( m_pItemBroadcaster.is() )
1947 : {
1948 0 : t = m_pItemBroadcaster;
1949 0 : m_pItemBroadcaster->removeEventsForProcessor( this );
1950 0 : m_pItemBroadcaster->terminate();
1951 0 : m_pItemBroadcaster = NULL;
1952 23 : }
1953 : }
1954 23 : if (t.is()) {
1955 0 : t->join();
1956 : }
1957 :
1958 46 : OBoundControl::disposing();
1959 23 : }
1960 :
1961 :
1962 0 : void OListBoxControl::processEvent( const AnyEvent& _rEvent )
1963 : {
1964 0 : Reference< XListBox > xKeepAlive( this );
1965 : {
1966 0 : ::osl::MutexGuard aGuard( m_aMutex );
1967 0 : if ( OComponentHelper::rBHelper.bDisposed )
1968 0 : return;
1969 : }
1970 0 : const ItemEventDescription& rItemEvent = static_cast< const ItemEventDescription& >( _rEvent );
1971 0 : m_aItemListeners.notifyEach( &XItemListener::itemStateChanged, rItemEvent.getEventObject() );
1972 : }
1973 :
1974 :
1975 0 : IMPL_LINK_NOARG_TYPED(OListBoxControl, OnTimeout, Idle*, void)
1976 : {
1977 0 : m_aChangeListeners.notifyEach( &XChangeListener::changed, EventObject( *this ) );
1978 0 : }
1979 :
1980 :
1981 1 : void SAL_CALL OListBoxControl::addItemListener( const Reference< XItemListener >& l ) throw (RuntimeException, std::exception)
1982 : {
1983 1 : m_aItemListeners.addInterface( l );
1984 1 : }
1985 :
1986 :
1987 0 : void SAL_CALL OListBoxControl::removeItemListener( const Reference< XItemListener >& l ) throw (RuntimeException, std::exception)
1988 : {
1989 0 : m_aItemListeners.removeInterface( l );
1990 0 : }
1991 :
1992 :
1993 1 : void SAL_CALL OListBoxControl::addActionListener( const Reference< XActionListener >& l ) throw (RuntimeException, std::exception)
1994 : {
1995 1 : if ( m_xAggregateListBox.is() )
1996 1 : m_xAggregateListBox->addActionListener( l );
1997 1 : }
1998 :
1999 :
2000 0 : void SAL_CALL OListBoxControl::removeActionListener( const Reference< XActionListener >& l ) throw (RuntimeException, std::exception)
2001 : {
2002 0 : if ( m_xAggregateListBox.is() )
2003 0 : m_xAggregateListBox->removeActionListener( l );
2004 0 : }
2005 :
2006 :
2007 0 : void SAL_CALL OListBoxControl::addItem( const OUString& aItem, ::sal_Int16 nPos ) throw (RuntimeException, std::exception)
2008 : {
2009 0 : if ( m_xAggregateListBox.is() )
2010 0 : m_xAggregateListBox->addItem( aItem, nPos );
2011 0 : }
2012 :
2013 :
2014 0 : void SAL_CALL OListBoxControl::addItems( const Sequence< OUString >& aItems, ::sal_Int16 nPos ) throw (RuntimeException, std::exception)
2015 : {
2016 0 : if ( m_xAggregateListBox.is() )
2017 0 : m_xAggregateListBox->addItems( aItems, nPos );
2018 0 : }
2019 :
2020 :
2021 0 : void SAL_CALL OListBoxControl::removeItems( ::sal_Int16 nPos, ::sal_Int16 nCount ) throw (RuntimeException, std::exception)
2022 : {
2023 0 : if ( m_xAggregateListBox.is() )
2024 0 : m_xAggregateListBox->removeItems( nPos, nCount );
2025 0 : }
2026 :
2027 :
2028 0 : ::sal_Int16 SAL_CALL OListBoxControl::getItemCount( ) throw (RuntimeException, std::exception)
2029 : {
2030 0 : if ( m_xAggregateListBox.is() )
2031 0 : return m_xAggregateListBox->getItemCount();
2032 0 : return 0;
2033 : }
2034 :
2035 :
2036 0 : OUString SAL_CALL OListBoxControl::getItem( ::sal_Int16 nPos ) throw (RuntimeException, std::exception)
2037 : {
2038 0 : if ( m_xAggregateListBox.is() )
2039 0 : return m_xAggregateListBox->getItem( nPos );
2040 0 : return OUString( );
2041 : }
2042 :
2043 :
2044 0 : Sequence< OUString > SAL_CALL OListBoxControl::getItems( ) throw (RuntimeException, std::exception)
2045 : {
2046 0 : if ( m_xAggregateListBox.is() )
2047 0 : return m_xAggregateListBox->getItems();
2048 0 : return Sequence< OUString >( );
2049 : }
2050 :
2051 :
2052 0 : ::sal_Int16 SAL_CALL OListBoxControl::getSelectedItemPos( ) throw (RuntimeException, std::exception)
2053 : {
2054 0 : if ( m_xAggregateListBox.is() )
2055 0 : return m_xAggregateListBox->getSelectedItemPos();
2056 0 : return 0;
2057 : }
2058 :
2059 :
2060 0 : Sequence< ::sal_Int16 > SAL_CALL OListBoxControl::getSelectedItemsPos( ) throw (RuntimeException, std::exception)
2061 : {
2062 0 : if ( m_xAggregateListBox.is() )
2063 0 : return m_xAggregateListBox->getSelectedItemsPos();
2064 0 : return Sequence< ::sal_Int16 >( );
2065 : }
2066 :
2067 :
2068 0 : OUString SAL_CALL OListBoxControl::getSelectedItem( ) throw (RuntimeException, std::exception)
2069 : {
2070 0 : if ( m_xAggregateListBox.is() )
2071 0 : return m_xAggregateListBox->getSelectedItem();
2072 0 : return OUString( );
2073 : }
2074 :
2075 :
2076 0 : Sequence< OUString > SAL_CALL OListBoxControl::getSelectedItems( ) throw (RuntimeException, std::exception)
2077 : {
2078 0 : if ( m_xAggregateListBox.is() )
2079 0 : return m_xAggregateListBox->getSelectedItems();
2080 0 : return Sequence< OUString >( );
2081 : }
2082 :
2083 :
2084 0 : void SAL_CALL OListBoxControl::selectItemPos( ::sal_Int16 nPos, sal_Bool bSelect ) throw (RuntimeException, std::exception)
2085 : {
2086 0 : if ( m_xAggregateListBox.is() )
2087 0 : m_xAggregateListBox->selectItemPos( nPos, bSelect );
2088 0 : }
2089 :
2090 :
2091 0 : void SAL_CALL OListBoxControl::selectItemsPos( const Sequence< ::sal_Int16 >& aPositions, sal_Bool bSelect ) throw (RuntimeException, std::exception)
2092 : {
2093 0 : if ( m_xAggregateListBox.is() )
2094 0 : m_xAggregateListBox->selectItemsPos( aPositions, bSelect );
2095 0 : }
2096 :
2097 :
2098 0 : void SAL_CALL OListBoxControl::selectItem( const OUString& aItem, sal_Bool bSelect ) throw (RuntimeException, std::exception)
2099 : {
2100 0 : if ( m_xAggregateListBox.is() )
2101 0 : m_xAggregateListBox->selectItem( aItem, bSelect );
2102 0 : }
2103 :
2104 :
2105 0 : sal_Bool SAL_CALL OListBoxControl::isMutipleMode( ) throw (RuntimeException, std::exception)
2106 : {
2107 0 : if ( m_xAggregateListBox.is() )
2108 0 : return m_xAggregateListBox->isMutipleMode();
2109 0 : return sal_False;
2110 : }
2111 :
2112 :
2113 0 : void SAL_CALL OListBoxControl::setMultipleMode( sal_Bool bMulti ) throw (RuntimeException, std::exception)
2114 : {
2115 0 : if ( m_xAggregateListBox.is() )
2116 0 : m_xAggregateListBox->setMultipleMode( bMulti );
2117 0 : }
2118 :
2119 :
2120 0 : ::sal_Int16 SAL_CALL OListBoxControl::getDropDownLineCount( ) throw (RuntimeException, std::exception)
2121 : {
2122 0 : if ( m_xAggregateListBox.is() )
2123 0 : return m_xAggregateListBox->getDropDownLineCount();
2124 0 : return 0;
2125 : }
2126 :
2127 :
2128 0 : void SAL_CALL OListBoxControl::setDropDownLineCount( ::sal_Int16 nLines ) throw (RuntimeException, std::exception)
2129 : {
2130 0 : if ( m_xAggregateListBox.is() )
2131 0 : m_xAggregateListBox->setDropDownLineCount( nLines );
2132 0 : }
2133 :
2134 :
2135 0 : void SAL_CALL OListBoxControl::makeVisible( ::sal_Int16 nEntry ) throw (RuntimeException, std::exception)
2136 : {
2137 0 : if ( m_xAggregateListBox.is() )
2138 0 : m_xAggregateListBox->makeVisible( nEntry );
2139 0 : }
2140 :
2141 : }
2142 :
2143 : extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
2144 18 : com_sun_star_form_OListBoxModel_get_implementation(::com::sun::star::uno::XComponentContext* component,
2145 : ::com::sun::star::uno::Sequence<css::uno::Any> const &)
2146 : {
2147 18 : return cppu::acquire(new frm::OListBoxModel(component));
2148 : }
2149 :
2150 : extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
2151 34 : com_sun_star_form_OListBoxControl_get_implementation(::com::sun::star::uno::XComponentContext* component,
2152 : ::com::sun::star::uno::Sequence<css::uno::Any> const &)
2153 : {
2154 34 : return cppu::acquire(new frm::OListBoxControl(component));
2155 138 : }
2156 :
2157 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|