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 "rangelst.hxx" 30 #include "scitems.hxx" 31 #include <sfx2/bindings.hxx> 32 #include <sfx2/imagemgr.hxx> 33 #include <svl/zforlist.hxx> 34 #include <vcl/msgbox.hxx> 35 #include <vcl/svapp.hxx> 36 37 #include "uiitems.hxx" 38 #include "reffact.hxx" 39 #include "docsh.hxx" 40 #include "docfunc.hxx" 41 #include "cell.hxx" 42 #include "rangeutl.hxx" 43 #include "scresid.hxx" 44 #include "convuno.hxx" 45 #include "unonames.hxx" 46 #include "solveroptions.hxx" 47 #include "solverutil.hxx" 48 #include "optsolver.hrc" 49 50 #include "optsolver.hxx" 51 52 #include <com/sun/star/sheet/Solver.hpp> 53 #include <com/sun/star/sheet/XSolverDescription.hpp> 54 55 using namespace com::sun::star; 56 57 //---------------------------------------------------------------------------- 58 59 ScSolverProgressDialog::ScSolverProgressDialog( Window* pParent ) 60 : ModelessDialog( pParent, ScResId( RID_SCDLG_SOLVER_PROGRESS ) ), 61 maFtProgress ( this, ScResId( FT_PROGRESS ) ), 62 maFtTime ( this, ScResId( FT_TIMELIMIT ) ), 63 maFlButtons ( this, ScResId( FL_BUTTONS ) ), 64 maBtnOk ( this, ScResId( BTN_OK ) ) 65 { 66 maBtnOk.Enable(sal_False); 67 FreeResource(); 68 } 69 70 ScSolverProgressDialog::~ScSolverProgressDialog() 71 { 72 } 73 74 void ScSolverProgressDialog::HideTimeLimit() 75 { 76 maFtTime.Hide(); 77 } 78 79 void ScSolverProgressDialog::SetTimeLimit( sal_Int32 nSeconds ) 80 { 81 String aOld = maFtTime.GetText(); 82 String aNew = aOld.GetToken(0,'#'); 83 aNew += String::CreateFromInt32( nSeconds ); 84 aNew += aOld.GetToken(1,'#'); 85 maFtTime.SetText( aNew ); 86 } 87 88 //---------------------------------------------------------------------------- 89 90 ScSolverNoSolutionDialog::ScSolverNoSolutionDialog( Window* pParent, const String& rErrorText ) 91 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_NOSOLUTION ) ), 92 maFtNoSolution ( this, ScResId( FT_NOSOLUTION ) ), 93 maFtErrorText ( this, ScResId( FT_ERRORTEXT ) ), 94 maFlButtons ( this, ScResId( FL_BUTTONS ) ), 95 maBtnOk ( this, ScResId( BTN_OK ) ) 96 { 97 maFtErrorText.SetText( rErrorText ); 98 FreeResource(); 99 } 100 101 ScSolverNoSolutionDialog::~ScSolverNoSolutionDialog() 102 { 103 } 104 105 //---------------------------------------------------------------------------- 106 107 ScSolverSuccessDialog::ScSolverSuccessDialog( Window* pParent, const String& rSolution ) 108 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_SUCCESS ) ), 109 maFtSuccess ( this, ScResId( FT_SUCCESS ) ), 110 maFtResult ( this, ScResId( FT_RESULT ) ), 111 maFtQuestion ( this, ScResId( FT_QUESTION ) ), 112 maFlButtons ( this, ScResId( FL_BUTTONS ) ), 113 maBtnOk ( this, ScResId( BTN_OK ) ), 114 maBtnCancel ( this, ScResId( BTN_CANCEL ) ) 115 { 116 String aMessage = maFtResult.GetText(); 117 aMessage.Append( (sal_Char) ' ' ); 118 aMessage.Append( rSolution ); 119 maFtResult.SetText( aMessage ); 120 FreeResource(); 121 } 122 123 ScSolverSuccessDialog::~ScSolverSuccessDialog() 124 { 125 } 126 127 //---------------------------------------------------------------------------- 128 129 ScCursorRefEdit::ScCursorRefEdit( ScAnyRefDlg* pParent, const ResId& rResId ) : 130 formula::RefEdit( pParent, pParent, rResId ) 131 { 132 } 133 134 void ScCursorRefEdit::SetCursorLinks( const Link& rUp, const Link& rDown ) 135 { 136 maCursorUpLink = rUp; 137 maCursorDownLink = rDown; 138 } 139 140 void ScCursorRefEdit::KeyInput( const KeyEvent& rKEvt ) 141 { 142 KeyCode aCode = rKEvt.GetKeyCode(); 143 bool bUp = (aCode.GetCode() == KEY_UP); 144 bool bDown = (aCode.GetCode() == KEY_DOWN); 145 if ( !aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() && ( bUp || bDown ) ) 146 { 147 if ( bUp ) 148 maCursorUpLink.Call( this ); 149 else 150 maCursorDownLink.Call( this ); 151 } 152 else 153 formula::RefEdit::KeyInput( rKEvt ); 154 } 155 156 //---------------------------------------------------------------------------- 157 158 ScOptSolverSave::ScOptSolverSave( const String& rObjective, sal_Bool bMax, sal_Bool bMin, sal_Bool bValue, 159 const String& rTarget, const String& rVariable, 160 const std::vector<ScOptConditionRow>& rConditions, 161 const String& rEngine, 162 const uno::Sequence<beans::PropertyValue>& rProperties ) : 163 maObjective( rObjective ), 164 mbMax( bMax ), 165 mbMin( bMin ), 166 mbValue( bValue ), 167 maTarget( rTarget ), 168 maVariable( rVariable ), 169 maConditions( rConditions ), 170 maEngine( rEngine ), 171 maProperties( rProperties ) 172 { 173 } 174 175 //============================================================================ 176 // class ScOptSolverDlg 177 //---------------------------------------------------------------------------- 178 179 ScOptSolverDlg::ScOptSolverDlg( SfxBindings* pB, SfxChildWindow* pCW, Window* pParent, 180 ScDocShell* pDocSh, ScAddress aCursorPos ) 181 182 : ScAnyRefDlg ( pB, pCW, pParent, RID_SCDLG_OPTSOLVER ), 183 // 184 maFtObjectiveCell ( this, ScResId( FT_OBJECTIVECELL ) ), 185 maEdObjectiveCell ( this, this, ScResId( ED_OBJECTIVECELL ) ), 186 maRBObjectiveCell ( this, ScResId( IB_OBJECTIVECELL ), &maEdObjectiveCell, this ), 187 maFtDirection ( this, ScResId( FT_DIRECTION ) ), 188 maRbMax ( this, ScResId( RB_MAX ) ), 189 maRbMin ( this, ScResId( RB_MIN ) ), 190 maRbValue ( this, ScResId( RB_VALUE ) ), 191 maEdTargetValue ( this, this, ScResId( ED_TARGET ) ), 192 maRBTargetValue ( this, ScResId( IB_TARGET ), &maEdTargetValue, this ), 193 maFtVariableCells ( this, ScResId( FT_VARIABLECELLS ) ), 194 maEdVariableCells ( this, this, ScResId( ED_VARIABLECELLS ) ), 195 maRBVariableCells ( this, ScResId( IB_VARIABLECELLS ), &maEdVariableCells, this), 196 maFlConditions ( this, ScResId( FL_CONDITIONS ) ), 197 maFtCellRef ( this, ScResId( FT_CELLREF ) ), 198 maEdLeft1 ( this, ScResId( ED_LEFT1 ) ), 199 maRBLeft1 ( this, ScResId( IB_LEFT1 ), &maEdLeft1, this ), 200 maFtOperator ( this, ScResId( FT_OPERATOR ) ), 201 maLbOp1 ( this, ScResId( LB_OP1 ) ), 202 maFtConstraint ( this, ScResId( FT_CONSTRAINT ) ), 203 maEdRight1 ( this, ScResId( ED_RIGHT1 ) ), 204 maRBRight1 ( this, ScResId( IB_RIGHT1 ), &maEdRight1, this ), 205 maBtnDel1 ( this, ScResId( IB_DELETE1 ) ), 206 maEdLeft2 ( this, ScResId( ED_LEFT2 ) ), 207 maRBLeft2 ( this, ScResId( IB_LEFT2 ), &maEdLeft2, this ), 208 maLbOp2 ( this, ScResId( LB_OP2 ) ), 209 maEdRight2 ( this, ScResId( ED_RIGHT2 ) ), 210 maRBRight2 ( this, ScResId( IB_RIGHT2 ), &maEdRight2, this ), 211 maBtnDel2 ( this, ScResId( IB_DELETE2 ) ), 212 maEdLeft3 ( this, ScResId( ED_LEFT3 ) ), 213 maRBLeft3 ( this, ScResId( IB_LEFT3 ), &maEdLeft3, this ), 214 maLbOp3 ( this, ScResId( LB_OP3 ) ), 215 maEdRight3 ( this, ScResId( ED_RIGHT3 ) ), 216 maRBRight3 ( this, ScResId( IB_RIGHT3 ), &maEdRight3, this ), 217 maBtnDel3 ( this, ScResId( IB_DELETE3 ) ), 218 maEdLeft4 ( this, ScResId( ED_LEFT4 ) ), 219 maRBLeft4 ( this, ScResId( IB_LEFT4 ), &maEdLeft4, this ), 220 maLbOp4 ( this, ScResId( LB_OP4 ) ), 221 maEdRight4 ( this, ScResId( ED_RIGHT4 ) ), 222 maRBRight4 ( this, ScResId( IB_RIGHT4 ), &maEdRight4, this ), 223 maBtnDel4 ( this, ScResId( IB_DELETE4 ) ), 224 maScrollBar ( this, ScResId( SB_SCROLL ) ), 225 maFlButtons ( this, ScResId( FL_BUTTONS ) ), 226 maBtnOpt ( this, ScResId( BTN_OPTIONS ) ), 227 maBtnHelp ( this, ScResId( BTN_HELP ) ), 228 maBtnCancel ( this, ScResId( BTN_CLOSE ) ), 229 maBtnSolve ( this, ScResId( BTN_SOLVE ) ), 230 maInputError ( ScResId( STR_INVALIDINPUT ) ), 231 maConditionError ( ScResId( STR_INVALIDCONDITION ) ), 232 // 233 mpDocShell ( pDocSh ), 234 mpDoc ( pDocSh->GetDocument() ), 235 mnCurTab ( aCursorPos.Tab() ), 236 mpEdActive ( NULL ), 237 mbDlgLostFocus ( false ), 238 nScrollPos ( 0 ) 239 { 240 mpLeftEdit[0] = &maEdLeft1; 241 mpLeftButton[0] = &maRBLeft1; 242 mpRightEdit[0] = &maEdRight1; 243 mpRightButton[0] = &maRBRight1; 244 mpOperator[0] = &maLbOp1; 245 mpDelButton[0] = &maBtnDel1; 246 247 mpLeftEdit[1] = &maEdLeft2; 248 mpLeftButton[1] = &maRBLeft2; 249 mpRightEdit[1] = &maEdRight2; 250 mpRightButton[1] = &maRBRight2; 251 mpOperator[1] = &maLbOp2; 252 mpDelButton[1] = &maBtnDel2; 253 254 mpLeftEdit[2] = &maEdLeft3; 255 mpLeftButton[2] = &maRBLeft3; 256 mpRightEdit[2] = &maEdRight3; 257 mpRightButton[2] = &maRBRight3; 258 mpOperator[2] = &maLbOp3; 259 mpDelButton[2] = &maBtnDel3; 260 261 mpLeftEdit[3] = &maEdLeft4; 262 mpLeftButton[3] = &maRBLeft4; 263 mpRightEdit[3] = &maEdRight4; 264 mpRightButton[3] = &maRBRight4; 265 mpOperator[3] = &maLbOp4; 266 mpDelButton[3] = &maBtnDel4; 267 268 maRbMax.SetAccessibleRelationMemberOf(&maFtDirection); 269 maRbMin.SetAccessibleRelationMemberOf(&maFtDirection); 270 maRbValue.SetAccessibleRelationMemberOf(&maFtDirection); 271 maEdLeft2.SetAccessibleName(maFtCellRef.GetText()); 272 maLbOp2.SetAccessibleName(maFtOperator.GetText()); 273 maEdRight2.SetAccessibleName(maFtConstraint.GetText()); 274 maEdLeft3.SetAccessibleName(maFtCellRef.GetText()); 275 maLbOp3.SetAccessibleName(maFtOperator.GetText()); 276 maEdRight3.SetAccessibleName(maFtConstraint.GetText()); 277 maEdLeft4.SetAccessibleName(maFtCellRef.GetText()); 278 maLbOp4.SetAccessibleName(maFtOperator.GetText()); 279 maEdRight4.SetAccessibleName(maFtConstraint.GetText()); 280 281 Init( aCursorPos ); 282 FreeResource(); 283 } 284 285 //---------------------------------------------------------------------------- 286 287 ScOptSolverDlg::~ScOptSolverDlg() 288 { 289 } 290 291 //---------------------------------------------------------------------------- 292 293 void ScOptSolverDlg::Init(const ScAddress& rCursorPos) 294 { 295 // Get the "Delete Rows" commandimagelist images from sfx instead of 296 // adding a second copy to sc (see ScTbxInsertCtrl::StateChanged) 297 298 rtl::OUString aSlotURL( RTL_CONSTASCII_USTRINGPARAM( "slot:" )); 299 aSlotURL += rtl::OUString::valueOf( sal_Int32( SID_DEL_ROWS ) ); 300 uno::Reference<frame::XFrame> xFrame = GetBindings().GetActiveFrame(); 301 Image aDelNm = ::GetImage( xFrame, aSlotURL, sal_False, sal_False ); 302 Image aDelHC = ::GetImage( xFrame, aSlotURL, sal_False, sal_True ); // high contrast 303 304 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) 305 { 306 mpDelButton[nRow]->SetModeImage( aDelNm, BMP_COLOR_NORMAL ); 307 mpDelButton[nRow]->SetModeImage( aDelHC, BMP_COLOR_HIGHCONTRAST ); 308 } 309 310 maBtnOpt.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) ); 311 maBtnCancel.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) ); 312 maBtnSolve.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) ); 313 314 Link aLink = LINK( this, ScOptSolverDlg, GetFocusHdl ); 315 maEdObjectiveCell.SetGetFocusHdl( aLink ); 316 maRBObjectiveCell.SetGetFocusHdl( aLink ); 317 maEdTargetValue.SetGetFocusHdl( aLink ); 318 maRBTargetValue.SetGetFocusHdl( aLink ); 319 maEdVariableCells.SetGetFocusHdl( aLink ); 320 maRBVariableCells.SetGetFocusHdl( aLink ); 321 maRbValue.SetGetFocusHdl( aLink ); 322 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) 323 { 324 mpLeftEdit[nRow]->SetGetFocusHdl( aLink ); 325 mpLeftButton[nRow]->SetGetFocusHdl( aLink ); 326 mpRightEdit[nRow]->SetGetFocusHdl( aLink ); 327 mpRightButton[nRow]->SetGetFocusHdl( aLink ); 328 mpOperator[nRow]->SetGetFocusHdl( aLink ); 329 } 330 331 aLink = LINK( this, ScOptSolverDlg, LoseFocusHdl ); 332 maEdObjectiveCell.SetLoseFocusHdl( aLink ); 333 maRBObjectiveCell.SetLoseFocusHdl( aLink ); 334 maEdTargetValue. SetLoseFocusHdl( aLink ); 335 maRBTargetValue. SetLoseFocusHdl( aLink ); 336 maEdVariableCells.SetLoseFocusHdl( aLink ); 337 maRBVariableCells.SetLoseFocusHdl( aLink ); 338 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) 339 { 340 mpLeftEdit[nRow]->SetLoseFocusHdl( aLink ); 341 mpLeftButton[nRow]->SetLoseFocusHdl( aLink ); 342 mpRightEdit[nRow]->SetLoseFocusHdl( aLink ); 343 mpRightButton[nRow]->SetLoseFocusHdl( aLink ); 344 } 345 346 Link aCursorUp = LINK( this, ScOptSolverDlg, CursorUpHdl ); 347 Link aCursorDown = LINK( this, ScOptSolverDlg, CursorDownHdl ); 348 Link aCondModify = LINK( this, ScOptSolverDlg, CondModifyHdl ); 349 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) 350 { 351 mpLeftEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown ); 352 mpRightEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown ); 353 mpLeftEdit[nRow]->SetModifyHdl( aCondModify ); 354 mpRightEdit[nRow]->SetModifyHdl( aCondModify ); 355 mpDelButton[nRow]->SetClickHdl( LINK( this, ScOptSolverDlg, DelBtnHdl ) ); 356 mpOperator[nRow]->SetSelectHdl( LINK( this, ScOptSolverDlg, SelectHdl ) ); 357 } 358 maEdTargetValue.SetModifyHdl( LINK( this, ScOptSolverDlg, TargetModifyHdl ) ); 359 360 maScrollBar.SetEndScrollHdl( LINK( this, ScOptSolverDlg, ScrollHdl ) ); 361 maScrollBar.SetScrollHdl( LINK( this, ScOptSolverDlg, ScrollHdl ) ); 362 363 maScrollBar.SetPageSize( EDIT_ROW_COUNT ); 364 maScrollBar.SetVisibleSize( EDIT_ROW_COUNT ); 365 maScrollBar.SetLineSize( 1 ); 366 // Range is set in ShowConditions 367 368 // get available solver implementations 369 //! sort by descriptions? 370 ScSolverUtil::GetImplementations( maImplNames, maDescriptions ); 371 sal_Int32 nImplCount = maImplNames.getLength(); 372 373 const ScOptSolverSave* pOldData = mpDocShell->GetSolverSaveData(); 374 if ( pOldData ) 375 { 376 maEdObjectiveCell.SetRefString( pOldData->GetObjective() ); 377 maRbMax.Check( pOldData->GetMax() ); 378 maRbMin.Check( pOldData->GetMin() ); 379 maRbValue.Check( pOldData->GetValue() ); 380 maEdTargetValue.SetRefString( pOldData->GetTarget() ); 381 maEdVariableCells.SetRefString( pOldData->GetVariable() ); 382 maConditions = pOldData->GetConditions(); 383 maEngine = pOldData->GetEngine(); 384 maProperties = pOldData->GetProperties(); 385 } 386 else 387 { 388 maRbMax.Check(); 389 String aCursorStr; 390 if ( !mpDoc->GetRangeAtBlock( ScRange(rCursorPos), &aCursorStr ) ) 391 rCursorPos.Format( aCursorStr, SCA_ABS, NULL, mpDoc->GetAddressConvention() ); 392 maEdObjectiveCell.SetRefString( aCursorStr ); 393 if ( nImplCount > 0 ) 394 maEngine = maImplNames[0]; // use first implementation 395 } 396 ShowConditions(); 397 398 maEdObjectiveCell.GrabFocus(); 399 mpEdActive = &maEdObjectiveCell; 400 } 401 402 //---------------------------------------------------------------------------- 403 404 void ScOptSolverDlg::ReadConditions() 405 { 406 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) 407 { 408 ScOptConditionRow aRowEntry; 409 aRowEntry.aLeftStr = mpLeftEdit[nRow]->GetText(); 410 aRowEntry.aRightStr = mpRightEdit[nRow]->GetText(); 411 aRowEntry.nOperator = mpOperator[nRow]->GetSelectEntryPos(); 412 413 long nVecPos = nScrollPos + nRow; 414 if ( nVecPos >= (long)maConditions.size() && !aRowEntry.IsDefault() ) 415 maConditions.resize( nVecPos + 1 ); 416 417 if ( nVecPos < (long)maConditions.size() ) 418 maConditions[nVecPos] = aRowEntry; 419 420 // remove default entries at the end 421 size_t nSize = maConditions.size(); 422 while ( nSize > 0 && maConditions[ nSize-1 ].IsDefault() ) 423 --nSize; 424 maConditions.resize( nSize ); 425 } 426 } 427 428 void ScOptSolverDlg::ShowConditions() 429 { 430 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) 431 { 432 ScOptConditionRow aRowEntry; 433 434 long nVecPos = nScrollPos + nRow; 435 if ( nVecPos < (long)maConditions.size() ) 436 aRowEntry = maConditions[nVecPos]; 437 438 mpLeftEdit[nRow]->SetRefString( aRowEntry.aLeftStr ); 439 mpRightEdit[nRow]->SetRefString( aRowEntry.aRightStr ); 440 mpOperator[nRow]->SelectEntryPos( aRowEntry.nOperator ); 441 } 442 443 // allow to scroll one page behind the visible or stored rows 444 long nVisible = nScrollPos + EDIT_ROW_COUNT; 445 long nMax = std::max( nVisible, (long) maConditions.size() ); 446 maScrollBar.SetRange( Range( 0, nMax + EDIT_ROW_COUNT ) ); 447 maScrollBar.SetThumbPos( nScrollPos ); 448 449 EnableButtons(); 450 } 451 452 void ScOptSolverDlg::EnableButtons() 453 { 454 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) 455 { 456 long nVecPos = nScrollPos + nRow; 457 mpDelButton[nRow]->Enable( nVecPos < (long)maConditions.size() ); 458 } 459 } 460 461 //---------------------------------------------------------------------------- 462 463 sal_Bool ScOptSolverDlg::Close() 464 { 465 return DoClose( ScOptSolverDlgWrapper::GetChildWindowId() ); 466 } 467 468 //---------------------------------------------------------------------------- 469 470 void ScOptSolverDlg::SetActive() 471 { 472 if ( mbDlgLostFocus ) 473 { 474 mbDlgLostFocus = false; 475 if( mpEdActive ) 476 mpEdActive->GrabFocus(); 477 } 478 else 479 { 480 GrabFocus(); 481 } 482 RefInputDone(); 483 } 484 485 //---------------------------------------------------------------------------- 486 487 void ScOptSolverDlg::SetReference( const ScRange& rRef, ScDocument* pDocP ) 488 { 489 if( mpEdActive ) 490 { 491 if ( rRef.aStart != rRef.aEnd ) 492 RefInputStart(mpEdActive); 493 494 // "target"/"value": single cell 495 bool bSingle = ( mpEdActive == &maEdObjectiveCell || mpEdActive == &maEdTargetValue ); 496 497 String aStr; 498 ScAddress aAdr = rRef.aStart; 499 ScRange aNewRef( rRef ); 500 if ( bSingle ) 501 aNewRef.aEnd = aAdr; 502 503 String aName; 504 if ( pDocP->GetRangeAtBlock( aNewRef, &aName ) ) // named range: show name 505 aStr = aName; 506 else // format cell/range reference 507 { 508 sal_uInt16 nFmt = ( aAdr.Tab() == mnCurTab ) ? SCA_ABS : SCA_ABS_3D; 509 if ( bSingle ) 510 aAdr.Format( aStr, nFmt, pDocP, pDocP->GetAddressConvention() ); 511 else 512 rRef.Format( aStr, nFmt | SCR_ABS, pDocP, pDocP->GetAddressConvention() ); 513 } 514 515 // variable cells can be several ranges, so only the selection is replaced 516 if ( mpEdActive == &maEdVariableCells ) 517 { 518 String aVal = mpEdActive->GetText(); 519 Selection aSel = mpEdActive->GetSelection(); 520 aSel.Justify(); 521 aVal.Erase( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() ); 522 aVal.Insert( aStr, (xub_StrLen)aSel.Min() ); 523 Selection aNewSel( aSel.Min(), aSel.Min()+aStr.Len() ); 524 mpEdActive->SetRefString( aVal ); 525 mpEdActive->SetSelection( aNewSel ); 526 } 527 else 528 mpEdActive->SetRefString( aStr ); 529 530 ReadConditions(); 531 EnableButtons(); 532 533 // select "Value of" if a ref is input into "target" edit 534 if ( mpEdActive == &maEdTargetValue ) 535 maRbValue.Check(); 536 } 537 } 538 539 //---------------------------------------------------------------------------- 540 541 sal_Bool ScOptSolverDlg::IsRefInputMode() const 542 { 543 return mpEdActive != NULL; 544 } 545 546 //---------------------------------------------------------------------------- 547 // Handler: 548 549 IMPL_LINK( ScOptSolverDlg, BtnHdl, PushButton*, pBtn ) 550 { 551 if ( pBtn == &maBtnSolve || pBtn == &maBtnCancel ) 552 { 553 bool bSolve = ( pBtn == &maBtnSolve ); 554 555 SetDispatcherLock( sal_False ); 556 SwitchToDocument(); 557 558 bool bClose = true; 559 if ( bSolve ) 560 bClose = CallSolver(); 561 562 if ( bClose ) 563 { 564 // Close: write dialog settings to DocShell for subsequent calls 565 ReadConditions(); 566 ScOptSolverSave aSave( 567 maEdObjectiveCell.GetText(), maRbMax.IsChecked(), maRbMin.IsChecked(), maRbValue.IsChecked(), 568 maEdTargetValue.GetText(), maEdVariableCells.GetText(), maConditions, maEngine, maProperties ); 569 mpDocShell->SetSolverSaveData( aSave ); 570 Close(); 571 } 572 else 573 { 574 // no solution -> dialog is kept open 575 SetDispatcherLock( sal_True ); 576 } 577 } 578 else if ( pBtn == &maBtnOpt ) 579 { 580 //! move options dialog to UI lib? 581 ScSolverOptionsDialog* pOptDlg = 582 new ScSolverOptionsDialog( this, maImplNames, maDescriptions, maEngine, maProperties ); 583 if ( pOptDlg->Execute() == RET_OK ) 584 { 585 maEngine = pOptDlg->GetEngine(); 586 maProperties = pOptDlg->GetProperties(); 587 } 588 delete pOptDlg; 589 } 590 591 return 0; 592 } 593 594 //---------------------------------------------------------------------------- 595 596 IMPL_LINK( ScOptSolverDlg, GetFocusHdl, Control*, pCtrl ) 597 { 598 Edit* pEdit = NULL; 599 mpEdActive = NULL; 600 601 if( pCtrl == &maEdObjectiveCell || pCtrl == &maRBObjectiveCell ) 602 pEdit = mpEdActive = &maEdObjectiveCell; 603 else if( pCtrl == &maEdTargetValue || pCtrl == &maRBTargetValue ) 604 pEdit = mpEdActive = &maEdTargetValue; 605 else if( pCtrl == &maEdVariableCells || pCtrl == &maRBVariableCells ) 606 pEdit = mpEdActive = &maEdVariableCells; 607 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) 608 { 609 if( pCtrl == mpLeftEdit[nRow] || pCtrl == mpLeftButton[nRow] ) 610 pEdit = mpEdActive = mpLeftEdit[nRow]; 611 else if( pCtrl == mpRightEdit[nRow] || pCtrl == mpRightButton[nRow] ) 612 pEdit = mpEdActive = mpRightEdit[nRow]; 613 else if( pCtrl == mpOperator[nRow] ) // focus on "operator" list box 614 mpEdActive = mpRightEdit[nRow]; // use right edit for ref input, but don't change selection 615 } 616 if( pCtrl == &maRbValue ) // focus on "Value of" radio button 617 mpEdActive = &maEdTargetValue; // use value edit for ref input, but don't change selection 618 619 if( pEdit ) 620 pEdit->SetSelection( Selection( 0, SELECTION_MAX ) ); 621 622 return 0; 623 } 624 625 //---------------------------------------------------------------------------- 626 627 IMPL_LINK( ScOptSolverDlg, LoseFocusHdl, Control*, EMPTYARG ) 628 { 629 mbDlgLostFocus = !IsActive(); 630 return 0; 631 } 632 633 //---------------------------------------------------------------------------- 634 635 IMPL_LINK( ScOptSolverDlg, DelBtnHdl, PushButton*, pBtn ) 636 { 637 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) 638 if( pBtn == mpDelButton[nRow] ) 639 { 640 sal_Bool bHadFocus = pBtn->HasFocus(); 641 642 ReadConditions(); 643 long nVecPos = nScrollPos + nRow; 644 if ( nVecPos < (long)maConditions.size() ) 645 { 646 maConditions.erase( maConditions.begin() + nVecPos ); 647 ShowConditions(); 648 649 if ( bHadFocus && !pBtn->IsEnabled() ) 650 { 651 // If the button is disabled, focus would normally move to the next control, 652 // (left edit of the next row). Move it to left edit of this row instead. 653 654 mpEdActive = mpLeftEdit[nRow]; 655 mpEdActive->GrabFocus(); 656 } 657 } 658 } 659 660 return 0; 661 } 662 663 //---------------------------------------------------------------------------- 664 665 IMPL_LINK( ScOptSolverDlg, TargetModifyHdl, Edit*, EMPTYARG ) 666 { 667 // modify handler for the target edit: 668 // select "Value of" if something is input into the edit 669 if ( maEdTargetValue.GetText().Len() ) 670 maRbValue.Check(); 671 return 0; 672 } 673 674 IMPL_LINK( ScOptSolverDlg, CondModifyHdl, Edit*, EMPTYARG ) 675 { 676 // modify handler for the condition edits, just to enable/disable "delete" buttons 677 ReadConditions(); 678 EnableButtons(); 679 return 0; 680 } 681 682 IMPL_LINK( ScOptSolverDlg, SelectHdl, ListBox*, EMPTYARG ) 683 { 684 // select handler for operator list boxes, just to enable/disable "delete" buttons 685 ReadConditions(); 686 EnableButtons(); 687 return 0; 688 } 689 690 IMPL_LINK( ScOptSolverDlg, ScrollHdl, ScrollBar*, EMPTYARG ) 691 { 692 ReadConditions(); 693 nScrollPos = maScrollBar.GetThumbPos(); 694 ShowConditions(); 695 if( mpEdActive ) 696 mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) ); 697 return 0; 698 } 699 700 IMPL_LINK( ScOptSolverDlg, CursorUpHdl, ScCursorRefEdit*, pEdit ) 701 { 702 if ( pEdit == mpLeftEdit[0] || pEdit == mpRightEdit[0] ) 703 { 704 if ( nScrollPos > 0 ) 705 { 706 ReadConditions(); 707 --nScrollPos; 708 ShowConditions(); 709 if( mpEdActive ) 710 mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) ); 711 } 712 } 713 else 714 { 715 formula::RefEdit* pFocus = NULL; 716 for ( sal_uInt16 nRow = 1; nRow < EDIT_ROW_COUNT; ++nRow ) // second row or below: move focus 717 { 718 if ( pEdit == mpLeftEdit[nRow] ) 719 pFocus = mpLeftEdit[nRow-1]; 720 else if ( pEdit == mpRightEdit[nRow] ) 721 pFocus = mpRightEdit[nRow-1]; 722 } 723 if (pFocus) 724 { 725 mpEdActive = pFocus; 726 pFocus->GrabFocus(); 727 } 728 } 729 730 return 0; 731 } 732 733 IMPL_LINK( ScOptSolverDlg, CursorDownHdl, ScCursorRefEdit*, pEdit ) 734 { 735 if ( pEdit == mpLeftEdit[EDIT_ROW_COUNT-1] || pEdit == mpRightEdit[EDIT_ROW_COUNT-1] ) 736 { 737 //! limit scroll position? 738 ReadConditions(); 739 ++nScrollPos; 740 ShowConditions(); 741 if( mpEdActive ) 742 mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) ); 743 } 744 else 745 { 746 formula::RefEdit* pFocus = NULL; 747 for ( sal_uInt16 nRow = 0; nRow+1 < EDIT_ROW_COUNT; ++nRow ) // before last row: move focus 748 { 749 if ( pEdit == mpLeftEdit[nRow] ) 750 pFocus = mpLeftEdit[nRow+1]; 751 else if ( pEdit == mpRightEdit[nRow] ) 752 pFocus = mpRightEdit[nRow+1]; 753 } 754 if (pFocus) 755 { 756 mpEdActive = pFocus; 757 pFocus->GrabFocus(); 758 } 759 } 760 761 return 0; 762 } 763 764 //---------------------------------------------------------------------------- 765 766 void ScOptSolverDlg::ShowError( bool bCondition, formula::RefEdit* pFocus ) 767 { 768 String aMessage = bCondition ? maConditionError : maInputError; 769 ErrorBox( this, WinBits( WB_OK | WB_DEF_OK ), aMessage ).Execute(); 770 if (pFocus) 771 { 772 mpEdActive = pFocus; 773 pFocus->GrabFocus(); 774 } 775 } 776 777 //---------------------------------------------------------------------------- 778 779 bool ScOptSolverDlg::ParseRef( ScRange& rRange, const String& rInput, bool bAllowRange ) 780 { 781 ScRangeUtil aRangeUtil; 782 ScAddress::Details aDetails(mpDoc->GetAddressConvention(), 0, 0); 783 sal_uInt16 nFlags = rRange.ParseAny( rInput, mpDoc, aDetails ); 784 if ( nFlags & SCA_VALID ) 785 { 786 if ( (nFlags & SCA_TAB_3D) == 0 ) 787 rRange.aStart.SetTab( mnCurTab ); 788 if ( (nFlags & SCA_TAB2_3D) == 0 ) 789 rRange.aEnd.SetTab( rRange.aStart.Tab() ); 790 return ( bAllowRange || rRange.aStart == rRange.aEnd ); 791 } 792 else if ( aRangeUtil.MakeRangeFromName( rInput, mpDoc, mnCurTab, rRange, RUTL_NAMES, aDetails ) ) 793 return ( bAllowRange || rRange.aStart == rRange.aEnd ); 794 795 return false; // not recognized 796 } 797 798 bool ScOptSolverDlg::FindTimeout( sal_Int32& rTimeout ) 799 { 800 bool bFound = false; 801 802 if ( !maProperties.getLength() ) 803 maProperties = ScSolverUtil::GetDefaults( maEngine ); // get property defaults from component 804 805 sal_Int32 nPropCount = maProperties.getLength(); 806 for (sal_Int32 nProp=0; nProp<nPropCount && !bFound; ++nProp) 807 { 808 const beans::PropertyValue& rValue = maProperties[nProp]; 809 if ( rValue.Name.equalsAscii( SC_UNONAME_TIMEOUT ) ) 810 bFound = ( rValue.Value >>= rTimeout ); 811 } 812 return bFound; 813 } 814 815 bool ScOptSolverDlg::CallSolver() // return true -> close dialog after calling 816 { 817 // show progress dialog 818 819 ScSolverProgressDialog aProgress( this ); 820 sal_Int32 nTimeout = 0; 821 if ( FindTimeout( nTimeout ) ) 822 aProgress.SetTimeLimit( nTimeout ); 823 else 824 aProgress.HideTimeLimit(); 825 aProgress.Show(); 826 aProgress.Update(); 827 aProgress.Sync(); 828 // try to make sure the progress dialog is painted before continuing 829 Application::Reschedule(true); 830 831 // collect solver parameters 832 833 ReadConditions(); 834 835 uno::Reference<sheet::XSpreadsheetDocument> xDocument( mpDocShell->GetModel(), uno::UNO_QUERY ); 836 837 ScRange aObjRange; 838 if ( !ParseRef( aObjRange, maEdObjectiveCell.GetText(), false ) ) 839 { 840 ShowError( false, &maEdObjectiveCell ); 841 return false; 842 } 843 table::CellAddress aObjective( aObjRange.aStart.Tab(), aObjRange.aStart.Col(), aObjRange.aStart.Row() ); 844 845 // "changing cells" can be several ranges 846 ScRangeList aVarRanges; 847 if ( !ParseWithNames( aVarRanges, maEdVariableCells.GetText(), mpDoc ) ) 848 { 849 ShowError( false, &maEdVariableCells ); 850 return false; 851 } 852 uno::Sequence<table::CellAddress> aVariables; 853 sal_Int32 nVarPos = 0; 854 sal_uLong nRangeCount = aVarRanges.Count(); 855 for (sal_uLong nRangePos=0; nRangePos<nRangeCount; ++nRangePos) 856 { 857 ScRange aRange(*aVarRanges.GetObject(nRangePos)); 858 aRange.Justify(); 859 SCTAB nTab = aRange.aStart.Tab(); 860 861 // resolve into single cells 862 863 sal_Int32 nAdd = ( aRange.aEnd.Col() - aRange.aStart.Col() + 1 ) * 864 ( aRange.aEnd.Row() - aRange.aStart.Row() + 1 ); 865 aVariables.realloc( nVarPos + nAdd ); 866 867 for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow) 868 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol) 869 aVariables[nVarPos++] = table::CellAddress( nTab, nCol, nRow ); 870 } 871 872 uno::Sequence<sheet::SolverConstraint> aConstraints; 873 sal_Int32 nConstrPos = 0; 874 for ( std::vector<ScOptConditionRow>::const_iterator aConstrIter = maConditions.begin(); 875 aConstrIter != maConditions.end(); ++aConstrIter ) 876 { 877 if ( aConstrIter->aLeftStr.Len() ) 878 { 879 sheet::SolverConstraint aConstraint; 880 // order of list box entries must match enum values 881 aConstraint.Operator = static_cast<sheet::SolverConstraintOperator>(aConstrIter->nOperator); 882 883 ScRange aLeftRange; 884 if ( !ParseRef( aLeftRange, aConstrIter->aLeftStr, true ) ) 885 { 886 ShowError( true, NULL ); 887 return false; 888 } 889 890 bool bIsRange = false; 891 ScRange aRightRange; 892 if ( ParseRef( aRightRange, aConstrIter->aRightStr, true ) ) 893 { 894 if ( aRightRange.aStart == aRightRange.aEnd ) 895 aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(), 896 aRightRange.aStart.Col(), aRightRange.aStart.Row() ); 897 else if ( aRightRange.aEnd.Col()-aRightRange.aStart.Col() == aLeftRange.aEnd.Col()-aLeftRange.aStart.Col() && 898 aRightRange.aEnd.Row()-aRightRange.aStart.Row() == aLeftRange.aEnd.Row()-aLeftRange.aStart.Row() ) 899 bIsRange = true; // same size as "left" range, resolve into single cells 900 else 901 { 902 ShowError( true, NULL ); 903 return false; 904 } 905 } 906 else 907 { 908 sal_uInt32 nFormat = 0; //! explicit language? 909 double fValue = 0.0; 910 if ( mpDoc->GetFormatTable()->IsNumberFormat( aConstrIter->aRightStr, nFormat, fValue ) ) 911 aConstraint.Right <<= fValue; 912 else if ( aConstraint.Operator != sheet::SolverConstraintOperator_INTEGER && 913 aConstraint.Operator != sheet::SolverConstraintOperator_BINARY ) 914 { 915 ShowError( true, NULL ); 916 return false; 917 } 918 } 919 920 // resolve into single cells 921 922 sal_Int32 nAdd = ( aLeftRange.aEnd.Col() - aLeftRange.aStart.Col() + 1 ) * 923 ( aLeftRange.aEnd.Row() - aLeftRange.aStart.Row() + 1 ); 924 aConstraints.realloc( nConstrPos + nAdd ); 925 926 for (SCROW nRow = aLeftRange.aStart.Row(); nRow <= aLeftRange.aEnd.Row(); ++nRow) 927 for (SCCOL nCol = aLeftRange.aStart.Col(); nCol <= aLeftRange.aEnd.Col(); ++nCol) 928 { 929 aConstraint.Left = table::CellAddress( aLeftRange.aStart.Tab(), nCol, nRow ); 930 if ( bIsRange ) 931 aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(), 932 aRightRange.aStart.Col() + ( nCol - aLeftRange.aStart.Col() ), 933 aRightRange.aStart.Row() + ( nRow - aLeftRange.aStart.Row() ) ); 934 935 aConstraints[nConstrPos++] = aConstraint; 936 } 937 } 938 } 939 940 sal_Bool bMaximize = maRbMax.IsChecked(); 941 if ( maRbValue.IsChecked() ) 942 { 943 // handle "value of" with an additional constraint (and then minimize) 944 945 sheet::SolverConstraint aConstraint; 946 aConstraint.Left = aObjective; 947 aConstraint.Operator = sheet::SolverConstraintOperator_EQUAL; 948 949 String aValStr = maEdTargetValue.GetText(); 950 ScRange aRightRange; 951 if ( ParseRef( aRightRange, aValStr, false ) ) 952 aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(), 953 aRightRange.aStart.Col(), aRightRange.aStart.Row() ); 954 else 955 { 956 sal_uInt32 nFormat = 0; //! explicit language? 957 double fValue = 0.0; 958 if ( mpDoc->GetFormatTable()->IsNumberFormat( aValStr, nFormat, fValue ) ) 959 aConstraint.Right <<= fValue; 960 else 961 { 962 ShowError( false, &maEdTargetValue ); 963 return false; 964 } 965 } 966 967 aConstraints.realloc( nConstrPos + 1 ); 968 aConstraints[nConstrPos++] = aConstraint; 969 } 970 971 // copy old document values 972 973 sal_Int32 nVarCount = aVariables.getLength(); 974 uno::Sequence<double> aOldValues; 975 aOldValues.realloc( nVarCount ); 976 for (nVarPos=0; nVarPos<nVarCount; ++nVarPos) 977 { 978 ScAddress aCellPos; 979 ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] ); 980 aOldValues[nVarPos] = mpDoc->GetValue( aCellPos ); 981 } 982 983 // create and initialize solver 984 985 uno::Reference<sheet::XSolver> xSolver = ScSolverUtil::GetSolver( maEngine ); 986 DBG_ASSERT( xSolver.is(), "can't get solver component" ); 987 if ( !xSolver.is() ) 988 return false; 989 990 xSolver->setDocument( xDocument ); 991 xSolver->setObjective( aObjective ); 992 xSolver->setVariables( aVariables ); 993 xSolver->setConstraints( aConstraints ); 994 xSolver->setMaximize( bMaximize ); 995 996 // set options 997 uno::Reference<beans::XPropertySet> xOptProp(xSolver, uno::UNO_QUERY); 998 if ( xOptProp.is() ) 999 { 1000 sal_Int32 nPropCount = maProperties.getLength(); 1001 for (sal_Int32 nProp=0; nProp<nPropCount; ++nProp) 1002 { 1003 const beans::PropertyValue& rValue = maProperties[nProp]; 1004 try 1005 { 1006 xOptProp->setPropertyValue( rValue.Name, rValue.Value ); 1007 } 1008 catch ( uno::Exception & ) 1009 { 1010 DBG_ERRORFILE("Exception in solver option property"); 1011 } 1012 } 1013 } 1014 1015 xSolver->solve(); 1016 sal_Bool bSuccess = xSolver->getSuccess(); 1017 1018 aProgress.Hide(); 1019 bool bClose = false; 1020 bool bRestore = true; // restore old values unless a solution is accepted 1021 if ( bSuccess ) 1022 { 1023 // put solution into document so it is visible when asking 1024 uno::Sequence<double> aSolution = xSolver->getSolution(); 1025 if ( aSolution.getLength() == nVarCount ) 1026 { 1027 mpDocShell->LockPaint(); 1028 ScDocFunc aFunc(*mpDocShell); 1029 for (nVarPos=0; nVarPos<nVarCount; ++nVarPos) 1030 { 1031 ScAddress aCellPos; 1032 ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] ); 1033 aFunc.PutCell( aCellPos, new ScValueCell( aSolution[nVarPos] ), sal_True ); 1034 } 1035 mpDocShell->UnlockPaint(); 1036 } 1037 //! else error? 1038 1039 // take formatted result from document (result value from component is ignored) 1040 String aResultStr; 1041 mpDoc->GetString( (SCCOL)aObjective.Column, (SCROW)aObjective.Row, (SCTAB)aObjective.Sheet, aResultStr ); 1042 ScSolverSuccessDialog aDialog( this, aResultStr ); 1043 if ( aDialog.Execute() == RET_OK ) 1044 { 1045 // keep results and close dialog 1046 bRestore = false; 1047 bClose = true; 1048 } 1049 } 1050 else 1051 { 1052 rtl::OUString aError; 1053 uno::Reference<sheet::XSolverDescription> xDesc( xSolver, uno::UNO_QUERY ); 1054 if ( xDesc.is() ) 1055 aError = xDesc->getStatusDescription(); // error description from component 1056 ScSolverNoSolutionDialog aDialog( this, aError ); 1057 aDialog.Execute(); 1058 } 1059 1060 if ( bRestore ) // restore old values 1061 { 1062 mpDocShell->LockPaint(); 1063 ScDocFunc aFunc(*mpDocShell); 1064 for (nVarPos=0; nVarPos<nVarCount; ++nVarPos) 1065 { 1066 ScAddress aCellPos; 1067 ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] ); 1068 aFunc.PutCell( aCellPos, new ScValueCell( aOldValues[nVarPos] ), sal_True ); 1069 } 1070 mpDocShell->UnlockPaint(); 1071 } 1072 1073 return bClose; 1074 } 1075 1076