diff options
Diffstat (limited to 'sc/source/ui/miscdlgs/optsolver.cxx')
-rw-r--r-- | sc/source/ui/miscdlgs/optsolver.cxx | 2138 |
1 files changed, 1069 insertions, 1069 deletions
diff --git a/sc/source/ui/miscdlgs/optsolver.cxx b/sc/source/ui/miscdlgs/optsolver.cxx index 68d418910..e7e902cae 100644 --- a/sc/source/ui/miscdlgs/optsolver.cxx +++ b/sc/source/ui/miscdlgs/optsolver.cxx @@ -1,1069 +1,1069 @@ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2008 by Sun Microsystems, Inc. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * $RCSfile: optsolver.cxx,v $ - * $Revision: 1.5 $ - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_sc.hxx" - -//---------------------------------------------------------------------------- - -#include "rangelst.hxx" -#include "scitems.hxx" -#include <sfx2/bindings.hxx> -#include <sfx2/imagemgr.hxx> -#include <svtools/zforlist.hxx> -#include <vcl/msgbox.hxx> -#include <vcl/svapp.hxx> - -#include "uiitems.hxx" -#include "reffact.hxx" -#include "docsh.hxx" -#include "docfunc.hxx" -#include "cell.hxx" -#include "rangeutl.hxx" -#include "scresid.hxx" -#include "convuno.hxx" -#include "unonames.hxx" -#include "solveroptions.hxx" -#include "solverutil.hxx" -#include "optsolver.hrc" - -#include "optsolver.hxx" - -#include <com/sun/star/sheet/Solver.hpp> -#include <com/sun/star/sheet/XSolverDescription.hpp> - -using namespace com::sun::star; - -//---------------------------------------------------------------------------- - -ScSolverProgressDialog::ScSolverProgressDialog( Window* pParent ) - : ModelessDialog( pParent, ScResId( RID_SCDLG_SOLVER_PROGRESS ) ), - maFtProgress ( this, ScResId( FT_PROGRESS ) ), - maFtTime ( this, ScResId( FT_TIMELIMIT ) ), - maFlButtons ( this, ScResId( FL_BUTTONS ) ), - maBtnOk ( this, ScResId( BTN_OK ) ) -{ - maBtnOk.Enable(FALSE); - FreeResource(); -} - -ScSolverProgressDialog::~ScSolverProgressDialog() -{ -} - -void ScSolverProgressDialog::HideTimeLimit() -{ - maFtTime.Hide(); -} - -void ScSolverProgressDialog::SetTimeLimit( sal_Int32 nSeconds ) -{ - String aOld = maFtTime.GetText(); - String aNew = aOld.GetToken(0,'#'); - aNew += String::CreateFromInt32( nSeconds ); - aNew += aOld.GetToken(1,'#'); - maFtTime.SetText( aNew ); -} - -//---------------------------------------------------------------------------- - -ScSolverNoSolutionDialog::ScSolverNoSolutionDialog( Window* pParent, const String& rErrorText ) - : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_NOSOLUTION ) ), - maFtNoSolution ( this, ScResId( FT_NOSOLUTION ) ), - maFtErrorText ( this, ScResId( FT_ERRORTEXT ) ), - maFlButtons ( this, ScResId( FL_BUTTONS ) ), - maBtnOk ( this, ScResId( BTN_OK ) ) -{ - maFtErrorText.SetText( rErrorText ); - FreeResource(); -} - -ScSolverNoSolutionDialog::~ScSolverNoSolutionDialog() -{ -} - -//---------------------------------------------------------------------------- - -ScSolverSuccessDialog::ScSolverSuccessDialog( Window* pParent, const String& rSolution ) - : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_SUCCESS ) ), - maFtSuccess ( this, ScResId( FT_SUCCESS ) ), - maFtResult ( this, ScResId( FT_RESULT ) ), - maFtQuestion ( this, ScResId( FT_QUESTION ) ), - maFlButtons ( this, ScResId( FL_BUTTONS ) ), - maBtnOk ( this, ScResId( BTN_OK ) ), - maBtnCancel ( this, ScResId( BTN_CANCEL ) ) -{ - String aMessage = maFtResult.GetText(); - aMessage.Append( (sal_Char) ' ' ); - aMessage.Append( rSolution ); - maFtResult.SetText( aMessage ); - FreeResource(); -} - -ScSolverSuccessDialog::~ScSolverSuccessDialog() -{ -} - -//---------------------------------------------------------------------------- - -ScCursorRefEdit::ScCursorRefEdit( ScAnyRefDlg* pParent, const ResId& rResId ) : - ScRefEdit( pParent, rResId ) -{ -} - -void ScCursorRefEdit::SetCursorLinks( const Link& rUp, const Link& rDown ) -{ - maCursorUpLink = rUp; - maCursorDownLink = rDown; -} - -void ScCursorRefEdit::KeyInput( const KeyEvent& rKEvt ) -{ - KeyCode aCode = rKEvt.GetKeyCode(); - bool bUp = (aCode.GetCode() == KEY_UP); - bool bDown = (aCode.GetCode() == KEY_DOWN); - if ( !aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() && ( bUp || bDown ) ) - { - if ( bUp ) - maCursorUpLink.Call( this ); - else - maCursorDownLink.Call( this ); - } - else - ScRefEdit::KeyInput( rKEvt ); -} - -//---------------------------------------------------------------------------- - -ScOptSolverSave::ScOptSolverSave( const String& rObjective, BOOL bMax, BOOL bMin, BOOL bValue, - const String& rTarget, const String& rVariable, - const std::vector<ScOptConditionRow>& rConditions, - const String& rEngine, - const uno::Sequence<beans::PropertyValue>& rProperties ) : - maObjective( rObjective ), - mbMax( bMax ), - mbMin( bMin ), - mbValue( bValue ), - maTarget( rTarget ), - maVariable( rVariable ), - maConditions( rConditions ), - maEngine( rEngine ), - maProperties( rProperties ) -{ -} - -//============================================================================ -// class ScOptSolverDlg -//---------------------------------------------------------------------------- - -ScOptSolverDlg::ScOptSolverDlg( SfxBindings* pB, SfxChildWindow* pCW, Window* pParent, - ScDocShell* pDocSh, ScAddress aCursorPos ) - - : ScAnyRefDlg ( pB, pCW, pParent, RID_SCDLG_OPTSOLVER ), - // - maFtObjectiveCell ( this, ScResId( FT_OBJECTIVECELL ) ), - maEdObjectiveCell ( this, ScResId( ED_OBJECTIVECELL ) ), - maRBObjectiveCell ( this, ScResId( IB_OBJECTIVECELL ), &maEdObjectiveCell ), - maFtDirection ( this, ScResId( FT_DIRECTION ) ), - maRbMax ( this, ScResId( RB_MAX ) ), - maRbMin ( this, ScResId( RB_MIN ) ), - maRbValue ( this, ScResId( RB_VALUE ) ), - maEdTargetValue ( this, ScResId( ED_TARGET ) ), - maRBTargetValue ( this, ScResId( IB_TARGET ), &maEdTargetValue ), - maFtVariableCells ( this, ScResId( FT_VARIABLECELLS ) ), - maEdVariableCells ( this, ScResId( ED_VARIABLECELLS ) ), - maRBVariableCells ( this, ScResId( IB_VARIABLECELLS ), &maEdVariableCells ), - maFlConditions ( this, ScResId( FL_CONDITIONS ) ), - maFtCellRef ( this, ScResId( FT_CELLREF ) ), - maEdLeft1 ( this, ScResId( ED_LEFT1 ) ), - maRBLeft1 ( this, ScResId( IB_LEFT1 ), &maEdLeft1 ), - maFtOperator ( this, ScResId( FT_OPERATOR ) ), - maLbOp1 ( this, ScResId( LB_OP1 ) ), - maFtConstraint ( this, ScResId( FT_CONSTRAINT ) ), - maEdRight1 ( this, ScResId( ED_RIGHT1 ) ), - maRBRight1 ( this, ScResId( IB_RIGHT1 ), &maEdRight1 ), - maBtnDel1 ( this, ScResId( IB_DELETE1 ) ), - maEdLeft2 ( this, ScResId( ED_LEFT2 ) ), - maRBLeft2 ( this, ScResId( IB_LEFT2 ), &maEdLeft2 ), - maLbOp2 ( this, ScResId( LB_OP2 ) ), - maEdRight2 ( this, ScResId( ED_RIGHT2 ) ), - maRBRight2 ( this, ScResId( IB_RIGHT2 ), &maEdRight2 ), - maBtnDel2 ( this, ScResId( IB_DELETE2 ) ), - maEdLeft3 ( this, ScResId( ED_LEFT3 ) ), - maRBLeft3 ( this, ScResId( IB_LEFT3 ), &maEdLeft3 ), - maLbOp3 ( this, ScResId( LB_OP3 ) ), - maEdRight3 ( this, ScResId( ED_RIGHT3 ) ), - maRBRight3 ( this, ScResId( IB_RIGHT3 ), &maEdRight3 ), - maBtnDel3 ( this, ScResId( IB_DELETE3 ) ), - maEdLeft4 ( this, ScResId( ED_LEFT4 ) ), - maRBLeft4 ( this, ScResId( IB_LEFT4 ), &maEdLeft4 ), - maLbOp4 ( this, ScResId( LB_OP4 ) ), - maEdRight4 ( this, ScResId( ED_RIGHT4 ) ), - maRBRight4 ( this, ScResId( IB_RIGHT4 ), &maEdRight4 ), - maBtnDel4 ( this, ScResId( IB_DELETE4 ) ), - maScrollBar ( this, ScResId( SB_SCROLL ) ), - maFlButtons ( this, ScResId( FL_BUTTONS ) ), - maBtnOpt ( this, ScResId( BTN_OPTIONS ) ), - maBtnHelp ( this, ScResId( BTN_HELP ) ), - maBtnCancel ( this, ScResId( BTN_CLOSE ) ), - maBtnSolve ( this, ScResId( BTN_SOLVE ) ), - maInputError ( ScResId( STR_INVALIDINPUT ) ), - maConditionError ( ScResId( STR_INVALIDCONDITION ) ), - // - mpDocShell ( pDocSh ), - mpDoc ( pDocSh->GetDocument() ), - mnCurTab ( aCursorPos.Tab() ), - mpEdActive ( NULL ), - mbDlgLostFocus ( false ), - nScrollPos ( 0 ) -{ - mpLeftEdit[0] = &maEdLeft1; - mpLeftButton[0] = &maRBLeft1; - mpRightEdit[0] = &maEdRight1; - mpRightButton[0] = &maRBRight1; - mpOperator[0] = &maLbOp1; - mpDelButton[0] = &maBtnDel1; - - mpLeftEdit[1] = &maEdLeft2; - mpLeftButton[1] = &maRBLeft2; - mpRightEdit[1] = &maEdRight2; - mpRightButton[1] = &maRBRight2; - mpOperator[1] = &maLbOp2; - mpDelButton[1] = &maBtnDel2; - - mpLeftEdit[2] = &maEdLeft3; - mpLeftButton[2] = &maRBLeft3; - mpRightEdit[2] = &maEdRight3; - mpRightButton[2] = &maRBRight3; - mpOperator[2] = &maLbOp3; - mpDelButton[2] = &maBtnDel3; - - mpLeftEdit[3] = &maEdLeft4; - mpLeftButton[3] = &maRBLeft4; - mpRightEdit[3] = &maEdRight4; - mpRightButton[3] = &maRBRight4; - mpOperator[3] = &maLbOp4; - mpDelButton[3] = &maBtnDel4; - - Init( aCursorPos ); - FreeResource(); -} - -//---------------------------------------------------------------------------- - -ScOptSolverDlg::~ScOptSolverDlg() -{ -} - -//---------------------------------------------------------------------------- - -void ScOptSolverDlg::Init(const ScAddress& rCursorPos) -{ - // Get the "Delete Rows" commandimagelist images from sfx instead of - // adding a second copy to sc (see ScTbxInsertCtrl::StateChanged) - - rtl::OUString aSlotURL( RTL_CONSTASCII_USTRINGPARAM( "slot:" )); - aSlotURL += rtl::OUString::valueOf( sal_Int32( SID_DEL_ROWS ) ); - uno::Reference<frame::XFrame> xFrame = GetBindings().GetActiveFrame(); - Image aDelNm = ::GetImage( xFrame, aSlotURL, FALSE, FALSE ); - Image aDelHC = ::GetImage( xFrame, aSlotURL, FALSE, TRUE ); // high contrast - - for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) - { - mpDelButton[nRow]->SetModeImage( aDelNm, BMP_COLOR_NORMAL ); - mpDelButton[nRow]->SetModeImage( aDelHC, BMP_COLOR_HIGHCONTRAST ); - } - - maBtnOpt.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) ); - maBtnCancel.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) ); - maBtnSolve.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) ); - - Link aLink = LINK( this, ScOptSolverDlg, GetFocusHdl ); - maEdObjectiveCell.SetGetFocusHdl( aLink ); - maRBObjectiveCell.SetGetFocusHdl( aLink ); - maEdTargetValue.SetGetFocusHdl( aLink ); - maRBTargetValue.SetGetFocusHdl( aLink ); - maEdVariableCells.SetGetFocusHdl( aLink ); - maRBVariableCells.SetGetFocusHdl( aLink ); - maRbValue.SetGetFocusHdl( aLink ); - for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) - { - mpLeftEdit[nRow]->SetGetFocusHdl( aLink ); - mpLeftButton[nRow]->SetGetFocusHdl( aLink ); - mpRightEdit[nRow]->SetGetFocusHdl( aLink ); - mpRightButton[nRow]->SetGetFocusHdl( aLink ); - mpOperator[nRow]->SetGetFocusHdl( aLink ); - } - - aLink = LINK( this, ScOptSolverDlg, LoseFocusHdl ); - maEdObjectiveCell.SetLoseFocusHdl( aLink ); - maRBObjectiveCell.SetLoseFocusHdl( aLink ); - maEdTargetValue. SetLoseFocusHdl( aLink ); - maRBTargetValue. SetLoseFocusHdl( aLink ); - maEdVariableCells.SetLoseFocusHdl( aLink ); - maRBVariableCells.SetLoseFocusHdl( aLink ); - for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) - { - mpLeftEdit[nRow]->SetLoseFocusHdl( aLink ); - mpLeftButton[nRow]->SetLoseFocusHdl( aLink ); - mpRightEdit[nRow]->SetLoseFocusHdl( aLink ); - mpRightButton[nRow]->SetLoseFocusHdl( aLink ); - } - - Link aCursorUp = LINK( this, ScOptSolverDlg, CursorUpHdl ); - Link aCursorDown = LINK( this, ScOptSolverDlg, CursorDownHdl ); - Link aCondModify = LINK( this, ScOptSolverDlg, CondModifyHdl ); - for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) - { - mpLeftEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown ); - mpRightEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown ); - mpLeftEdit[nRow]->SetModifyHdl( aCondModify ); - mpRightEdit[nRow]->SetModifyHdl( aCondModify ); - mpDelButton[nRow]->SetClickHdl( LINK( this, ScOptSolverDlg, DelBtnHdl ) ); - mpOperator[nRow]->SetSelectHdl( LINK( this, ScOptSolverDlg, SelectHdl ) ); - } - maEdTargetValue.SetModifyHdl( LINK( this, ScOptSolverDlg, TargetModifyHdl ) ); - - maScrollBar.SetEndScrollHdl( LINK( this, ScOptSolverDlg, ScrollHdl ) ); - maScrollBar.SetScrollHdl( LINK( this, ScOptSolverDlg, ScrollHdl ) ); - - maScrollBar.SetPageSize( EDIT_ROW_COUNT ); - maScrollBar.SetVisibleSize( EDIT_ROW_COUNT ); - maScrollBar.SetLineSize( 1 ); - // Range is set in ShowConditions - - // get available solver implementations - //! sort by descriptions? - ScSolverUtil::GetImplementations( maImplNames, maDescriptions ); - sal_Int32 nImplCount = maImplNames.getLength(); - - const ScOptSolverSave* pOldData = mpDocShell->GetSolverSaveData(); - if ( pOldData ) - { - maEdObjectiveCell.SetRefString( pOldData->GetObjective() ); - maRbMax.Check( pOldData->GetMax() ); - maRbMin.Check( pOldData->GetMin() ); - maRbValue.Check( pOldData->GetValue() ); - maEdTargetValue.SetRefString( pOldData->GetTarget() ); - maEdVariableCells.SetRefString( pOldData->GetVariable() ); - maConditions = pOldData->GetConditions(); - maEngine = pOldData->GetEngine(); - maProperties = pOldData->GetProperties(); - } - else - { - maRbMax.Check(); - String aCursorStr; - if ( !mpDoc->GetRangeAtBlock( ScRange(rCursorPos), &aCursorStr ) ) - rCursorPos.Format( aCursorStr, SCA_ABS, NULL, mpDoc->GetAddressConvention() ); - maEdObjectiveCell.SetRefString( aCursorStr ); - if ( nImplCount > 0 ) - maEngine = maImplNames[0]; // use first implementation - } - ShowConditions(); - - maEdObjectiveCell.GrabFocus(); - mpEdActive = &maEdObjectiveCell; -} - -//---------------------------------------------------------------------------- - -void ScOptSolverDlg::ReadConditions() -{ - for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) - { - ScOptConditionRow aRowEntry; - aRowEntry.aLeftStr = mpLeftEdit[nRow]->GetText(); - aRowEntry.aRightStr = mpRightEdit[nRow]->GetText(); - aRowEntry.nOperator = mpOperator[nRow]->GetSelectEntryPos(); - - long nVecPos = nScrollPos + nRow; - if ( nVecPos >= (long)maConditions.size() && !aRowEntry.IsDefault() ) - maConditions.resize( nVecPos + 1 ); - - if ( nVecPos < (long)maConditions.size() ) - maConditions[nVecPos] = aRowEntry; - - // remove default entries at the end - size_t nSize = maConditions.size(); - while ( nSize > 0 && maConditions[ nSize-1 ].IsDefault() ) - --nSize; - maConditions.resize( nSize ); - } -} - -void ScOptSolverDlg::ShowConditions() -{ - for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) - { - ScOptConditionRow aRowEntry; - - long nVecPos = nScrollPos + nRow; - if ( nVecPos < (long)maConditions.size() ) - aRowEntry = maConditions[nVecPos]; - - mpLeftEdit[nRow]->SetRefString( aRowEntry.aLeftStr ); - mpRightEdit[nRow]->SetRefString( aRowEntry.aRightStr ); - mpOperator[nRow]->SelectEntryPos( aRowEntry.nOperator ); - } - - // allow to scroll one page behind the visible or stored rows - long nVisible = nScrollPos + EDIT_ROW_COUNT; - long nMax = std::max( nVisible, (long) maConditions.size() ); - maScrollBar.SetRange( Range( 0, nMax + EDIT_ROW_COUNT ) ); - maScrollBar.SetThumbPos( nScrollPos ); - - EnableButtons(); -} - -void ScOptSolverDlg::EnableButtons() -{ - for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) - { - long nVecPos = nScrollPos + nRow; - mpDelButton[nRow]->Enable( nVecPos < (long)maConditions.size() ); - } -} - -//---------------------------------------------------------------------------- - -BOOL ScOptSolverDlg::Close() -{ - return DoClose( ScOptSolverDlgWrapper::GetChildWindowId() ); -} - -//---------------------------------------------------------------------------- - -void ScOptSolverDlg::SetActive() -{ - if ( mbDlgLostFocus ) - { - mbDlgLostFocus = false; - if( mpEdActive ) - mpEdActive->GrabFocus(); - } - else - { - GrabFocus(); - } - RefInputDone(); -} - -//---------------------------------------------------------------------------- - -void ScOptSolverDlg::SetReference( const ScRange& rRef, ScDocument* pDocP ) -{ - if( mpEdActive ) - { - if ( rRef.aStart != rRef.aEnd ) - RefInputStart(mpEdActive); - - // "target"/"value": single cell - bool bSingle = ( mpEdActive == &maEdObjectiveCell || mpEdActive == &maEdTargetValue ); - - String aStr; - ScAddress aAdr = rRef.aStart; - ScRange aNewRef( rRef ); - if ( bSingle ) - aNewRef.aEnd = aAdr; - - String aName; - if ( pDocP->GetRangeAtBlock( aNewRef, &aName ) ) // named range: show name - aStr = aName; - else // format cell/range reference - { - USHORT nFmt = ( aAdr.Tab() == mnCurTab ) ? SCA_ABS : SCA_ABS_3D; - if ( bSingle ) - aAdr.Format( aStr, nFmt, pDocP, pDocP->GetAddressConvention() ); - else - rRef.Format( aStr, nFmt | SCR_ABS, pDocP, pDocP->GetAddressConvention() ); - } - - // variable cells can be several ranges, so only the selection is replaced - if ( mpEdActive == &maEdVariableCells ) - { - String aVal = mpEdActive->GetText(); - Selection aSel = mpEdActive->GetSelection(); - aSel.Justify(); - aVal.Erase( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() ); - aVal.Insert( aStr, (xub_StrLen)aSel.Min() ); - Selection aNewSel( aSel.Min(), aSel.Min()+aStr.Len() ); - mpEdActive->SetRefString( aVal ); - mpEdActive->SetSelection( aNewSel ); - } - else - mpEdActive->SetRefString( aStr ); - - ReadConditions(); - EnableButtons(); - - // select "Value of" if a ref is input into "target" edit - if ( mpEdActive == &maEdTargetValue ) - maRbValue.Check(); - } -} - -//---------------------------------------------------------------------------- - -BOOL ScOptSolverDlg::IsRefInputMode() const -{ - return mpEdActive != NULL; -} - -//---------------------------------------------------------------------------- -// Handler: - -IMPL_LINK( ScOptSolverDlg, BtnHdl, PushButton*, pBtn ) -{ - if ( pBtn == &maBtnSolve || pBtn == &maBtnCancel ) - { - bool bSolve = ( pBtn == &maBtnSolve ); - - SetDispatcherLock( FALSE ); - SwitchToDocument(); - - bool bClose = true; - if ( bSolve ) - bClose = CallSolver(); - - if ( bClose ) - { - // Close: write dialog settings to DocShell for subsequent calls - ReadConditions(); - ScOptSolverSave aSave( - maEdObjectiveCell.GetText(), maRbMax.IsChecked(), maRbMin.IsChecked(), maRbValue.IsChecked(), - maEdTargetValue.GetText(), maEdVariableCells.GetText(), maConditions, maEngine, maProperties ); - mpDocShell->SetSolverSaveData( aSave ); - Close(); - } - else - { - // no solution -> dialog is kept open - SetDispatcherLock( TRUE ); - } - } - else if ( pBtn == &maBtnOpt ) - { - //! move options dialog to UI lib? - ScSolverOptionsDialog* pOptDlg = - new ScSolverOptionsDialog( this, maImplNames, maDescriptions, maEngine, maProperties ); - if ( pOptDlg->Execute() == RET_OK ) - { - maEngine = pOptDlg->GetEngine(); - maProperties = pOptDlg->GetProperties(); - } - delete pOptDlg; - } - - return 0; -} - -//---------------------------------------------------------------------------- - -IMPL_LINK( ScOptSolverDlg, GetFocusHdl, Control*, pCtrl ) -{ - Edit* pEdit = NULL; - mpEdActive = NULL; - - if( pCtrl == &maEdObjectiveCell || pCtrl == &maRBObjectiveCell ) - pEdit = mpEdActive = &maEdObjectiveCell; - else if( pCtrl == &maEdTargetValue || pCtrl == &maRBTargetValue ) - pEdit = mpEdActive = &maEdTargetValue; - else if( pCtrl == &maEdVariableCells || pCtrl == &maRBVariableCells ) - pEdit = mpEdActive = &maEdVariableCells; - for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) - { - if( pCtrl == mpLeftEdit[nRow] || pCtrl == mpLeftButton[nRow] ) - pEdit = mpEdActive = mpLeftEdit[nRow]; - else if( pCtrl == mpRightEdit[nRow] || pCtrl == mpRightButton[nRow] ) - pEdit = mpEdActive = mpRightEdit[nRow]; - else if( pCtrl == mpOperator[nRow] ) // focus on "operator" list box - mpEdActive = mpRightEdit[nRow]; // use right edit for ref input, but don't change selection - } - if( pCtrl == &maRbValue ) // focus on "Value of" radio button - mpEdActive = &maEdTargetValue; // use value edit for ref input, but don't change selection - - if( pEdit ) - pEdit->SetSelection( Selection( 0, SELECTION_MAX ) ); - - return 0; -} - -//---------------------------------------------------------------------------- - -IMPL_LINK( ScOptSolverDlg, LoseFocusHdl, Control*, EMPTYARG ) -{ - mbDlgLostFocus = !IsActive(); - return 0; -} - -//---------------------------------------------------------------------------- - -IMPL_LINK( ScOptSolverDlg, DelBtnHdl, PushButton*, pBtn ) -{ - for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) - if( pBtn == mpDelButton[nRow] ) - { - BOOL bHadFocus = pBtn->HasFocus(); - - ReadConditions(); - long nVecPos = nScrollPos + nRow; - if ( nVecPos < (long)maConditions.size() ) - { - maConditions.erase( maConditions.begin() + nVecPos ); - ShowConditions(); - - if ( bHadFocus && !pBtn->IsEnabled() ) - { - // If the button is disabled, focus would normally move to the next control, - // (left edit of the next row). Move it to left edit of this row instead. - - mpEdActive = mpLeftEdit[nRow]; - mpEdActive->GrabFocus(); - } - } - } - - return 0; -} - -//---------------------------------------------------------------------------- - -IMPL_LINK( ScOptSolverDlg, TargetModifyHdl, Edit*, EMPTYARG ) -{ - // modify handler for the target edit: - // select "Value of" if something is input into the edit - if ( maEdTargetValue.GetText().Len() ) - maRbValue.Check(); - return 0; -} - -IMPL_LINK( ScOptSolverDlg, CondModifyHdl, Edit*, EMPTYARG ) -{ - // modify handler for the condition edits, just to enable/disable "delete" buttons - ReadConditions(); - EnableButtons(); - return 0; -} - -IMPL_LINK( ScOptSolverDlg, SelectHdl, ListBox*, EMPTYARG ) -{ - // select handler for operator list boxes, just to enable/disable "delete" buttons - ReadConditions(); - EnableButtons(); - return 0; -} - -IMPL_LINK( ScOptSolverDlg, ScrollHdl, ScrollBar*, EMPTYARG ) -{ - ReadConditions(); - nScrollPos = maScrollBar.GetThumbPos(); - ShowConditions(); - if( mpEdActive ) - mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) ); - return 0; -} - -IMPL_LINK( ScOptSolverDlg, CursorUpHdl, ScCursorRefEdit*, pEdit ) -{ - if ( pEdit == mpLeftEdit[0] || pEdit == mpRightEdit[0] ) - { - if ( nScrollPos > 0 ) - { - ReadConditions(); - --nScrollPos; - ShowConditions(); - if( mpEdActive ) - mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) ); - } - } - else - { - ScRefEdit* pFocus = NULL; - for ( sal_uInt16 nRow = 1; nRow < EDIT_ROW_COUNT; ++nRow ) // second row or below: move focus - { - if ( pEdit == mpLeftEdit[nRow] ) - pFocus = mpLeftEdit[nRow-1]; - else if ( pEdit == mpRightEdit[nRow] ) - pFocus = mpRightEdit[nRow-1]; - } - if (pFocus) - { - mpEdActive = pFocus; - pFocus->GrabFocus(); - } - } - - return 0; -} - -IMPL_LINK( ScOptSolverDlg, CursorDownHdl, ScCursorRefEdit*, pEdit ) -{ - if ( pEdit == mpLeftEdit[EDIT_ROW_COUNT-1] || pEdit == mpRightEdit[EDIT_ROW_COUNT-1] ) - { - //! limit scroll position? - ReadConditions(); - ++nScrollPos; - ShowConditions(); - if( mpEdActive ) - mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) ); - } - else - { - ScRefEdit* pFocus = NULL; - for ( sal_uInt16 nRow = 0; nRow+1 < EDIT_ROW_COUNT; ++nRow ) // before last row: move focus - { - if ( pEdit == mpLeftEdit[nRow] ) - pFocus = mpLeftEdit[nRow+1]; - else if ( pEdit == mpRightEdit[nRow] ) - pFocus = mpRightEdit[nRow+1]; - } - if (pFocus) - { - mpEdActive = pFocus; - pFocus->GrabFocus(); - } - } - - return 0; -} - -//---------------------------------------------------------------------------- - -void ScOptSolverDlg::ShowError( bool bCondition, ScRefEdit* pFocus ) -{ - String aMessage = bCondition ? maConditionError : maInputError; - ErrorBox( this, WinBits( WB_OK | WB_DEF_OK ), aMessage ).Execute(); - if (pFocus) - { - mpEdActive = pFocus; - pFocus->GrabFocus(); - } -} - -//---------------------------------------------------------------------------- - -bool ScOptSolverDlg::ParseRef( ScRange& rRange, const String& rInput, bool bAllowRange ) -{ - ScRangeUtil aRangeUtil; - ScAddress::Details aDetails(mpDoc->GetAddressConvention(), 0, 0); - USHORT nFlags = rRange.ParseAny( rInput, mpDoc, aDetails ); - if ( nFlags & SCA_VALID ) - { - if ( (nFlags & SCA_TAB_3D) == 0 ) - rRange.aStart.SetTab( mnCurTab ); - if ( (nFlags & SCA_TAB2_3D) == 0 ) - rRange.aEnd.SetTab( rRange.aStart.Tab() ); - return ( bAllowRange || rRange.aStart == rRange.aEnd ); - } - else if ( aRangeUtil.MakeRangeFromName( rInput, mpDoc, mnCurTab, rRange, RUTL_NAMES, aDetails ) ) - return ( bAllowRange || rRange.aStart == rRange.aEnd ); - - return false; // not recognized -} - -bool ScOptSolverDlg::FindTimeout( sal_Int32& rTimeout ) -{ - bool bFound = false; - - if ( !maProperties.getLength() ) - maProperties = ScSolverUtil::GetDefaults( maEngine ); // get property defaults from component - - sal_Int32 nPropCount = maProperties.getLength(); - for (sal_Int32 nProp=0; nProp<nPropCount && !bFound; ++nProp) - { - const beans::PropertyValue& rValue = maProperties[nProp]; - if ( rValue.Name.equalsAscii( SC_UNONAME_TIMEOUT ) ) - bFound = ( rValue.Value >>= rTimeout ); - } - return bFound; -} - -bool ScOptSolverDlg::CallSolver() // return true -> close dialog after calling -{ - // show progress dialog - - ScSolverProgressDialog aProgress( this ); - sal_Int32 nTimeout = 0; - if ( FindTimeout( nTimeout ) ) - aProgress.SetTimeLimit( nTimeout ); - else - aProgress.HideTimeLimit(); - aProgress.Show(); - aProgress.Update(); - aProgress.Sync(); - // try to make sure the progress dialog is painted before continuing - Application::Reschedule(true); - - // collect solver parameters - - ReadConditions(); - - uno::Reference<sheet::XSpreadsheetDocument> xDocument( mpDocShell->GetModel(), uno::UNO_QUERY ); - - ScRange aObjRange; - if ( !ParseRef( aObjRange, maEdObjectiveCell.GetText(), false ) ) - { - ShowError( false, &maEdObjectiveCell ); - return false; - } - table::CellAddress aObjective( aObjRange.aStart.Tab(), aObjRange.aStart.Col(), aObjRange.aStart.Row() ); - - // "changing cells" can be several ranges - ScRangeList aVarRanges; - if ( !ParseWithNames( aVarRanges, maEdVariableCells.GetText(), mpDoc ) ) - { - ShowError( false, &maEdVariableCells ); - return false; - } - uno::Sequence<table::CellAddress> aVariables; - sal_Int32 nVarPos = 0; - ULONG nRangeCount = aVarRanges.Count(); - for (ULONG nRangePos=0; nRangePos<nRangeCount; ++nRangePos) - { - ScRange aRange(*aVarRanges.GetObject(nRangePos)); - aRange.Justify(); - SCTAB nTab = aRange.aStart.Tab(); - - // resolve into single cells - - sal_Int32 nAdd = ( aRange.aEnd.Col() - aRange.aStart.Col() + 1 ) * - ( aRange.aEnd.Row() - aRange.aStart.Row() + 1 ); - aVariables.realloc( nVarPos + nAdd ); - - for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow) - for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol) - aVariables[nVarPos++] = table::CellAddress( nTab, nCol, nRow ); - } - - uno::Sequence<sheet::SolverConstraint> aConstraints; - sal_Int32 nConstrPos = 0; - for ( std::vector<ScOptConditionRow>::const_iterator aConstrIter = maConditions.begin(); - aConstrIter != maConditions.end(); ++aConstrIter ) - { - if ( aConstrIter->aLeftStr.Len() ) - { - sheet::SolverConstraint aConstraint; - // order of list box entries must match enum values - aConstraint.Operator = static_cast<sheet::SolverConstraintOperator>(aConstrIter->nOperator); - - ScRange aLeftRange; - if ( !ParseRef( aLeftRange, aConstrIter->aLeftStr, true ) ) - { - ShowError( true, NULL ); - return false; - } - - bool bIsRange = false; - ScRange aRightRange; - if ( ParseRef( aRightRange, aConstrIter->aRightStr, true ) ) - { - if ( aRightRange.aStart == aRightRange.aEnd ) - aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(), - aRightRange.aStart.Col(), aRightRange.aStart.Row() ); - else if ( aRightRange.aEnd.Col()-aRightRange.aStart.Col() == aLeftRange.aEnd.Col()-aLeftRange.aStart.Col() && - aRightRange.aEnd.Row()-aRightRange.aStart.Row() == aLeftRange.aEnd.Row()-aLeftRange.aStart.Row() ) - bIsRange = true; // same size as "left" range, resolve into single cells - else - { - ShowError( true, NULL ); - return false; - } - } - else - { - sal_uInt32 nFormat = 0; //! explicit language? - double fValue = 0.0; - if ( mpDoc->GetFormatTable()->IsNumberFormat( aConstrIter->aRightStr, nFormat, fValue ) ) - aConstraint.Right <<= fValue; - else if ( aConstraint.Operator != sheet::SolverConstraintOperator_INTEGER && - aConstraint.Operator != sheet::SolverConstraintOperator_BINARY ) - { - ShowError( true, NULL ); - return false; - } - } - - // resolve into single cells - - sal_Int32 nAdd = ( aLeftRange.aEnd.Col() - aLeftRange.aStart.Col() + 1 ) * - ( aLeftRange.aEnd.Row() - aLeftRange.aStart.Row() + 1 ); - aConstraints.realloc( nConstrPos + nAdd ); - - for (SCROW nRow = aLeftRange.aStart.Row(); nRow <= aLeftRange.aEnd.Row(); ++nRow) - for (SCCOL nCol = aLeftRange.aStart.Col(); nCol <= aLeftRange.aEnd.Col(); ++nCol) - { - aConstraint.Left = table::CellAddress( aLeftRange.aStart.Tab(), nCol, nRow ); - if ( bIsRange ) - aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(), - aRightRange.aStart.Col() + ( nCol - aLeftRange.aStart.Col() ), - aRightRange.aStart.Row() + ( nRow - aLeftRange.aStart.Row() ) ); - - aConstraints[nConstrPos++] = aConstraint; - } - } - } - - sal_Bool bMaximize = maRbMax.IsChecked(); - if ( maRbValue.IsChecked() ) - { - // handle "value of" with an additional constraint (and then minimize) - - sheet::SolverConstraint aConstraint; - aConstraint.Left = aObjective; - aConstraint.Operator = sheet::SolverConstraintOperator_EQUAL; - - String aValStr = maEdTargetValue.GetText(); - ScRange aRightRange; - if ( ParseRef( aRightRange, aValStr, false ) ) - aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(), - aRightRange.aStart.Col(), aRightRange.aStart.Row() ); - else - { - sal_uInt32 nFormat = 0; //! explicit language? - double fValue = 0.0; - if ( mpDoc->GetFormatTable()->IsNumberFormat( aValStr, nFormat, fValue ) ) - aConstraint.Right <<= fValue; - else - { - ShowError( false, &maEdTargetValue ); - return false; - } - } - - aConstraints.realloc( nConstrPos + 1 ); - aConstraints[nConstrPos++] = aConstraint; - } - - // copy old document values - - sal_Int32 nVarCount = aVariables.getLength(); - uno::Sequence<double> aOldValues; - aOldValues.realloc( nVarCount ); - for (nVarPos=0; nVarPos<nVarCount; ++nVarPos) - { - ScAddress aCellPos; - ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] ); - aOldValues[nVarPos] = mpDoc->GetValue( aCellPos ); - } - - // create and initialize solver - - uno::Reference<sheet::XSolver> xSolver = ScSolverUtil::GetSolver( maEngine ); - DBG_ASSERT( xSolver.is(), "can't get solver component" ); - if ( !xSolver.is() ) - return false; - - xSolver->setDocument( xDocument ); - xSolver->setObjective( aObjective ); - xSolver->setVariables( aVariables ); - xSolver->setConstraints( aConstraints ); - xSolver->setMaximize( bMaximize ); - - // set options - uno::Reference<beans::XPropertySet> xOptProp(xSolver, uno::UNO_QUERY); - if ( xOptProp.is() ) - { - sal_Int32 nPropCount = maProperties.getLength(); - for (sal_Int32 nProp=0; nProp<nPropCount; ++nProp) - { - const beans::PropertyValue& rValue = maProperties[nProp]; - try - { - xOptProp->setPropertyValue( rValue.Name, rValue.Value ); - } - catch ( uno::Exception & ) - { - DBG_ERRORFILE("Exception in solver option property"); - } - } - } - - xSolver->solve(); - sal_Bool bSuccess = xSolver->getSuccess(); - - aProgress.Hide(); - bool bClose = false; - bool bRestore = true; // restore old values unless a solution is accepted - if ( bSuccess ) - { - // put solution into document so it is visible when asking - uno::Sequence<double> aSolution = xSolver->getSolution(); - if ( aSolution.getLength() == nVarCount ) - { - mpDocShell->LockPaint(); - ScDocFunc aFunc(*mpDocShell); - for (nVarPos=0; nVarPos<nVarCount; ++nVarPos) - { - ScAddress aCellPos; - ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] ); - aFunc.PutCell( aCellPos, new ScValueCell( aSolution[nVarPos] ), TRUE ); - } - mpDocShell->UnlockPaint(); - } - //! else error? - - // take formatted result from document (result value from component is ignored) - String aResultStr; - mpDoc->GetString( (SCCOL)aObjective.Column, (SCROW)aObjective.Row, (SCTAB)aObjective.Sheet, aResultStr ); - ScSolverSuccessDialog aDialog( this, aResultStr ); - if ( aDialog.Execute() == RET_OK ) - { - // keep results and close dialog - bRestore = false; - bClose = true; - } - } - else - { - rtl::OUString aError; - uno::Reference<sheet::XSolverDescription> xDesc( xSolver, uno::UNO_QUERY ); - if ( xDesc.is() ) - aError = xDesc->getStatusDescription(); // error description from component - ScSolverNoSolutionDialog aDialog( this, aError ); - aDialog.Execute(); - } - - if ( bRestore ) // restore old values - { - mpDocShell->LockPaint(); - ScDocFunc aFunc(*mpDocShell); - for (nVarPos=0; nVarPos<nVarCount; ++nVarPos) - { - ScAddress aCellPos; - ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] ); - aFunc.PutCell( aCellPos, new ScValueCell( aOldValues[nVarPos] ), TRUE ); - } - mpDocShell->UnlockPaint(); - } - - return bClose; -} - +/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: optsolver.cxx,v $
+ * $Revision: 1.5 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+//----------------------------------------------------------------------------
+
+#include "rangelst.hxx"
+#include "scitems.hxx"
+#include <sfx2/bindings.hxx>
+#include <sfx2/imagemgr.hxx>
+#include <svtools/zforlist.hxx>
+#include <vcl/msgbox.hxx>
+#include <vcl/svapp.hxx>
+
+#include "uiitems.hxx"
+#include "reffact.hxx"
+#include "docsh.hxx"
+#include "docfunc.hxx"
+#include "cell.hxx"
+#include "rangeutl.hxx"
+#include "scresid.hxx"
+#include "convuno.hxx"
+#include "unonames.hxx"
+#include "solveroptions.hxx"
+#include "solverutil.hxx"
+#include "optsolver.hrc"
+
+#include "optsolver.hxx"
+
+#include <com/sun/star/sheet/Solver.hpp>
+#include <com/sun/star/sheet/XSolverDescription.hpp>
+
+using namespace com::sun::star;
+
+//----------------------------------------------------------------------------
+
+ScSolverProgressDialog::ScSolverProgressDialog( Window* pParent )
+ : ModelessDialog( pParent, ScResId( RID_SCDLG_SOLVER_PROGRESS ) ),
+ maFtProgress ( this, ScResId( FT_PROGRESS ) ),
+ maFtTime ( this, ScResId( FT_TIMELIMIT ) ),
+ maFlButtons ( this, ScResId( FL_BUTTONS ) ),
+ maBtnOk ( this, ScResId( BTN_OK ) )
+{
+ maBtnOk.Enable(FALSE);
+ FreeResource();
+}
+
+ScSolverProgressDialog::~ScSolverProgressDialog()
+{
+}
+
+void ScSolverProgressDialog::HideTimeLimit()
+{
+ maFtTime.Hide();
+}
+
+void ScSolverProgressDialog::SetTimeLimit( sal_Int32 nSeconds )
+{
+ String aOld = maFtTime.GetText();
+ String aNew = aOld.GetToken(0,'#');
+ aNew += String::CreateFromInt32( nSeconds );
+ aNew += aOld.GetToken(1,'#');
+ maFtTime.SetText( aNew );
+}
+
+//----------------------------------------------------------------------------
+
+ScSolverNoSolutionDialog::ScSolverNoSolutionDialog( Window* pParent, const String& rErrorText )
+ : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_NOSOLUTION ) ),
+ maFtNoSolution ( this, ScResId( FT_NOSOLUTION ) ),
+ maFtErrorText ( this, ScResId( FT_ERRORTEXT ) ),
+ maFlButtons ( this, ScResId( FL_BUTTONS ) ),
+ maBtnOk ( this, ScResId( BTN_OK ) )
+{
+ maFtErrorText.SetText( rErrorText );
+ FreeResource();
+}
+
+ScSolverNoSolutionDialog::~ScSolverNoSolutionDialog()
+{
+}
+
+//----------------------------------------------------------------------------
+
+ScSolverSuccessDialog::ScSolverSuccessDialog( Window* pParent, const String& rSolution )
+ : ModalDialog( pParent, ScResId( RID_SCDLG_SOLVER_SUCCESS ) ),
+ maFtSuccess ( this, ScResId( FT_SUCCESS ) ),
+ maFtResult ( this, ScResId( FT_RESULT ) ),
+ maFtQuestion ( this, ScResId( FT_QUESTION ) ),
+ maFlButtons ( this, ScResId( FL_BUTTONS ) ),
+ maBtnOk ( this, ScResId( BTN_OK ) ),
+ maBtnCancel ( this, ScResId( BTN_CANCEL ) )
+{
+ String aMessage = maFtResult.GetText();
+ aMessage.Append( (sal_Char) ' ' );
+ aMessage.Append( rSolution );
+ maFtResult.SetText( aMessage );
+ FreeResource();
+}
+
+ScSolverSuccessDialog::~ScSolverSuccessDialog()
+{
+}
+
+//----------------------------------------------------------------------------
+
+ScCursorRefEdit::ScCursorRefEdit( ScAnyRefDlg* pParent, const ResId& rResId ) :
+ formula::RefEdit( pParent, rResId )
+{
+}
+
+void ScCursorRefEdit::SetCursorLinks( const Link& rUp, const Link& rDown )
+{
+ maCursorUpLink = rUp;
+ maCursorDownLink = rDown;
+}
+
+void ScCursorRefEdit::KeyInput( const KeyEvent& rKEvt )
+{
+ KeyCode aCode = rKEvt.GetKeyCode();
+ bool bUp = (aCode.GetCode() == KEY_UP);
+ bool bDown = (aCode.GetCode() == KEY_DOWN);
+ if ( !aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() && ( bUp || bDown ) )
+ {
+ if ( bUp )
+ maCursorUpLink.Call( this );
+ else
+ maCursorDownLink.Call( this );
+ }
+ else
+ formula::RefEdit::KeyInput( rKEvt );
+}
+
+//----------------------------------------------------------------------------
+
+ScOptSolverSave::ScOptSolverSave( const String& rObjective, BOOL bMax, BOOL bMin, BOOL bValue,
+ const String& rTarget, const String& rVariable,
+ const std::vector<ScOptConditionRow>& rConditions,
+ const String& rEngine,
+ const uno::Sequence<beans::PropertyValue>& rProperties ) :
+ maObjective( rObjective ),
+ mbMax( bMax ),
+ mbMin( bMin ),
+ mbValue( bValue ),
+ maTarget( rTarget ),
+ maVariable( rVariable ),
+ maConditions( rConditions ),
+ maEngine( rEngine ),
+ maProperties( rProperties )
+{
+}
+
+//============================================================================
+// class ScOptSolverDlg
+//----------------------------------------------------------------------------
+
+ScOptSolverDlg::ScOptSolverDlg( SfxBindings* pB, SfxChildWindow* pCW, Window* pParent,
+ ScDocShell* pDocSh, ScAddress aCursorPos )
+
+ : ScAnyRefDlg ( pB, pCW, pParent, RID_SCDLG_OPTSOLVER ),
+ //
+ maFtObjectiveCell ( this, ScResId( FT_OBJECTIVECELL ) ),
+ maEdObjectiveCell ( this, ScResId( ED_OBJECTIVECELL ) ),
+ maRBObjectiveCell ( this, ScResId( IB_OBJECTIVECELL ), &maEdObjectiveCell, this ),
+ maFtDirection ( this, ScResId( FT_DIRECTION ) ),
+ maRbMax ( this, ScResId( RB_MAX ) ),
+ maRbMin ( this, ScResId( RB_MIN ) ),
+ maRbValue ( this, ScResId( RB_VALUE ) ),
+ maEdTargetValue ( this, ScResId( ED_TARGET ) ),
+ maRBTargetValue ( this, ScResId( IB_TARGET ), &maEdTargetValue, this ),
+ maFtVariableCells ( this, ScResId( FT_VARIABLECELLS ) ),
+ maEdVariableCells ( this, ScResId( ED_VARIABLECELLS ) ),
+ maRBVariableCells ( this, ScResId( IB_VARIABLECELLS ), &maEdVariableCells, this),
+ maFlConditions ( this, ScResId( FL_CONDITIONS ) ),
+ maFtCellRef ( this, ScResId( FT_CELLREF ) ),
+ maEdLeft1 ( this, ScResId( ED_LEFT1 ) ),
+ maRBLeft1 ( this, ScResId( IB_LEFT1 ), &maEdLeft1, this ),
+ maFtOperator ( this, ScResId( FT_OPERATOR ) ),
+ maLbOp1 ( this, ScResId( LB_OP1 ) ),
+ maFtConstraint ( this, ScResId( FT_CONSTRAINT ) ),
+ maEdRight1 ( this, ScResId( ED_RIGHT1 ) ),
+ maRBRight1 ( this, ScResId( IB_RIGHT1 ), &maEdRight1, this ),
+ maBtnDel1 ( this, ScResId( IB_DELETE1 ) ),
+ maEdLeft2 ( this, ScResId( ED_LEFT2 ) ),
+ maRBLeft2 ( this, ScResId( IB_LEFT2 ), &maEdLeft2, this ),
+ maLbOp2 ( this, ScResId( LB_OP2 ) ),
+ maEdRight2 ( this, ScResId( ED_RIGHT2 ) ),
+ maRBRight2 ( this, ScResId( IB_RIGHT2 ), &maEdRight2, this ),
+ maBtnDel2 ( this, ScResId( IB_DELETE2 ) ),
+ maEdLeft3 ( this, ScResId( ED_LEFT3 ) ),
+ maRBLeft3 ( this, ScResId( IB_LEFT3 ), &maEdLeft3, this ),
+ maLbOp3 ( this, ScResId( LB_OP3 ) ),
+ maEdRight3 ( this, ScResId( ED_RIGHT3 ) ),
+ maRBRight3 ( this, ScResId( IB_RIGHT3 ), &maEdRight3, this ),
+ maBtnDel3 ( this, ScResId( IB_DELETE3 ) ),
+ maEdLeft4 ( this, ScResId( ED_LEFT4 ) ),
+ maRBLeft4 ( this, ScResId( IB_LEFT4 ), &maEdLeft4, this ),
+ maLbOp4 ( this, ScResId( LB_OP4 ) ),
+ maEdRight4 ( this, ScResId( ED_RIGHT4 ) ),
+ maRBRight4 ( this, ScResId( IB_RIGHT4 ), &maEdRight4, this ),
+ maBtnDel4 ( this, ScResId( IB_DELETE4 ) ),
+ maScrollBar ( this, ScResId( SB_SCROLL ) ),
+ maFlButtons ( this, ScResId( FL_BUTTONS ) ),
+ maBtnOpt ( this, ScResId( BTN_OPTIONS ) ),
+ maBtnHelp ( this, ScResId( BTN_HELP ) ),
+ maBtnCancel ( this, ScResId( BTN_CLOSE ) ),
+ maBtnSolve ( this, ScResId( BTN_SOLVE ) ),
+ maInputError ( ScResId( STR_INVALIDINPUT ) ),
+ maConditionError ( ScResId( STR_INVALIDCONDITION ) ),
+ //
+ mpDocShell ( pDocSh ),
+ mpDoc ( pDocSh->GetDocument() ),
+ mnCurTab ( aCursorPos.Tab() ),
+ mpEdActive ( NULL ),
+ mbDlgLostFocus ( false ),
+ nScrollPos ( 0 )
+{
+ mpLeftEdit[0] = &maEdLeft1;
+ mpLeftButton[0] = &maRBLeft1;
+ mpRightEdit[0] = &maEdRight1;
+ mpRightButton[0] = &maRBRight1;
+ mpOperator[0] = &maLbOp1;
+ mpDelButton[0] = &maBtnDel1;
+
+ mpLeftEdit[1] = &maEdLeft2;
+ mpLeftButton[1] = &maRBLeft2;
+ mpRightEdit[1] = &maEdRight2;
+ mpRightButton[1] = &maRBRight2;
+ mpOperator[1] = &maLbOp2;
+ mpDelButton[1] = &maBtnDel2;
+
+ mpLeftEdit[2] = &maEdLeft3;
+ mpLeftButton[2] = &maRBLeft3;
+ mpRightEdit[2] = &maEdRight3;
+ mpRightButton[2] = &maRBRight3;
+ mpOperator[2] = &maLbOp3;
+ mpDelButton[2] = &maBtnDel3;
+
+ mpLeftEdit[3] = &maEdLeft4;
+ mpLeftButton[3] = &maRBLeft4;
+ mpRightEdit[3] = &maEdRight4;
+ mpRightButton[3] = &maRBRight4;
+ mpOperator[3] = &maLbOp4;
+ mpDelButton[3] = &maBtnDel4;
+
+ Init( aCursorPos );
+ FreeResource();
+}
+
+//----------------------------------------------------------------------------
+
+ScOptSolverDlg::~ScOptSolverDlg()
+{
+}
+
+//----------------------------------------------------------------------------
+
+void ScOptSolverDlg::Init(const ScAddress& rCursorPos)
+{
+ // Get the "Delete Rows" commandimagelist images from sfx instead of
+ // adding a second copy to sc (see ScTbxInsertCtrl::StateChanged)
+
+ rtl::OUString aSlotURL( RTL_CONSTASCII_USTRINGPARAM( "slot:" ));
+ aSlotURL += rtl::OUString::valueOf( sal_Int32( SID_DEL_ROWS ) );
+ uno::Reference<frame::XFrame> xFrame = GetBindings().GetActiveFrame();
+ Image aDelNm = ::GetImage( xFrame, aSlotURL, FALSE, FALSE );
+ Image aDelHC = ::GetImage( xFrame, aSlotURL, FALSE, TRUE ); // high contrast
+
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ mpDelButton[nRow]->SetModeImage( aDelNm, BMP_COLOR_NORMAL );
+ mpDelButton[nRow]->SetModeImage( aDelHC, BMP_COLOR_HIGHCONTRAST );
+ }
+
+ maBtnOpt.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) );
+ maBtnCancel.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) );
+ maBtnSolve.SetClickHdl( LINK( this, ScOptSolverDlg, BtnHdl ) );
+
+ Link aLink = LINK( this, ScOptSolverDlg, GetFocusHdl );
+ maEdObjectiveCell.SetGetFocusHdl( aLink );
+ maRBObjectiveCell.SetGetFocusHdl( aLink );
+ maEdTargetValue.SetGetFocusHdl( aLink );
+ maRBTargetValue.SetGetFocusHdl( aLink );
+ maEdVariableCells.SetGetFocusHdl( aLink );
+ maRBVariableCells.SetGetFocusHdl( aLink );
+ maRbValue.SetGetFocusHdl( aLink );
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ mpLeftEdit[nRow]->SetGetFocusHdl( aLink );
+ mpLeftButton[nRow]->SetGetFocusHdl( aLink );
+ mpRightEdit[nRow]->SetGetFocusHdl( aLink );
+ mpRightButton[nRow]->SetGetFocusHdl( aLink );
+ mpOperator[nRow]->SetGetFocusHdl( aLink );
+ }
+
+ aLink = LINK( this, ScOptSolverDlg, LoseFocusHdl );
+ maEdObjectiveCell.SetLoseFocusHdl( aLink );
+ maRBObjectiveCell.SetLoseFocusHdl( aLink );
+ maEdTargetValue. SetLoseFocusHdl( aLink );
+ maRBTargetValue. SetLoseFocusHdl( aLink );
+ maEdVariableCells.SetLoseFocusHdl( aLink );
+ maRBVariableCells.SetLoseFocusHdl( aLink );
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ mpLeftEdit[nRow]->SetLoseFocusHdl( aLink );
+ mpLeftButton[nRow]->SetLoseFocusHdl( aLink );
+ mpRightEdit[nRow]->SetLoseFocusHdl( aLink );
+ mpRightButton[nRow]->SetLoseFocusHdl( aLink );
+ }
+
+ Link aCursorUp = LINK( this, ScOptSolverDlg, CursorUpHdl );
+ Link aCursorDown = LINK( this, ScOptSolverDlg, CursorDownHdl );
+ Link aCondModify = LINK( this, ScOptSolverDlg, CondModifyHdl );
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ mpLeftEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown );
+ mpRightEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown );
+ mpLeftEdit[nRow]->SetModifyHdl( aCondModify );
+ mpRightEdit[nRow]->SetModifyHdl( aCondModify );
+ mpDelButton[nRow]->SetClickHdl( LINK( this, ScOptSolverDlg, DelBtnHdl ) );
+ mpOperator[nRow]->SetSelectHdl( LINK( this, ScOptSolverDlg, SelectHdl ) );
+ }
+ maEdTargetValue.SetModifyHdl( LINK( this, ScOptSolverDlg, TargetModifyHdl ) );
+
+ maScrollBar.SetEndScrollHdl( LINK( this, ScOptSolverDlg, ScrollHdl ) );
+ maScrollBar.SetScrollHdl( LINK( this, ScOptSolverDlg, ScrollHdl ) );
+
+ maScrollBar.SetPageSize( EDIT_ROW_COUNT );
+ maScrollBar.SetVisibleSize( EDIT_ROW_COUNT );
+ maScrollBar.SetLineSize( 1 );
+ // Range is set in ShowConditions
+
+ // get available solver implementations
+ //! sort by descriptions?
+ ScSolverUtil::GetImplementations( maImplNames, maDescriptions );
+ sal_Int32 nImplCount = maImplNames.getLength();
+
+ const ScOptSolverSave* pOldData = mpDocShell->GetSolverSaveData();
+ if ( pOldData )
+ {
+ maEdObjectiveCell.SetRefString( pOldData->GetObjective() );
+ maRbMax.Check( pOldData->GetMax() );
+ maRbMin.Check( pOldData->GetMin() );
+ maRbValue.Check( pOldData->GetValue() );
+ maEdTargetValue.SetRefString( pOldData->GetTarget() );
+ maEdVariableCells.SetRefString( pOldData->GetVariable() );
+ maConditions = pOldData->GetConditions();
+ maEngine = pOldData->GetEngine();
+ maProperties = pOldData->GetProperties();
+ }
+ else
+ {
+ maRbMax.Check();
+ String aCursorStr;
+ if ( !mpDoc->GetRangeAtBlock( ScRange(rCursorPos), &aCursorStr ) )
+ rCursorPos.Format( aCursorStr, SCA_ABS, NULL, mpDoc->GetAddressConvention() );
+ maEdObjectiveCell.SetRefString( aCursorStr );
+ if ( nImplCount > 0 )
+ maEngine = maImplNames[0]; // use first implementation
+ }
+ ShowConditions();
+
+ maEdObjectiveCell.GrabFocus();
+ mpEdActive = &maEdObjectiveCell;
+}
+
+//----------------------------------------------------------------------------
+
+void ScOptSolverDlg::ReadConditions()
+{
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ ScOptConditionRow aRowEntry;
+ aRowEntry.aLeftStr = mpLeftEdit[nRow]->GetText();
+ aRowEntry.aRightStr = mpRightEdit[nRow]->GetText();
+ aRowEntry.nOperator = mpOperator[nRow]->GetSelectEntryPos();
+
+ long nVecPos = nScrollPos + nRow;
+ if ( nVecPos >= (long)maConditions.size() && !aRowEntry.IsDefault() )
+ maConditions.resize( nVecPos + 1 );
+
+ if ( nVecPos < (long)maConditions.size() )
+ maConditions[nVecPos] = aRowEntry;
+
+ // remove default entries at the end
+ size_t nSize = maConditions.size();
+ while ( nSize > 0 && maConditions[ nSize-1 ].IsDefault() )
+ --nSize;
+ maConditions.resize( nSize );
+ }
+}
+
+void ScOptSolverDlg::ShowConditions()
+{
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ ScOptConditionRow aRowEntry;
+
+ long nVecPos = nScrollPos + nRow;
+ if ( nVecPos < (long)maConditions.size() )
+ aRowEntry = maConditions[nVecPos];
+
+ mpLeftEdit[nRow]->SetRefString( aRowEntry.aLeftStr );
+ mpRightEdit[nRow]->SetRefString( aRowEntry.aRightStr );
+ mpOperator[nRow]->SelectEntryPos( aRowEntry.nOperator );
+ }
+
+ // allow to scroll one page behind the visible or stored rows
+ long nVisible = nScrollPos + EDIT_ROW_COUNT;
+ long nMax = std::max( nVisible, (long) maConditions.size() );
+ maScrollBar.SetRange( Range( 0, nMax + EDIT_ROW_COUNT ) );
+ maScrollBar.SetThumbPos( nScrollPos );
+
+ EnableButtons();
+}
+
+void ScOptSolverDlg::EnableButtons()
+{
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ long nVecPos = nScrollPos + nRow;
+ mpDelButton[nRow]->Enable( nVecPos < (long)maConditions.size() );
+ }
+}
+
+//----------------------------------------------------------------------------
+
+BOOL ScOptSolverDlg::Close()
+{
+ return DoClose( ScOptSolverDlgWrapper::GetChildWindowId() );
+}
+
+//----------------------------------------------------------------------------
+
+void ScOptSolverDlg::SetActive()
+{
+ if ( mbDlgLostFocus )
+ {
+ mbDlgLostFocus = false;
+ if( mpEdActive )
+ mpEdActive->GrabFocus();
+ }
+ else
+ {
+ GrabFocus();
+ }
+ RefInputDone();
+}
+
+//----------------------------------------------------------------------------
+
+void ScOptSolverDlg::SetReference( const ScRange& rRef, ScDocument* pDocP )
+{
+ if( mpEdActive )
+ {
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart(mpEdActive);
+
+ // "target"/"value": single cell
+ bool bSingle = ( mpEdActive == &maEdObjectiveCell || mpEdActive == &maEdTargetValue );
+
+ String aStr;
+ ScAddress aAdr = rRef.aStart;
+ ScRange aNewRef( rRef );
+ if ( bSingle )
+ aNewRef.aEnd = aAdr;
+
+ String aName;
+ if ( pDocP->GetRangeAtBlock( aNewRef, &aName ) ) // named range: show name
+ aStr = aName;
+ else // format cell/range reference
+ {
+ USHORT nFmt = ( aAdr.Tab() == mnCurTab ) ? SCA_ABS : SCA_ABS_3D;
+ if ( bSingle )
+ aAdr.Format( aStr, nFmt, pDocP, pDocP->GetAddressConvention() );
+ else
+ rRef.Format( aStr, nFmt | SCR_ABS, pDocP, pDocP->GetAddressConvention() );
+ }
+
+ // variable cells can be several ranges, so only the selection is replaced
+ if ( mpEdActive == &maEdVariableCells )
+ {
+ String aVal = mpEdActive->GetText();
+ Selection aSel = mpEdActive->GetSelection();
+ aSel.Justify();
+ aVal.Erase( (xub_StrLen)aSel.Min(), (xub_StrLen)aSel.Len() );
+ aVal.Insert( aStr, (xub_StrLen)aSel.Min() );
+ Selection aNewSel( aSel.Min(), aSel.Min()+aStr.Len() );
+ mpEdActive->SetRefString( aVal );
+ mpEdActive->SetSelection( aNewSel );
+ }
+ else
+ mpEdActive->SetRefString( aStr );
+
+ ReadConditions();
+ EnableButtons();
+
+ // select "Value of" if a ref is input into "target" edit
+ if ( mpEdActive == &maEdTargetValue )
+ maRbValue.Check();
+ }
+}
+
+//----------------------------------------------------------------------------
+
+BOOL ScOptSolverDlg::IsRefInputMode() const
+{
+ return mpEdActive != NULL;
+}
+
+//----------------------------------------------------------------------------
+// Handler:
+
+IMPL_LINK( ScOptSolverDlg, BtnHdl, PushButton*, pBtn )
+{
+ if ( pBtn == &maBtnSolve || pBtn == &maBtnCancel )
+ {
+ bool bSolve = ( pBtn == &maBtnSolve );
+
+ SetDispatcherLock( FALSE );
+ SwitchToDocument();
+
+ bool bClose = true;
+ if ( bSolve )
+ bClose = CallSolver();
+
+ if ( bClose )
+ {
+ // Close: write dialog settings to DocShell for subsequent calls
+ ReadConditions();
+ ScOptSolverSave aSave(
+ maEdObjectiveCell.GetText(), maRbMax.IsChecked(), maRbMin.IsChecked(), maRbValue.IsChecked(),
+ maEdTargetValue.GetText(), maEdVariableCells.GetText(), maConditions, maEngine, maProperties );
+ mpDocShell->SetSolverSaveData( aSave );
+ Close();
+ }
+ else
+ {
+ // no solution -> dialog is kept open
+ SetDispatcherLock( TRUE );
+ }
+ }
+ else if ( pBtn == &maBtnOpt )
+ {
+ //! move options dialog to UI lib?
+ ScSolverOptionsDialog* pOptDlg =
+ new ScSolverOptionsDialog( this, maImplNames, maDescriptions, maEngine, maProperties );
+ if ( pOptDlg->Execute() == RET_OK )
+ {
+ maEngine = pOptDlg->GetEngine();
+ maProperties = pOptDlg->GetProperties();
+ }
+ delete pOptDlg;
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+
+IMPL_LINK( ScOptSolverDlg, GetFocusHdl, Control*, pCtrl )
+{
+ Edit* pEdit = NULL;
+ mpEdActive = NULL;
+
+ if( pCtrl == &maEdObjectiveCell || pCtrl == &maRBObjectiveCell )
+ pEdit = mpEdActive = &maEdObjectiveCell;
+ else if( pCtrl == &maEdTargetValue || pCtrl == &maRBTargetValue )
+ pEdit = mpEdActive = &maEdTargetValue;
+ else if( pCtrl == &maEdVariableCells || pCtrl == &maRBVariableCells )
+ pEdit = mpEdActive = &maEdVariableCells;
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ if( pCtrl == mpLeftEdit[nRow] || pCtrl == mpLeftButton[nRow] )
+ pEdit = mpEdActive = mpLeftEdit[nRow];
+ else if( pCtrl == mpRightEdit[nRow] || pCtrl == mpRightButton[nRow] )
+ pEdit = mpEdActive = mpRightEdit[nRow];
+ else if( pCtrl == mpOperator[nRow] ) // focus on "operator" list box
+ mpEdActive = mpRightEdit[nRow]; // use right edit for ref input, but don't change selection
+ }
+ if( pCtrl == &maRbValue ) // focus on "Value of" radio button
+ mpEdActive = &maEdTargetValue; // use value edit for ref input, but don't change selection
+
+ if( pEdit )
+ pEdit->SetSelection( Selection( 0, SELECTION_MAX ) );
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+
+IMPL_LINK( ScOptSolverDlg, LoseFocusHdl, Control*, EMPTYARG )
+{
+ mbDlgLostFocus = !IsActive();
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+
+IMPL_LINK( ScOptSolverDlg, DelBtnHdl, PushButton*, pBtn )
+{
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ if( pBtn == mpDelButton[nRow] )
+ {
+ BOOL bHadFocus = pBtn->HasFocus();
+
+ ReadConditions();
+ long nVecPos = nScrollPos + nRow;
+ if ( nVecPos < (long)maConditions.size() )
+ {
+ maConditions.erase( maConditions.begin() + nVecPos );
+ ShowConditions();
+
+ if ( bHadFocus && !pBtn->IsEnabled() )
+ {
+ // If the button is disabled, focus would normally move to the next control,
+ // (left edit of the next row). Move it to left edit of this row instead.
+
+ mpEdActive = mpLeftEdit[nRow];
+ mpEdActive->GrabFocus();
+ }
+ }
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+
+IMPL_LINK( ScOptSolverDlg, TargetModifyHdl, Edit*, EMPTYARG )
+{
+ // modify handler for the target edit:
+ // select "Value of" if something is input into the edit
+ if ( maEdTargetValue.GetText().Len() )
+ maRbValue.Check();
+ return 0;
+}
+
+IMPL_LINK( ScOptSolverDlg, CondModifyHdl, Edit*, EMPTYARG )
+{
+ // modify handler for the condition edits, just to enable/disable "delete" buttons
+ ReadConditions();
+ EnableButtons();
+ return 0;
+}
+
+IMPL_LINK( ScOptSolverDlg, SelectHdl, ListBox*, EMPTYARG )
+{
+ // select handler for operator list boxes, just to enable/disable "delete" buttons
+ ReadConditions();
+ EnableButtons();
+ return 0;
+}
+
+IMPL_LINK( ScOptSolverDlg, ScrollHdl, ScrollBar*, EMPTYARG )
+{
+ ReadConditions();
+ nScrollPos = maScrollBar.GetThumbPos();
+ ShowConditions();
+ if( mpEdActive )
+ mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) );
+ return 0;
+}
+
+IMPL_LINK( ScOptSolverDlg, CursorUpHdl, ScCursorRefEdit*, pEdit )
+{
+ if ( pEdit == mpLeftEdit[0] || pEdit == mpRightEdit[0] )
+ {
+ if ( nScrollPos > 0 )
+ {
+ ReadConditions();
+ --nScrollPos;
+ ShowConditions();
+ if( mpEdActive )
+ mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) );
+ }
+ }
+ else
+ {
+ formula::RefEdit* pFocus = NULL;
+ for ( sal_uInt16 nRow = 1; nRow < EDIT_ROW_COUNT; ++nRow ) // second row or below: move focus
+ {
+ if ( pEdit == mpLeftEdit[nRow] )
+ pFocus = mpLeftEdit[nRow-1];
+ else if ( pEdit == mpRightEdit[nRow] )
+ pFocus = mpRightEdit[nRow-1];
+ }
+ if (pFocus)
+ {
+ mpEdActive = pFocus;
+ pFocus->GrabFocus();
+ }
+ }
+
+ return 0;
+}
+
+IMPL_LINK( ScOptSolverDlg, CursorDownHdl, ScCursorRefEdit*, pEdit )
+{
+ if ( pEdit == mpLeftEdit[EDIT_ROW_COUNT-1] || pEdit == mpRightEdit[EDIT_ROW_COUNT-1] )
+ {
+ //! limit scroll position?
+ ReadConditions();
+ ++nScrollPos;
+ ShowConditions();
+ if( mpEdActive )
+ mpEdActive->SetSelection( Selection( 0, SELECTION_MAX ) );
+ }
+ else
+ {
+ formula::RefEdit* pFocus = NULL;
+ for ( sal_uInt16 nRow = 0; nRow+1 < EDIT_ROW_COUNT; ++nRow ) // before last row: move focus
+ {
+ if ( pEdit == mpLeftEdit[nRow] )
+ pFocus = mpLeftEdit[nRow+1];
+ else if ( pEdit == mpRightEdit[nRow] )
+ pFocus = mpRightEdit[nRow+1];
+ }
+ if (pFocus)
+ {
+ mpEdActive = pFocus;
+ pFocus->GrabFocus();
+ }
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+
+void ScOptSolverDlg::ShowError( bool bCondition, formula::RefEdit* pFocus )
+{
+ String aMessage = bCondition ? maConditionError : maInputError;
+ ErrorBox( this, WinBits( WB_OK | WB_DEF_OK ), aMessage ).Execute();
+ if (pFocus)
+ {
+ mpEdActive = pFocus;
+ pFocus->GrabFocus();
+ }
+}
+
+//----------------------------------------------------------------------------
+
+bool ScOptSolverDlg::ParseRef( ScRange& rRange, const String& rInput, bool bAllowRange )
+{
+ ScRangeUtil aRangeUtil;
+ ScAddress::Details aDetails(mpDoc->GetAddressConvention(), 0, 0);
+ USHORT nFlags = rRange.ParseAny( rInput, mpDoc, aDetails );
+ if ( nFlags & SCA_VALID )
+ {
+ if ( (nFlags & SCA_TAB_3D) == 0 )
+ rRange.aStart.SetTab( mnCurTab );
+ if ( (nFlags & SCA_TAB2_3D) == 0 )
+ rRange.aEnd.SetTab( rRange.aStart.Tab() );
+ return ( bAllowRange || rRange.aStart == rRange.aEnd );
+ }
+ else if ( aRangeUtil.MakeRangeFromName( rInput, mpDoc, mnCurTab, rRange, RUTL_NAMES, aDetails ) )
+ return ( bAllowRange || rRange.aStart == rRange.aEnd );
+
+ return false; // not recognized
+}
+
+bool ScOptSolverDlg::FindTimeout( sal_Int32& rTimeout )
+{
+ bool bFound = false;
+
+ if ( !maProperties.getLength() )
+ maProperties = ScSolverUtil::GetDefaults( maEngine ); // get property defaults from component
+
+ sal_Int32 nPropCount = maProperties.getLength();
+ for (sal_Int32 nProp=0; nProp<nPropCount && !bFound; ++nProp)
+ {
+ const beans::PropertyValue& rValue = maProperties[nProp];
+ if ( rValue.Name.equalsAscii( SC_UNONAME_TIMEOUT ) )
+ bFound = ( rValue.Value >>= rTimeout );
+ }
+ return bFound;
+}
+
+bool ScOptSolverDlg::CallSolver() // return true -> close dialog after calling
+{
+ // show progress dialog
+
+ ScSolverProgressDialog aProgress( this );
+ sal_Int32 nTimeout = 0;
+ if ( FindTimeout( nTimeout ) )
+ aProgress.SetTimeLimit( nTimeout );
+ else
+ aProgress.HideTimeLimit();
+ aProgress.Show();
+ aProgress.Update();
+ aProgress.Sync();
+ // try to make sure the progress dialog is painted before continuing
+ Application::Reschedule(true);
+
+ // collect solver parameters
+
+ ReadConditions();
+
+ uno::Reference<sheet::XSpreadsheetDocument> xDocument( mpDocShell->GetModel(), uno::UNO_QUERY );
+
+ ScRange aObjRange;
+ if ( !ParseRef( aObjRange, maEdObjectiveCell.GetText(), false ) )
+ {
+ ShowError( false, &maEdObjectiveCell );
+ return false;
+ }
+ table::CellAddress aObjective( aObjRange.aStart.Tab(), aObjRange.aStart.Col(), aObjRange.aStart.Row() );
+
+ // "changing cells" can be several ranges
+ ScRangeList aVarRanges;
+ if ( !ParseWithNames( aVarRanges, maEdVariableCells.GetText(), mpDoc ) )
+ {
+ ShowError( false, &maEdVariableCells );
+ return false;
+ }
+ uno::Sequence<table::CellAddress> aVariables;
+ sal_Int32 nVarPos = 0;
+ ULONG nRangeCount = aVarRanges.Count();
+ for (ULONG nRangePos=0; nRangePos<nRangeCount; ++nRangePos)
+ {
+ ScRange aRange(*aVarRanges.GetObject(nRangePos));
+ aRange.Justify();
+ SCTAB nTab = aRange.aStart.Tab();
+
+ // resolve into single cells
+
+ sal_Int32 nAdd = ( aRange.aEnd.Col() - aRange.aStart.Col() + 1 ) *
+ ( aRange.aEnd.Row() - aRange.aStart.Row() + 1 );
+ aVariables.realloc( nVarPos + nAdd );
+
+ for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
+ for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
+ aVariables[nVarPos++] = table::CellAddress( nTab, nCol, nRow );
+ }
+
+ uno::Sequence<sheet::SolverConstraint> aConstraints;
+ sal_Int32 nConstrPos = 0;
+ for ( std::vector<ScOptConditionRow>::const_iterator aConstrIter = maConditions.begin();
+ aConstrIter != maConditions.end(); ++aConstrIter )
+ {
+ if ( aConstrIter->aLeftStr.Len() )
+ {
+ sheet::SolverConstraint aConstraint;
+ // order of list box entries must match enum values
+ aConstraint.Operator = static_cast<sheet::SolverConstraintOperator>(aConstrIter->nOperator);
+
+ ScRange aLeftRange;
+ if ( !ParseRef( aLeftRange, aConstrIter->aLeftStr, true ) )
+ {
+ ShowError( true, NULL );
+ return false;
+ }
+
+ bool bIsRange = false;
+ ScRange aRightRange;
+ if ( ParseRef( aRightRange, aConstrIter->aRightStr, true ) )
+ {
+ if ( aRightRange.aStart == aRightRange.aEnd )
+ aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(),
+ aRightRange.aStart.Col(), aRightRange.aStart.Row() );
+ else if ( aRightRange.aEnd.Col()-aRightRange.aStart.Col() == aLeftRange.aEnd.Col()-aLeftRange.aStart.Col() &&
+ aRightRange.aEnd.Row()-aRightRange.aStart.Row() == aLeftRange.aEnd.Row()-aLeftRange.aStart.Row() )
+ bIsRange = true; // same size as "left" range, resolve into single cells
+ else
+ {
+ ShowError( true, NULL );
+ return false;
+ }
+ }
+ else
+ {
+ sal_uInt32 nFormat = 0; //! explicit language?
+ double fValue = 0.0;
+ if ( mpDoc->GetFormatTable()->IsNumberFormat( aConstrIter->aRightStr, nFormat, fValue ) )
+ aConstraint.Right <<= fValue;
+ else if ( aConstraint.Operator != sheet::SolverConstraintOperator_INTEGER &&
+ aConstraint.Operator != sheet::SolverConstraintOperator_BINARY )
+ {
+ ShowError( true, NULL );
+ return false;
+ }
+ }
+
+ // resolve into single cells
+
+ sal_Int32 nAdd = ( aLeftRange.aEnd.Col() - aLeftRange.aStart.Col() + 1 ) *
+ ( aLeftRange.aEnd.Row() - aLeftRange.aStart.Row() + 1 );
+ aConstraints.realloc( nConstrPos + nAdd );
+
+ for (SCROW nRow = aLeftRange.aStart.Row(); nRow <= aLeftRange.aEnd.Row(); ++nRow)
+ for (SCCOL nCol = aLeftRange.aStart.Col(); nCol <= aLeftRange.aEnd.Col(); ++nCol)
+ {
+ aConstraint.Left = table::CellAddress( aLeftRange.aStart.Tab(), nCol, nRow );
+ if ( bIsRange )
+ aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(),
+ aRightRange.aStart.Col() + ( nCol - aLeftRange.aStart.Col() ),
+ aRightRange.aStart.Row() + ( nRow - aLeftRange.aStart.Row() ) );
+
+ aConstraints[nConstrPos++] = aConstraint;
+ }
+ }
+ }
+
+ sal_Bool bMaximize = maRbMax.IsChecked();
+ if ( maRbValue.IsChecked() )
+ {
+ // handle "value of" with an additional constraint (and then minimize)
+
+ sheet::SolverConstraint aConstraint;
+ aConstraint.Left = aObjective;
+ aConstraint.Operator = sheet::SolverConstraintOperator_EQUAL;
+
+ String aValStr = maEdTargetValue.GetText();
+ ScRange aRightRange;
+ if ( ParseRef( aRightRange, aValStr, false ) )
+ aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(),
+ aRightRange.aStart.Col(), aRightRange.aStart.Row() );
+ else
+ {
+ sal_uInt32 nFormat = 0; //! explicit language?
+ double fValue = 0.0;
+ if ( mpDoc->GetFormatTable()->IsNumberFormat( aValStr, nFormat, fValue ) )
+ aConstraint.Right <<= fValue;
+ else
+ {
+ ShowError( false, &maEdTargetValue );
+ return false;
+ }
+ }
+
+ aConstraints.realloc( nConstrPos + 1 );
+ aConstraints[nConstrPos++] = aConstraint;
+ }
+
+ // copy old document values
+
+ sal_Int32 nVarCount = aVariables.getLength();
+ uno::Sequence<double> aOldValues;
+ aOldValues.realloc( nVarCount );
+ for (nVarPos=0; nVarPos<nVarCount; ++nVarPos)
+ {
+ ScAddress aCellPos;
+ ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] );
+ aOldValues[nVarPos] = mpDoc->GetValue( aCellPos );
+ }
+
+ // create and initialize solver
+
+ uno::Reference<sheet::XSolver> xSolver = ScSolverUtil::GetSolver( maEngine );
+ DBG_ASSERT( xSolver.is(), "can't get solver component" );
+ if ( !xSolver.is() )
+ return false;
+
+ xSolver->setDocument( xDocument );
+ xSolver->setObjective( aObjective );
+ xSolver->setVariables( aVariables );
+ xSolver->setConstraints( aConstraints );
+ xSolver->setMaximize( bMaximize );
+
+ // set options
+ uno::Reference<beans::XPropertySet> xOptProp(xSolver, uno::UNO_QUERY);
+ if ( xOptProp.is() )
+ {
+ sal_Int32 nPropCount = maProperties.getLength();
+ for (sal_Int32 nProp=0; nProp<nPropCount; ++nProp)
+ {
+ const beans::PropertyValue& rValue = maProperties[nProp];
+ try
+ {
+ xOptProp->setPropertyValue( rValue.Name, rValue.Value );
+ }
+ catch ( uno::Exception & )
+ {
+ DBG_ERRORFILE("Exception in solver option property");
+ }
+ }
+ }
+
+ xSolver->solve();
+ sal_Bool bSuccess = xSolver->getSuccess();
+
+ aProgress.Hide();
+ bool bClose = false;
+ bool bRestore = true; // restore old values unless a solution is accepted
+ if ( bSuccess )
+ {
+ // put solution into document so it is visible when asking
+ uno::Sequence<double> aSolution = xSolver->getSolution();
+ if ( aSolution.getLength() == nVarCount )
+ {
+ mpDocShell->LockPaint();
+ ScDocFunc aFunc(*mpDocShell);
+ for (nVarPos=0; nVarPos<nVarCount; ++nVarPos)
+ {
+ ScAddress aCellPos;
+ ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] );
+ aFunc.PutCell( aCellPos, new ScValueCell( aSolution[nVarPos] ), TRUE );
+ }
+ mpDocShell->UnlockPaint();
+ }
+ //! else error?
+
+ // take formatted result from document (result value from component is ignored)
+ String aResultStr;
+ mpDoc->GetString( (SCCOL)aObjective.Column, (SCROW)aObjective.Row, (SCTAB)aObjective.Sheet, aResultStr );
+ ScSolverSuccessDialog aDialog( this, aResultStr );
+ if ( aDialog.Execute() == RET_OK )
+ {
+ // keep results and close dialog
+ bRestore = false;
+ bClose = true;
+ }
+ }
+ else
+ {
+ rtl::OUString aError;
+ uno::Reference<sheet::XSolverDescription> xDesc( xSolver, uno::UNO_QUERY );
+ if ( xDesc.is() )
+ aError = xDesc->getStatusDescription(); // error description from component
+ ScSolverNoSolutionDialog aDialog( this, aError );
+ aDialog.Execute();
+ }
+
+ if ( bRestore ) // restore old values
+ {
+ mpDocShell->LockPaint();
+ ScDocFunc aFunc(*mpDocShell);
+ for (nVarPos=0; nVarPos<nVarCount; ++nVarPos)
+ {
+ ScAddress aCellPos;
+ ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] );
+ aFunc.PutCell( aCellPos, new ScValueCell( aOldValues[nVarPos] ), TRUE );
+ }
+ mpDocShell->UnlockPaint();
+ }
+
+ return bClose;
+}
+
|