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