sync master with lastest vba changes
[ooovba.git] / sc / source / ui / miscdlgs / optsolver.cxx
blob71215009ede3ecb122d69bce1c61d3714dce87dd
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: optsolver.cxx,v $
10 * $Revision: 1.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 //----------------------------------------------------------------------------
36 #include "rangelst.hxx"
37 #include "scitems.hxx"
38 #include <sfx2/bindings.hxx>
39 #include <sfx2/imagemgr.hxx>
40 #include <svtools/zforlist.hxx>
41 #include <vcl/msgbox.hxx>
42 #include <vcl/svapp.hxx>
44 #include "uiitems.hxx"
45 #include "reffact.hxx"
46 #include "docsh.hxx"
47 #include "docfunc.hxx"
48 #include "cell.hxx"
49 #include "rangeutl.hxx"
50 #include "scresid.hxx"
51 #include "convuno.hxx"
52 #include "unonames.hxx"
53 #include "solveroptions.hxx"
54 #include "solverutil.hxx"
55 #include "optsolver.hrc"
57 #include "optsolver.hxx"
59 #include <com/sun/star/sheet/Solver.hpp>
60 #include <com/sun/star/sheet/XSolverDescription.hpp>
62 using namespace com::sun::star;
64 //----------------------------------------------------------------------------
66 ScSolverProgressDialog::ScSolverProgressDialog( Window* pParent )
67 : ModelessDialog( pParent, ScResId( RID_SCDLG_SOLVER_PROGRESS ) ),
68 maFtProgress ( this, ScResId( FT_PROGRESS ) ),
69 maFtTime ( this, ScResId( FT_TIMELIMIT ) ),
70 maFlButtons ( this, ScResId( FL_BUTTONS ) ),
71 maBtnOk ( this, ScResId( BTN_OK ) )
73 maBtnOk.Enable(FALSE);
74 FreeResource();
77 ScSolverProgressDialog::~ScSolverProgressDialog()
81 void ScSolverProgressDialog::HideTimeLimit()
83 maFtTime.Hide();
86 void ScSolverProgressDialog::SetTimeLimit( sal_Int32 nSeconds )
88 String aOld = maFtTime.GetText();
89 String aNew = aOld.GetToken(0,'#');
90 aNew += String::CreateFromInt32( nSeconds );
91 aNew += aOld.GetToken(1,'#');
92 maFtTime.SetText( aNew );
95 //----------------------------------------------------------------------------
97 ScSolverNoSolutionDialog::ScSolverNoSolutionDialog( Window* pParent, const String& rErrorText )
98 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_NOSOLUTION ) ),
99 maFtNoSolution ( this, ScResId( FT_NOSOLUTION ) ),
100 maFtErrorText ( this, ScResId( FT_ERRORTEXT ) ),
101 maFlButtons ( this, ScResId( FL_BUTTONS ) ),
102 maBtnOk ( this, ScResId( BTN_OK ) )
104 maFtErrorText.SetText( rErrorText );
105 FreeResource();
108 ScSolverNoSolutionDialog::~ScSolverNoSolutionDialog()
112 //----------------------------------------------------------------------------
114 ScSolverSuccessDialog::ScSolverSuccessDialog( Window* pParent, const String& rSolution )
115 : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_SUCCESS ) ),
116 maFtSuccess ( this, ScResId( FT_SUCCESS ) ),
117 maFtResult ( this, ScResId( FT_RESULT ) ),
118 maFtQuestion ( this, ScResId( FT_QUESTION ) ),
119 maFlButtons ( this, ScResId( FL_BUTTONS ) ),
120 maBtnOk ( this, ScResId( BTN_OK ) ),
121 maBtnCancel ( this, ScResId( BTN_CANCEL ) )
123 String aMessage = maFtResult.GetText();
124 aMessage.Append( (sal_Char) ' ' );
125 aMessage.Append( rSolution );
126 maFtResult.SetText( aMessage );
127 FreeResource();
130 ScSolverSuccessDialog::~ScSolverSuccessDialog()
134 //----------------------------------------------------------------------------
136 ScCursorRefEdit::ScCursorRefEdit( ScAnyRefDlg* pParent, const ResId& rResId ) :
137 formula::RefEdit( pParent, pParent, rResId )
141 void ScCursorRefEdit::SetCursorLinks( const Link& rUp, const Link& rDown )
143 maCursorUpLink = rUp;
144 maCursorDownLink = rDown;
147 void ScCursorRefEdit::KeyInput( const KeyEvent& rKEvt )
149 KeyCode aCode = rKEvt.GetKeyCode();
150 bool bUp = (aCode.GetCode() == KEY_UP);
151 bool bDown = (aCode.GetCode() == KEY_DOWN);
152 if ( !aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() && ( bUp || bDown ) )
154 if ( bUp )
155 maCursorUpLink.Call( this );
156 else
157 maCursorDownLink.Call( this );
159 else
160 formula::RefEdit::KeyInput( rKEvt );
163 //----------------------------------------------------------------------------
165 ScOptSolverSave::ScOptSolverSave( const String& rObjective, BOOL bMax, BOOL bMin, BOOL bValue,
166 const String& rTarget, const String& rVariable,
167 const std::vector<ScOptConditionRow>& rConditions,
168 const String& rEngine,
169 const uno::Sequence<beans::PropertyValue>& rProperties ) :
170 maObjective( rObjective ),
171 mbMax( bMax ),
172 mbMin( bMin ),
173 mbValue( bValue ),
174 maTarget( rTarget ),
175 maVariable( rVariable ),
176 maConditions( rConditions ),
177 maEngine( rEngine ),
178 maProperties( rProperties )
182 //============================================================================
183 // class ScOptSolverDlg
184 //----------------------------------------------------------------------------
186 ScOptSolverDlg::ScOptSolverDlg( SfxBindings* pB, SfxChildWindow* pCW, Window* pParent,
187 ScDocShell* pDocSh, ScAddress aCursorPos )
189 : ScAnyRefDlg ( pB, pCW, pParent, RID_SCDLG_OPTSOLVER ),
191 maFtObjectiveCell ( this, ScResId( FT_OBJECTIVECELL ) ),
192 maEdObjectiveCell ( this, this, ScResId( ED_OBJECTIVECELL ) ),
193 maRBObjectiveCell ( this, ScResId( IB_OBJECTIVECELL ), &maEdObjectiveCell, this ),
194 maFtDirection ( this, ScResId( FT_DIRECTION ) ),
195 maRbMax ( this, ScResId( RB_MAX ) ),
196 maRbMin ( this, ScResId( RB_MIN ) ),
197 maRbValue ( this, ScResId( RB_VALUE ) ),
198 maEdTargetValue ( this, this, ScResId( ED_TARGET ) ),
199 maRBTargetValue ( this, ScResId( IB_TARGET ), &maEdTargetValue, this ),
200 maFtVariableCells ( this, ScResId( FT_VARIABLECELLS ) ),
201 maEdVariableCells ( this, this, ScResId( ED_VARIABLECELLS ) ),
202 maRBVariableCells ( this, ScResId( IB_VARIABLECELLS ), &maEdVariableCells, this),
203 maFlConditions ( this, ScResId( FL_CONDITIONS ) ),
204 maFtCellRef ( this, ScResId( FT_CELLREF ) ),
205 maEdLeft1 ( this, ScResId( ED_LEFT1 ) ),
206 maRBLeft1 ( this, ScResId( IB_LEFT1 ), &maEdLeft1, this ),
207 maFtOperator ( this, ScResId( FT_OPERATOR ) ),
208 maLbOp1 ( this, ScResId( LB_OP1 ) ),
209 maFtConstraint ( this, ScResId( FT_CONSTRAINT ) ),
210 maEdRight1 ( this, ScResId( ED_RIGHT1 ) ),
211 maRBRight1 ( this, ScResId( IB_RIGHT1 ), &maEdRight1, this ),
212 maBtnDel1 ( this, ScResId( IB_DELETE1 ) ),
213 maEdLeft2 ( this, ScResId( ED_LEFT2 ) ),
214 maRBLeft2 ( this, ScResId( IB_LEFT2 ), &maEdLeft2, this ),
215 maLbOp2 ( this, ScResId( LB_OP2 ) ),
216 maEdRight2 ( this, ScResId( ED_RIGHT2 ) ),
217 maRBRight2 ( this, ScResId( IB_RIGHT2 ), &maEdRight2, this ),
218 maBtnDel2 ( this, ScResId( IB_DELETE2 ) ),
219 maEdLeft3 ( this, ScResId( ED_LEFT3 ) ),
220 maRBLeft3 ( this, ScResId( IB_LEFT3 ), &maEdLeft3, this ),
221 maLbOp3 ( this, ScResId( LB_OP3 ) ),
222 maEdRight3 ( this, ScResId( ED_RIGHT3 ) ),
223 maRBRight3 ( this, ScResId( IB_RIGHT3 ), &maEdRight3, this ),
224 maBtnDel3 ( this, ScResId( IB_DELETE3 ) ),
225 maEdLeft4 ( this, ScResId( ED_LEFT4 ) ),
226 maRBLeft4 ( this, ScResId( IB_LEFT4 ), &maEdLeft4, this ),
227 maLbOp4 ( this, ScResId( LB_OP4 ) ),
228 maEdRight4 ( this, ScResId( ED_RIGHT4 ) ),
229 maRBRight4 ( this, ScResId( IB_RIGHT4 ), &maEdRight4, this ),
230 maBtnDel4 ( this, ScResId( IB_DELETE4 ) ),
231 maScrollBar ( this, ScResId( SB_SCROLL ) ),
232 maFlButtons ( this, ScResId( FL_BUTTONS ) ),
233 maBtnOpt ( this, ScResId( BTN_OPTIONS ) ),
234 maBtnHelp ( this, ScResId( BTN_HELP ) ),
235 maBtnCancel ( this, ScResId( BTN_CLOSE ) ),
236 maBtnSolve ( this, ScResId( BTN_SOLVE ) ),
237 maInputError ( ScResId( STR_INVALIDINPUT ) ),
238 maConditionError ( ScResId( STR_INVALIDCONDITION ) ),
240 mpDocShell ( pDocSh ),
241 mpDoc ( pDocSh->GetDocument() ),
242 mnCurTab ( aCursorPos.Tab() ),
243 mpEdActive ( NULL ),
244 mbDlgLostFocus ( false ),
245 nScrollPos ( 0 )
247 mpLeftEdit[0] = &maEdLeft1;
248 mpLeftButton[0] = &maRBLeft1;
249 mpRightEdit[0] = &maEdRight1;
250 mpRightButton[0] = &maRBRight1;
251 mpOperator[0] = &maLbOp1;
252 mpDelButton[0] = &maBtnDel1;
254 mpLeftEdit[1] = &maEdLeft2;
255 mpLeftButton[1] = &maRBLeft2;
256 mpRightEdit[1] = &maEdRight2;
257 mpRightButton[1] = &maRBRight2;
258 mpOperator[1] = &maLbOp2;
259 mpDelButton[1] = &maBtnDel2;
261 mpLeftEdit[2] = &maEdLeft3;
262 mpLeftButton[2] = &maRBLeft3;
263 mpRightEdit[2] = &maEdRight3;
264 mpRightButton[2] = &maRBRight3;
265 mpOperator[2] = &maLbOp3;
266 mpDelButton[2] = &maBtnDel3;
268 mpLeftEdit[3] = &maEdLeft4;
269 mpLeftButton[3] = &maRBLeft4;
270 mpRightEdit[3] = &maEdRight4;
271 mpRightButton[3] = &maRBRight4;
272 mpOperator[3] = &maLbOp4;
273 mpDelButton[3] = &maBtnDel4;
275 Init( aCursorPos );
276 FreeResource();
279 //----------------------------------------------------------------------------
281 ScOptSolverDlg::~ScOptSolverDlg()
285 //----------------------------------------------------------------------------
287 void ScOptSolverDlg::Init(const ScAddress& rCursorPos)
289 // Get the "Delete Rows" commandimagelist images from sfx instead of
290 // adding a second copy to sc (see ScTbxInsertCtrl::StateChanged)
292 rtl::OUString aSlotURL( RTL_CONSTASCII_USTRINGPARAM( "slot:" ));
293 aSlotURL += rtl::OUString::valueOf( sal_Int32( SID_DEL_ROWS ) );
294 uno::Reference<frame::XFrame> xFrame = GetBindings().GetActiveFrame();
295 Image aDelNm = ::GetImage( xFrame, aSlotURL, FALSE, FALSE );
296 Image aDelHC = ::GetImage( xFrame, aSlotURL, FALSE, TRUE ); // high contrast
298 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
300 mpDelButton[nRow]->SetModeImage( aDelNm, BMP_COLOR_NORMAL );
301 mpDelButton[nRow]->SetModeImage( aDelHC, BMP_COLOR_HIGHCONTRAST );
304 maBtnOpt.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) );
305 maBtnCancel.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) );
306 maBtnSolve.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) );
308 Link aLink = LINK( this, ScOptSolverDlg, GetFocusHdl );
309 maEdObjectiveCell.SetGetFocusHdl( aLink );
310 maRBObjectiveCell.SetGetFocusHdl( aLink );
311 maEdTargetValue.SetGetFocusHdl( aLink );
312 maRBTargetValue.SetGetFocusHdl( aLink );
313 maEdVariableCells.SetGetFocusHdl( aLink );
314 maRBVariableCells.SetGetFocusHdl( aLink );
315 maRbValue.SetGetFocusHdl( aLink );
316 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
318 mpLeftEdit[nRow]->SetGetFocusHdl( aLink );
319 mpLeftButton[nRow]->SetGetFocusHdl( aLink );
320 mpRightEdit[nRow]->SetGetFocusHdl( aLink );
321 mpRightButton[nRow]->SetGetFocusHdl( aLink );
322 mpOperator[nRow]->SetGetFocusHdl( aLink );
325 aLink = LINK( this, ScOptSolverDlg, LoseFocusHdl );
326 maEdObjectiveCell.SetLoseFocusHdl( aLink );
327 maRBObjectiveCell.SetLoseFocusHdl( aLink );
328 maEdTargetValue. SetLoseFocusHdl( aLink );
329 maRBTargetValue. SetLoseFocusHdl( aLink );
330 maEdVariableCells.SetLoseFocusHdl( aLink );
331 maRBVariableCells.SetLoseFocusHdl( aLink );
332 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
334 mpLeftEdit[nRow]->SetLoseFocusHdl( aLink );
335 mpLeftButton[nRow]->SetLoseFocusHdl( aLink );
336 mpRightEdit[nRow]->SetLoseFocusHdl( aLink );
337 mpRightButton[nRow]->SetLoseFocusHdl( aLink );
340 Link aCursorUp = LINK( this, ScOptSolverDlg, CursorUpHdl );
341 Link aCursorDown = LINK( this, ScOptSolverDlg, CursorDownHdl );
342 Link aCondModify = LINK( this, ScOptSolverDlg, CondModifyHdl );
343 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
345 mpLeftEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown );
346 mpRightEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown );
347 mpLeftEdit[nRow]->SetModifyHdl( aCondModify );
348 mpRightEdit[nRow]->SetModifyHdl( aCondModify );
349 mpDelButton[nRow]->SetClickHdl( LINK( this, ScOptSolverDlg, DelBtnHdl ) );
350 mpOperator[nRow]->SetSelectHdl( LINK( this, ScOptSolverDlg, SelectHdl ) );
352 maEdTargetValue.SetModifyHdl( LINK( this, ScOptSolverDlg, TargetModifyHdl ) );
354 maScrollBar.SetEndScrollHdl( LINK( this, ScOptSolverDlg, ScrollHdl ) );
355 maScrollBar.SetScrollHdl( LINK( this, ScOptSolverDlg, ScrollHdl ) );
357 maScrollBar.SetPageSize( EDIT_ROW_COUNT );
358 maScrollBar.SetVisibleSize( EDIT_ROW_COUNT );
359 maScrollBar.SetLineSize( 1 );
360 // Range is set in ShowConditions
362 // get available solver implementations
363 //! sort by descriptions?
364 ScSolverUtil::GetImplementations( maImplNames, maDescriptions );
365 sal_Int32 nImplCount = maImplNames.getLength();
367 const ScOptSolverSave* pOldData = mpDocShell->GetSolverSaveData();
368 if ( pOldData )
370 maEdObjectiveCell.SetRefString( pOldData->GetObjective() );
371 maRbMax.Check( pOldData->GetMax() );
372 maRbMin.Check( pOldData->GetMin() );
373 maRbValue.Check( pOldData->GetValue() );
374 maEdTargetValue.SetRefString( pOldData->GetTarget() );
375 maEdVariableCells.SetRefString( pOldData->GetVariable() );
376 maConditions = pOldData->GetConditions();
377 maEngine = pOldData->GetEngine();
378 maProperties = pOldData->GetProperties();
380 else
382 maRbMax.Check();
383 String aCursorStr;
384 if ( !mpDoc->GetRangeAtBlock( ScRange(rCursorPos), &aCursorStr ) )
385 rCursorPos.Format( aCursorStr, SCA_ABS, NULL, mpDoc->GetAddressConvention() );
386 maEdObjectiveCell.SetRefString( aCursorStr );
387 if ( nImplCount > 0 )
388 maEngine = maImplNames[0]; // use first implementation
390 ShowConditions();
392 maEdObjectiveCell.GrabFocus();
393 mpEdActive = &maEdObjectiveCell;
396 //----------------------------------------------------------------------------
398 void ScOptSolverDlg::ReadConditions()
400 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
402 ScOptConditionRow aRowEntry;
403 aRowEntry.aLeftStr = mpLeftEdit[nRow]->GetText();
404 aRowEntry.aRightStr = mpRightEdit[nRow]->GetText();
405 aRowEntry.nOperator = mpOperator[nRow]->GetSelectEntryPos();
407 long nVecPos = nScrollPos + nRow;
408 if ( nVecPos >= (long)maConditions.size() && !aRowEntry.IsDefault() )
409 maConditions.resize( nVecPos + 1 );
411 if ( nVecPos < (long)maConditions.size() )
412 maConditions[nVecPos] = aRowEntry;
414 // remove default entries at the end
415 size_t nSize = maConditions.size();
416 while ( nSize > 0 && maConditions[ nSize-1 ].IsDefault() )
417 --nSize;
418 maConditions.resize( nSize );
422 void ScOptSolverDlg::ShowConditions()
424 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
426 ScOptConditionRow aRowEntry;
428 long nVecPos = nScrollPos + nRow;
429 if ( nVecPos < (long)maConditions.size() )
430 aRowEntry = maConditions[nVecPos];
432 mpLeftEdit[nRow]->SetRefString( aRowEntry.aLeftStr );
433 mpRightEdit[nRow]->SetRefString( aRowEntry.aRightStr );
434 mpOperator[nRow]->SelectEntryPos( aRowEntry.nOperator );
437 // allow to scroll one page behind the visible or stored rows
438 long nVisible = nScrollPos + EDIT_ROW_COUNT;
439 long nMax = std::max( nVisible, (long) maConditions.size() );
440 maScrollBar.SetRange( Range( 0, nMax + EDIT_ROW_COUNT ) );
441 maScrollBar.SetThumbPos( nScrollPos );
443 EnableButtons();
446 void ScOptSolverDlg::EnableButtons()
448 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
450 long nVecPos = nScrollPos + nRow;
451 mpDelButton[nRow]->Enable( nVecPos < (long)maConditions.size() );
455 //----------------------------------------------------------------------------
457 BOOL ScOptSolverDlg::Close()
459 return DoClose( ScOptSolverDlgWrapper::GetChildWindowId() );
462 //----------------------------------------------------------------------------
464 void ScOptSolverDlg::SetActive()
466 if ( mbDlgLostFocus )
468 mbDlgLostFocus = false;
469 if( mpEdActive )
470 mpEdActive->GrabFocus();
472 else
474 GrabFocus();
476 RefInputDone();
479 //----------------------------------------------------------------------------
481 void ScOptSolverDlg::SetReference( const ScRange& rRef, ScDocument* pDocP )
483 if( mpEdActive )
485 if ( rRef.aStart != rRef.aEnd )
486 RefInputStart(mpEdActive);
488 // "target"/"value": single cell
489 bool bSingle = ( mpEdActive == &maEdObjectiveCell || mpEdActive == &maEdTargetValue );
491 String aStr;
492 ScAddress aAdr = rRef.aStart;
493 ScRange aNewRef( rRef );
494 if ( bSingle )
495 aNewRef.aEnd = aAdr;
497 String aName;
498 if ( pDocP->GetRangeAtBlock( aNewRef, &aName ) ) // named range: show name
499 aStr = aName;
500 else // format cell/range reference
502 USHORT nFmt = ( aAdr.Tab() == mnCurTab ) ? SCA_ABS : SCA_ABS_3D;
503 if ( bSingle )
504 aAdr.Format( aStr, nFmt, pDocP, pDocP->GetAddressConvention() );
505 else
506 rRef.Format( aStr, nFmt | SCR_ABS, pDocP, pDocP->GetAddressConvention() );
509 // variable cells can be several ranges, so only the selection is replaced
510 if ( mpEdActive == &maEdVariableCells )
512 String aVal = mpEdActive->GetText();
513 Selection aSel = mpEdActive->GetSelection();
514 aSel.Justify();
515 aVal.Erase( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() );
516 aVal.Insert( aStr, (xub_StrLen)aSel.Min() );
517 Selection aNewSel( aSel.Min(), aSel.Min()+aStr.Len() );
518 mpEdActive->SetRefString( aVal );
519 mpEdActive->SetSelection( aNewSel );
521 else
522 mpEdActive->SetRefString( aStr );
524 ReadConditions();
525 EnableButtons();
527 // select "Value of" if a ref is input into "target" edit
528 if ( mpEdActive == &maEdTargetValue )
529 maRbValue.Check();
533 //----------------------------------------------------------------------------
535 BOOL ScOptSolverDlg::IsRefInputMode() const
537 return mpEdActive != NULL;
540 //----------------------------------------------------------------------------
541 // Handler:
543 IMPL_LINK( ScOptSolverDlg, BtnHdl, PushButton*, pBtn )
545 if ( pBtn == &maBtnSolve || pBtn == &maBtnCancel )
547 bool bSolve = ( pBtn == &maBtnSolve );
549 SetDispatcherLock( FALSE );
550 SwitchToDocument();
552 bool bClose = true;
553 if ( bSolve )
554 bClose = CallSolver();
556 if ( bClose )
558 // Close: write dialog settings to DocShell for subsequent calls
559 ReadConditions();
560 ScOptSolverSave aSave(
561 maEdObjectiveCell.GetText(), maRbMax.IsChecked(), maRbMin.IsChecked(), maRbValue.IsChecked(),
562 maEdTargetValue.GetText(), maEdVariableCells.GetText(), maConditions, maEngine, maProperties );
563 mpDocShell->SetSolverSaveData( aSave );
564 Close();
566 else
568 // no solution -> dialog is kept open
569 SetDispatcherLock( TRUE );
572 else if ( pBtn == &maBtnOpt )
574 //! move options dialog to UI lib?
575 ScSolverOptionsDialog* pOptDlg =
576 new ScSolverOptionsDialog( this, maImplNames, maDescriptions, maEngine, maProperties );
577 if ( pOptDlg->Execute() == RET_OK )
579 maEngine = pOptDlg->GetEngine();
580 maProperties = pOptDlg->GetProperties();
582 delete pOptDlg;
585 return 0;
588 //----------------------------------------------------------------------------
590 IMPL_LINK( ScOptSolverDlg, GetFocusHdl, Control*, pCtrl )
592 Edit* pEdit = NULL;
593 mpEdActive = NULL;
595 if( pCtrl == &maEdObjectiveCell || pCtrl == &maRBObjectiveCell )
596 pEdit = mpEdActive = &maEdObjectiveCell;
597 else if( pCtrl == &maEdTargetValue || pCtrl == &maRBTargetValue )
598 pEdit = mpEdActive = &maEdTargetValue;
599 else if( pCtrl == &maEdVariableCells || pCtrl == &maRBVariableCells )
600 pEdit = mpEdActive = &maEdVariableCells;
601 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
603 if( pCtrl == mpLeftEdit[nRow] || pCtrl == mpLeftButton[nRow] )
604 pEdit = mpEdActive = mpLeftEdit[nRow];
605 else if( pCtrl == mpRightEdit[nRow] || pCtrl == mpRightButton[nRow] )
606 pEdit = mpEdActive = mpRightEdit[nRow];
607 else if( pCtrl == mpOperator[nRow] ) // focus on "operator" list box
608 mpEdActive = mpRightEdit[nRow]; // use right edit for ref input, but don't change selection
610 if( pCtrl == &maRbValue ) // focus on "Value of" radio button
611 mpEdActive = &maEdTargetValue; // use value edit for ref input, but don't change selection
613 if( pEdit )
614 pEdit->SetSelection( Selection( 0, SELECTION_MAX ) );
616 return 0;
619 //----------------------------------------------------------------------------
621 IMPL_LINK( ScOptSolverDlg, LoseFocusHdl, Control*, EMPTYARG )
623 mbDlgLostFocus = !IsActive();
624 return 0;
627 //----------------------------------------------------------------------------
629 IMPL_LINK( ScOptSolverDlg, DelBtnHdl, PushButton*, pBtn )
631 for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
632 if( pBtn == mpDelButton[nRow] )
634 BOOL bHadFocus = pBtn->HasFocus();
636 ReadConditions();
637 long nVecPos = nScrollPos + nRow;
638 if ( nVecPos < (long)maConditions.size() )
640 maConditions.erase( maConditions.begin() + nVecPos );
641 ShowConditions();
643 if ( bHadFocus && !pBtn->IsEnabled() )
645 // If the button is disabled, focus would normally move to the next control,
646 // (left edit of the next row). Move it to left edit of this row instead.
648 mpEdActive = mpLeftEdit[nRow];
649 mpEdActive->GrabFocus();
654 return 0;
657 //----------------------------------------------------------------------------
659 IMPL_LINK( ScOptSolverDlg, TargetModifyHdl, Edit*, EMPTYARG )
661 // modify handler for the target edit:
662 // select "Value of" if something is input into the edit
663 if ( maEdTargetValue.GetText().Len() )
664 maRbValue.Check();
665 return 0;
668 IMPL_LINK( ScOptSolverDlg, CondModifyHdl, Edit*, EMPTYARG )
670 // modify handler for the condition edits, just to enable/disable "delete" buttons
671 ReadConditions();
672 EnableButtons();
673 return 0;
676 IMPL_LINK( ScOptSolverDlg, SelectHdl, ListBox*, EMPTYARG )
678 // select handler for operator list boxes, just to enable/disable "delete" buttons
679 ReadConditions();
680 EnableButtons();
681 return 0;
684 IMPL_LINK( ScOptSolverDlg, ScrollHdl, ScrollBar*, EMPTYARG )
686 ReadConditions();
687 nScrollPos = maScrollBar.GetThumbPos();
688 ShowConditions();
689 if( mpEdActive )
690 mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) );
691 return 0;
694 IMPL_LINK( ScOptSolverDlg, CursorUpHdl, ScCursorRefEdit*, pEdit )
696 if ( pEdit == mpLeftEdit[0] || pEdit == mpRightEdit[0] )
698 if ( nScrollPos > 0 )
700 ReadConditions();
701 --nScrollPos;
702 ShowConditions();
703 if( mpEdActive )
704 mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) );
707 else
709 formula::RefEdit* pFocus = NULL;
710 for ( sal_uInt16 nRow = 1; nRow < EDIT_ROW_COUNT; ++nRow ) // second row or below: move focus
712 if ( pEdit == mpLeftEdit[nRow] )
713 pFocus = mpLeftEdit[nRow-1];
714 else if ( pEdit == mpRightEdit[nRow] )
715 pFocus = mpRightEdit[nRow-1];
717 if (pFocus)
719 mpEdActive = pFocus;
720 pFocus->GrabFocus();
724 return 0;
727 IMPL_LINK( ScOptSolverDlg, CursorDownHdl, ScCursorRefEdit*, pEdit )
729 if ( pEdit == mpLeftEdit[EDIT_ROW_COUNT-1] || pEdit == mpRightEdit[EDIT_ROW_COUNT-1] )
731 //! limit scroll position?
732 ReadConditions();
733 ++nScrollPos;
734 ShowConditions();
735 if( mpEdActive )
736 mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) );
738 else
740 formula::RefEdit* pFocus = NULL;
741 for ( sal_uInt16 nRow = 0; nRow+1 < EDIT_ROW_COUNT; ++nRow ) // before last row: move focus
743 if ( pEdit == mpLeftEdit[nRow] )
744 pFocus = mpLeftEdit[nRow+1];
745 else if ( pEdit == mpRightEdit[nRow] )
746 pFocus = mpRightEdit[nRow+1];
748 if (pFocus)
750 mpEdActive = pFocus;
751 pFocus->GrabFocus();
755 return 0;
758 //----------------------------------------------------------------------------
760 void ScOptSolverDlg::ShowError( bool bCondition, formula::RefEdit* pFocus )
762 String aMessage = bCondition ? maConditionError : maInputError;
763 ErrorBox( this, WinBits( WB_OK | WB_DEF_OK ), aMessage ).Execute();
764 if (pFocus)
766 mpEdActive = pFocus;
767 pFocus->GrabFocus();
771 //----------------------------------------------------------------------------
773 bool ScOptSolverDlg::ParseRef( ScRange& rRange, const String& rInput, bool bAllowRange )
775 ScRangeUtil aRangeUtil;
776 ScAddress::Details aDetails(mpDoc->GetAddressConvention(), 0, 0);
777 USHORT nFlags = rRange.ParseAny( rInput, mpDoc, aDetails );
778 if ( nFlags & SCA_VALID )
780 if ( (nFlags & SCA_TAB_3D) == 0 )
781 rRange.aStart.SetTab( mnCurTab );
782 if ( (nFlags & SCA_TAB2_3D) == 0 )
783 rRange.aEnd.SetTab( rRange.aStart.Tab() );
784 return ( bAllowRange || rRange.aStart == rRange.aEnd );
786 else if ( aRangeUtil.MakeRangeFromName( rInput, mpDoc, mnCurTab, rRange, RUTL_NAMES, aDetails ) )
787 return ( bAllowRange || rRange.aStart == rRange.aEnd );
789 return false; // not recognized
792 bool ScOptSolverDlg::FindTimeout( sal_Int32& rTimeout )
794 bool bFound = false;
796 if ( !maProperties.getLength() )
797 maProperties = ScSolverUtil::GetDefaults( maEngine ); // get property defaults from component
799 sal_Int32 nPropCount = maProperties.getLength();
800 for (sal_Int32 nProp=0; nProp<nPropCount && !bFound; ++nProp)
802 const beans::PropertyValue& rValue = maProperties[nProp];
803 if ( rValue.Name.equalsAscii( SC_UNONAME_TIMEOUT ) )
804 bFound = ( rValue.Value >>= rTimeout );
806 return bFound;
809 bool ScOptSolverDlg::CallSolver() // return true -> close dialog after calling
811 // show progress dialog
813 ScSolverProgressDialog aProgress( this );
814 sal_Int32 nTimeout = 0;
815 if ( FindTimeout( nTimeout ) )
816 aProgress.SetTimeLimit( nTimeout );
817 else
818 aProgress.HideTimeLimit();
819 aProgress.Show();
820 aProgress.Update();
821 aProgress.Sync();
822 // try to make sure the progress dialog is painted before continuing
823 Application::Reschedule(true);
825 // collect solver parameters
827 ReadConditions();
829 uno::Reference<sheet::XSpreadsheetDocument> xDocument( mpDocShell->GetModel(), uno::UNO_QUERY );
831 ScRange aObjRange;
832 if ( !ParseRef( aObjRange, maEdObjectiveCell.GetText(), false ) )
834 ShowError( false, &maEdObjectiveCell );
835 return false;
837 table::CellAddress aObjective( aObjRange.aStart.Tab(), aObjRange.aStart.Col(), aObjRange.aStart.Row() );
839 // "changing cells" can be several ranges
840 ScRangeList aVarRanges;
841 if ( !ParseWithNames( aVarRanges, maEdVariableCells.GetText(), mpDoc ) )
843 ShowError( false, &maEdVariableCells );
844 return false;
846 uno::Sequence<table::CellAddress> aVariables;
847 sal_Int32 nVarPos = 0;
848 ULONG nRangeCount = aVarRanges.Count();
849 for (ULONG nRangePos=0; nRangePos<nRangeCount; ++nRangePos)
851 ScRange aRange(*aVarRanges.GetObject(nRangePos));
852 aRange.Justify();
853 SCTAB nTab = aRange.aStart.Tab();
855 // resolve into single cells
857 sal_Int32 nAdd = ( aRange.aEnd.Col() - aRange.aStart.Col() + 1 ) *
858 ( aRange.aEnd.Row() - aRange.aStart.Row() + 1 );
859 aVariables.realloc( nVarPos + nAdd );
861 for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
862 for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
863 aVariables[nVarPos++] = table::CellAddress( nTab, nCol, nRow );
866 uno::Sequence<sheet::SolverConstraint> aConstraints;
867 sal_Int32 nConstrPos = 0;
868 for ( std::vector<ScOptConditionRow>::const_iterator aConstrIter = maConditions.begin();
869 aConstrIter != maConditions.end(); ++aConstrIter )
871 if ( aConstrIter->aLeftStr.Len() )
873 sheet::SolverConstraint aConstraint;
874 // order of list box entries must match enum values
875 aConstraint.Operator = static_cast<sheet::SolverConstraintOperator>(aConstrIter->nOperator);
877 ScRange aLeftRange;
878 if ( !ParseRef( aLeftRange, aConstrIter->aLeftStr, true ) )
880 ShowError( true, NULL );
881 return false;
884 bool bIsRange = false;
885 ScRange aRightRange;
886 if ( ParseRef( aRightRange, aConstrIter->aRightStr, true ) )
888 if ( aRightRange.aStart == aRightRange.aEnd )
889 aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(),
890 aRightRange.aStart.Col(), aRightRange.aStart.Row() );
891 else if ( aRightRange.aEnd.Col()-aRightRange.aStart.Col() == aLeftRange.aEnd.Col()-aLeftRange.aStart.Col() &&
892 aRightRange.aEnd.Row()-aRightRange.aStart.Row() == aLeftRange.aEnd.Row()-aLeftRange.aStart.Row() )
893 bIsRange = true; // same size as "left" range, resolve into single cells
894 else
896 ShowError( true, NULL );
897 return false;
900 else
902 sal_uInt32 nFormat = 0; //! explicit language?
903 double fValue = 0.0;
904 if ( mpDoc->GetFormatTable()->IsNumberFormat( aConstrIter->aRightStr, nFormat, fValue ) )
905 aConstraint.Right <<= fValue;
906 else if ( aConstraint.Operator != sheet::SolverConstraintOperator_INTEGER &&
907 aConstraint.Operator != sheet::SolverConstraintOperator_BINARY )
909 ShowError( true, NULL );
910 return false;
914 // resolve into single cells
916 sal_Int32 nAdd = ( aLeftRange.aEnd.Col() - aLeftRange.aStart.Col() + 1 ) *
917 ( aLeftRange.aEnd.Row() - aLeftRange.aStart.Row() + 1 );
918 aConstraints.realloc( nConstrPos + nAdd );
920 for (SCROW nRow = aLeftRange.aStart.Row(); nRow <= aLeftRange.aEnd.Row(); ++nRow)
921 for (SCCOL nCol = aLeftRange.aStart.Col(); nCol <= aLeftRange.aEnd.Col(); ++nCol)
923 aConstraint.Left = table::CellAddress( aLeftRange.aStart.Tab(), nCol, nRow );
924 if ( bIsRange )
925 aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(),
926 aRightRange.aStart.Col() + ( nCol - aLeftRange.aStart.Col() ),
927 aRightRange.aStart.Row() + ( nRow - aLeftRange.aStart.Row() ) );
929 aConstraints[nConstrPos++] = aConstraint;
934 sal_Bool bMaximize = maRbMax.IsChecked();
935 if ( maRbValue.IsChecked() )
937 // handle "value of" with an additional constraint (and then minimize)
939 sheet::SolverConstraint aConstraint;
940 aConstraint.Left = aObjective;
941 aConstraint.Operator = sheet::SolverConstraintOperator_EQUAL;
943 String aValStr = maEdTargetValue.GetText();
944 ScRange aRightRange;
945 if ( ParseRef( aRightRange, aValStr, false ) )
946 aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(),
947 aRightRange.aStart.Col(), aRightRange.aStart.Row() );
948 else
950 sal_uInt32 nFormat = 0; //! explicit language?
951 double fValue = 0.0;
952 if ( mpDoc->GetFormatTable()->IsNumberFormat( aValStr, nFormat, fValue ) )
953 aConstraint.Right <<= fValue;
954 else
956 ShowError( false, &maEdTargetValue );
957 return false;
961 aConstraints.realloc( nConstrPos + 1 );
962 aConstraints[nConstrPos++] = aConstraint;
965 // copy old document values
967 sal_Int32 nVarCount = aVariables.getLength();
968 uno::Sequence<double> aOldValues;
969 aOldValues.realloc( nVarCount );
970 for (nVarPos=0; nVarPos<nVarCount; ++nVarPos)
972 ScAddress aCellPos;
973 ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] );
974 aOldValues[nVarPos] = mpDoc->GetValue( aCellPos );
977 // create and initialize solver
979 uno::Reference<sheet::XSolver> xSolver = ScSolverUtil::GetSolver( maEngine );
980 DBG_ASSERT( xSolver.is(), "can't get solver component" );
981 if ( !xSolver.is() )
982 return false;
984 xSolver->setDocument( xDocument );
985 xSolver->setObjective( aObjective );
986 xSolver->setVariables( aVariables );
987 xSolver->setConstraints( aConstraints );
988 xSolver->setMaximize( bMaximize );
990 // set options
991 uno::Reference<beans::XPropertySet> xOptProp(xSolver, uno::UNO_QUERY);
992 if ( xOptProp.is() )
994 sal_Int32 nPropCount = maProperties.getLength();
995 for (sal_Int32 nProp=0; nProp<nPropCount; ++nProp)
997 const beans::PropertyValue& rValue = maProperties[nProp];
1000 xOptProp->setPropertyValue( rValue.Name, rValue.Value );
1002 catch ( uno::Exception & )
1004 DBG_ERRORFILE("Exception in solver option property");
1009 xSolver->solve();
1010 sal_Bool bSuccess = xSolver->getSuccess();
1012 aProgress.Hide();
1013 bool bClose = false;
1014 bool bRestore = true; // restore old values unless a solution is accepted
1015 if ( bSuccess )
1017 // put solution into document so it is visible when asking
1018 uno::Sequence<double> aSolution = xSolver->getSolution();
1019 if ( aSolution.getLength() == nVarCount )
1021 mpDocShell->LockPaint();
1022 ScDocFunc aFunc(*mpDocShell);
1023 for (nVarPos=0; nVarPos<nVarCount; ++nVarPos)
1025 ScAddress aCellPos;
1026 ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] );
1027 aFunc.PutCell( aCellPos, new ScValueCell( aSolution[nVarPos] ), TRUE );
1029 mpDocShell->UnlockPaint();
1031 //! else error?
1033 // take formatted result from document (result value from component is ignored)
1034 String aResultStr;
1035 mpDoc->GetString( (SCCOL)aObjective.Column, (SCROW)aObjective.Row, (SCTAB)aObjective.Sheet, aResultStr );
1036 ScSolverSuccessDialog aDialog( this, aResultStr );
1037 if ( aDialog.Execute() == RET_OK )
1039 // keep results and close dialog
1040 bRestore = false;
1041 bClose = true;
1044 else
1046 rtl::OUString aError;
1047 uno::Reference<sheet::XSolverDescription> xDesc( xSolver, uno::UNO_QUERY );
1048 if ( xDesc.is() )
1049 aError = xDesc->getStatusDescription(); // error description from component
1050 ScSolverNoSolutionDialog aDialog( this, aError );
1051 aDialog.Execute();
1054 if ( bRestore ) // restore old values
1056 mpDocShell->LockPaint();
1057 ScDocFunc aFunc(*mpDocShell);
1058 for (nVarPos=0; nVarPos<nVarCount; ++nVarPos)
1060 ScAddress aCellPos;
1061 ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] );
1062 aFunc.PutCell( aCellPos, new ScValueCell( aOldValues[nVarPos] ), TRUE );
1064 mpDocShell->UnlockPaint();
1067 return bClose;