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 88 virtual void Paint( const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags, SvLBoxEntry* pEntry ); 89 }; 90 91 void ScSolverOptionsString::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16, SvLBoxEntry* /* pEntry */ ) 92 { 93 //! move position? (SvxLinguTabPage: aPos.X() += 20) 94 String aNormalStr( GetText() ); 95 aNormalStr.Append( (sal_Unicode) ':' ); 96 rDev.DrawText( rPos, aNormalStr ); 97 98 Point aNewPos( rPos ); 99 aNewPos.X() += rDev.GetTextWidth( aNormalStr ); 100 Font aOldFont( rDev.GetFont() ); 101 Font aFont( aOldFont ); 102 aFont.SetWeight( WEIGHT_BOLD ); 103 104 String sTxt( ' ' ); 105 if ( mbIsDouble ) 106 sTxt += (String)rtl::math::doubleToUString( mfDoubleValue, 107 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 108 ScGlobal::GetpLocaleData()->getNumDecimalSep().GetChar(0), true ); 109 else 110 sTxt += String::CreateFromInt32( mnIntValue ); 111 rDev.SetFont( aFont ); 112 rDev.DrawText( aNewPos, sTxt ); 113 114 rDev.SetFont( aOldFont ); 115 } 116 117 //------------------------------------------------------------------ 118 119 ScSolverOptionsDialog::ScSolverOptionsDialog( Window* pParent, 120 const uno::Sequence<rtl::OUString>& rImplNames, 121 const uno::Sequence<rtl::OUString>& rDescriptions, 122 const String& rEngine, 123 const uno::Sequence<beans::PropertyValue>& rProperties ) 124 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVEROPTIONS ) ), 125 maFtEngine ( this, ScResId( FT_ENGINE ) ), 126 maLbEngine ( this, ScResId( LB_ENGINE ) ), 127 maFtSettings ( this, ScResId( FT_SETTINGS ) ), 128 maLbSettings ( this, ScResId( LB_SETTINGS ) ), 129 maBtnEdit ( this, ScResId( BTN_EDIT ) ), 130 maFlButtons ( this, ScResId( FL_BUTTONS ) ), 131 maBtnHelp ( this, ScResId( BTN_HELP ) ), 132 maBtnOk ( this, ScResId( BTN_OK ) ), 133 maBtnCancel ( this, ScResId( BTN_CANCEL ) ), 134 mpCheckButtonData( NULL ), 135 maImplNames( rImplNames ), 136 maDescriptions( rDescriptions ), 137 maEngine( rEngine ), 138 maProperties( rProperties ) 139 { 140 maLbEngine.SetSelectHdl( LINK( this, ScSolverOptionsDialog, EngineSelectHdl ) ); 141 142 maBtnEdit.SetClickHdl( LINK( this, ScSolverOptionsDialog, ButtonHdl ) ); 143 144 maLbSettings.SetStyle( maLbSettings.GetStyle()|WB_CLIPCHILDREN|WB_FORCE_MAKEVISIBLE ); 145 maLbSettings.SetHelpId( HID_SC_SOLVEROPTIONS_LB ); 146 maLbSettings.SetHighlightRange(); 147 148 maLbSettings.SetSelectHdl( LINK( this, ScSolverOptionsDialog, SettingsSelHdl ) ); 149 maLbSettings.SetDoubleClickHdl( LINK( this, ScSolverOptionsDialog, SettingsDoubleClickHdl ) ); 150 151 sal_Int32 nSelect = -1; 152 sal_Int32 nImplCount = maImplNames.getLength(); 153 for (sal_Int32 nImpl=0; nImpl<nImplCount; ++nImpl) 154 { 155 String aImplName( maImplNames[nImpl] ); 156 String aDescription( maDescriptions[nImpl] ); // user-visible descriptions in list box 157 maLbEngine.InsertEntry( aDescription ); 158 if ( aImplName == maEngine ) 159 nSelect = nImpl; 160 } 161 if ( nSelect < 0 ) // no (valid) engine given 162 { 163 if ( nImplCount > 0 ) 164 { 165 maEngine = maImplNames[0]; // use first implementation 166 nSelect = 0; 167 } 168 else 169 maEngine.Erase(); 170 maProperties.realloc(0); // don't use options from different engine 171 } 172 if ( nSelect >= 0 ) // select in list box 173 maLbEngine.SelectEntryPos( static_cast<sal_uInt16>(nSelect) ); 174 175 if ( !maProperties.getLength() ) 176 ReadFromComponent(); // fill maProperties from component (using maEngine) 177 FillListBox(); // using maProperties 178 179 FreeResource(); 180 } 181 182 ScSolverOptionsDialog::~ScSolverOptionsDialog() 183 { 184 delete mpCheckButtonData; 185 } 186 187 const String& ScSolverOptionsDialog::GetEngine() const 188 { 189 return maEngine; // already updated in selection handler 190 } 191 192 const uno::Sequence<beans::PropertyValue>& ScSolverOptionsDialog::GetProperties() 193 { 194 // update maProperties from list box content 195 // order of entries in list box and maProperties is the same 196 sal_Int32 nEntryCount = maProperties.getLength(); 197 SvLBoxTreeList* pModel = maLbSettings.GetModel(); 198 if ( nEntryCount == (sal_Int32)pModel->GetEntryCount() ) 199 { 200 for (sal_Int32 nEntryPos=0; nEntryPos<nEntryCount; ++nEntryPos) 201 { 202 uno::Any& rValue = maProperties[nEntryPos].Value; 203 SvLBoxEntry* pEntry = pModel->GetEntry(nEntryPos); 204 205 bool bHasData = false; 206 sal_uInt16 nItemCount = pEntry->ItemCount(); 207 for (sal_uInt16 nItemPos=0; nItemPos<nItemCount && !bHasData; ++nItemPos) 208 { 209 SvLBoxItem* pItem = pEntry->GetItem( nItemPos ); 210 ScSolverOptionsString* pStringItem = dynamic_cast<ScSolverOptionsString*>(pItem); 211 if ( pStringItem ) 212 { 213 if ( pStringItem->IsDouble() ) 214 rValue <<= pStringItem->GetDoubleValue(); 215 else 216 rValue <<= pStringItem->GetIntValue(); 217 bHasData = true; 218 } 219 } 220 if ( !bHasData ) 221 ScUnoHelpFunctions::SetBoolInAny( rValue, 222 maLbSettings.GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED ); 223 } 224 } 225 else 226 { 227 DBG_ERRORFILE( "wrong count" ); 228 } 229 230 return maProperties; 231 } 232 233 void ScSolverOptionsDialog::FillListBox() 234 { 235 // get property descriptions, sort by them 236 237 uno::Reference<sheet::XSolverDescription> xDesc( ScSolverUtil::GetSolver( maEngine ), uno::UNO_QUERY ); 238 sal_Int32 nCount = maProperties.getLength(); 239 std::vector<ScSolverOptionsEntry> aDescriptions( nCount ); 240 for (sal_Int32 nPos=0; nPos<nCount; nPos++) 241 { 242 rtl::OUString aPropName( maProperties[nPos].Name ); 243 rtl::OUString aVisName; 244 if ( xDesc.is() ) 245 aVisName = xDesc->getPropertyDescription( aPropName ); 246 if ( !aVisName.getLength() ) 247 aVisName = aPropName; 248 aDescriptions[nPos].nPosition = nPos; 249 aDescriptions[nPos].aDescription = aVisName; 250 } 251 std::sort( aDescriptions.begin(), aDescriptions.end() ); 252 253 // also update maProperties to the order of descriptions 254 255 uno::Sequence<beans::PropertyValue> aNewSeq; 256 aNewSeq.realloc( nCount ); 257 for (sal_Int32 nPos=0; nPos<nCount; nPos++) 258 aNewSeq[nPos] = maProperties[ aDescriptions[nPos].nPosition ]; 259 maProperties = aNewSeq; 260 261 // fill the list box 262 263 maLbSettings.SetUpdateMode(sal_False); 264 maLbSettings.Clear(); 265 266 String sEmpty; 267 if (!mpCheckButtonData) 268 mpCheckButtonData = new SvLBoxButtonData( &maLbSettings ); 269 270 SvLBoxTreeList* pModel = maLbSettings.GetModel(); 271 SvLBoxEntry* pEntry = NULL; 272 273 for (sal_Int32 nPos=0; nPos<nCount; nPos++) 274 { 275 rtl::OUString aVisName = aDescriptions[nPos].aDescription; 276 277 uno::Any aValue = maProperties[nPos].Value; 278 uno::TypeClass eClass = aValue.getValueTypeClass(); 279 if ( eClass == uno::TypeClass_BOOLEAN ) 280 { 281 // check box entry 282 pEntry = new SvLBoxEntry; 283 SvLBoxButton* pButton = new SvLBoxButton( pEntry, SvLBoxButtonKind_enabledCheckbox, 0, mpCheckButtonData ); 284 if ( ScUnoHelpFunctions::GetBoolFromAny( aValue ) ) 285 pButton->SetStateChecked(); 286 else 287 pButton->SetStateUnchecked(); 288 pEntry->AddItem( pButton ); 289 pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), 0 ) ); 290 pEntry->AddItem( new SvLBoxString( pEntry, 0, aVisName ) ); 291 } 292 else 293 { 294 // value entry 295 pEntry = new SvLBoxEntry; 296 pEntry->AddItem( new SvLBoxString( pEntry, 0, sEmpty ) ); // empty column 297 pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), 0 ) ); 298 ScSolverOptionsString* pItem = new ScSolverOptionsString( pEntry, 0, aVisName ); 299 if ( eClass == uno::TypeClass_DOUBLE ) 300 { 301 double fDoubleValue = 0.0; 302 if ( aValue >>= fDoubleValue ) 303 pItem->SetDoubleValue( fDoubleValue ); 304 } 305 else 306 { 307 sal_Int32 nIntValue = 0; 308 if ( aValue >>= nIntValue ) 309 pItem->SetIntValue( nIntValue ); 310 } 311 pEntry->AddItem( pItem ); 312 } 313 pModel->Insert( pEntry ); 314 } 315 316 maLbSettings.SetUpdateMode(sal_True); 317 } 318 319 void ScSolverOptionsDialog::ReadFromComponent() 320 { 321 maProperties = ScSolverUtil::GetDefaults( maEngine ); 322 } 323 324 void ScSolverOptionsDialog::EditOption() 325 { 326 SvLBoxEntry* pEntry = maLbSettings.GetCurEntry(); 327 if (pEntry) 328 { 329 sal_uInt16 nItemCount = pEntry->ItemCount(); 330 for (sal_uInt16 nPos=0; nPos<nItemCount; ++nPos) 331 { 332 SvLBoxItem* pItem = pEntry->GetItem( nPos ); 333 ScSolverOptionsString* pStringItem = dynamic_cast<ScSolverOptionsString*>(pItem); 334 if ( pStringItem ) 335 { 336 if ( pStringItem->IsDouble() ) 337 { 338 ScSolverValueDialog aValDialog( this ); 339 aValDialog.SetOptionName( pStringItem->GetText() ); 340 aValDialog.SetValue( pStringItem->GetDoubleValue() ); 341 if ( aValDialog.Execute() == RET_OK ) 342 { 343 pStringItem->SetDoubleValue( aValDialog.GetValue() ); 344 maLbSettings.InvalidateEntry( pEntry ); 345 } 346 } 347 else 348 { 349 ScSolverIntegerDialog aIntDialog( this ); 350 aIntDialog.SetOptionName( pStringItem->GetText() ); 351 aIntDialog.SetValue( pStringItem->GetIntValue() ); 352 if ( aIntDialog.Execute() == RET_OK ) 353 { 354 pStringItem->SetIntValue( aIntDialog.GetValue() ); 355 maLbSettings.InvalidateEntry( pEntry ); 356 } 357 } 358 } 359 } 360 } 361 } 362 363 IMPL_LINK( ScSolverOptionsDialog, ButtonHdl, PushButton*, pBtn ) 364 { 365 if ( pBtn == &maBtnEdit ) 366 EditOption(); 367 368 return 0; 369 } 370 371 IMPL_LINK( ScSolverOptionsDialog, SettingsDoubleClickHdl, SvTreeListBox*, EMPTYARG ) 372 { 373 EditOption(); 374 return 0; 375 } 376 377 IMPL_LINK( ScSolverOptionsDialog, EngineSelectHdl, ListBox*, EMPTYARG ) 378 { 379 sal_uInt16 nSelectPos = maLbEngine.GetSelectEntryPos(); 380 if ( nSelectPos < maImplNames.getLength() ) 381 { 382 String aNewEngine( maImplNames[nSelectPos] ); 383 if ( aNewEngine != maEngine ) 384 { 385 maEngine = aNewEngine; 386 ReadFromComponent(); // fill maProperties from component (using maEngine) 387 FillListBox(); // using maProperties 388 } 389 } 390 return 0; 391 } 392 393 IMPL_LINK( ScSolverOptionsDialog, SettingsSelHdl, SvxCheckListBox*, EMPTYARG ) 394 { 395 sal_Bool bCheckbox = sal_False; 396 397 SvLBoxEntry* pEntry = maLbSettings.GetCurEntry(); 398 if (pEntry) 399 { 400 SvLBoxItem* pItem = pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON); 401 if ( pItem && pItem->IsA() == SV_ITEM_ID_LBOXBUTTON ) 402 bCheckbox = sal_True; 403 } 404 405 maBtnEdit.Enable( !bCheckbox ); 406 407 return 0; 408 } 409 410 //------------------------------------------------------------------ 411 412 ScSolverIntegerDialog::ScSolverIntegerDialog( Window * pParent ) 413 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_INTEGER ) ), 414 maFtName ( this, ScResId( FT_OPTIONNAME ) ), 415 maNfValue ( this, ScResId( NF_VALUE ) ), 416 maFlButtons ( this, ScResId( FL_BUTTONS ) ), 417 maBtnOk ( this, ScResId( BTN_OK ) ), 418 maBtnCancel ( this, ScResId( BTN_CANCEL ) ) 419 { 420 FreeResource(); 421 } 422 423 ScSolverIntegerDialog::~ScSolverIntegerDialog() 424 { 425 } 426 427 void ScSolverIntegerDialog::SetOptionName( const String& rName ) 428 { 429 maFtName.SetText( rName ); 430 } 431 432 void ScSolverIntegerDialog::SetValue( sal_Int32 nValue ) 433 { 434 maNfValue.SetValue( nValue ); 435 } 436 437 sal_Int32 ScSolverIntegerDialog::GetValue() const 438 { 439 sal_Int64 nValue = maNfValue.GetValue(); 440 if ( nValue < SAL_MIN_INT32 ) 441 return SAL_MIN_INT32; 442 if ( nValue > SAL_MAX_INT32 ) 443 return SAL_MAX_INT32; 444 return (sal_Int32) nValue; 445 } 446 447 //------------------------------------------------------------------ 448 449 ScSolverValueDialog::ScSolverValueDialog( Window * pParent ) 450 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_DOUBLE ) ), 451 maFtName ( this, ScResId( FT_OPTIONNAME ) ), 452 maEdValue ( this, ScResId( ED_VALUE ) ), 453 maFlButtons ( this, ScResId( FL_BUTTONS ) ), 454 maBtnOk ( this, ScResId( BTN_OK ) ), 455 maBtnCancel ( this, ScResId( BTN_CANCEL ) ) 456 { 457 FreeResource(); 458 } 459 460 ScSolverValueDialog::~ScSolverValueDialog() 461 { 462 } 463 464 void ScSolverValueDialog::SetOptionName( const String& rName ) 465 { 466 maFtName.SetText( rName ); 467 } 468 469 void ScSolverValueDialog::SetValue( double fValue ) 470 { 471 maEdValue.SetText( rtl::math::doubleToUString( fValue, 472 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 473 ScGlobal::GetpLocaleData()->getNumDecimalSep().GetChar(0), true ) ); 474 } 475 476 double ScSolverValueDialog::GetValue() const 477 { 478 String aInput = maEdValue.GetText(); 479 480 const LocaleDataWrapper* pLocaleData = ScGlobal::GetpLocaleData(); 481 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; 482 double fValue = rtl::math::stringToDouble( aInput, 483 pLocaleData->getNumDecimalSep().GetChar(0), 484 pLocaleData->getNumThousandSep().GetChar(0), 485 &eStatus, NULL ); 486 return fValue; 487 } 488 489