1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "rangelst.hxx"
21 #include "scitems.hxx"
22 #include <sfx2/bindings.hxx>
23 #include <sfx2/imagemgr.hxx>
24 #include <svl/zforlist.hxx>
25 #include <vcl/builder.hxx>
26 #include <vcl/msgbox.hxx>
27 #include <vcl/svapp.hxx>
29 #include "uiitems.hxx"
30 #include "reffact.hxx"
32 #include "docfunc.hxx"
33 #include "formulacell.hxx"
34 #include "rangeutl.hxx"
35 #include "scresid.hxx"
36 #include "convuno.hxx"
37 #include "unonames.hxx"
38 #include "solveroptions.hxx"
39 #include "solverutil.hxx"
40 #include "globstr.hrc"
41 #include "optsolver.hrc"
43 #include "optsolver.hxx"
45 #include <com/sun/star/sheet/Solver.hpp>
46 #include <com/sun/star/sheet/XSolverDescription.hpp>
48 using namespace com::sun::star
;
50 //----------------------------------------------------------------------------
52 ScSolverProgressDialog::ScSolverProgressDialog( Window
* pParent
)
53 : ModelessDialog( pParent
, ScResId( RID_SCDLG_SOLVER_PROGRESS
) ),
54 maFtProgress ( this, ScResId( FT_PROGRESS
) ),
55 maFtTime ( this, ScResId( FT_TIMELIMIT
) ),
56 maFlButtons ( this, ScResId( FL_BUTTONS
) ),
57 maBtnOk ( this, ScResId( BTN_OK
) )
59 maBtnOk
.Enable(false);
63 ScSolverProgressDialog::~ScSolverProgressDialog()
67 void ScSolverProgressDialog::HideTimeLimit()
72 void ScSolverProgressDialog::SetTimeLimit( sal_Int32 nSeconds
)
74 OUString aOld
= maFtTime
.GetText();
75 OUString aNew
= aOld
.getToken(0,'#') + OUString::number( nSeconds
) + aOld
.getToken(1,'#');
76 maFtTime
.SetText( aNew
);
79 //----------------------------------------------------------------------------
81 ScSolverNoSolutionDialog::ScSolverNoSolutionDialog( Window
* pParent
, const OUString
& rErrorText
)
82 : ModalDialog( pParent
, ScResId( RID_SCDLG_SOLVER_NOSOLUTION
) ),
83 maFtNoSolution ( this, ScResId( FT_NOSOLUTION
) ),
84 maFtErrorText ( this, ScResId( FT_ERRORTEXT
) ),
85 maFlButtons ( this, ScResId( FL_BUTTONS
) ),
86 maBtnOk ( this, ScResId( BTN_OK
) )
88 maFtErrorText
.SetText( rErrorText
);
92 ScSolverNoSolutionDialog::~ScSolverNoSolutionDialog()
96 //----------------------------------------------------------------------------
98 ScSolverSuccessDialog::ScSolverSuccessDialog( Window
* pParent
, const OUString
& rSolution
)
99 : ModalDialog( pParent
, ScResId( RID_SCDLG_SOLVER_SUCCESS
) ),
100 maFtSuccess ( this, ScResId( FT_SUCCESS
) ),
101 maFtResult ( this, ScResId( FT_RESULT
) ),
102 maFtQuestion ( this, ScResId( FT_QUESTION
) ),
103 maFlButtons ( this, ScResId( FL_BUTTONS
) ),
104 maBtnOk ( this, ScResId( BTN_OK
) ),
105 maBtnCancel ( this, ScResId( BTN_CANCEL
) )
107 OUString aMessage
= maFtResult
.GetText() + " " + rSolution
;
108 maFtResult
.SetText( aMessage
);
112 ScSolverSuccessDialog::~ScSolverSuccessDialog()
116 //----------------------------------------------------------------------------
118 ScCursorRefEdit::ScCursorRefEdit( Window
* pParent
, Window
*pLabel
)
119 : formula::RefEdit( pParent
, pLabel
)
123 extern "C" SAL_DLLPUBLIC_EXPORT Window
* SAL_CALL
makeScCursorRefEdit(Window
*pParent
,
124 VclBuilder::stringmap
&)
126 return new ScCursorRefEdit(pParent
, NULL
);
129 void ScCursorRefEdit::SetCursorLinks( const Link
& rUp
, const Link
& rDown
)
131 maCursorUpLink
= rUp
;
132 maCursorDownLink
= rDown
;
135 void ScCursorRefEdit::KeyInput( const KeyEvent
& rKEvt
)
137 KeyCode aCode
= rKEvt
.GetKeyCode();
138 bool bUp
= (aCode
.GetCode() == KEY_UP
);
139 bool bDown
= (aCode
.GetCode() == KEY_DOWN
);
140 if ( !aCode
.IsShift() && !aCode
.IsMod1() && !aCode
.IsMod2() && ( bUp
|| bDown
) )
143 maCursorUpLink
.Call( this );
145 maCursorDownLink
.Call( this );
148 formula::RefEdit::KeyInput( rKEvt
);
151 //----------------------------------------------------------------------------
153 ScOptSolverSave::ScOptSolverSave( const OUString
& rObjective
, sal_Bool bMax
, sal_Bool bMin
, sal_Bool bValue
,
154 const OUString
& rTarget
, const OUString
& rVariable
,
155 const std::vector
<ScOptConditionRow
>& rConditions
,
156 const OUString
& rEngine
,
157 const uno::Sequence
<beans::PropertyValue
>& rProperties
) :
158 maObjective( rObjective
),
163 maVariable( rVariable
),
164 maConditions( rConditions
),
166 maProperties( rProperties
)
170 //============================================================================
171 // class ScOptSolverDlg
172 //----------------------------------------------------------------------------
174 ScOptSolverDlg::ScOptSolverDlg( SfxBindings
* pB
, SfxChildWindow
* pCW
, Window
* pParent
,
175 ScDocShell
* pDocSh
, ScAddress aCursorPos
)
177 : ScAnyRefDlg(pB
, pCW
, pParent
, "SolverDialog", "modules/scalc/ui/solverdlg.ui")
178 , maInputError(ScGlobal::GetRscString(STR_INVALIDINPUT
))
179 , maConditionError(ScGlobal::GetRscString(STR_INVALIDCONDITION
))
182 , mpDoc(pDocSh
->GetDocument())
183 , mnCurTab(aCursorPos
.Tab())
185 , mbDlgLostFocus(false)
188 get(m_pFtObjectiveCell
, "targetlabel");
189 get(m_pEdObjectiveCell
, "targetedit");
190 m_pEdObjectiveCell
->SetReferences(this, m_pFtObjectiveCell
);
191 get(m_pRBObjectiveCell
, "targetbutton");
192 m_pRBObjectiveCell
->SetReferences(this, m_pEdObjectiveCell
);
193 get(m_pRbMax
, "max");
194 get(m_pRbMin
, "min");
195 get(m_pRbValue
, "value");
196 get(m_pEdTargetValue
, "valueedit");
197 m_pEdTargetValue
->SetReferences(this, get
<FixedText
>("result"));
198 get(m_pRBTargetValue
, "valuebutton");
199 m_pRBTargetValue
->SetReferences(this, m_pEdTargetValue
);
200 get(m_pFtVariableCells
, "changelabel");
201 get(m_pEdVariableCells
, "changeedit");
202 m_pEdVariableCells
->SetReferences(this, m_pFtVariableCells
);
203 get(m_pRBVariableCells
, "changebutton");
204 m_pRBVariableCells
->SetReferences(this, m_pEdVariableCells
);
205 get(m_pFtCellRef
, "cellreflabel");
206 get(m_pEdLeft1
, "ref1edit");
207 m_pEdLeft1
->SetReferences(this, m_pFtCellRef
);
208 get(m_pRBLeft1
, "ref1button");
209 m_pRBLeft1
->SetReferences(this, m_pEdLeft1
);
210 get(m_pFtOperator
, "oplabel");
211 get(m_pLbOp1
, "op1list");
212 get(m_pFtConstraint
, "constraintlabel");
213 get(m_pEdRight1
, "val1edit");
214 m_pEdRight1
->SetReferences(this, m_pFtConstraint
);
215 get(m_pRBRight1
, "val1button");
216 m_pRBRight1
->SetReferences(this, m_pEdRight1
);
217 get(m_pBtnDel1
, "del1");
218 get(m_pEdLeft2
, "ref2edit");
219 m_pEdLeft2
->SetReferences(this, m_pFtCellRef
);
220 get(m_pRBLeft2
, "ref2button");
221 m_pRBLeft2
->SetReferences(this, m_pEdLeft2
);
222 get(m_pLbOp2
, "op2list");
223 get(m_pEdRight2
, "val2edit");
224 m_pEdRight2
->SetReferences(this, m_pFtConstraint
);
225 get(m_pRBRight2
, "val2button");
226 m_pRBRight2
->SetReferences(this, m_pEdRight2
);
227 get(m_pBtnDel2
, "del2");
228 get(m_pEdLeft3
, "ref3edit");
229 m_pEdLeft3
->SetReferences(this, m_pFtCellRef
);
230 get(m_pRBLeft3
, "ref3button");
231 m_pRBLeft3
->SetReferences(this, m_pEdLeft3
);
232 get(m_pLbOp3
, "op3list");
233 get(m_pEdRight3
, "val3edit");
234 m_pEdRight3
->SetReferences(this, m_pFtConstraint
);
235 get(m_pRBRight3
, "val3button");
236 m_pRBRight3
->SetReferences(this, m_pEdRight3
);
237 get(m_pBtnDel3
, "del3");
238 get(m_pEdLeft4
, "ref4edit");
239 m_pEdLeft4
->SetReferences(this, m_pFtCellRef
);
240 get(m_pRBLeft4
, "ref4button");
241 m_pRBLeft4
->SetReferences(this, m_pEdLeft4
);
242 get(m_pLbOp4
, "op4list");
243 get(m_pEdRight4
, "val4edit");
244 m_pEdRight4
->SetReferences(this, m_pFtConstraint
);
245 get(m_pRBRight4
, "val4button");
246 m_pRBRight4
->SetReferences(this, m_pEdRight4
);
247 get(m_pBtnDel4
, "del4");
248 get(m_pScrollBar
, "scrollbar");
249 get(m_pBtnOpt
, "options");
250 get(m_pBtnCancel
, "close");
251 get(m_pBtnSolve
, "solve");
253 mpLeftEdit
[0] = m_pEdLeft1
;
254 mpLeftButton
[0] = m_pRBLeft1
;
255 mpRightEdit
[0] = m_pEdRight1
;
256 mpRightButton
[0] = m_pRBRight1
;
257 mpOperator
[0] = m_pLbOp1
;
258 mpDelButton
[0] = m_pBtnDel1
;
260 mpLeftEdit
[1] = m_pEdLeft2
;
261 mpLeftButton
[1] = m_pRBLeft2
;
262 mpRightEdit
[1] = m_pEdRight2
;
263 mpRightButton
[1] = m_pRBRight2
;
264 mpOperator
[1] = m_pLbOp2
;
265 mpDelButton
[1] = m_pBtnDel2
;
267 mpLeftEdit
[2] = m_pEdLeft3
;
268 mpLeftButton
[2] = m_pRBLeft3
;
269 mpRightEdit
[2] = m_pEdRight3
;
270 mpRightButton
[2] = m_pRBRight3
;
271 mpOperator
[2] = m_pLbOp3
;
272 mpDelButton
[2] = m_pBtnDel3
;
274 mpLeftEdit
[3] = m_pEdLeft4
;
275 mpLeftButton
[3] = m_pRBLeft4
;
276 mpRightEdit
[3] = m_pEdRight4
;
277 mpRightButton
[3] = m_pRBRight4
;
278 mpOperator
[3] = m_pLbOp4
;
279 mpDelButton
[3] = m_pBtnDel4
;
281 m_pEdLeft2
->SetAccessibleName(m_pFtCellRef
->GetText());
282 m_pLbOp2
->SetAccessibleName(m_pFtOperator
->GetText());
283 m_pEdRight2
->SetAccessibleName(m_pFtConstraint
->GetText());
284 m_pEdLeft3
->SetAccessibleName(m_pFtCellRef
->GetText());
285 m_pLbOp3
->SetAccessibleName(m_pFtOperator
->GetText());
286 m_pEdRight3
->SetAccessibleName(m_pFtConstraint
->GetText());
287 m_pEdLeft4
->SetAccessibleName(m_pFtCellRef
->GetText());
288 m_pLbOp4
->SetAccessibleName(m_pFtOperator
->GetText());
289 m_pEdRight4
->SetAccessibleName(m_pFtConstraint
->GetText());
294 //----------------------------------------------------------------------------
296 ScOptSolverDlg::~ScOptSolverDlg()
300 //----------------------------------------------------------------------------
302 void ScOptSolverDlg::Init(const ScAddress
& rCursorPos
)
304 // Get the "Delete Rows" commandimagelist images from sfx instead of
305 // adding a second copy to sc (see ScTbxInsertCtrl::StateChanged)
307 OUString
aSlotURL( "slot:" );
308 aSlotURL
+= OUString::number( SID_DEL_ROWS
);
309 uno::Reference
<frame::XFrame
> xFrame
= GetBindings().GetActiveFrame();
310 Image aDelNm
= ::GetImage( xFrame
, aSlotURL
, false );
312 for ( sal_uInt16 nRow
= 0; nRow
< EDIT_ROW_COUNT
; ++nRow
)
314 mpDelButton
[nRow
]->SetModeImage( aDelNm
);
317 m_pBtnOpt
->SetClickHdl( LINK( this, ScOptSolverDlg
, BtnHdl
) );
318 m_pBtnCancel
->SetClickHdl( LINK( this, ScOptSolverDlg
, BtnHdl
) );
319 m_pBtnSolve
->SetClickHdl( LINK( this, ScOptSolverDlg
, BtnHdl
) );
321 Link aLink
= LINK( this, ScOptSolverDlg
, GetFocusHdl
);
322 m_pEdObjectiveCell
->SetGetFocusHdl( aLink
);
323 m_pRBObjectiveCell
->SetGetFocusHdl( aLink
);
324 m_pEdTargetValue
->SetGetFocusHdl( aLink
);
325 m_pRBTargetValue
->SetGetFocusHdl( aLink
);
326 m_pEdVariableCells
->SetGetFocusHdl( aLink
);
327 m_pRBVariableCells
->SetGetFocusHdl( aLink
);
328 m_pRbValue
->SetGetFocusHdl( aLink
);
329 for ( sal_uInt16 nRow
= 0; nRow
< EDIT_ROW_COUNT
; ++nRow
)
331 mpLeftEdit
[nRow
]->SetGetFocusHdl( aLink
);
332 mpLeftButton
[nRow
]->SetGetFocusHdl( aLink
);
333 mpRightEdit
[nRow
]->SetGetFocusHdl( aLink
);
334 mpRightButton
[nRow
]->SetGetFocusHdl( aLink
);
335 mpOperator
[nRow
]->SetGetFocusHdl( aLink
);
338 aLink
= LINK( this, ScOptSolverDlg
, LoseFocusHdl
);
339 m_pEdObjectiveCell
->SetLoseFocusHdl( aLink
);
340 m_pRBObjectiveCell
->SetLoseFocusHdl( aLink
);
341 m_pEdTargetValue
->SetLoseFocusHdl( aLink
);
342 m_pRBTargetValue
-> SetLoseFocusHdl( aLink
);
343 m_pEdVariableCells
->SetLoseFocusHdl( aLink
);
344 m_pRBVariableCells
->SetLoseFocusHdl( aLink
);
345 for ( sal_uInt16 nRow
= 0; nRow
< EDIT_ROW_COUNT
; ++nRow
)
347 mpLeftEdit
[nRow
]->SetLoseFocusHdl( aLink
);
348 mpLeftButton
[nRow
]->SetLoseFocusHdl( aLink
);
349 mpRightEdit
[nRow
]->SetLoseFocusHdl( aLink
);
350 mpRightButton
[nRow
]->SetLoseFocusHdl( aLink
);
353 Link aCursorUp
= LINK( this, ScOptSolverDlg
, CursorUpHdl
);
354 Link aCursorDown
= LINK( this, ScOptSolverDlg
, CursorDownHdl
);
355 Link aCondModify
= LINK( this, ScOptSolverDlg
, CondModifyHdl
);
356 for ( sal_uInt16 nRow
= 0; nRow
< EDIT_ROW_COUNT
; ++nRow
)
358 mpLeftEdit
[nRow
]->SetCursorLinks( aCursorUp
, aCursorDown
);
359 mpRightEdit
[nRow
]->SetCursorLinks( aCursorUp
, aCursorDown
);
360 mpLeftEdit
[nRow
]->SetModifyHdl( aCondModify
);
361 mpRightEdit
[nRow
]->SetModifyHdl( aCondModify
);
362 mpDelButton
[nRow
]->SetClickHdl( LINK( this, ScOptSolverDlg
, DelBtnHdl
) );
363 mpOperator
[nRow
]->SetSelectHdl( LINK( this, ScOptSolverDlg
, SelectHdl
) );
365 m_pEdTargetValue
->SetModifyHdl( LINK( this, ScOptSolverDlg
, TargetModifyHdl
) );
367 m_pScrollBar
->SetEndScrollHdl( LINK( this, ScOptSolverDlg
, ScrollHdl
) );
368 m_pScrollBar
->SetScrollHdl( LINK( this, ScOptSolverDlg
, ScrollHdl
) );
370 m_pScrollBar
->SetPageSize( EDIT_ROW_COUNT
);
371 m_pScrollBar
->SetVisibleSize( EDIT_ROW_COUNT
);
372 m_pScrollBar
->SetLineSize( 1 );
373 // Range is set in ShowConditions
375 // get available solver implementations
376 //! sort by descriptions?
377 ScSolverUtil::GetImplementations( maImplNames
, maDescriptions
);
378 sal_Int32 nImplCount
= maImplNames
.getLength();
380 const ScOptSolverSave
* pOldData
= mpDocShell
->GetSolverSaveData();
383 m_pEdObjectiveCell
->SetRefString( pOldData
->GetObjective() );
384 m_pRbMax
->Check( pOldData
->GetMax() );
385 m_pRbMin
->Check( pOldData
->GetMin() );
386 m_pRbValue
->Check( pOldData
->GetValue() );
387 m_pEdTargetValue
->SetRefString( pOldData
->GetTarget() );
388 m_pEdVariableCells
->SetRefString( pOldData
->GetVariable() );
389 maConditions
= pOldData
->GetConditions();
390 maEngine
= pOldData
->GetEngine();
391 maProperties
= pOldData
->GetProperties();
397 if ( !mpDoc
->GetRangeAtBlock( ScRange(rCursorPos
), &aCursorStr
) )
398 aCursorStr
= rCursorPos
.Format(SCA_ABS
, NULL
, mpDoc
->GetAddressConvention());
399 m_pEdObjectiveCell
->SetRefString( aCursorStr
);
400 if ( nImplCount
> 0 )
401 maEngine
= maImplNames
[0]; // use first implementation
405 m_pEdObjectiveCell
->GrabFocus();
406 mpEdActive
= m_pEdObjectiveCell
;
409 //----------------------------------------------------------------------------
411 void ScOptSolverDlg::ReadConditions()
413 for ( sal_uInt16 nRow
= 0; nRow
< EDIT_ROW_COUNT
; ++nRow
)
415 ScOptConditionRow aRowEntry
;
416 aRowEntry
.aLeftStr
= mpLeftEdit
[nRow
]->GetText();
417 aRowEntry
.aRightStr
= mpRightEdit
[nRow
]->GetText();
418 aRowEntry
.nOperator
= mpOperator
[nRow
]->GetSelectEntryPos();
420 long nVecPos
= nScrollPos
+ nRow
;
421 if ( nVecPos
>= (long)maConditions
.size() && !aRowEntry
.IsDefault() )
422 maConditions
.resize( nVecPos
+ 1 );
424 if ( nVecPos
< (long)maConditions
.size() )
425 maConditions
[nVecPos
] = aRowEntry
;
427 // remove default entries at the end
428 size_t nSize
= maConditions
.size();
429 while ( nSize
> 0 && maConditions
[ nSize
-1 ].IsDefault() )
431 maConditions
.resize( nSize
);
435 void ScOptSolverDlg::ShowConditions()
437 for ( sal_uInt16 nRow
= 0; nRow
< EDIT_ROW_COUNT
; ++nRow
)
439 ScOptConditionRow aRowEntry
;
441 long nVecPos
= nScrollPos
+ nRow
;
442 if ( nVecPos
< (long)maConditions
.size() )
443 aRowEntry
= maConditions
[nVecPos
];
445 mpLeftEdit
[nRow
]->SetRefString( aRowEntry
.aLeftStr
);
446 mpRightEdit
[nRow
]->SetRefString( aRowEntry
.aRightStr
);
447 mpOperator
[nRow
]->SelectEntryPos( aRowEntry
.nOperator
);
450 // allow to scroll one page behind the visible or stored rows
451 long nVisible
= nScrollPos
+ EDIT_ROW_COUNT
;
452 long nMax
= std::max( nVisible
, (long) maConditions
.size() );
453 m_pScrollBar
->SetRange( Range( 0, nMax
+ EDIT_ROW_COUNT
) );
454 m_pScrollBar
->SetThumbPos( nScrollPos
);
459 void ScOptSolverDlg::EnableButtons()
461 for ( sal_uInt16 nRow
= 0; nRow
< EDIT_ROW_COUNT
; ++nRow
)
463 long nVecPos
= nScrollPos
+ nRow
;
464 mpDelButton
[nRow
]->Enable( nVecPos
< (long)maConditions
.size() );
468 //----------------------------------------------------------------------------
470 sal_Bool
ScOptSolverDlg::Close()
472 return DoClose( ScOptSolverDlgWrapper::GetChildWindowId() );
475 //----------------------------------------------------------------------------
477 void ScOptSolverDlg::SetActive()
479 if ( mbDlgLostFocus
)
481 mbDlgLostFocus
= false;
483 mpEdActive
->GrabFocus();
492 //----------------------------------------------------------------------------
494 void ScOptSolverDlg::SetReference( const ScRange
& rRef
, ScDocument
* pDocP
)
498 if ( rRef
.aStart
!= rRef
.aEnd
)
499 RefInputStart(mpEdActive
);
501 // "target"/"value": single cell
502 bool bSingle
= ( mpEdActive
== m_pEdObjectiveCell
|| mpEdActive
== m_pEdTargetValue
);
505 ScAddress aAdr
= rRef
.aStart
;
506 ScRange
aNewRef( rRef
);
511 if ( pDocP
->GetRangeAtBlock( aNewRef
, &aName
) ) // named range: show name
513 else // format cell/range reference
515 sal_uInt16 nFmt
= ( aAdr
.Tab() == mnCurTab
) ? SCA_ABS
: SCA_ABS_3D
;
517 aStr
= aAdr
.Format(nFmt
, pDocP
, pDocP
->GetAddressConvention());
519 aStr
= rRef
.Format(nFmt
| SCR_ABS
, pDocP
, pDocP
->GetAddressConvention());
522 // variable cells can be several ranges, so only the selection is replaced
523 if ( mpEdActive
== m_pEdVariableCells
)
525 OUString aVal
= mpEdActive
->GetText();
526 Selection aSel
= mpEdActive
->GetSelection();
528 aVal
= aVal
.replaceAt( aSel
.Min(), aSel
.Len(), aStr
);
529 Selection
aNewSel( aSel
.Min(), aSel
.Min()+aStr
.getLength() );
530 mpEdActive
->SetRefString( aVal
);
531 mpEdActive
->SetSelection( aNewSel
);
534 mpEdActive
->SetRefString( aStr
);
539 // select "Value of" if a ref is input into "target" edit
540 if ( mpEdActive
== m_pEdTargetValue
)
545 //----------------------------------------------------------------------------
547 sal_Bool
ScOptSolverDlg::IsRefInputMode() const
549 return mpEdActive
!= NULL
;
552 //----------------------------------------------------------------------------
555 IMPL_LINK( ScOptSolverDlg
, BtnHdl
, PushButton
*, pBtn
)
557 if ( pBtn
== m_pBtnSolve
|| pBtn
== m_pBtnCancel
)
559 bool bSolve
= ( pBtn
== m_pBtnSolve
);
561 SetDispatcherLock( false );
566 bClose
= CallSolver();
570 // Close: write dialog settings to DocShell for subsequent calls
572 ScOptSolverSave
aSave(
573 m_pEdObjectiveCell
->GetText(), m_pRbMax
->IsChecked(), m_pRbMin
->IsChecked(), m_pRbValue
->IsChecked(),
574 m_pEdTargetValue
->GetText(), m_pEdVariableCells
->GetText(), maConditions
, maEngine
, maProperties
);
575 mpDocShell
->SetSolverSaveData( aSave
);
580 // no solution -> dialog is kept open
581 SetDispatcherLock( sal_True
);
584 else if ( pBtn
== m_pBtnOpt
)
586 //! move options dialog to UI lib?
587 ScSolverOptionsDialog
* pOptDlg
=
588 new ScSolverOptionsDialog( this, maImplNames
, maDescriptions
, maEngine
, maProperties
);
589 if ( pOptDlg
->Execute() == RET_OK
)
591 maEngine
= pOptDlg
->GetEngine();
592 maProperties
= pOptDlg
->GetProperties();
600 //----------------------------------------------------------------------------
602 IMPL_LINK( ScOptSolverDlg
, GetFocusHdl
, Control
*, pCtrl
)
607 if( pCtrl
== m_pEdObjectiveCell
|| pCtrl
== m_pRBObjectiveCell
)
608 pEdit
= mpEdActive
= m_pEdObjectiveCell
;
609 else if( pCtrl
== m_pEdTargetValue
|| pCtrl
== m_pRBTargetValue
)
610 pEdit
= mpEdActive
= m_pEdTargetValue
;
611 else if( pCtrl
== m_pEdVariableCells
|| pCtrl
== m_pRBVariableCells
)
612 pEdit
= mpEdActive
= m_pEdVariableCells
;
613 for ( sal_uInt16 nRow
= 0; nRow
< EDIT_ROW_COUNT
; ++nRow
)
615 if( pCtrl
== mpLeftEdit
[nRow
] || pCtrl
== mpLeftButton
[nRow
] )
616 pEdit
= mpEdActive
= mpLeftEdit
[nRow
];
617 else if( pCtrl
== mpRightEdit
[nRow
] || pCtrl
== mpRightButton
[nRow
] )
618 pEdit
= mpEdActive
= mpRightEdit
[nRow
];
619 else if( pCtrl
== mpOperator
[nRow
] ) // focus on "operator" list box
620 mpEdActive
= mpRightEdit
[nRow
]; // use right edit for ref input, but don't change selection
622 if( pCtrl
== m_pRbValue
) // focus on "Value of" radio button
623 mpEdActive
= m_pEdTargetValue
; // use value edit for ref input, but don't change selection
626 pEdit
->SetSelection( Selection( 0, SELECTION_MAX
) );
631 //----------------------------------------------------------------------------
633 IMPL_LINK_NOARG(ScOptSolverDlg
, LoseFocusHdl
)
635 mbDlgLostFocus
= !IsActive();
639 //----------------------------------------------------------------------------
641 IMPL_LINK( ScOptSolverDlg
, DelBtnHdl
, PushButton
*, pBtn
)
643 for ( sal_uInt16 nRow
= 0; nRow
< EDIT_ROW_COUNT
; ++nRow
)
644 if( pBtn
== mpDelButton
[nRow
] )
646 sal_Bool bHadFocus
= pBtn
->HasFocus();
649 long nVecPos
= nScrollPos
+ nRow
;
650 if ( nVecPos
< (long)maConditions
.size() )
652 maConditions
.erase( maConditions
.begin() + nVecPos
);
655 if ( bHadFocus
&& !pBtn
->IsEnabled() )
657 // If the button is disabled, focus would normally move to the next control,
658 // (left edit of the next row). Move it to left edit of this row instead.
660 mpEdActive
= mpLeftEdit
[nRow
];
661 mpEdActive
->GrabFocus();
669 //----------------------------------------------------------------------------
671 IMPL_LINK_NOARG(ScOptSolverDlg
, TargetModifyHdl
)
673 // modify handler for the target edit:
674 // select "Value of" if something is input into the edit
675 if ( !m_pEdTargetValue
->GetText().isEmpty() )
680 IMPL_LINK_NOARG(ScOptSolverDlg
, CondModifyHdl
)
682 // modify handler for the condition edits, just to enable/disable "delete" buttons
688 IMPL_LINK_NOARG(ScOptSolverDlg
, SelectHdl
)
690 // select handler for operator list boxes, just to enable/disable "delete" buttons
696 IMPL_LINK_NOARG(ScOptSolverDlg
, ScrollHdl
)
699 nScrollPos
= m_pScrollBar
->GetThumbPos();
702 mpEdActive
->SetSelection( Selection( 0, SELECTION_MAX
) );
706 IMPL_LINK( ScOptSolverDlg
, CursorUpHdl
, ScCursorRefEdit
*, pEdit
)
708 if ( pEdit
== mpLeftEdit
[0] || pEdit
== mpRightEdit
[0] )
710 if ( nScrollPos
> 0 )
716 mpEdActive
->SetSelection( Selection( 0, SELECTION_MAX
) );
721 formula::RefEdit
* pFocus
= NULL
;
722 for ( sal_uInt16 nRow
= 1; nRow
< EDIT_ROW_COUNT
; ++nRow
) // second row or below: move focus
724 if ( pEdit
== mpLeftEdit
[nRow
] )
725 pFocus
= mpLeftEdit
[nRow
-1];
726 else if ( pEdit
== mpRightEdit
[nRow
] )
727 pFocus
= mpRightEdit
[nRow
-1];
739 IMPL_LINK( ScOptSolverDlg
, CursorDownHdl
, ScCursorRefEdit
*, pEdit
)
741 if ( pEdit
== mpLeftEdit
[EDIT_ROW_COUNT
-1] || pEdit
== mpRightEdit
[EDIT_ROW_COUNT
-1] )
743 //! limit scroll position?
748 mpEdActive
->SetSelection( Selection( 0, SELECTION_MAX
) );
752 formula::RefEdit
* pFocus
= NULL
;
753 for ( sal_uInt16 nRow
= 0; nRow
+1 < EDIT_ROW_COUNT
; ++nRow
) // before last row: move focus
755 if ( pEdit
== mpLeftEdit
[nRow
] )
756 pFocus
= mpLeftEdit
[nRow
+1];
757 else if ( pEdit
== mpRightEdit
[nRow
] )
758 pFocus
= mpRightEdit
[nRow
+1];
770 //----------------------------------------------------------------------------
772 void ScOptSolverDlg::ShowError( bool bCondition
, formula::RefEdit
* pFocus
)
774 OUString aMessage
= bCondition
? maConditionError
: maInputError
;
775 ErrorBox( this, WinBits( WB_OK
| WB_DEF_OK
), aMessage
).Execute();
783 //----------------------------------------------------------------------------
785 bool ScOptSolverDlg::ParseRef( ScRange
& rRange
, const OUString
& rInput
, bool bAllowRange
)
787 ScRangeUtil aRangeUtil
;
788 ScAddress::Details
aDetails(mpDoc
->GetAddressConvention(), 0, 0);
789 sal_uInt16 nFlags
= rRange
.ParseAny( rInput
, mpDoc
, aDetails
);
790 if ( nFlags
& SCA_VALID
)
792 if ( (nFlags
& SCA_TAB_3D
) == 0 )
793 rRange
.aStart
.SetTab( mnCurTab
);
794 if ( (nFlags
& SCA_TAB2_3D
) == 0 )
795 rRange
.aEnd
.SetTab( rRange
.aStart
.Tab() );
796 return ( bAllowRange
|| rRange
.aStart
== rRange
.aEnd
);
798 else if ( aRangeUtil
.MakeRangeFromName( rInput
, mpDoc
, mnCurTab
, rRange
, RUTL_NAMES
, aDetails
) )
799 return ( bAllowRange
|| rRange
.aStart
== rRange
.aEnd
);
801 return false; // not recognized
804 bool ScOptSolverDlg::FindTimeout( sal_Int32
& rTimeout
)
808 if ( !maProperties
.getLength() )
809 maProperties
= ScSolverUtil::GetDefaults( maEngine
); // get property defaults from component
811 sal_Int32 nPropCount
= maProperties
.getLength();
812 for (sal_Int32 nProp
=0; nProp
<nPropCount
&& !bFound
; ++nProp
)
814 const beans::PropertyValue
& rValue
= maProperties
[nProp
];
815 if ( rValue
.Name
== SC_UNONAME_TIMEOUT
)
816 bFound
= ( rValue
.Value
>>= rTimeout
);
821 bool ScOptSolverDlg::CallSolver() // return true -> close dialog after calling
823 // show progress dialog
825 ScSolverProgressDialog
aProgress( this );
826 sal_Int32 nTimeout
= 0;
827 if ( FindTimeout( nTimeout
) )
828 aProgress
.SetTimeLimit( nTimeout
);
830 aProgress
.HideTimeLimit();
834 // try to make sure the progress dialog is painted before continuing
835 Application::Reschedule(true);
837 // collect solver parameters
841 uno::Reference
<sheet::XSpreadsheetDocument
> xDocument( mpDocShell
->GetModel(), uno::UNO_QUERY
);
844 if ( !ParseRef( aObjRange
, m_pEdObjectiveCell
->GetText(), false ) )
846 ShowError( false, m_pEdObjectiveCell
);
849 table::CellAddress
aObjective( aObjRange
.aStart
.Tab(), aObjRange
.aStart
.Col(), aObjRange
.aStart
.Row() );
851 // "changing cells" can be several ranges
852 ScRangeList aVarRanges
;
853 if ( !ParseWithNames( aVarRanges
, m_pEdVariableCells
->GetText(), mpDoc
) )
855 ShowError( false, m_pEdVariableCells
);
858 uno::Sequence
<table::CellAddress
> aVariables
;
859 sal_Int32 nVarPos
= 0;
861 for ( size_t nRangePos
=0, nRange
= aVarRanges
.size(); nRangePos
< nRange
; ++nRangePos
)
863 ScRange
aRange(*aVarRanges
[ nRangePos
] );
865 SCTAB nTab
= aRange
.aStart
.Tab();
867 // resolve into single cells
869 sal_Int32 nAdd
= ( aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1 ) *
870 ( aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1 );
871 aVariables
.realloc( nVarPos
+ nAdd
);
873 for (SCROW nRow
= aRange
.aStart
.Row(); nRow
<= aRange
.aEnd
.Row(); ++nRow
)
874 for (SCCOL nCol
= aRange
.aStart
.Col(); nCol
<= aRange
.aEnd
.Col(); ++nCol
)
875 aVariables
[nVarPos
++] = table::CellAddress( nTab
, nCol
, nRow
);
878 uno::Sequence
<sheet::SolverConstraint
> aConstraints
;
879 sal_Int32 nConstrPos
= 0;
880 for ( std::vector
<ScOptConditionRow
>::const_iterator aConstrIter
= maConditions
.begin();
881 aConstrIter
!= maConditions
.end(); ++aConstrIter
)
883 if ( !aConstrIter
->aLeftStr
.isEmpty() )
885 sheet::SolverConstraint aConstraint
;
886 // order of list box entries must match enum values
887 aConstraint
.Operator
= static_cast<sheet::SolverConstraintOperator
>(aConstrIter
->nOperator
);
890 if ( !ParseRef( aLeftRange
, aConstrIter
->aLeftStr
, true ) )
892 ShowError( true, NULL
);
896 bool bIsRange
= false;
898 if ( ParseRef( aRightRange
, aConstrIter
->aRightStr
, true ) )
900 if ( aRightRange
.aStart
== aRightRange
.aEnd
)
901 aConstraint
.Right
<<= table::CellAddress( aRightRange
.aStart
.Tab(),
902 aRightRange
.aStart
.Col(), aRightRange
.aStart
.Row() );
903 else if ( aRightRange
.aEnd
.Col()-aRightRange
.aStart
.Col() == aLeftRange
.aEnd
.Col()-aLeftRange
.aStart
.Col() &&
904 aRightRange
.aEnd
.Row()-aRightRange
.aStart
.Row() == aLeftRange
.aEnd
.Row()-aLeftRange
.aStart
.Row() )
905 bIsRange
= true; // same size as "left" range, resolve into single cells
908 ShowError( true, NULL
);
914 sal_uInt32 nFormat
= 0; //! explicit language?
916 if ( mpDoc
->GetFormatTable()->IsNumberFormat( aConstrIter
->aRightStr
, nFormat
, fValue
) )
917 aConstraint
.Right
<<= fValue
;
918 else if ( aConstraint
.Operator
!= sheet::SolverConstraintOperator_INTEGER
&&
919 aConstraint
.Operator
!= sheet::SolverConstraintOperator_BINARY
)
921 ShowError( true, NULL
);
926 // resolve into single cells
928 sal_Int32 nAdd
= ( aLeftRange
.aEnd
.Col() - aLeftRange
.aStart
.Col() + 1 ) *
929 ( aLeftRange
.aEnd
.Row() - aLeftRange
.aStart
.Row() + 1 );
930 aConstraints
.realloc( nConstrPos
+ nAdd
);
932 for (SCROW nRow
= aLeftRange
.aStart
.Row(); nRow
<= aLeftRange
.aEnd
.Row(); ++nRow
)
933 for (SCCOL nCol
= aLeftRange
.aStart
.Col(); nCol
<= aLeftRange
.aEnd
.Col(); ++nCol
)
935 aConstraint
.Left
= table::CellAddress( aLeftRange
.aStart
.Tab(), nCol
, nRow
);
937 aConstraint
.Right
<<= table::CellAddress( aRightRange
.aStart
.Tab(),
938 aRightRange
.aStart
.Col() + ( nCol
- aLeftRange
.aStart
.Col() ),
939 aRightRange
.aStart
.Row() + ( nRow
- aLeftRange
.aStart
.Row() ) );
941 aConstraints
[nConstrPos
++] = aConstraint
;
946 sal_Bool bMaximize
= m_pRbMax
->IsChecked();
947 if ( m_pRbValue
->IsChecked() )
949 // handle "value of" with an additional constraint (and then minimize)
951 sheet::SolverConstraint aConstraint
;
952 aConstraint
.Left
= aObjective
;
953 aConstraint
.Operator
= sheet::SolverConstraintOperator_EQUAL
;
955 OUString aValStr
= m_pEdTargetValue
->GetText();
957 if ( ParseRef( aRightRange
, aValStr
, false ) )
958 aConstraint
.Right
<<= table::CellAddress( aRightRange
.aStart
.Tab(),
959 aRightRange
.aStart
.Col(), aRightRange
.aStart
.Row() );
962 sal_uInt32 nFormat
= 0; //! explicit language?
964 if ( mpDoc
->GetFormatTable()->IsNumberFormat( aValStr
, nFormat
, fValue
) )
965 aConstraint
.Right
<<= fValue
;
968 ShowError( false, m_pEdTargetValue
);
973 aConstraints
.realloc( nConstrPos
+ 1 );
974 aConstraints
[nConstrPos
++] = aConstraint
;
977 // copy old document values
979 sal_Int32 nVarCount
= aVariables
.getLength();
980 uno::Sequence
<double> aOldValues
;
981 aOldValues
.realloc( nVarCount
);
982 for (nVarPos
=0; nVarPos
<nVarCount
; ++nVarPos
)
985 ScUnoConversion::FillScAddress( aCellPos
, aVariables
[nVarPos
] );
986 aOldValues
[nVarPos
] = mpDoc
->GetValue( aCellPos
);
989 // create and initialize solver
991 uno::Reference
<sheet::XSolver
> xSolver
= ScSolverUtil::GetSolver( maEngine
);
992 OSL_ENSURE( xSolver
.is(), "can't get solver component" );
996 xSolver
->setDocument( xDocument
);
997 xSolver
->setObjective( aObjective
);
998 xSolver
->setVariables( aVariables
);
999 xSolver
->setConstraints( aConstraints
);
1000 xSolver
->setMaximize( bMaximize
);
1003 uno::Reference
<beans::XPropertySet
> xOptProp(xSolver
, uno::UNO_QUERY
);
1004 if ( xOptProp
.is() )
1006 sal_Int32 nPropCount
= maProperties
.getLength();
1007 for (sal_Int32 nProp
=0; nProp
<nPropCount
; ++nProp
)
1009 const beans::PropertyValue
& rValue
= maProperties
[nProp
];
1012 xOptProp
->setPropertyValue( rValue
.Name
, rValue
.Value
);
1014 catch ( uno::Exception
& )
1016 OSL_FAIL("Exception in solver option property");
1022 sal_Bool bSuccess
= xSolver
->getSuccess();
1025 bool bClose
= false;
1026 bool bRestore
= true; // restore old values unless a solution is accepted
1029 // put solution into document so it is visible when asking
1030 uno::Sequence
<double> aSolution
= xSolver
->getSolution();
1031 if ( aSolution
.getLength() == nVarCount
)
1033 mpDocShell
->LockPaint();
1034 ScDocFunc
&rFunc
= mpDocShell
->GetDocFunc();
1035 for (nVarPos
=0; nVarPos
<nVarCount
; ++nVarPos
)
1038 ScUnoConversion::FillScAddress( aCellPos
, aVariables
[nVarPos
] );
1039 rFunc
.SetValueCell(aCellPos
, aSolution
[nVarPos
], false);
1041 mpDocShell
->UnlockPaint();
1045 // take formatted result from document (result value from component is ignored)
1046 OUString aResultStr
= mpDoc
->GetString(
1047 static_cast<SCCOL
>(aObjective
.Column
), static_cast<SCROW
>(aObjective
.Row
),
1048 static_cast<SCTAB
>(aObjective
.Sheet
));
1050 ScSolverSuccessDialog
aDialog( this, aResultStr
);
1051 if ( aDialog
.Execute() == RET_OK
)
1053 // keep results and close dialog
1061 uno::Reference
<sheet::XSolverDescription
> xDesc( xSolver
, uno::UNO_QUERY
);
1063 aError
= xDesc
->getStatusDescription(); // error description from component
1064 ScSolverNoSolutionDialog
aDialog( this, aError
);
1068 if ( bRestore
) // restore old values
1070 mpDocShell
->LockPaint();
1071 ScDocFunc
&rFunc
= mpDocShell
->GetDocFunc();
1072 for (nVarPos
=0; nVarPos
<nVarCount
; ++nVarPos
)
1075 ScUnoConversion::FillScAddress( aCellPos
, aVariables
[nVarPos
] );
1076 rFunc
.SetValueCell(aCellPos
, aOldValues
[nVarPos
], false);
1078 mpDocShell
->UnlockPaint();
1084 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */