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