LibreOffice Module forms (master) 1
ComboBox.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20
21#include "ComboBox.hxx"
22#include <property.hxx>
23#include <services.hxx>
24
25#include <frm_resource.hxx>
26#include <strings.hrc>
27#include "BaseListBox.hxx"
28
29#include <com/sun/star/beans/PropertyAttribute.hpp>
30#include <com/sun/star/form/FormComponentType.hpp>
31#include <com/sun/star/sdbc/XRowSet.hpp>
32#include <com/sun/star/container/XIndexAccess.hpp>
33#include <com/sun/star/sdbc/XConnection.hpp>
34
38#include <tools/debug.hxx>
41
42#include <limits.h>
43
44using namespace dbtools;
45
46
47namespace frm
48{
49using namespace ::com::sun::star::uno;
50using namespace ::com::sun::star::sdb;
51using namespace ::com::sun::star::sdbc;
52using namespace ::com::sun::star::sdbcx;
53using namespace ::com::sun::star::beans;
54using namespace ::com::sun::star::container;
55using namespace ::com::sun::star::form;
56using namespace ::com::sun::star::awt;
57using namespace ::com::sun::star::io;
58using namespace ::com::sun::star::lang;
59using namespace ::com::sun::star::util;
60using namespace ::com::sun::star::form::binding;
61
62
64{
65 return ::comphelper::concatSequences(
69 );
70}
71
72// XServiceInfo
73
74css::uno::Sequence<OUString> SAL_CALL OComboBoxModel::getSupportedServiceNames()
75{
76 css::uno::Sequence<OUString> aSupported = OBoundControlModel::getSupportedServiceNames();
77
78 sal_Int32 nOldLen = aSupported.getLength();
79 aSupported.realloc( nOldLen + 9 );
80 OUString* pStoreTo = aSupported.getArray() + nOldLen;
81
82 *pStoreTo++ = BINDABLE_CONTROL_MODEL;
83 *pStoreTo++ = DATA_AWARE_CONTROL_MODEL;
84 *pStoreTo++ = VALIDATABLE_CONTROL_MODEL;
85
88
89 *pStoreTo++ = FRM_SUN_COMPONENT_COMBOBOX;
91 *pStoreTo++ = BINDABLE_DATABASE_COMBO_BOX;
92
93 *pStoreTo++ = FRM_COMPONENT_COMBOBOX;
94
95 return aSupported;
96}
97
98
100{
101 Any aReturn = OBoundControlModel::queryAggregation( _rType );
102 if ( !aReturn.hasValue() )
103 aReturn = OEntryListHelper::queryInterface( _rType );
104 if ( !aReturn.hasValue() )
105 aReturn = OErrorBroadcaster::queryInterface( _rType );
106 return aReturn;
107}
108
109
110OComboBoxModel::OComboBoxModel(const Reference<XComponentContext>& _rxFactory)
112 // use the old control name for compatibility reasons
113 ,OEntryListHelper( static_cast<OControlModel&>(*this) )
114 ,OErrorBroadcaster( OComponentHelper::rBHelper )
115 ,m_eListSourceType(ListSourceType_TABLE)
116 ,m_bEmptyIsNull(true)
117{
118 m_nClassId = FormComponentType::COMBOBOX;
120}
121
122
123OComboBoxModel::OComboBoxModel( const OComboBoxModel* _pOriginal, const Reference<XComponentContext>& _rxFactory )
124 :OBoundControlModel( _pOriginal, _rxFactory )
125 ,OEntryListHelper( *_pOriginal, static_cast<OControlModel&>(*this) )
126 ,OErrorBroadcaster( OComponentHelper::rBHelper )
127 ,m_aListSource( _pOriginal->m_aListSource )
128 ,m_aDefaultText( _pOriginal->m_aDefaultText )
129 ,m_eListSourceType( _pOriginal->m_eListSourceType )
130 ,m_bEmptyIsNull( _pOriginal->m_bEmptyIsNull )
131{
132}
133
134
136{
137 if (!OComponentHelper::rBHelper.bDisposed)
138 {
139 acquire();
140 dispose();
141 }
142
143}
144
145// XCloneable
146
147css::uno::Reference< css::util::XCloneable > SAL_CALL OComboBoxModel::createClone()
148{
150 pClone->clonedFrom(this);
151 return pClone;
152}
153
154
156{
160}
161
162
163void OComboBoxModel::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
164{
165 switch (_nHandle)
166 {
168 _rValue <<= m_eListSourceType;
169 break;
170
172 _rValue <<= m_aListSource;
173 break;
174
176 _rValue <<= m_bEmptyIsNull;
177 break;
178
180 _rValue <<= m_aDefaultText;
181 break;
182
185 break;
186
188 _rValue <<= getTypedItemList();
189 break;
190
191 default:
193 }
194}
195
196
197void OComboBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
198{
199 switch (_nHandle)
200 {
202 DBG_ASSERT(_rValue.getValueType().equals(::cppu::UnoType<ListSourceType>::get()),
203 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
204 _rValue >>= m_eListSourceType;
205 break;
206
208 DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_STRING,
209 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
210 _rValue >>= m_aListSource;
211 // The ListSource has changed -> reload
212 if (ListSourceType_VALUELIST != m_eListSourceType)
213 {
214 if ( m_xCursor.is() && !hasField() && !hasExternalListSource() )
215 // combo box is already connected to a database, and no external list source
216 // data source changed -> refresh
217 loadData( false );
218 }
219 break;
220
222 DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN,
223 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
224 _rValue >>= m_bEmptyIsNull;
225 break;
226
228 DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_STRING,
229 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
230 _rValue >>= m_aDefaultText;
232 break;
233
235 {
236 ControlModelLock aLock( *this );
237 setNewStringItemList( _rValue, aLock );
238 // FIXME: this is bogus. setNewStringItemList expects a guard which has the *only*
239 // lock to the mutex, but setFastPropertyValue_NoBroadcast is already called with
240 // a lock - so we effectively has two locks here, of which setNewStringItemList can
241 // only control one.
242 }
243 break;
244
246 {
247 ControlModelLock aLock( *this );
248 setNewTypedItemList( _rValue, aLock );
249 // Same FIXME as above.
250 }
251 break;
252
253 default:
255 }
256}
257
259 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
260{
261 bool bModified(false);
262 switch (_nHandle)
263 {
265 bModified = tryPropertyValueEnum(_rConvertedValue, _rOldValue, _rValue, m_eListSourceType);
266 break;
267
269 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aListSource);
270 break;
271
273 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bEmptyIsNull);
274 break;
275
277 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aDefaultText);
278 break;
279
281 bModified = convertNewListSourceProperty( _rConvertedValue, _rOldValue, _rValue );
282 break;
283
286 throw IllegalArgumentException();
287 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, getTypedItemList());
288 break;
289
290 default:
291 bModified = OBoundControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
292 break;
293 }
294 return bModified;
295}
296
297void OComboBoxModel::describeFixedProperties( Sequence< Property >& _rProps ) const
298{
300 sal_Int32 nOldCount = _rProps.getLength();
301 _rProps.realloc( nOldCount + 7);
302 css::beans::Property* pProperties = _rProps.getArray() + nOldCount;
303 *pProperties++ = css::beans::Property(PROPERTY_TABINDEX, PROPERTY_ID_TABINDEX, cppu::UnoType<sal_Int16>::get(), css::beans::PropertyAttribute::BOUND);
304 *pProperties++ = css::beans::Property(PROPERTY_LISTSOURCETYPE, PROPERTY_ID_LISTSOURCETYPE, cppu::UnoType<ListSourceType>::get(), css::beans::PropertyAttribute::BOUND);
305 *pProperties++ = css::beans::Property(PROPERTY_LISTSOURCE, PROPERTY_ID_LISTSOURCE, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND);
306 *pProperties++ = css::beans::Property(PROPERTY_EMPTY_IS_NULL, PROPERTY_ID_EMPTY_IS_NULL, cppu::UnoType<bool>::get(),
307 css::beans::PropertyAttribute::BOUND);
308 *pProperties++ = css::beans::Property(PROPERTY_DEFAULT_TEXT, PROPERTY_ID_DEFAULT_TEXT, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND);
309 *pProperties++ = css::beans::Property(PROPERTY_STRINGITEMLIST, PROPERTY_ID_STRINGITEMLIST, cppu::UnoType<Sequence< OUString >>::get(), css::beans::PropertyAttribute::BOUND);
310 *pProperties++ = css::beans::Property(PROPERTY_TYPEDITEMLIST, PROPERTY_ID_TYPEDITEMLIST, cppu::UnoType<Sequence< Any >>::get(), css::beans::PropertyAttribute::OPTIONAL);
311 DBG_ASSERT( pProperties == _rProps.getArray() + _rProps.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?");
312}
313
314
315void OComboBoxModel::describeAggregateProperties( Sequence< Property >& _rAggregateProps ) const
316{
318
319 // superseded properties:
320 RemoveProperty( _rAggregateProps, PROPERTY_STRINGITEMLIST );
321 RemoveProperty( _rAggregateProps, PROPERTY_TYPEDITEMLIST );
322}
323
324
326{
327 return FRM_COMPONENT_COMBOBOX; // old (non-sun) name for compatibility !
328}
329
330
331void SAL_CALL OComboBoxModel::write(const Reference<css::io::XObjectOutputStream>& _rxOutStream)
332{
333 OBoundControlModel::write(_rxOutStream);
334
335 // Version
336 // Version 0x0002: EmptyIsNull
337 // Version 0x0003: ListSource->Seq
338 // Version 0x0004: DefaultText
339 // Version 0x0005: HelpText
340 _rxOutStream->writeShort(0x0006);
341
342 // Mask for Any
343 sal_uInt16 nAnyMask = 0;
344 if (m_aBoundColumn.getValueType().getTypeClass() == TypeClass_SHORT)
345 nAnyMask |= BOUNDCOLUMN;
346 _rxOutStream << nAnyMask;
347
348 css::uno::Sequence<OUString> aListSourceSeq(&m_aListSource, 1);
349 _rxOutStream << aListSourceSeq;
350 _rxOutStream << static_cast<sal_Int16>(m_eListSourceType);
351
352 if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
353 {
354 sal_Int16 nBoundColumn = 0;
355 m_aBoundColumn >>= nBoundColumn;
356 _rxOutStream << nBoundColumn;
357 }
358
359 _rxOutStream << m_bEmptyIsNull;
360 _rxOutStream << m_aDefaultText;
361 writeHelpTextCompatibly(_rxOutStream);
362
363 // from version 0x0006 : common properties
364 writeCommonProperties(_rxOutStream);
365}
366
367
368void SAL_CALL OComboBoxModel::read(const Reference<css::io::XObjectInputStream>& _rxInStream)
369{
370 OBoundControlModel::read(_rxInStream);
371 ControlModelLock aLock( *this );
372
373 // since we are "overwriting" the StringItemList of our aggregate (means we have
374 // an own place to store the value, instead of relying on our aggregate storing it),
375 // we need to respect what the aggregate just read for the StringItemList property.
376 try
377 {
378 if ( m_xAggregateSet.is() )
379 setNewStringItemList( m_xAggregateSet->getPropertyValue( PROPERTY_STRINGITEMLIST ), aLock );
380 }
381 catch( const Exception& )
382 {
383 TOOLS_WARN_EXCEPTION( "forms.component", "OComboBoxModel::read: caught an exception while examining the aggregate's string item list!" );
384 }
385
386 // Version
387 sal_uInt16 nVersion = _rxInStream->readShort();
388 DBG_ASSERT(nVersion > 0, "OComboBoxModel::read : version 0 ? this should never have been written !");
389
390 if (nVersion > 0x0006)
391 {
392 OSL_FAIL("OComboBoxModel::read : invalid (means unknown) version !");
393 m_aListSource.clear();
394 m_aBoundColumn <<= sal_Int16(0);
395 m_aDefaultText.clear();
396 m_eListSourceType = ListSourceType_TABLE;
397 m_bEmptyIsNull = true;
399 return;
400 }
401
402 // Mask for Any
403 sal_uInt16 nAnyMask;
404 _rxInStream >> nAnyMask;
405
406 // ListSource
407 if (nVersion < 0x0003)
408 {
409 _rxInStream >> m_aListSource;
410 }
411 else // nVersion == 4
412 {
413 m_aListSource.clear();
414 css::uno::Sequence<OUString> aListSource;
415 _rxInStream >> aListSource;
416 for (const OUString& rToken : std::as_const(aListSource))
417 m_aListSource += rToken;
418 }
419
420 sal_Int16 nListSourceType;
421 _rxInStream >> nListSourceType;
422 m_eListSourceType = static_cast<ListSourceType>(nListSourceType);
423
424 if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
425 {
426 sal_Int16 nValue;
427 _rxInStream >> nValue;
429 }
430
431 if (nVersion > 0x0001)
432 {
433 bool bNull;
434 _rxInStream >> bNull;
435 m_bEmptyIsNull = bNull;
436 }
437
438 if (nVersion > 0x0003) // nVersion == 4
439 _rxInStream >> m_aDefaultText;
440
441 // StringList must be emptied if a ListSource is set.
442 // This can be the case if we save in alive mode.
443 if ( !m_aListSource.isEmpty()
445 )
446 {
447 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, Any( css::uno::Sequence<OUString>() ) );
448 setFastPropertyValue( PROPERTY_ID_TYPEDITEMLIST, Any( css::uno::Sequence<css::uno::Any>() ) );
449 }
450
451 if (nVersion > 0x0004)
452 readHelpTextCompatibly(_rxInStream);
453
454 if (nVersion > 0x0005)
455 readCommonProperties(_rxInStream);
456
457 // After reading in, display the default values
458 if ( !getControlSource().isEmpty() )
459 {
460 // (not if we don't have a control source - the "State" property acts like it is persistent, then
462 }
463}
464
465
466void OComboBoxModel::loadData( bool _bForce )
467{
468 DBG_ASSERT(m_eListSourceType != ListSourceType_VALUELIST, "OComboBoxModel::loadData : do not call for a value list !");
469 DBG_ASSERT( !hasExternalListSource(), "OComboBoxModel::loadData: cannot load from DB when I have an external list source!" );
470
471 if ( hasExternalListSource() )
472 return;
473
474 // Get Connection
475 if (!m_xCursor.is())
476 return;
477 Reference<XConnection> xConnection = getConnection(m_xCursor);
478 if (!xConnection.is())
479 return;
480
481 Reference<XServiceInfo> xServiceInfo(xConnection, UNO_QUERY);
482 if (!xServiceInfo.is() || !xServiceInfo->supportsService(SRV_SDB_CONNECTION))
483 {
484 OSL_FAIL("OComboBoxModel::loadData : invalid connection !");
485 return;
486 }
487
488 if (m_aListSource.isEmpty() || m_eListSourceType == ListSourceType_VALUELIST)
489 return;
490
492 try
493 {
494 m_aListRowSet.setConnection( xConnection );
495
496 bool bExecuteRowSet( false );
497 switch (m_eListSourceType)
498 {
499 case ListSourceType_TABLEFIELDS:
500 // don't work with a statement here, the fields will be collected below
501 break;
502 case ListSourceType_TABLE:
503 {
504 // does the bound field belong to the table ?
505 // if we use an alias for the bound field, we won't find it
506 // in that case we use the first field of the table
507
508 Reference<XNameAccess> xFieldsByName = getTableFields(xConnection, m_aListSource);
509
510 OUString aFieldName;
511 if ( xFieldsByName.is() && xFieldsByName->hasByName( getControlSource() ) )
512 {
513 aFieldName = getControlSource();
514 }
515 else
516 {
517 // otherwise look for the alias
518 Reference<XPropertySet> xFormProp(m_xCursor,UNO_QUERY);
519 Reference< XColumnsSupplier > xSupplyFields;
520 xFormProp->getPropertyValue("SingleSelectQueryComposer") >>= xSupplyFields;
521
522 // search the field
523 DBG_ASSERT(xSupplyFields.is(), "OComboBoxModel::loadData : invalid query composer !");
524
525 Reference< XNameAccess > xFieldNames = xSupplyFields->getColumns();
526 if ( xFieldNames->hasByName( getControlSource() ) )
527 {
528 Reference< XPropertySet > xComposerFieldAsSet;
529 xFieldNames->getByName( getControlSource() ) >>= xComposerFieldAsSet;
530 if (hasProperty(PROPERTY_FIELDSOURCE, xComposerFieldAsSet))
531 xComposerFieldAsSet->getPropertyValue(PROPERTY_FIELDSOURCE) >>= aFieldName;
532 }
533 }
534
535 if (aFieldName.isEmpty())
536 break;
537
538 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
539 OSL_ENSURE(xMeta.is(),"No database meta data!");
540 if ( xMeta.is() )
541 {
542 OUString aQuote = xMeta->getIdentifierQuoteString();
543
544 OUString sCatalog, sSchema, sTable;
545 qualifiedNameComponents( xMeta, m_aListSource, sCatalog, sSchema, sTable, EComposeRule::InDataManipulation );
546
547 OUString aStatement =
548 "SELECT DISTINCT " +
549 quoteName( aQuote, aFieldName ) +
550 " FROM " +
551 composeTableNameForSelect( xConnection, sCatalog, sSchema, sTable );
552
554 m_aListRowSet.setCommand( aStatement );
555 bExecuteRowSet = true;
556 }
557 } break;
558 case ListSourceType_QUERY:
559 {
561 bExecuteRowSet = true;
562 }
563 break;
564
565 default:
566 {
567 m_aListRowSet.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH != m_eListSourceType );
569 bExecuteRowSet = true;
570 }
571 }
572
573 if ( bExecuteRowSet )
574 {
575 if ( !_bForce && !m_aListRowSet.isDirty() )
576 {
577 // if none of the settings of the row set changed, compared to the last
578 // invocation of loadData, then don't re-fill the list. Instead, assume
579 // the list entries are the same.
580 return;
581 }
582 xListCursor.reset( m_aListRowSet.execute() );
583 }
584 }
585 catch(const SQLException& eSQL)
586 {
587 onError(eSQL, ResourceManager::loadString(RID_BASELISTBOX_ERROR_FILLLIST));
588 return;
589 }
590 catch( const Exception& )
591 {
592 DBG_UNHANDLED_EXCEPTION("forms.component");
593 return;
594 }
595
596 ::std::vector< OUString > aStringList;
597 aStringList.reserve(16);
598 try
599 {
600 OSL_ENSURE( xListCursor.is() || ( ListSourceType_TABLEFIELDS == m_eListSourceType ),
601 "OComboBoxModel::loadData: logic error!" );
602 if ( !xListCursor.is() && ( ListSourceType_TABLEFIELDS != m_eListSourceType ) )
603 return;
604
605 switch (m_eListSourceType)
606 {
607 case ListSourceType_SQL:
608 case ListSourceType_SQLPASSTHROUGH:
609 case ListSourceType_TABLE:
610 case ListSourceType_QUERY:
611 {
612 // The XDatabaseVariant of the first column
613 Reference<XColumnsSupplier> xSupplyCols(xListCursor, UNO_QUERY);
614 DBG_ASSERT(xSupplyCols.is(), "OComboBoxModel::loadData : cursor supports the row set service but is no column supplier?!");
615 Reference<XIndexAccess> xColumns;
616 if (xSupplyCols.is())
617 {
618 xColumns.set(xSupplyCols->getColumns(), UNO_QUERY);
619 DBG_ASSERT(xColumns.is(), "OComboBoxModel::loadData : no columns supplied by the row set !");
620 }
621 Reference< XPropertySet > xDataField;
622 if ( xColumns.is() )
623 xColumns->getByIndex(0) >>= xDataField;
624 if ( !xDataField.is() )
625 return;
626
627 ::dbtools::FormattedColumnValue aValueFormatter( getContext(), m_xCursor, xDataField );
628
629 // Fill Lists
630 sal_Int16 i = 0;
631 // At the moment by definition the list cursor is positioned _before_ the first row
632 while (xListCursor->next() && (i++<SHRT_MAX)) // Set max. count
633 {
634 aStringList.push_back( aValueFormatter.getFormattedValue() );
635 }
636 }
637 break;
638 case ListSourceType_TABLEFIELDS:
639 {
640 Reference<XNameAccess> xFieldNames = getTableFields(xConnection, m_aListSource);
641 if (xFieldNames.is())
642 {
643 const Sequence<OUString> aFieldNames = xFieldNames->getElementNames();
644 aStringList.insert(aStringList.end(), aFieldNames.begin(), aFieldNames.end());
645 }
646 }
647 break;
648 default:
649 OSL_FAIL( "OComboBoxModel::loadData: unreachable!" );
650 break;
651 }
652 }
653 catch(const SQLException& eSQL)
654 {
655 onError(eSQL, ResourceManager::loadString(RID_BASELISTBOX_ERROR_FILLLIST));
656 return;
657 }
658 catch( const Exception& )
659 {
660 DBG_UNHANDLED_EXCEPTION("forms.component");
661 return;
662 }
663
664 // Set String-Sequence at ListBox
666 // Reset TypedItemList, no matching data.
667 setFastPropertyValue( PROPERTY_ID_TYPEDITEMLIST, Any( css::uno::Sequence<css::uno::Any>() ) );
668}
669
670
671void OComboBoxModel::onConnectedDbColumn( const Reference< XInterface >& _rxForm )
672{
673 Reference<XPropertySet> xField = getField();
674 if ( xField.is() )
675 m_pValueFormatter.reset( new ::dbtools::FormattedColumnValue( getContext(), Reference< XRowSet >( _rxForm, UNO_QUERY ), xField ) );
677
678 // Only load data if a ListSource was supplied
679 if ( !m_aListSource.isEmpty() && m_xCursor.is() && !hasExternalListSource() )
680 loadData( false );
681}
682
683
685{
686 m_pValueFormatter.reset();
687
688 // reset the string item list
689 if ( !hasExternalListSource() )
690 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, Any( m_aDesignModeStringItems ) );
691
693}
694
695
696void SAL_CALL OComboBoxModel::reloaded( const EventObject& aEvent )
697{
699
700 // reload data if we have a list source
701 if ( !m_aListSource.isEmpty() && m_xCursor.is() && !hasExternalListSource() )
702 loadData( false );
703}
704
705
707{
709 m_aLastKnownValue.clear();
710}
711
712
714{
715 Any aNewValue( m_xAggregateFastSet->getFastPropertyValue( getValuePropertyAggHandle() ) );
716
717 OUString sNewValue;
718 aNewValue >>= sNewValue;
719
720 bool bModified = ( aNewValue != m_aLastKnownValue );
721 if ( bModified )
722 {
723 if ( !aNewValue.hasValue()
724 || ( sNewValue.isEmpty() // an empty string
725 && m_bEmptyIsNull // which should be interpreted as NULL
726 )
727 )
728 {
729 m_xColumnUpdate->updateNull();
730 }
731 else
732 {
733 try
734 {
735 OSL_PRECOND(m_pValueFormatter,
736 "OComboBoxModel::commitControlValueToDbColumn: no value formatter!");
738 {
739 if ( !m_pValueFormatter->setFormattedValue( sNewValue ) )
740 return false;
741 }
742 else
743 m_xColumnUpdate->updateString( sNewValue );
744 }
745 catch ( const Exception& )
746 {
747 return false;
748 }
749 }
750
751 m_aLastKnownValue = aNewValue;
752 }
753
754 // add the new value to the list
755 bool bAddToList = bModified && !_bPostReset;
756 // (only if this is not the "commit" triggered by a "reset")
757
758 if ( !bAddToList )
759 return true;
760
761 css::uno::Sequence<OUString> aStringItemList;
762 if ( !(getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aStringItemList) )
763 return true;
764
765 bool bFound = false;
766 for (const OUString& rStringItem : std::as_const(aStringItemList))
767 {
768 if ( (bFound = rStringItem == sNewValue) )
769 break;
770 }
771
772 // not found -> add
773 if (!bFound)
774 {
775 sal_Int32 nOldLen = aStringItemList.getLength();
776 aStringItemList.realloc( nOldLen + 1 );
777 aStringItemList.getArray()[ nOldLen ] = sNewValue;
778
779 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, Any( aStringItemList ) );
780 setFastPropertyValue( PROPERTY_ID_TYPEDITEMLIST, Any( css::uno::Sequence<css::uno::Any>() ) );
781 }
782
783 return true;
784}
785
786// XPropertiesChangeListener
787
789{
790 OSL_PRECOND(m_pValueFormatter,
791 "OComboBoxModel::translateDbColumnToControlValue: no value formatter!");
793 {
794 OUString sValue( m_pValueFormatter->getFormattedValue() );
795 if ( sValue.isEmpty()
796 && m_pValueFormatter->getColumn().is()
797 && m_pValueFormatter->getColumn()->wasNull()
798 )
799 {
800 m_aLastKnownValue.clear();
801 }
802 else
803 {
804
805 m_aLastKnownValue <<= sValue;
806 }
807 }
808 else
809 m_aLastKnownValue.clear();
810
811 return m_aLastKnownValue.hasValue() ? m_aLastKnownValue : Any( OUString() );
812 // (m_aLastKnownValue is allowed to be VOID, the control value isn't)
813}
814
815
817{
818 return Any( m_aDefaultText );
819}
820
821
823{
824 if ( m_xAggregateSet.is() )
825 {
826 m_xAggregateSet->setPropertyValue( PROPERTY_STRINGITEMLIST, Any( comphelper::containerToSequence(getStringItemList()) ) );
827 m_xAggregateSet->setPropertyValue( PROPERTY_TYPEDITEMLIST, Any( getTypedItemList()) ) ;
828 }
829}
830
831
833{
834 DBG_ASSERT( !hasExternalListSource(), "OComboBoxModel::refreshInternalEntryList: invalid call!" );
835
836 if ( !hasExternalListSource( )
837 && ( m_eListSourceType != ListSourceType_VALUELIST )
838 && ( m_xCursor.is() )
839 )
840 {
841 loadData( true );
842 }
843}
844
845
846void SAL_CALL OComboBoxModel::disposing( const EventObject& _rSource )
847{
848 if ( !OEntryListHelper::handleDisposing( _rSource ) )
850}
851
852
853//= OComboBoxControl
854
855OComboBoxControl::OComboBoxControl(const Reference<XComponentContext>& _rxContext)
857{
858}
859
860
861css::uno::Sequence<OUString> SAL_CALL OComboBoxControl::getSupportedServiceNames()
862{
863 css::uno::Sequence<OUString> aSupported = OBoundControl::getSupportedServiceNames();
864 aSupported.realloc(aSupported.getLength() + 2);
865
866 OUString* pArray = aSupported.getArray();
867 pArray[aSupported.getLength()-2] = FRM_SUN_CONTROL_COMBOBOX;
868 pArray[aSupported.getLength()-1] = STARDIV_ONE_FORM_CONTROL_COMBOBOX;
869 return aSupported;
870}
871
872}
873
874extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
875com_sun_star_form_OComboBoxModel_get_implementation(css::uno::XComponentContext* component,
876 css::uno::Sequence<css::uno::Any> const &)
877{
878 return cppu::acquire(new frm::OComboBoxModel(component));
879}
880
881extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
882com_sun_star_form_OComboBoxControl_get_implementation(css::uno::XComponentContext* component,
883 css::uno::Sequence<css::uno::Any> const &)
884{
885 return cppu::acquire(new frm::OComboBoxControl(component));
886}
887
888/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_form_OComboBoxControl_get_implementation(css::uno::XComponentContext *component, css::uno::Sequence< css::uno::Any > const &)
Definition: ComboBox.cxx:882
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_form_OComboBoxModel_get_implementation(css::uno::XComponentContext *component, css::uno::Sequence< css::uno::Any > const &)
Definition: ComboBox.cxx:875
OptionalString sSchema
OptionalString sCatalog
AnyEventRef aEvent
const char *const aFieldNames[]
virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const &rType) SAL_OVERRIDE
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() SAL_OVERRIDE
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() SAL_OVERRIDE
virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const &rType) SAL_OVERRIDE
virtual void SAL_CALL acquire() SAL_NOEXCEPT SAL_OVERRIDE
virtual void SAL_CALL dispose() SAL_OVERRIDE
OUString getFormattedValue() const
void setCommand(const OUString &_rCommand)
void setCommandFromQuery(const OUString &_rQueryName)
sets the command of a query as command to be executed
css::uno::Reference< css::sdbc::XResultSet > execute()
executes the statement
void dispose()
disposes the instance and frees all associated resources
bool isDirty() const
determines whether the row set properties are dirty, i.e. have changed since the last call to execute
void setConnection(const css::uno::Reference< css::sdbc::XConnection > &_rxConnection)
void setEscapeProcessing(const bool _bEscapeProcessing)
class whose instances lock an OControlModel
void writeCommonProperties(const css::uno::Reference< css::io::XObjectOutputStream > &_rxOutStream)
We can't write (new) common properties in this base class, as the file format doesn't allow this (unf...
sal_Int32 getValuePropertyAggHandle() const
virtual css::uno::Any SAL_CALL queryAggregation(const css::uno::Type &_rType) override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const css::uno::Any &rValue) override
virtual void SAL_CALL disposing() override
void initValueProperty(const OUString &_rValuePropertyName, sal_Int32 _nValuePropertyExternalHandle)
initializes the part of the class which is related to the control value.
virtual void describeFixedProperties(css::uno::Sequence< css::beans::Property > &_rProps) const override
describes the properties provided by this class, or its respective derived class
virtual void resetNoBroadcast()
called to reset the control to some kind of default.
const OUString & getControlSource() const
virtual css::uno::Sequence< css::uno::Type > _getTypes() override
virtual void SAL_CALL write(const css::uno::Reference< css::io::XObjectOutputStream > &OutStream) override
virtual void SAL_CALL getFastPropertyValue(css::uno::Any &rValue, sal_Int32 nHandle) const override
virtual sal_Bool SAL_CALL convertFastPropertyValue(css::uno::Any &_rConvertedValue, css::uno::Any &_rOldValue, sal_Int32 _nHandle, const css::uno::Any &_rValue) override
virtual void SAL_CALL read(const css::uno::Reference< css::io::XObjectInputStream > &InStream) override
void readCommonProperties(const css::uno::Reference< css::io::XObjectInputStream > &_rxInStream)
css::uno::Reference< css::sdbc::XRowSet > m_xCursor
const css::uno::Reference< css::beans::XPropertySet > & getField() const
css::uno::Reference< css::sdb::XColumnUpdate > m_xColumnUpdate
virtual void SAL_CALL reloaded(const css::lang::EventObject &aEvent) override
OComboBoxControl(const css::uno::Reference< css::uno::XComponentContext > &_rxContext)
Definition: ComboBox.cxx:855
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
Definition: ComboBox.cxx:861
css::uno::Any m_aBoundColumn
Definition: ComboBox.hxx:42
virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override
Definition: ComboBox.cxx:147
virtual sal_Bool SAL_CALL convertFastPropertyValue(css::uno::Any &_rConvertedValue, css::uno::Any &_rOldValue, sal_Int32 _nHandle, const css::uno::Any &_rValue) override
Definition: ComboBox.cxx:258
virtual css::uno::Any SAL_CALL queryAggregation(const css::uno::Type &_rType) override
Definition: ComboBox.cxx:99
virtual css::uno::Any getDefaultForReset() const override
returns the default which should be used when resetting the control
Definition: ComboBox.cxx:816
OUString m_aDefaultText
Definition: ComboBox.hxx:44
virtual void SAL_CALL write(const css::uno::Reference< css::io::XObjectOutputStream > &_rxOutStream) override
Definition: ComboBox.cxx:331
virtual void describeAggregateProperties(css::uno::Sequence< css::beans::Property > &_rAggregateProps) const override
describes the properties of our aggregate
Definition: ComboBox.cxx:315
virtual void onDisconnectedDbColumn() override
called whenever a connection to a database column has been suspended
Definition: ComboBox.cxx:684
virtual void resetNoBroadcast() override
called to reset the control to some kind of default.
Definition: ComboBox.cxx:706
css::form::ListSourceType m_eListSourceType
Definition: ComboBox.hxx:49
virtual void SAL_CALL read(const css::uno::Reference< css::io::XObjectInputStream > &_rxInStream) override
Definition: ComboBox.cxx:368
virtual void onConnectedDbColumn(const css::uno::Reference< css::uno::XInterface > &_rxForm) override
called whenever a connection to a database column has been established
Definition: ComboBox.cxx:671
virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const css::uno::Any &rValue) override
Definition: ComboBox.cxx:197
virtual void stringItemListChanged(ControlModelLock &_rInstanceLock) override
announces that the list of entries has changed.
Definition: ComboBox.cxx:822
virtual void refreshInternalEntryList() override
called when XRefreshable::refresh has been called, and we do not have an external list source
Definition: ComboBox.cxx:832
void loadData(bool _bForce)
Definition: ComboBox.cxx:466
virtual void SAL_CALL getFastPropertyValue(css::uno::Any &rValue, sal_Int32 nHandle) const override
Definition: ComboBox.cxx:163
virtual void SAL_CALL disposing() override
Definition: ComboBox.cxx:155
virtual css::uno::Sequence< css::uno::Type > _getTypes() override
Definition: ComboBox.cxx:63
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
Definition: ComboBox.cxx:74
OComboBoxModel(const css::uno::Reference< css::uno::XComponentContext > &_rxFactory)
OUString m_aListSource
Definition: ComboBox.hxx:43
virtual void describeFixedProperties(css::uno::Sequence< css::beans::Property > &_rProps) const override
describes the properties provided by this class, or its respective derived class
Definition: ComboBox.cxx:297
virtual void SAL_CALL reloaded(const css::lang::EventObject &aEvent) override
Definition: ComboBox.cxx:696
virtual ~OComboBoxModel() override
Definition: ComboBox.cxx:135
CachedRowSet m_aListRowSet
Definition: ComboBox.hxx:41
virtual bool commitControlValueToDbColumn(bool _bPostReset) override
commits the current control value to the database column we're bound to @precond we're properly bound...
Definition: ComboBox.cxx:713
virtual OUString SAL_CALL getServiceName() override
Definition: ComboBox.cxx:325
::std::unique_ptr< ::dbtools::FormattedColumnValue > m_pValueFormatter
Definition: ComboBox.hxx:52
virtual css::uno::Any translateDbColumnToControlValue() override
translates a db column value into a control value.
Definition: ComboBox.cxx:788
css::uno::Any m_aLastKnownValue
Definition: ComboBox.hxx:45
css::uno::Sequence< OUString > m_aDesignModeStringItems
Definition: ComboBox.hxx:47
const css::uno::Reference< css::uno::XComponentContext > & getContext() const
virtual void describeAggregateProperties(css::uno::Sequence< css::beans::Property > &_rAggregateProps) const
describes the properties of our aggregate
void writeHelpTextCompatibly(const css::uno::Reference< css::io::XObjectOutputStream > &_rxOutStream)
void readHelpTextCompatibly(const css::uno::Reference< css::io::XObjectInputStream > &_rxInStream)
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
bool convertNewListSourceProperty(css::uno::Any &_rConvertedValue, css::uno::Any &_rOldValue, const css::uno::Any &_rValue)
helper for implementing convertFastPropertyValue( StringItemList )
void setNewStringItemList(const css::uno::Any &_rValue, ControlModelLock &_rInstanceLock)
helper for implementing setFastPropertyValueNoBroadcast
void disposing()
to be called by derived classes' instances when they're being disposed
void setNewTypedItemList(const css::uno::Any &_rValue, ControlModelLock &_rInstanceLock)
helper for implementing setFastPropertyValueNoBroadcast
const css::uno::Sequence< css::uno::Any > & getTypedItemList() const
returns the current typed item list
bool handleDisposing(const css::lang::EventObject &_rEvent)
handling the XEventListener::disposing call for the case where our list source is being disposed
bool hasExternalListSource() const
determines whether we actually have an external list source
const std::vector< OUString > & getStringItemList() const
returns the current string item list
void onError(const css::sdbc::SQLException &_rException, const OUString &_rContextDescription)
void reset(const css::uno::Reference< INTERFACE > &_rxComponent, AssignmentMode _eMode=TakeOwnership)
#define DBG_ASSERT(sCon, aError)
#define TOOLS_WARN_EXCEPTION(area, stream)
#define DBG_UNHANDLED_EXCEPTION(...)
sal_Int16 nVersion
sal_Int16 nValue
constexpr OUStringLiteral PROPERTY_TABINDEX
Definition: frm_strings.hxx:26
constexpr OUStringLiteral PROPERTY_DEFAULT_TEXT
Definition: frm_strings.hxx:64
constexpr OUStringLiteral PROPERTY_TEXT
Definition: frm_strings.hxx:33
constexpr OUStringLiteral PROPERTY_EMPTY_IS_NULL
Definition: frm_strings.hxx:75
constexpr OUStringLiteral PROPERTY_LISTSOURCETYPE
Definition: frm_strings.hxx:76
constexpr OUStringLiteral PROPERTY_TYPEDITEMLIST
Definition: frm_strings.hxx:63
constexpr OUStringLiteral PROPERTY_STRINGITEMLIST
Definition: frm_strings.hxx:62
constexpr OUStringLiteral PROPERTY_LISTSOURCE
Definition: frm_strings.hxx:77
constexpr OUStringLiteral PROPERTY_FIELDSOURCE
@ Exception
bool hasProperty(const OUString &_rName, const Reference< XPropertySet > &_rxSet)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
bool tryPropertyValue(Any &_rConvertedValue, Any &_rOldValue, const Any &_rValueToSet, const Any &_rCurrentValue, const Type &_rExpectedType)
std::enable_if< std::is_enum< ENUMTYPE >::value, bool >::type tryPropertyValueEnum(css::uno::Any &_rConvertedValue, css::uno::Any &_rOldValue, const css::uno::Any &_rValueToSet, const ENUMTYPE &_rCurrentValue)
void RemoveProperty(Sequence< Property > &_rProps, const OUString &_rPropName)
Type
Reference< XConnection > getConnection(const Reference< XRowSet > &_rxRowSet)
void qualifiedNameComponents(const Reference< XDatabaseMetaData > &_rxConnMetaData, const OUString &_rQualifiedName, OUString &_rCatalog, OUString &_rSchema, OUString &_rName, EComposeRule _eComposeRule)
OUString composeTableNameForSelect(const Reference< XConnection > &_rxConnection, const OUString &_rCatalog, const OUString &_rSchema, const OUString &_rName)
OUString quoteName(std::u16string_view _rQuote, const OUString &_rName)
Reference< XNameAccess > getTableFields(const Reference< XConnection > &_rxConn, const OUString &_rName)
OUString loadString(TranslateId aResId)
loads the string with the specified resource id from the FormLayer mo file
ListBox is a bit confusing / different from other form components, so here are a few notes:
Definition: BaseListBox.hxx:25
const sal_uInt16 BOUNDCOLUMN
Definition: BaseListBox.hxx:27
int i
bool getPropertyValue(ValueType &rValue, css::uno::Reference< css::beans::XPropertySet > const &xPropSet, OUString const &propName)
#define PROPERTY_ID_TYPEDITEMLIST
Definition: property.hxx:304
#define PROPERTY_ID_STRINGITEMLIST
Definition: property.hxx:84
#define PROPERTY_ID_LISTSOURCETYPE
Definition: property.hxx:80
#define PROPERTY_ID_EMPTY_IS_NULL
Definition: property.hxx:161
#define PROPERTY_ID_DEFAULT_TEXT
Definition: property.hxx:106
#define PROPERTY_ID_LISTSOURCE
Definition: property.hxx:81
#define PROPERTY_ID_TEXT
Definition: property.hxx:83
#define PROPERTY_ID_TABINDEX
Definition: property.hxx:41
constexpr OUStringLiteral FRM_SUN_CONTROL_COMBOBOX
Definition: services.hxx:152
constexpr OUStringLiteral BINDABLE_DATABASE_COMBO_BOX
Definition: services.hxx:170
constexpr OUStringLiteral STARDIV_ONE_FORM_CONTROL_COMBOBOX
Definition: services.hxx:94
constexpr OUStringLiteral FRM_SUN_COMPONENT_COMBOBOX
Definition: services.hxx:115
constexpr OUStringLiteral FRM_COMPONENT_COMBOBOX
Definition: services.hxx:68
constexpr OUStringLiteral VALIDATABLE_BINDABLE_CONTROL_MODEL
Definition: services.hxx:184
constexpr OUStringLiteral FRM_SUN_COMPONENT_DATABASE_COMBOBOX
Definition: services.hxx:141
constexpr OUStringLiteral VCL_CONTROL_COMBOBOX
Definition: services.hxx:25
constexpr OUStringLiteral BINDABLE_DATA_AWARE_CONTROL_MODEL
Definition: services.hxx:181
constexpr OUStringLiteral VCL_CONTROLMODEL_COMBOBOX
Definition: services.hxx:41
constexpr OUStringLiteral DATA_AWARE_CONTROL_MODEL
Definition: services.hxx:182
constexpr OUStringLiteral SRV_SDB_CONNECTION
Definition: services.hxx:193
constexpr OUStringLiteral VALIDATABLE_CONTROL_MODEL
Definition: services.hxx:183
constexpr OUStringLiteral BINDABLE_CONTROL_MODEL
Definition: services.hxx:179
unsigned char sal_Bool
const std::u16string_view aStringList[]