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