Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / ui / miscdlgs / optsolver.cxx
blob873a81a71673b8a80ec2063ce829acdcdd12ce29
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
31 #include "docsh.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);
60 FreeResource();
63 ScSolverProgressDialog::~ScSolverProgressDialog()
67 void ScSolverProgressDialog::HideTimeLimit()
69 maFtTime.Hide();
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 );
89 FreeResource();
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 );
109 FreeResource();
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 ) )
142 if ( bUp )
143 maCursorUpLink.Call( this );
144 else
145 maCursorDownLink.Call( this );
147 else
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 ),
159 mbMax( bMax ),
160 mbMin( bMin ),
161 mbValue( bValue ),
162 maTarget( rTarget ),
163 maVariable( rVariable ),
164 maConditions( rConditions ),
165 maEngine( rEngine ),
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))
181 , mpDocShell(pDocSh)
182 , mpDoc(pDocSh->GetDocument())
183 , mnCurTab(aCursorPos.Tab())
184 , mpEdActive(NULL)
185 , mbDlgLostFocus(false)
186 , nScrollPos(0)
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());
291 Init( aCursorPos );
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();
381 if ( pOldData )
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();
393 else
395 m_pRbMax->Check();
396 OUString aCursorStr;
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
403 ShowConditions();
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() )
430 --nSize;
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 );
456 EnableButtons();
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;
482 if( mpEdActive )
483 mpEdActive->GrabFocus();
485 else
487 GrabFocus();
489 RefInputDone();
492 //----------------------------------------------------------------------------
494 void ScOptSolverDlg::SetReference( const ScRange& rRef, ScDocument* pDocP )
496 if( mpEdActive )
498 if ( rRef.aStart != rRef.aEnd )
499 RefInputStart(mpEdActive);
501 // "target"/"value": single cell
502 bool bSingle = ( mpEdActive == m_pEdObjectiveCell || mpEdActive == m_pEdTargetValue );
504 OUString aStr;
505 ScAddress aAdr = rRef.aStart;
506 ScRange aNewRef( rRef );
507 if ( bSingle )
508 aNewRef.aEnd = aAdr;
510 OUString aName;
511 if ( pDocP->GetRangeAtBlock( aNewRef, &aName ) ) // named range: show name
512 aStr = aName;
513 else // format cell/range reference
515 sal_uInt16 nFmt = ( aAdr.Tab() == mnCurTab ) ? SCA_ABS : SCA_ABS_3D;
516 if ( bSingle )
517 aStr = aAdr.Format(nFmt, pDocP, pDocP->GetAddressConvention());
518 else
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();
527 aSel.Justify();
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 );
533 else
534 mpEdActive->SetRefString( aStr );
536 ReadConditions();
537 EnableButtons();
539 // select "Value of" if a ref is input into "target" edit
540 if ( mpEdActive == m_pEdTargetValue )
541 m_pRbValue->Check();
545 //----------------------------------------------------------------------------
547 sal_Bool ScOptSolverDlg::IsRefInputMode() const
549 return mpEdActive != NULL;
552 //----------------------------------------------------------------------------
553 // Handler:
555 IMPL_LINK( ScOptSolverDlg, BtnHdl, PushButton*, pBtn )
557 if ( pBtn == m_pBtnSolve || pBtn == m_pBtnCancel )
559 bool bSolve = ( pBtn == m_pBtnSolve );
561 SetDispatcherLock( false );
562 SwitchToDocument();
564 bool bClose = true;
565 if ( bSolve )
566 bClose = CallSolver();
568 if ( bClose )
570 // Close: write dialog settings to DocShell for subsequent calls
571 ReadConditions();
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 );
576 Close();
578 else
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();
594 delete pOptDlg;
597 return 0;
600 //----------------------------------------------------------------------------
602 IMPL_LINK( ScOptSolverDlg, GetFocusHdl, Control*, pCtrl )
604 Edit* pEdit = NULL;
605 mpEdActive = NULL;
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
625 if( pEdit )
626 pEdit->SetSelection( Selection( 0, SELECTION_MAX ) );
628 return 0;
631 //----------------------------------------------------------------------------
633 IMPL_LINK_NOARG(ScOptSolverDlg, LoseFocusHdl)
635 mbDlgLostFocus = !IsActive();
636 return 0;
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();
648 ReadConditions();
649 long nVecPos = nScrollPos + nRow;
650 if ( nVecPos < (long)maConditions.size() )
652 maConditions.erase( maConditions.begin() + nVecPos );
653 ShowConditions();
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();
666 return 0;
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() )
676 m_pRbValue->Check();
677 return 0;
680 IMPL_LINK_NOARG(ScOptSolverDlg, CondModifyHdl)
682 // modify handler for the condition edits, just to enable/disable "delete" buttons
683 ReadConditions();
684 EnableButtons();
685 return 0;
688 IMPL_LINK_NOARG(ScOptSolverDlg, SelectHdl)
690 // select handler for operator list boxes, just to enable/disable "delete" buttons
691 ReadConditions();
692 EnableButtons();
693 return 0;
696 IMPL_LINK_NOARG(ScOptSolverDlg, ScrollHdl)
698 ReadConditions();
699 nScrollPos = m_pScrollBar->GetThumbPos();
700 ShowConditions();
701 if( mpEdActive )
702 mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) );
703 return 0;
706 IMPL_LINK( ScOptSolverDlg, CursorUpHdl, ScCursorRefEdit*, pEdit )
708 if ( pEdit == mpLeftEdit[0] || pEdit == mpRightEdit[0] )
710 if ( nScrollPos > 0 )
712 ReadConditions();
713 --nScrollPos;
714 ShowConditions();
715 if( mpEdActive )
716 mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) );
719 else
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];
729 if (pFocus)
731 mpEdActive = pFocus;
732 pFocus->GrabFocus();
736 return 0;
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?
744 ReadConditions();
745 ++nScrollPos;
746 ShowConditions();
747 if( mpEdActive )
748 mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) );
750 else
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];
760 if (pFocus)
762 mpEdActive = pFocus;
763 pFocus->GrabFocus();
767 return 0;
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();
776 if (pFocus)
778 mpEdActive = pFocus;
779 pFocus->GrabFocus();
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 )
806 bool bFound = false;
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 );
818 return bFound;
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 );
829 else
830 aProgress.HideTimeLimit();
831 aProgress.Show();
832 aProgress.Update();
833 aProgress.Sync();
834 // try to make sure the progress dialog is painted before continuing
835 Application::Reschedule(true);
837 // collect solver parameters
839 ReadConditions();
841 uno::Reference<sheet::XSpreadsheetDocument> xDocument( mpDocShell->GetModel(), uno::UNO_QUERY );
843 ScRange aObjRange;
844 if ( !ParseRef( aObjRange, m_pEdObjectiveCell->GetText(), false ) )
846 ShowError( false, m_pEdObjectiveCell );
847 return false;
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 );
856 return false;
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 ] );
864 aRange.Justify();
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);
889 ScRange aLeftRange;
890 if ( !ParseRef( aLeftRange, aConstrIter->aLeftStr, true ) )
892 ShowError( true, NULL );
893 return false;
896 bool bIsRange = false;
897 ScRange aRightRange;
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
906 else
908 ShowError( true, NULL );
909 return false;
912 else
914 sal_uInt32 nFormat = 0; //! explicit language?
915 double fValue = 0.0;
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 );
922 return false;
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 );
936 if ( bIsRange )
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();
956 ScRange aRightRange;
957 if ( ParseRef( aRightRange, aValStr, false ) )
958 aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(),
959 aRightRange.aStart.Col(), aRightRange.aStart.Row() );
960 else
962 sal_uInt32 nFormat = 0; //! explicit language?
963 double fValue = 0.0;
964 if ( mpDoc->GetFormatTable()->IsNumberFormat( aValStr, nFormat, fValue ) )
965 aConstraint.Right <<= fValue;
966 else
968 ShowError( false, m_pEdTargetValue );
969 return false;
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)
984 ScAddress aCellPos;
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" );
993 if ( !xSolver.is() )
994 return false;
996 xSolver->setDocument( xDocument );
997 xSolver->setObjective( aObjective );
998 xSolver->setVariables( aVariables );
999 xSolver->setConstraints( aConstraints );
1000 xSolver->setMaximize( bMaximize );
1002 // set options
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");
1021 xSolver->solve();
1022 sal_Bool bSuccess = xSolver->getSuccess();
1024 aProgress.Hide();
1025 bool bClose = false;
1026 bool bRestore = true; // restore old values unless a solution is accepted
1027 if ( bSuccess )
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)
1037 ScAddress aCellPos;
1038 ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] );
1039 rFunc.SetValueCell(aCellPos, aSolution[nVarPos], false);
1041 mpDocShell->UnlockPaint();
1043 //! else error?
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
1054 bRestore = false;
1055 bClose = true;
1058 else
1060 OUString aError;
1061 uno::Reference<sheet::XSolverDescription> xDesc( xSolver, uno::UNO_QUERY );
1062 if ( xDesc.is() )
1063 aError = xDesc->getStatusDescription(); // error description from component
1064 ScSolverNoSolutionDialog aDialog( this, aError );
1065 aDialog.Execute();
1068 if ( bRestore ) // restore old values
1070 mpDocShell->LockPaint();
1071 ScDocFunc &rFunc = mpDocShell->GetDocFunc();
1072 for (nVarPos=0; nVarPos<nVarCount; ++nVarPos)
1074 ScAddress aCellPos;
1075 ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] );
1076 rFunc.SetValueCell(aCellPos, aOldValues[nVarPos], false);
1078 mpDocShell->UnlockPaint();
1081 return bClose;
1084 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */