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