1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: optsolver.cxx,v $
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"
47 #include "docfunc.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
);
77 ScSolverProgressDialog::~ScSolverProgressDialog()
81 void ScSolverProgressDialog::HideTimeLimit()
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
);
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
);
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
) )
155 maCursorUpLink
.Call( this );
157 maCursorDownLink
.Call( this );
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
),
175 maVariable( rVariable
),
176 maConditions( rConditions
),
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() ),
244 mbDlgLostFocus ( false ),
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
;
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();
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();
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
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() )
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
);
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;
470 mpEdActive
->GrabFocus();
479 //----------------------------------------------------------------------------
481 void ScOptSolverDlg::SetReference( const ScRange
& rRef
, ScDocument
* pDocP
)
485 if ( rRef
.aStart
!= rRef
.aEnd
)
486 RefInputStart(mpEdActive
);
488 // "target"/"value": single cell
489 bool bSingle
= ( mpEdActive
== &maEdObjectiveCell
|| mpEdActive
== &maEdTargetValue
);
492 ScAddress aAdr
= rRef
.aStart
;
493 ScRange
aNewRef( rRef
);
498 if ( pDocP
->GetRangeAtBlock( aNewRef
, &aName
) ) // named range: show name
500 else // format cell/range reference
502 USHORT nFmt
= ( aAdr
.Tab() == mnCurTab
) ? SCA_ABS
: SCA_ABS_3D
;
504 aAdr
.Format( aStr
, nFmt
, pDocP
, pDocP
->GetAddressConvention() );
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();
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
);
522 mpEdActive
->SetRefString( aStr
);
527 // select "Value of" if a ref is input into "target" edit
528 if ( mpEdActive
== &maEdTargetValue
)
533 //----------------------------------------------------------------------------
535 BOOL
ScOptSolverDlg::IsRefInputMode() const
537 return mpEdActive
!= NULL
;
540 //----------------------------------------------------------------------------
543 IMPL_LINK( ScOptSolverDlg
, BtnHdl
, PushButton
*, pBtn
)
545 if ( pBtn
== &maBtnSolve
|| pBtn
== &maBtnCancel
)
547 bool bSolve
= ( pBtn
== &maBtnSolve
);
549 SetDispatcherLock( FALSE
);
554 bClose
= CallSolver();
558 // Close: write dialog settings to DocShell for subsequent calls
560 ScOptSolverSave
aSave(
561 maEdObjectiveCell
.GetText(), maRbMax
.IsChecked(), maRbMin
.IsChecked(), maRbValue
.IsChecked(),
562 maEdTargetValue
.GetText(), maEdVariableCells
.GetText(), maConditions
, maEngine
, maProperties
);
563 mpDocShell
->SetSolverSaveData( aSave
);
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();
588 //----------------------------------------------------------------------------
590 IMPL_LINK( ScOptSolverDlg
, GetFocusHdl
, Control
*, pCtrl
)
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
614 pEdit
->SetSelection( Selection( 0, SELECTION_MAX
) );
619 //----------------------------------------------------------------------------
621 IMPL_LINK( ScOptSolverDlg
, LoseFocusHdl
, Control
*, EMPTYARG
)
623 mbDlgLostFocus
= !IsActive();
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();
637 long nVecPos
= nScrollPos
+ nRow
;
638 if ( nVecPos
< (long)maConditions
.size() )
640 maConditions
.erase( maConditions
.begin() + nVecPos
);
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();
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() )
668 IMPL_LINK( ScOptSolverDlg
, CondModifyHdl
, Edit
*, EMPTYARG
)
670 // modify handler for the condition edits, just to enable/disable "delete" buttons
676 IMPL_LINK( ScOptSolverDlg
, SelectHdl
, ListBox
*, EMPTYARG
)
678 // select handler for operator list boxes, just to enable/disable "delete" buttons
684 IMPL_LINK( ScOptSolverDlg
, ScrollHdl
, ScrollBar
*, EMPTYARG
)
687 nScrollPos
= maScrollBar
.GetThumbPos();
690 mpEdActive
->SetSelection( Selection( 0, SELECTION_MAX
) );
694 IMPL_LINK( ScOptSolverDlg
, CursorUpHdl
, ScCursorRefEdit
*, pEdit
)
696 if ( pEdit
== mpLeftEdit
[0] || pEdit
== mpRightEdit
[0] )
698 if ( nScrollPos
> 0 )
704 mpEdActive
->SetSelection( Selection( 0, SELECTION_MAX
) );
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];
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?
736 mpEdActive
->SetSelection( Selection( 0, SELECTION_MAX
) );
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];
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();
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
)
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
);
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
);
818 aProgress
.HideTimeLimit();
822 // try to make sure the progress dialog is painted before continuing
823 Application::Reschedule(true);
825 // collect solver parameters
829 uno::Reference
<sheet::XSpreadsheetDocument
> xDocument( mpDocShell
->GetModel(), uno::UNO_QUERY
);
832 if ( !ParseRef( aObjRange
, maEdObjectiveCell
.GetText(), false ) )
834 ShowError( false, &maEdObjectiveCell
);
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
);
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
));
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
);
878 if ( !ParseRef( aLeftRange
, aConstrIter
->aLeftStr
, true ) )
880 ShowError( true, NULL
);
884 bool bIsRange
= false;
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
896 ShowError( true, NULL
);
902 sal_uInt32 nFormat
= 0; //! explicit language?
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
);
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
);
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();
945 if ( ParseRef( aRightRange
, aValStr
, false ) )
946 aConstraint
.Right
<<= table::CellAddress( aRightRange
.aStart
.Tab(),
947 aRightRange
.aStart
.Col(), aRightRange
.aStart
.Row() );
950 sal_uInt32 nFormat
= 0; //! explicit language?
952 if ( mpDoc
->GetFormatTable()->IsNumberFormat( aValStr
, nFormat
, fValue
) )
953 aConstraint
.Right
<<= fValue
;
956 ShowError( false, &maEdTargetValue
);
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
)
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" );
984 xSolver
->setDocument( xDocument
);
985 xSolver
->setObjective( aObjective
);
986 xSolver
->setVariables( aVariables
);
987 xSolver
->setConstraints( aConstraints
);
988 xSolver
->setMaximize( bMaximize
);
991 uno::Reference
<beans::XPropertySet
> xOptProp(xSolver
, uno::UNO_QUERY
);
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");
1010 sal_Bool bSuccess
= xSolver
->getSuccess();
1013 bool bClose
= false;
1014 bool bRestore
= true; // restore old values unless a solution is accepted
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
)
1026 ScUnoConversion::FillScAddress( aCellPos
, aVariables
[nVarPos
] );
1027 aFunc
.PutCell( aCellPos
, new ScValueCell( aSolution
[nVarPos
] ), TRUE
);
1029 mpDocShell
->UnlockPaint();
1033 // take formatted result from document (result value from component is ignored)
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
1046 rtl::OUString aError
;
1047 uno::Reference
<sheet::XSolverDescription
> xDesc( xSolver
, uno::UNO_QUERY
);
1049 aError
= xDesc
->getStatusDescription(); // error description from component
1050 ScSolverNoSolutionDialog
aDialog( this, aError
);
1054 if ( bRestore
) // restore old values
1056 mpDocShell
->LockPaint();
1057 ScDocFunc
aFunc(*mpDocShell
);
1058 for (nVarPos
=0; nVarPos
<nVarCount
; ++nVarPos
)
1061 ScUnoConversion::FillScAddress( aCellPos
, aVariables
[nVarPos
] );
1062 aFunc
.PutCell( aCellPos
, new ScValueCell( aOldValues
[nVarPos
] ), TRUE
);
1064 mpDocShell
->UnlockPaint();