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