1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sc.hxx" 26 27 //------------------------------------------------------------------ 28 29 #include "solveroptions.hxx" 30 #include "solveroptions.hrc" 31 #include "scresid.hxx" 32 #include "global.hxx" 33 #include "miscuno.hxx" 34 #include "solverutil.hxx" 35 36 #include <rtl/math.hxx> 37 #include <vcl/msgbox.hxx> 38 #include <unotools/collatorwrapper.hxx> 39 #include <unotools/localedatawrapper.hxx> 40 41 #include <algorithm> 42 43 #include <com/sun/star/sheet/Solver.hpp> 44 #include <com/sun/star/sheet/XSolverDescription.hpp> 45 #include <com/sun/star/beans/PropertyValue.hpp> 46 #include <com/sun/star/beans/XPropertySet.hpp> 47 48 using namespace com::sun::star; 49 50 //================================================================== 51 52 /// Helper for sorting properties 53 struct ScSolverOptionsEntry 54 { 55 sal_Int32 nPosition; 56 rtl::OUString aDescription; 57 58 ScSolverOptionsEntry() : nPosition(0) {} 59 60 bool operator< (const ScSolverOptionsEntry& rOther) const 61 { 62 return ( ScGlobal::GetCollator()->compareString( aDescription, rOther.aDescription ) == COMPARE_LESS ); 63 } 64 }; 65 66 //------------------------------------------------------------------ 67 68 class ScSolverOptionsString : public SvLBoxString 69 { 70 bool mbIsDouble; 71 double mfDoubleValue; 72 sal_Int32 mnIntValue; 73 74 public: 75 ScSolverOptionsString( SvLBoxEntry* pEntry, sal_uInt16 nFlags, const String& rStr ) : 76 SvLBoxString( pEntry, nFlags, rStr ), 77 mbIsDouble( false ), 78 mfDoubleValue( 0.0 ), 79 mnIntValue( 0 ) {} 80 81 bool IsDouble() const { return mbIsDouble; } 82 double GetDoubleValue() const { return mfDoubleValue; } 83 sal_Int32 GetIntValue() const { return mnIntValue; } 84 85 void SetDoubleValue( double fNew ) { mbIsDouble = true; mfDoubleValue = fNew; } 86 void SetIntValue( sal_Int32 nNew ) { mbIsDouble = false; mnIntValue = nNew; } 87 //IAccessibility2 Implementation 2009----- 88 // MT: Commented out SV_ITEM_ID_EXTENDRLBOXSTRING and GetExtendText() in svlbitem.hxx - needed? 89 // virtual USHORT IsA() {return SV_ITEM_ID_EXTENDRLBOXSTRING;} 90 // virtual XubString GetExtendText() const; 91 //-----IAccessibility2 Implementation 2009 92 virtual void Paint( const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags, SvLBoxEntry* pEntry ); 93 }; 94 95 //IAccessibility2 Implementation 2009----- 96 // MT: Commented out SV_ITEM_ID_EXTENDRLBOXSTRING and GetExtendText() in svlbitem.hxx - needed? 97 /* 98 XubString ScSolverOptionsString::GetExtendText() const 99 { 100 String aNormalStr( GetText() ); 101 aNormalStr.Append( (sal_Unicode) ':' ); 102 String sTxt( ' ' ); 103 if ( mbIsDouble ) 104 sTxt += (String)rtl::math::doubleToUString( mfDoubleValue, 105 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 106 ScGlobal::GetpLocaleData()->getNumDecimalSep().GetChar(0), true ); 107 else 108 sTxt += String::CreateFromInt32( mnIntValue ); 109 aNormalStr.Append(sTxt); 110 return aNormalStr; 111 } 112 */ 113 //-----IAccessibility2 Implementation 2009 114 115 void ScSolverOptionsString::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16, SvLBoxEntry* /* pEntry */ ) 116 { 117 //! move position? (SvxLinguTabPage: aPos.X() += 20) 118 String aNormalStr( GetText() ); 119 aNormalStr.Append( (sal_Unicode) ':' ); 120 rDev.DrawText( rPos, aNormalStr ); 121 122 Point aNewPos( rPos ); 123 aNewPos.X() += rDev.GetTextWidth( aNormalStr ); 124 Font aOldFont( rDev.GetFont() ); 125 Font aFont( aOldFont ); 126 aFont.SetWeight( WEIGHT_BOLD ); 127 128 String sTxt( ' ' ); 129 if ( mbIsDouble ) 130 sTxt += (String)rtl::math::doubleToUString( mfDoubleValue, 131 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 132 ScGlobal::GetpLocaleData()->getNumDecimalSep().GetChar(0), true ); 133 else 134 sTxt += String::CreateFromInt32( mnIntValue ); 135 rDev.SetFont( aFont ); 136 rDev.DrawText( aNewPos, sTxt ); 137 138 rDev.SetFont( aOldFont ); 139 } 140 141 //------------------------------------------------------------------ 142 143 ScSolverOptionsDialog::ScSolverOptionsDialog( Window* pParent, 144 const uno::Sequence<rtl::OUString>& rImplNames, 145 const uno::Sequence<rtl::OUString>& rDescriptions, 146 const String& rEngine, 147 const uno::Sequence<beans::PropertyValue>& rProperties ) 148 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVEROPTIONS ) ), 149 maFtEngine ( this, ScResId( FT_ENGINE ) ), 150 maLbEngine ( this, ScResId( LB_ENGINE ) ), 151 maFtSettings ( this, ScResId( FT_SETTINGS ) ), 152 maLbSettings ( this, ScResId( LB_SETTINGS ) ), 153 maBtnEdit ( this, ScResId( BTN_EDIT ) ), 154 maFlButtons ( this, ScResId( FL_BUTTONS ) ), 155 maBtnHelp ( this, ScResId( BTN_HELP ) ), 156 maBtnOk ( this, ScResId( BTN_OK ) ), 157 maBtnCancel ( this, ScResId( BTN_CANCEL ) ), 158 mpCheckButtonData( NULL ), 159 maImplNames( rImplNames ), 160 maDescriptions( rDescriptions ), 161 maEngine( rEngine ), 162 maProperties( rProperties ) 163 { 164 maLbEngine.SetSelectHdl( LINK( this, ScSolverOptionsDialog, EngineSelectHdl ) ); 165 166 maBtnEdit.SetClickHdl( LINK( this, ScSolverOptionsDialog, ButtonHdl ) ); 167 168 maLbSettings.SetStyle( maLbSettings.GetStyle()|WB_CLIPCHILDREN|WB_FORCE_MAKEVISIBLE ); 169 maLbSettings.SetHelpId( HID_SC_SOLVEROPTIONS_LB ); 170 maLbSettings.SetHighlightRange(); 171 172 maLbSettings.SetSelectHdl( LINK( this, ScSolverOptionsDialog, SettingsSelHdl ) ); 173 maLbSettings.SetDoubleClickHdl( LINK( this, ScSolverOptionsDialog, SettingsDoubleClickHdl ) ); 174 175 sal_Int32 nSelect = -1; 176 sal_Int32 nImplCount = maImplNames.getLength(); 177 for (sal_Int32 nImpl=0; nImpl<nImplCount; ++nImpl) 178 { 179 String aImplName( maImplNames[nImpl] ); 180 String aDescription( maDescriptions[nImpl] ); // user-visible descriptions in list box 181 maLbEngine.InsertEntry( aDescription ); 182 if ( aImplName == maEngine ) 183 nSelect = nImpl; 184 } 185 if ( nSelect < 0 ) // no (valid) engine given 186 { 187 if ( nImplCount > 0 ) 188 { 189 maEngine = maImplNames[0]; // use first implementation 190 nSelect = 0; 191 } 192 else 193 maEngine.Erase(); 194 maProperties.realloc(0); // don't use options from different engine 195 } 196 if ( nSelect >= 0 ) // select in list box 197 maLbEngine.SelectEntryPos( static_cast<sal_uInt16>(nSelect) ); 198 199 if ( !maProperties.getLength() ) 200 ReadFromComponent(); // fill maProperties from component (using maEngine) 201 FillListBox(); // using maProperties 202 203 FreeResource(); 204 } 205 206 ScSolverOptionsDialog::~ScSolverOptionsDialog() 207 { 208 delete mpCheckButtonData; 209 } 210 211 const String& ScSolverOptionsDialog::GetEngine() const 212 { 213 return maEngine; // already updated in selection handler 214 } 215 216 const uno::Sequence<beans::PropertyValue>& ScSolverOptionsDialog::GetProperties() 217 { 218 // update maProperties from list box content 219 // order of entries in list box and maProperties is the same 220 sal_Int32 nEntryCount = maProperties.getLength(); 221 SvLBoxTreeList* pModel = maLbSettings.GetModel(); 222 if ( nEntryCount == (sal_Int32)pModel->GetEntryCount() ) 223 { 224 for (sal_Int32 nEntryPos=0; nEntryPos<nEntryCount; ++nEntryPos) 225 { 226 uno::Any& rValue = maProperties[nEntryPos].Value; 227 SvLBoxEntry* pEntry = pModel->GetEntry(nEntryPos); 228 229 bool bHasData = false; 230 sal_uInt16 nItemCount = pEntry->ItemCount(); 231 for (sal_uInt16 nItemPos=0; nItemPos<nItemCount && !bHasData; ++nItemPos) 232 { 233 SvLBoxItem* pItem = pEntry->GetItem( nItemPos ); 234 ScSolverOptionsString* pStringItem = dynamic_cast<ScSolverOptionsString*>(pItem); 235 if ( pStringItem ) 236 { 237 if ( pStringItem->IsDouble() ) 238 rValue <<= pStringItem->GetDoubleValue(); 239 else 240 rValue <<= pStringItem->GetIntValue(); 241 bHasData = true; 242 } 243 } 244 if ( !bHasData ) 245 ScUnoHelpFunctions::SetBoolInAny( rValue, 246 maLbSettings.GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED ); 247 } 248 } 249 else 250 { 251 DBG_ERRORFILE( "wrong count" ); 252 } 253 254 return maProperties; 255 } 256 257 void ScSolverOptionsDialog::FillListBox() 258 { 259 // get property descriptions, sort by them 260 261 uno::Reference<sheet::XSolverDescription> xDesc( ScSolverUtil::GetSolver( maEngine ), uno::UNO_QUERY ); 262 sal_Int32 nCount = maProperties.getLength(); 263 std::vector<ScSolverOptionsEntry> aDescriptions( nCount ); 264 for (sal_Int32 nPos=0; nPos<nCount; nPos++) 265 { 266 rtl::OUString aPropName( maProperties[nPos].Name ); 267 rtl::OUString aVisName; 268 if ( xDesc.is() ) 269 aVisName = xDesc->getPropertyDescription( aPropName ); 270 if ( !aVisName.getLength() ) 271 aVisName = aPropName; 272 aDescriptions[nPos].nPosition = nPos; 273 aDescriptions[nPos].aDescription = aVisName; 274 } 275 std::sort( aDescriptions.begin(), aDescriptions.end() ); 276 277 // also update maProperties to the order of descriptions 278 279 uno::Sequence<beans::PropertyValue> aNewSeq; 280 aNewSeq.realloc( nCount ); 281 for (sal_Int32 nPos=0; nPos<nCount; nPos++) 282 aNewSeq[nPos] = maProperties[ aDescriptions[nPos].nPosition ]; 283 maProperties = aNewSeq; 284 285 // fill the list box 286 287 maLbSettings.SetUpdateMode(sal_False); 288 maLbSettings.Clear(); 289 290 String sEmpty; 291 if (!mpCheckButtonData) 292 mpCheckButtonData = new SvLBoxButtonData( &maLbSettings ); 293 294 SvLBoxTreeList* pModel = maLbSettings.GetModel(); 295 SvLBoxEntry* pEntry = NULL; 296 297 for (sal_Int32 nPos=0; nPos<nCount; nPos++) 298 { 299 rtl::OUString aVisName = aDescriptions[nPos].aDescription; 300 301 uno::Any aValue = maProperties[nPos].Value; 302 uno::TypeClass eClass = aValue.getValueTypeClass(); 303 if ( eClass == uno::TypeClass_BOOLEAN ) 304 { 305 // check box entry 306 pEntry = new SvLBoxEntry; 307 SvLBoxButton* pButton = new SvLBoxButton( pEntry, SvLBoxButtonKind_enabledCheckbox, 0, mpCheckButtonData ); 308 if ( ScUnoHelpFunctions::GetBoolFromAny( aValue ) ) 309 pButton->SetStateChecked(); 310 else 311 pButton->SetStateUnchecked(); 312 pEntry->AddItem( pButton ); 313 pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), 0 ) ); 314 pEntry->AddItem( new SvLBoxString( pEntry, 0, aVisName ) ); 315 } 316 else 317 { 318 // value entry 319 pEntry = new SvLBoxEntry; 320 pEntry->AddItem( new SvLBoxString( pEntry, 0, sEmpty ) ); // empty column 321 pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), 0 ) ); 322 ScSolverOptionsString* pItem = new ScSolverOptionsString( pEntry, 0, aVisName ); 323 if ( eClass == uno::TypeClass_DOUBLE ) 324 { 325 double fDoubleValue = 0.0; 326 if ( aValue >>= fDoubleValue ) 327 pItem->SetDoubleValue( fDoubleValue ); 328 } 329 else 330 { 331 sal_Int32 nIntValue = 0; 332 if ( aValue >>= nIntValue ) 333 pItem->SetIntValue( nIntValue ); 334 } 335 pEntry->AddItem( pItem ); 336 } 337 pModel->Insert( pEntry ); 338 } 339 340 maLbSettings.SetUpdateMode(sal_True); 341 } 342 343 void ScSolverOptionsDialog::ReadFromComponent() 344 { 345 maProperties = ScSolverUtil::GetDefaults( maEngine ); 346 } 347 348 void ScSolverOptionsDialog::EditOption() 349 { 350 SvLBoxEntry* pEntry = maLbSettings.GetCurEntry(); 351 if (pEntry) 352 { 353 sal_uInt16 nItemCount = pEntry->ItemCount(); 354 for (sal_uInt16 nPos=0; nPos<nItemCount; ++nPos) 355 { 356 SvLBoxItem* pItem = pEntry->GetItem( nPos ); 357 ScSolverOptionsString* pStringItem = dynamic_cast<ScSolverOptionsString*>(pItem); 358 if ( pStringItem ) 359 { 360 if ( pStringItem->IsDouble() ) 361 { 362 ScSolverValueDialog aValDialog( this ); 363 aValDialog.SetOptionName( pStringItem->GetText() ); 364 aValDialog.SetValue( pStringItem->GetDoubleValue() ); 365 if ( aValDialog.Execute() == RET_OK ) 366 { 367 pStringItem->SetDoubleValue( aValDialog.GetValue() ); 368 maLbSettings.InvalidateEntry( pEntry ); 369 } 370 } 371 else 372 { 373 ScSolverIntegerDialog aIntDialog( this ); 374 aIntDialog.SetOptionName( pStringItem->GetText() ); 375 aIntDialog.SetValue( pStringItem->GetIntValue() ); 376 if ( aIntDialog.Execute() == RET_OK ) 377 { 378 pStringItem->SetIntValue( aIntDialog.GetValue() ); 379 maLbSettings.InvalidateEntry( pEntry ); 380 } 381 } 382 } 383 } 384 } 385 } 386 387 IMPL_LINK( ScSolverOptionsDialog, ButtonHdl, PushButton*, pBtn ) 388 { 389 if ( pBtn == &maBtnEdit ) 390 EditOption(); 391 392 return 0; 393 } 394 395 IMPL_LINK( ScSolverOptionsDialog, SettingsDoubleClickHdl, SvTreeListBox*, EMPTYARG ) 396 { 397 EditOption(); 398 return 0; 399 } 400 401 IMPL_LINK( ScSolverOptionsDialog, EngineSelectHdl, ListBox*, EMPTYARG ) 402 { 403 sal_uInt16 nSelectPos = maLbEngine.GetSelectEntryPos(); 404 if ( nSelectPos < maImplNames.getLength() ) 405 { 406 String aNewEngine( maImplNames[nSelectPos] ); 407 if ( aNewEngine != maEngine ) 408 { 409 maEngine = aNewEngine; 410 ReadFromComponent(); // fill maProperties from component (using maEngine) 411 FillListBox(); // using maProperties 412 } 413 } 414 return 0; 415 } 416 417 IMPL_LINK( ScSolverOptionsDialog, SettingsSelHdl, SvxCheckListBox*, EMPTYARG ) 418 { 419 sal_Bool bCheckbox = sal_False; 420 421 SvLBoxEntry* pEntry = maLbSettings.GetCurEntry(); 422 if (pEntry) 423 { 424 SvLBoxItem* pItem = pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON); 425 if ( pItem && pItem->IsA() == SV_ITEM_ID_LBOXBUTTON ) 426 bCheckbox = sal_True; 427 } 428 429 maBtnEdit.Enable( !bCheckbox ); 430 431 return 0; 432 } 433 434 //------------------------------------------------------------------ 435 436 ScSolverIntegerDialog::ScSolverIntegerDialog( Window * pParent ) 437 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_INTEGER ) ), 438 maFtName ( this, ScResId( FT_OPTIONNAME ) ), 439 maNfValue ( this, ScResId( NF_VALUE ) ), 440 maFlButtons ( this, ScResId( FL_BUTTONS ) ), 441 maBtnOk ( this, ScResId( BTN_OK ) ), 442 maBtnCancel ( this, ScResId( BTN_CANCEL ) ) 443 { 444 FreeResource(); 445 } 446 447 ScSolverIntegerDialog::~ScSolverIntegerDialog() 448 { 449 } 450 451 void ScSolverIntegerDialog::SetOptionName( const String& rName ) 452 { 453 maFtName.SetText( rName ); 454 } 455 456 void ScSolverIntegerDialog::SetValue( sal_Int32 nValue ) 457 { 458 maNfValue.SetValue( nValue ); 459 } 460 461 sal_Int32 ScSolverIntegerDialog::GetValue() const 462 { 463 sal_Int64 nValue = maNfValue.GetValue(); 464 if ( nValue < SAL_MIN_INT32 ) 465 return SAL_MIN_INT32; 466 if ( nValue > SAL_MAX_INT32 ) 467 return SAL_MAX_INT32; 468 return (sal_Int32) nValue; 469 } 470 471 //------------------------------------------------------------------ 472 473 ScSolverValueDialog::ScSolverValueDialog( Window * pParent ) 474 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_DOUBLE ) ), 475 maFtName ( this, ScResId( FT_OPTIONNAME ) ), 476 maEdValue ( this, ScResId( ED_VALUE ) ), 477 maFlButtons ( this, ScResId( FL_BUTTONS ) ), 478 maBtnOk ( this, ScResId( BTN_OK ) ), 479 maBtnCancel ( this, ScResId( BTN_CANCEL ) ) 480 { 481 FreeResource(); 482 } 483 484 ScSolverValueDialog::~ScSolverValueDialog() 485 { 486 } 487 488 void ScSolverValueDialog::SetOptionName( const String& rName ) 489 { 490 maFtName.SetText( rName ); 491 } 492 493 void ScSolverValueDialog::SetValue( double fValue ) 494 { 495 maEdValue.SetText( rtl::math::doubleToUString( fValue, 496 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 497 ScGlobal::GetpLocaleData()->getNumDecimalSep().GetChar(0), true ) ); 498 } 499 500 double ScSolverValueDialog::GetValue() const 501 { 502 String aInput = maEdValue.GetText(); 503 504 const LocaleDataWrapper* pLocaleData = ScGlobal::GetpLocaleData(); 505 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; 506 double fValue = rtl::math::stringToDouble( aInput, 507 pLocaleData->getNumDecimalSep().GetChar(0), 508 pLocaleData->getNumThousandSep().GetChar(0), 509 &eStatus, NULL ); 510 return fValue; 511 } 512 513