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 <formcontrolfactory.hxx>
22 #include <fmcontrollayout.hxx>
23 #include <fmprop.hxx>
24 #include <svx/strings.hrc>
25 #include <fmservs.hxx>
26 #include <svx/dialmgr.hxx>
27 #include <svx/svdouno.hxx>
28 
29 #include <com/sun/star/form/XFormComponent.hpp>
30 #include <com/sun/star/form/FormComponentType.hpp>
31 #include <com/sun/star/awt/ScrollBarOrientation.hpp>
32 #include <com/sun/star/awt/MouseWheelBehavior.hpp>
33 #include <com/sun/star/form/XGridColumnFactory.hpp>
34 #include <com/sun/star/style/VerticalAlignment.hpp>
35 #include <com/sun/star/awt/LineEndFormat.hpp>
36 #include <com/sun/star/awt/ImageScaleMode.hpp>
37 #include <com/sun/star/sdbc/DataType.hpp>
38 #include <com/sun/star/util/XNumberFormatTypes.hpp>
39 #include <com/sun/star/sdbc/ColumnValue.hpp>
40 #include <com/sun/star/text/WritingMode2.hpp>
41 
42 #include <comphelper/numbers.hxx>
43 #include <comphelper/processfactory.hxx>
44 #include <unotools/syslocale.hxx>
45 #include <tools/gen.hxx>
46 #include <tools/diagnose_ex.h>
47 #include <connectivity/dbtools.hxx>
48 #include <i18nlangtag/languagetag.hxx>
49 
50 #include <set>
51 
52 using namespace ::dbtools;
53 
54 namespace svxform
55 {
56 
57 
58     using ::com::sun::star::uno::Reference;
59     using ::com::sun::star::uno::UNO_QUERY;
60     using ::com::sun::star::uno::UNO_QUERY_THROW;
61     using ::com::sun::star::uno::UNO_SET_THROW;
62     using ::com::sun::star::uno::Exception;
63     using ::com::sun::star::uno::Any;
64     using ::com::sun::star::uno::makeAny;
65     using ::com::sun::star::uno::Sequence;
66     using ::com::sun::star::uno::Type;
67     using ::com::sun::star::uno::XComponentContext;
68     using ::com::sun::star::beans::XPropertySet;
69     using ::com::sun::star::form::XFormComponent;
70     using ::com::sun::star::container::XIndexAccess;
71     using ::com::sun::star::beans::XPropertySetInfo;
72     using ::com::sun::star::beans::PropertyValue;
73     using ::com::sun::star::container::XChild;
74     using ::com::sun::star::form::XGridColumnFactory;
75     using ::com::sun::star::style::VerticalAlignment_MIDDLE;
76     using ::com::sun::star::beans::Property;
77     using ::com::sun::star::uno::TypeClass_DOUBLE;
78     using ::com::sun::star::uno::TypeClass_LONG;
79     using ::com::sun::star::util::XNumberFormats;
80     using ::com::sun::star::util::XNumberFormatTypes;
81     using ::com::sun::star::lang::XServiceInfo;
82     using ::com::sun::star::container::XNameAccess;
83 
84     namespace FormComponentType = ::com::sun::star::form::FormComponentType;
85     namespace ScrollBarOrientation = ::com::sun::star::awt::ScrollBarOrientation;
86     namespace MouseWheelBehavior = ::com::sun::star::awt::MouseWheelBehavior;
87     namespace LineEndFormat = ::com::sun::star::awt::LineEndFormat;
88     namespace ImageScaleMode = ::com::sun::star::awt::ImageScaleMode;
89     namespace DataType = ::com::sun::star::sdbc::DataType;
90     namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue;
91     namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
92 
93     struct FormControlFactory_Data
94     {
95         Reference<XComponentContext>  m_xContext;
96 
FormControlFactory_Datasvxform::FormControlFactory_Data97         explicit FormControlFactory_Data( const Reference<XComponentContext>& _rContext )
98             :m_xContext( _rContext )
99         {
100         }
101     };
102 
FormControlFactory(const Reference<XComponentContext> & _rContext)103     FormControlFactory::FormControlFactory( const Reference<XComponentContext>& _rContext )
104         :m_pData( new FormControlFactory_Data( _rContext ) )
105     {
106     }
107 
FormControlFactory()108     FormControlFactory::FormControlFactory( )
109         :m_pData( new FormControlFactory_Data( comphelper::getProcessComponentContext() ) )
110     {
111     }
112 
113 
~FormControlFactory()114     FormControlFactory::~FormControlFactory()
115     {
116     }
117 
118 
initializeControlModel(const DocumentType _eDocType,const SdrUnoObj & _rObject)119     sal_Int16 FormControlFactory::initializeControlModel( const DocumentType _eDocType, const SdrUnoObj& _rObject )
120     {
121         return initializeControlModel(
122             _eDocType,
123             Reference< XPropertySet >( _rObject.GetUnoControlModel(), UNO_QUERY ),
124             _rObject.GetCurrentBoundRect()
125         );
126     }
127 
128 
initializeControlModel(const DocumentType _eDocType,const Reference<XPropertySet> & _rxControlModel)129     void FormControlFactory::initializeControlModel( const DocumentType _eDocType, const Reference< XPropertySet >& _rxControlModel )
130     {
131         initializeControlModel(
132             _eDocType, _rxControlModel, tools::Rectangle()
133         );
134     }
135 
136 
137     namespace
138     {
139 
lcl_getUniqueLabel_nothrow(const Reference<XPropertySet> & _rxControlModel,const OUString & _rBaseLabel)140         OUString lcl_getUniqueLabel_nothrow( const Reference< XPropertySet >& _rxControlModel, const OUString& _rBaseLabel )
141         {
142             OUString sLabel( _rBaseLabel );
143             try
144             {
145                 typedef ::std::set< OUString > StringBag;
146                 StringBag aUsedLabels;
147 
148                 Reference< XFormComponent > xFormComponent( _rxControlModel, UNO_QUERY_THROW );
149                 Reference< XIndexAccess > xContainer( xFormComponent->getParent(), UNO_QUERY_THROW );
150                 // loop through all siblings of the control model, and collect their labels
151                 for ( sal_Int32 index=xContainer->getCount(); index>0; )
152                 {
153                     Reference< XPropertySet > xElement( xContainer->getByIndex( --index ), UNO_QUERY_THROW );
154                     if ( xElement == _rxControlModel )
155                         continue;
156 
157                     Reference< XPropertySetInfo > xPSI( xElement->getPropertySetInfo(), UNO_SET_THROW );
158                     if ( !xPSI->hasPropertyByName( FM_PROP_LABEL ) )
159                         continue;
160 
161                     OUString sElementLabel;
162                     OSL_VERIFY( xElement->getPropertyValue( FM_PROP_LABEL ) >>= sElementLabel );
163                     aUsedLabels.insert( sElementLabel );
164                 }
165 
166                 // now find a free label
167                 sal_Int32 i=2;
168                 while ( aUsedLabels.find( sLabel ) != aUsedLabels.end() )
169                 {
170                     OUStringBuffer aBuffer( _rBaseLabel );
171                     aBuffer.append( " " );
172                     aBuffer.append( i++ );
173                     sLabel = aBuffer.makeStringAndClear();
174                 }
175             }
176             catch( const Exception& )
177             {
178                 DBG_UNHANDLED_EXCEPTION("svx");
179             }
180             return sLabel;
181         }
182 
183 
lcl_getDataSourceIndirectProperties(const Reference<XPropertySet> & _rxControlModel,const Reference<XComponentContext> & _rContext)184         Sequence< PropertyValue > lcl_getDataSourceIndirectProperties( const Reference< XPropertySet >& _rxControlModel,
185             const Reference<XComponentContext>& _rContext )
186         {
187             OSL_PRECOND( _rxControlModel.is(), "lcl_getDataSourceIndirectProperties: invalid model!" );
188 
189             Sequence< PropertyValue > aInfo;
190             try
191             {
192                 Reference< XChild > xChild( _rxControlModel, UNO_QUERY );
193                 Reference< XPropertySet > xForm;
194                 if ( xChild.is() )
195                     xForm.set(xChild->getParent(), css::uno::UNO_QUERY);
196 
197                 if ( Reference< XGridColumnFactory >( xForm, UNO_QUERY ).is() )
198                 {   // hmm. the model is a grid column, in real
199                     xChild.set(xForm, css::uno::UNO_QUERY);
200                     xForm.set(xChild->getParent(), css::uno::UNO_QUERY);
201                 }
202 
203                 OSL_ENSURE( xForm.is(), "lcl_getDataSourceIndirectProperties: could not determine the form!" );
204                 if ( !xForm.is() )
205                     return aInfo;
206                 OUString sDataSourceName;
207                 xForm->getPropertyValue( FM_PROP_DATASOURCE ) >>= sDataSourceName;
208 
209                 Reference< XPropertySet > xDsProperties;
210                 if ( !sDataSourceName.isEmpty() )
211                     xDsProperties.set(getDataSource( sDataSourceName, _rContext ), css::uno::UNO_QUERY);
212                 if ( xDsProperties.is() )
213                     xDsProperties->getPropertyValue("Info") >>= aInfo;
214             }
215             catch( const Exception& )
216             {
217                 OSL_FAIL( "lcl_getDataSourceIndirectProperties: caught an exception!" );
218             }
219             return aInfo;
220         }
221 
222 
223         static const sal_Char* aCharacterAndParagraphProperties[] =
224         {
225             "CharFontName",
226             "CharFontStyleName",
227             "CharFontFamily",
228             "CharFontCharSet",
229             "CharFontPitch",
230             "CharColor",
231             "CharEscapement",
232             "CharHeight",
233             "CharUnderline",
234             "CharWeight",
235             "CharPosture",
236             "CharAutoKerning",
237             "CharBackColor",
238             "CharBackTransparent",
239             "CharCaseMap",
240             "CharCrossedOut",
241             "CharFlash",
242             "CharStrikeout",
243             "CharWordMode",
244             "CharKerning",
245             "CharLocale",
246             "CharKeepTogether",
247             "CharNoLineBreak",
248             "CharShadowed",
249             "CharFontType",
250             "CharStyleName",
251             "CharContoured",
252             "CharCombineIsOn",
253             "CharCombinePrefix",
254             "CharCombineSuffix",
255             "CharEmphasize",
256             "CharRelief",
257             "RubyText",
258             "RubyAdjust",
259             "RubyCharStyleName",
260             "RubyIsAbove",
261             "CharRotation",
262             "CharRotationIsFitToLine",
263             "CharScaleWidth",
264             "HyperLinkURL",
265             "HyperLinkTarget",
266             "HyperLinkName",
267             "VisitedCharStyleName",
268             "UnvisitedCharStyleName",
269             "CharEscapementHeight",
270             "CharNoHyphenation",
271             "CharUnderlineColor",
272             "CharUnderlineHasColor",
273             "CharStyleNames",
274             "CharHeightAsian",
275             "CharWeightAsian",
276             "CharFontNameAsian",
277             "CharFontStyleNameAsian",
278             "CharFontFamilyAsian",
279             "CharFontCharSetAsian",
280             "CharFontPitchAsian",
281             "CharPostureAsian",
282             "CharLocaleAsian",
283             "ParaIsCharacterDistance",
284             "ParaIsForbiddenRules",
285             "ParaIsHangingPunctuation",
286             "CharHeightComplex",
287             "CharWeightComplex",
288             "CharFontNameComplex",
289             "CharFontStyleNameComplex",
290             "CharFontFamilyComplex",
291             "CharFontCharSetComplex",
292             "CharFontPitchComplex",
293             "CharPostureComplex",
294             "CharLocaleComplex",
295             "ParaAdjust",
296             "ParaLineSpacing",
297             "ParaBackColor",
298             "ParaBackTransparent",
299             "ParaBackGraphic",
300             "ParaBackGraphicURL",
301             "ParaBackGraphicFilter",
302             "ParaBackGraphicLocation",
303             "ParaLastLineAdjust",
304             "ParaExpandSingleWord",
305             "ParaLeftMargin",
306             "ParaRightMargin",
307             "ParaTopMargin",
308             "ParaBottomMargin",
309             "ParaLineNumberCount",
310             "ParaLineNumberStartValue",
311             "PageDescName",
312             "PageNumberOffset",
313             "ParaRegisterModeActive",
314             "ParaTabStops",
315             "ParaStyleName",
316             "DropCapFormat",
317             "DropCapWholeWord",
318             "ParaKeepTogether",
319             "Setting",
320             "ParaSplit",
321             "Setting",
322             "NumberingLevel",
323             "NumberingRules",
324             "NumberingStartValue",
325             "ParaIsNumberingRestart",
326             "NumberingStyleName",
327             "ParaOrphans",
328             "ParaWidows",
329             "ParaShadowFormat",
330             "LeftBorder",
331             "RightBorder",
332             "TopBorder",
333             "BottomBorder",
334             "BorderDistance",
335             "LeftBorderDistance",
336             "RightBorderDistance",
337             "TopBorderDistance",
338             "BottomBorderDistance",
339             "BreakType",
340             "DropCapCharStyleName",
341             "ParaFirstLineIndent",
342             "ParaIsAutoFirstLineIndent",
343             "ParaIsHyphenation",
344             "ParaHyphenationMaxHyphens",
345             "ParaHyphenationMaxLeadingChars",
346             "ParaHyphenationMaxTrailingChars",
347             "ParaVertAlignment",
348             "ParaUserDefinedAttributes",
349             "NumberingIsNumber",
350             "ParaIsConnectBorder",
351             nullptr
352         };
353 
354 
lcl_initializeCharacterAttributes(const Reference<XPropertySet> & _rxModel)355         void lcl_initializeCharacterAttributes( const Reference< XPropertySet >& _rxModel )
356         {
357             try
358             {
359                 Reference< XPropertySet > xStyle( ControlLayouter::getDefaultDocumentTextStyle( _rxModel ), UNO_SET_THROW );
360 
361                 // transfer all properties which are described by the style
362                 Reference< XPropertySetInfo > xSourcePropInfo( xStyle->getPropertySetInfo(), UNO_SET_THROW );
363                 Reference< XPropertySetInfo > xDestPropInfo( _rxModel->getPropertySetInfo(), UNO_SET_THROW );
364 
365                 OUString sPropertyName;
366                 const sal_Char** pCharacterProperty = aCharacterAndParagraphProperties;
367                 while ( *pCharacterProperty )
368                 {
369                     sPropertyName = OUString::createFromAscii( *pCharacterProperty );
370 
371                     if ( xSourcePropInfo->hasPropertyByName( sPropertyName ) && xDestPropInfo->hasPropertyByName( sPropertyName ) )
372                         _rxModel->setPropertyValue( sPropertyName, xStyle->getPropertyValue( sPropertyName ) );
373 
374                     ++pCharacterProperty;
375                 }
376             }
377             catch( const Exception& )
378             {
379                 DBG_UNHANDLED_EXCEPTION("svx");
380             }
381         }
382     }
383 
384 
initializeControlModel(const DocumentType _eDocType,const Reference<XPropertySet> & _rxControlModel,const tools::Rectangle & _rControlBoundRect)385     sal_Int16 FormControlFactory::initializeControlModel( const DocumentType _eDocType, const Reference< XPropertySet >& _rxControlModel,
386         const tools::Rectangle& _rControlBoundRect )
387     {
388         sal_Int16 nClassId = FormComponentType::CONTROL;
389 
390         OSL_ENSURE( _rxControlModel.is(), "FormControlFactory::initializeControlModel: invalid model!" );
391         if ( !_rxControlModel.is() )
392             return nClassId;
393 
394         try
395         {
396             ControlLayouter::initializeControlLayout( _rxControlModel, _eDocType );
397 
398             _rxControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId;
399             Reference< XPropertySetInfo > xPSI( _rxControlModel->getPropertySetInfo(), UNO_SET_THROW );
400             switch ( nClassId )
401             {
402                 case FormComponentType::SCROLLBAR:
403                     _rxControlModel->setPropertyValue("LiveScroll", makeAny( true ) );
404                     [[fallthrough]];
405                 case FormComponentType::SPINBUTTON:
406                 {
407                     sal_Int32 eOrientation = ScrollBarOrientation::HORIZONTAL;
408                     if ( !_rControlBoundRect.IsEmpty() && ( _rControlBoundRect.GetWidth() < _rControlBoundRect.GetHeight() ) )
409                         eOrientation = ScrollBarOrientation::VERTICAL;
410                     _rxControlModel->setPropertyValue( FM_PROP_ORIENTATION, makeAny( eOrientation ) );
411                 }
412                 break;
413 
414                 case FormComponentType::LISTBOX:
415                 case FormComponentType::COMBOBOX:
416                 {
417                     bool bDropDown = !_rControlBoundRect.IsEmpty() && ( _rControlBoundRect.GetWidth() >= 3 * _rControlBoundRect.GetHeight() );
418                     if ( xPSI->hasPropertyByName( FM_PROP_DROPDOWN ) )
419                         _rxControlModel->setPropertyValue( FM_PROP_DROPDOWN, makeAny( bDropDown ) );
420                     _rxControlModel->setPropertyValue( FM_PROP_LINECOUNT, makeAny( sal_Int16( 20 ) ) );
421                 }
422                 break;
423 
424                 case FormComponentType::TEXTFIELD:
425                 {
426                     initializeTextFieldLineEnds( _rxControlModel );
427                     lcl_initializeCharacterAttributes( _rxControlModel );
428 
429                     if  (   !_rControlBoundRect.IsEmpty()
430                         &&  ( _rControlBoundRect.GetWidth() <= 4 * _rControlBoundRect.GetHeight() )
431                         )
432                     {
433                         if ( xPSI->hasPropertyByName( FM_PROP_MULTILINE ) )
434                             _rxControlModel->setPropertyValue( FM_PROP_MULTILINE, makeAny( true ) );
435                     }
436                 }
437                 break;
438 
439                 case FormComponentType::RADIOBUTTON:
440                 case FormComponentType::CHECKBOX:
441                 case FormComponentType::FIXEDTEXT:
442                 {
443                     OUString sVertAlignPropertyName( "VerticalAlign" );
444                     if ( xPSI->hasPropertyByName( sVertAlignPropertyName ) )
445                         _rxControlModel->setPropertyValue( sVertAlignPropertyName, makeAny( VerticalAlignment_MIDDLE ) );
446                 }
447                 break;
448 
449                 case FormComponentType::IMAGEBUTTON:
450                 case FormComponentType::IMAGECONTROL:
451                 {
452                     const OUString sScaleModeProperty( "ScaleMode" );
453                     if ( xPSI->hasPropertyByName( sScaleModeProperty ) )
454                         _rxControlModel->setPropertyValue( sScaleModeProperty, makeAny( ImageScaleMode::ISOTROPIC ) );
455                 }
456                 break;
457             }
458 
459             // initial default label for the control
460             if ( xPSI->hasPropertyByName( FM_PROP_LABEL ) )
461             {
462                 OUString sExistingLabel;
463                 OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_LABEL ) >>= sExistingLabel );
464                 if ( sExistingLabel.isEmpty() )
465                 {
466                     OUString sInitialLabel;
467                     OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_NAME ) >>= sInitialLabel );
468 
469                     const char* pTitleResId = nullptr;
470                     switch ( nClassId )
471                     {
472                         case FormComponentType::COMMANDBUTTON:  pTitleResId = RID_STR_PROPTITLE_PUSHBUTTON;      break;
473                         case FormComponentType::RADIOBUTTON:    pTitleResId = RID_STR_PROPTITLE_RADIOBUTTON;     break;
474                         case FormComponentType::CHECKBOX:       pTitleResId = RID_STR_PROPTITLE_CHECKBOX;        break;
475                         case FormComponentType::GROUPBOX:       pTitleResId = RID_STR_PROPTITLE_GROUPBOX;        break;
476                         case FormComponentType::FIXEDTEXT:      pTitleResId = RID_STR_PROPTITLE_FIXEDTEXT;       break;
477                     }
478 
479                     if (pTitleResId)
480                         sInitialLabel = SvxResId(pTitleResId);
481 
482                     _rxControlModel->setPropertyValue(
483                         FM_PROP_LABEL,
484                         makeAny( lcl_getUniqueLabel_nothrow( _rxControlModel, sInitialLabel ) )
485                     );
486                 }
487             }
488 
489             // strict format = yes is the default (i93467)
490             if ( xPSI->hasPropertyByName( FM_PROP_STRICTFORMAT ) )
491             {
492                 _rxControlModel->setPropertyValue( FM_PROP_STRICTFORMAT, makeAny( true ) );
493             }
494 
495             // mouse wheel: don't use it for scrolling by default (i110036)
496             if ( xPSI->hasPropertyByName( FM_PROP_MOUSE_WHEEL_BEHAVIOR ) )
497             {
498                 _rxControlModel->setPropertyValue( FM_PROP_MOUSE_WHEEL_BEHAVIOR, makeAny( MouseWheelBehavior::SCROLL_DISABLED ) );
499             }
500 
501             if ( xPSI->hasPropertyByName( FM_PROP_WRITING_MODE ) )
502                 _rxControlModel->setPropertyValue( FM_PROP_WRITING_MODE, makeAny( WritingMode2::CONTEXT ) );
503         }
504         catch( const Exception& )
505         {
506             DBG_UNHANDLED_EXCEPTION("svx");
507         }
508         return nClassId;
509     }
510 
511 
initializeTextFieldLineEnds(const Reference<XPropertySet> & _rxModel)512     void FormControlFactory::initializeTextFieldLineEnds( const Reference< XPropertySet >& _rxModel )
513     {
514         OSL_PRECOND( _rxModel.is(), "initializeTextFieldLineEnds: invalid model!" );
515         if ( !_rxModel.is() )
516             return;
517 
518         try
519         {
520             Reference< XPropertySetInfo > xInfo = _rxModel->getPropertySetInfo();
521             if ( !xInfo.is() || !xInfo->hasPropertyByName( FM_PROP_LINEENDFORMAT ) )
522                 return;
523 
524             // let's see if the data source which the form belongs to (if any)
525             // has a setting for the preferred line end format
526             bool bDosLineEnds = false;
527             Sequence< PropertyValue > aInfo = lcl_getDataSourceIndirectProperties( _rxModel, m_pData->m_xContext );
528             const PropertyValue* pInfo = std::find_if(aInfo.begin(), aInfo.end(),
529                 [](const PropertyValue& rInfo) { return rInfo.Name == "PreferDosLikeLineEnds"; });
530             if (pInfo != aInfo.end())
531                 pInfo->Value >>= bDosLineEnds;
532 
533             sal_Int16 nLineEndFormat = bDosLineEnds ? LineEndFormat::CARRIAGE_RETURN_LINE_FEED : LineEndFormat::LINE_FEED;
534             _rxModel->setPropertyValue( FM_PROP_LINEENDFORMAT, makeAny( nLineEndFormat ) );
535         }
536         catch( const Exception& )
537         {
538             DBG_UNHANDLED_EXCEPTION("svx");
539         }
540     }
541 
542 
initializeFieldDependentProperties(const Reference<XPropertySet> & _rxDatabaseField,const Reference<XPropertySet> & _rxControlModel,const Reference<XNumberFormats> & _rxNumberFormats)543     void FormControlFactory::initializeFieldDependentProperties( const Reference< XPropertySet >& _rxDatabaseField,
544         const Reference< XPropertySet >& _rxControlModel, const Reference< XNumberFormats >& _rxNumberFormats )
545     {
546         OSL_PRECOND( _rxDatabaseField.is() && _rxControlModel.is(),
547             "FormControlFactory::initializeFieldDependentProperties: illegal params!" );
548         if ( !_rxDatabaseField.is() || !_rxControlModel.is() )
549             return;
550 
551         try
552         {
553 
554             // if the field has a numeric format, and the model has a "Scale" property, sync it
555             Reference< XPropertySetInfo > xFieldPSI( _rxDatabaseField->getPropertySetInfo(), UNO_SET_THROW );
556             Reference< XPropertySetInfo > xModelPSI( _rxControlModel->getPropertySetInfo(), UNO_SET_THROW );
557 
558             if ( xModelPSI->hasPropertyByName( FM_PROP_DECIMAL_ACCURACY ) )
559             {
560                 sal_Int32 nFormatKey = 0;
561                 if ( xFieldPSI->hasPropertyByName( FM_PROP_FORMATKEY ) )
562                 {
563                     _rxDatabaseField->getPropertyValue( FM_PROP_FORMATKEY ) >>= nFormatKey;
564                 }
565                 else
566                 {
567                     nFormatKey = getDefaultNumberFormat(
568                         _rxDatabaseField,
569                         Reference< XNumberFormatTypes >( _rxNumberFormats, UNO_QUERY ),
570                         SvtSysLocale().GetLanguageTag().getLocale()
571                     );
572                 }
573 
574                 Any aScaleVal( ::comphelper::getNumberFormatDecimals( _rxNumberFormats, nFormatKey ) );
575                 _rxControlModel->setPropertyValue( FM_PROP_DECIMAL_ACCURACY, aScaleVal );
576             }
577 
578 
579             // minimum and maximum of the control according to the type of the database field
580             sal_Int32 nDataType = DataType::OTHER;
581             OSL_VERIFY( _rxDatabaseField->getPropertyValue( FM_PROP_FIELDTYPE ) >>= nDataType );
582 
583             if  (   xModelPSI->hasPropertyByName( FM_PROP_VALUEMIN )
584                 &&  xModelPSI->hasPropertyByName( FM_PROP_VALUEMAX )
585                 )
586             {
587                 sal_Int32 nMinValue = -1000000000, nMaxValue = 1000000000;
588                 switch ( nDataType )
589                 {
590                     case DataType::TINYINT  : nMinValue = 0; nMaxValue = 255; break;
591                     case DataType::SMALLINT : nMinValue = -32768; nMaxValue = 32767; break;
592                     case DataType::INTEGER  : nMinValue = 0x80000000; nMaxValue = 0x7FFFFFFF; break;
593                         // double and singles are ignored
594                 }
595 
596                 Any aValue;
597 
598                 // both the minimum and the maximum value properties can be either Long or Double
599                 Property aProperty = xModelPSI->getPropertyByName( FM_PROP_VALUEMIN );
600                 if ( aProperty.Type.getTypeClass() == TypeClass_DOUBLE )
601                     aValue <<= static_cast<double>(nMinValue);
602                 else if ( aProperty.Type.getTypeClass() == TypeClass_LONG )
603                     aValue <<= nMinValue;
604                 else
605                 {
606                     OSL_FAIL( "FormControlFactory::initializeFieldDependentProperties: unexpected property type (MinValue)!" );
607                 }
608                 _rxControlModel->setPropertyValue( FM_PROP_VALUEMIN, aValue );
609 
610                 // both the minimum and the maximum value properties can be either Long or Double
611                 aProperty = xModelPSI->getPropertyByName( FM_PROP_VALUEMAX );
612                 if ( aProperty.Type.getTypeClass() == TypeClass_DOUBLE )
613                     aValue <<= static_cast<double>(nMaxValue);
614                 else if ( aProperty.Type.getTypeClass() == TypeClass_LONG )
615                     aValue <<= nMaxValue;
616                 else
617                 {
618                     OSL_FAIL( "FormControlFactory::initializeFieldDependentProperties: unexpected property type (MaxValue)!" );
619                 }
620                 _rxControlModel->setPropertyValue( FM_PROP_VALUEMAX, aValue );
621             }
622 
623 
624             // a check box can be tristate if and only if the column it is bound to is nullable
625             sal_Int16 nClassId = FormComponentType::CONTROL;
626             OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
627             if ( nClassId == FormComponentType::CHECKBOX )
628             {
629                 sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN;
630                 OSL_VERIFY( _rxDatabaseField->getPropertyValue( FM_PROP_ISNULLABLE ) >>= nNullable );
631                 _rxControlModel->setPropertyValue( FM_PROP_TRISTATE, makeAny( ColumnValue::NO_NULLS != nNullable ) );
632             }
633         }
634         catch( const Exception& )
635         {
636             DBG_UNHANDLED_EXCEPTION("svx");
637         }
638     }
639 
640 
getDefaultName(sal_Int16 _nClassId,const Reference<XServiceInfo> & _rxObject)641     OUString FormControlFactory::getDefaultName( sal_Int16 _nClassId, const Reference< XServiceInfo >& _rxObject )
642     {
643         const char* pResId(nullptr);
644 
645         switch ( _nClassId )
646         {
647             case FormComponentType::COMMANDBUTTON:  pResId = RID_STR_PROPTITLE_PUSHBUTTON;  break;
648             case FormComponentType::RADIOBUTTON:    pResId = RID_STR_PROPTITLE_RADIOBUTTON; break;
649             case FormComponentType::CHECKBOX:       pResId = RID_STR_PROPTITLE_CHECKBOX;    break;
650             case FormComponentType::LISTBOX:        pResId = RID_STR_PROPTITLE_LISTBOX;     break;
651             case FormComponentType::COMBOBOX:       pResId = RID_STR_PROPTITLE_COMBOBOX;    break;
652             case FormComponentType::GROUPBOX:       pResId = RID_STR_PROPTITLE_GROUPBOX;    break;
653             case FormComponentType::IMAGEBUTTON:    pResId = RID_STR_PROPTITLE_IMAGEBUTTON; break;
654             case FormComponentType::FIXEDTEXT:      pResId = RID_STR_PROPTITLE_FIXEDTEXT;   break;
655             case FormComponentType::GRIDCONTROL:    pResId = RID_STR_PROPTITLE_DBGRID;      break;
656             case FormComponentType::FILECONTROL:    pResId = RID_STR_PROPTITLE_FILECONTROL; break;
657             case FormComponentType::DATEFIELD:      pResId = RID_STR_PROPTITLE_DATEFIELD;   break;
658             case FormComponentType::TIMEFIELD:      pResId = RID_STR_PROPTITLE_TIMEFIELD;   break;
659             case FormComponentType::NUMERICFIELD:   pResId = RID_STR_PROPTITLE_NUMERICFIELD;    break;
660             case FormComponentType::CURRENCYFIELD:  pResId = RID_STR_PROPTITLE_CURRENCYFIELD;   break;
661             case FormComponentType::PATTERNFIELD:   pResId = RID_STR_PROPTITLE_PATTERNFIELD;    break;
662             case FormComponentType::IMAGECONTROL:   pResId = RID_STR_PROPTITLE_IMAGECONTROL;    break;
663             case FormComponentType::HIDDENCONTROL:  pResId = RID_STR_PROPTITLE_HIDDEN;      break;
664             case FormComponentType::SCROLLBAR:      pResId = RID_STR_PROPTITLE_SCROLLBAR;   break;
665             case FormComponentType::SPINBUTTON:     pResId = RID_STR_PROPTITLE_SPINBUTTON;  break;
666             case FormComponentType::NAVIGATIONBAR:  pResId = RID_STR_PROPTITLE_NAVBAR;      break;
667 
668             case FormComponentType::TEXTFIELD:
669                 pResId = RID_STR_PROPTITLE_EDIT;
670                 if ( _rxObject.is() && _rxObject->supportsService( FM_SUN_COMPONENT_FORMATTEDFIELD ) )
671                     pResId = RID_STR_PROPTITLE_FORMATTED;
672                 break;
673 
674             default:
675                 pResId = RID_STR_CONTROL;     break;
676         }
677 
678         return SvxResId(pResId);
679     }
680 
681 
getDefaultUniqueName_ByComponentType(const Reference<XNameAccess> & _rxContainer,const Reference<XPropertySet> & _rxObject)682     OUString FormControlFactory::getDefaultUniqueName_ByComponentType( const Reference< XNameAccess >& _rxContainer,
683         const Reference< XPropertySet >& _rxObject )
684     {
685         sal_Int16 nClassId = FormComponentType::CONTROL;
686         OSL_VERIFY( _rxObject->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
687         OUString sBaseName = getDefaultName( nClassId, Reference< XServiceInfo >( _rxObject, UNO_QUERY ) );
688 
689         return getUniqueName( _rxContainer, sBaseName );
690     }
691 
692 
getUniqueName(const Reference<XNameAccess> & _rxContainer,const OUString & _rBaseName)693     OUString FormControlFactory::getUniqueName( const Reference< XNameAccess >& _rxContainer, const OUString& _rBaseName )
694     {
695         sal_Int32 n = 0;
696         OUString sName;
697         do
698         {
699             OUStringBuffer aBuf( _rBaseName );
700             aBuf.append( " " );
701             aBuf.append( ++n );
702             sName = aBuf.makeStringAndClear();
703         }
704         while ( _rxContainer->hasByName( sName ) );
705 
706         return sName;
707     }
708 
709 
710 }
711 
712 
713 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
714