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