1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <scitems.hxx>
21 #include <sfx2/dispatch.hxx>
22 #include <svl/numformat.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/weld.hxx>
26 #include <uiitems.hxx>
27 #include <reffact.hxx>
28 #include <document.hxx>
29 #include <globstr.hrc>
30 #include <scresid.hxx>
32 #include <solvrdlg.hxx>
34 ScSolverDlg::ScSolverDlg( SfxBindings
* pB
, SfxChildWindow
* pCW
, weld::Window
* pParent
,
35 ScDocument
* pDocument
,
36 const ScAddress
& aCursorPos
)
38 : ScAnyRefDlgController(pB
, pCW
, pParent
, u
"modules/scalc/ui/goalseekdlg.ui"_ustr
, u
"GoalSeekDialog"_ustr
)
39 , theFormulaCell(aCursorPos
)
40 , theVariableCell(aCursorPos
)
42 , nCurTab(aCursorPos
.Tab())
43 , bDlgLostFocus(false)
44 , errMsgInvalidVar(ScResId(STR_INVALIDVAR
))
45 , errMsgInvalidForm(ScResId(STR_INVALIDFORM
))
46 , errMsgNoFormula(ScResId(STR_NOFORMULA
))
47 , errMsgInvalidVal(ScResId(STR_INVALIDVAL
))
48 , m_pEdActive(nullptr)
49 , m_xFtFormulaCell(m_xBuilder
->weld_label(u
"formulatext"_ustr
))
50 , m_xEdFormulaCell(new formula::RefEdit(m_xBuilder
->weld_entry(u
"formulaedit"_ustr
)))
51 , m_xRBFormulaCell(new formula::RefButton(m_xBuilder
->weld_button(u
"formulabutton"_ustr
)))
52 , m_xEdTargetVal(m_xBuilder
->weld_entry(u
"target"_ustr
))
53 , m_xFtVariableCell(m_xBuilder
->weld_label(u
"vartext"_ustr
))
54 , m_xEdVariableCell(new formula::RefEdit(m_xBuilder
->weld_entry(u
"varedit"_ustr
)))
55 , m_xRBVariableCell(new formula::RefButton(m_xBuilder
->weld_button(u
"varbutton"_ustr
)))
56 , m_xBtnOk(m_xBuilder
->weld_button(u
"ok"_ustr
))
57 , m_xBtnCancel(m_xBuilder
->weld_button(u
"cancel"_ustr
))
59 m_xEdFormulaCell
->SetReferences(this, m_xFtFormulaCell
.get());
60 m_xRBFormulaCell
->SetReferences(this, m_xEdFormulaCell
.get());
61 m_xEdVariableCell
->SetReferences(this, m_xFtVariableCell
.get());
62 m_xRBVariableCell
->SetReferences(this, m_xEdVariableCell
.get());
66 ScSolverDlg::~ScSolverDlg()
69 m_xMessageBox
->response(RET_CANCEL
);
70 assert(!m_xMessageBox
);
73 void ScSolverDlg::Init()
75 m_xBtnOk
->connect_clicked( LINK( this, ScSolverDlg
, BtnHdl
) );
76 m_xBtnCancel
->connect_clicked( LINK( this, ScSolverDlg
, BtnHdl
) );
78 Link
<formula::RefEdit
&,void> aEditLink
= LINK( this, ScSolverDlg
, GetEditFocusHdl
);
79 m_xEdFormulaCell
->SetGetFocusHdl( aEditLink
);
80 m_xEdVariableCell
->SetGetFocusHdl( aEditLink
);
82 Link
<formula::RefButton
&,void> aButtonLink
= LINK( this, ScSolverDlg
, GetButtonFocusHdl
);
83 m_xRBFormulaCell
->SetGetFocusHdl( aButtonLink
);
84 m_xRBVariableCell
->SetGetFocusHdl( aButtonLink
);
86 m_xEdTargetVal
->connect_focus_in(LINK(this, ScSolverDlg
, GetFocusHdl
));
88 aEditLink
= LINK( this, ScSolverDlg
, LoseEditFocusHdl
);
89 m_xEdFormulaCell
->SetLoseFocusHdl ( aEditLink
);
90 m_xEdVariableCell
->SetLoseFocusHdl ( aEditLink
);
92 aButtonLink
= LINK( this, ScSolverDlg
, LoseButtonFocusHdl
);
93 m_xRBFormulaCell
->SetLoseFocusHdl ( aButtonLink
);
94 m_xRBVariableCell
->SetLoseFocusHdl ( aButtonLink
);
96 OUString
aStr(theFormulaCell
.Format(ScRefFlags::ADDR_ABS
, nullptr, pDoc
->GetAddressConvention()));
98 // If Goal Seek settings are stored in the document, restore them
99 const ScGoalSeekSettings
& rSettings
= pDoc
->GetGoalSeekSettings();
100 if (rSettings
.bDefined
)
102 OUString
sFormulaString(rSettings
.aFormulaCell
.Format(ScRefFlags::ADDR_ABS
, nullptr, pDoc
->GetAddressConvention()));
103 OUString
sVariableString(rSettings
.aVariableCell
.Format(ScRefFlags::ADDR_ABS
, nullptr, pDoc
->GetAddressConvention()));
104 m_xEdFormulaCell
->SetText(sFormulaString
);
105 m_xEdVariableCell
->SetText(sVariableString
);
106 m_xEdTargetVal
->set_text(rSettings
.sTargetValue
);
110 m_xEdFormulaCell
->SetText( aStr
);
113 m_xEdFormulaCell
->GrabFocus();
114 m_pEdActive
= m_xEdFormulaCell
.get();
117 void ScSolverDlg::Close()
119 DoClose( ScSolverDlgWrapper::GetChildWindowId() );
122 void ScSolverDlg::SetActive()
126 bDlgLostFocus
= false;
128 m_pEdActive
->GrabFocus();
132 m_xDialog
->grab_focus();
137 void ScSolverDlg::SetReference( const ScRange
& rRef
, ScDocument
& rDocP
)
142 if ( rRef
.aStart
!= rRef
.aEnd
)
143 RefInputStart(m_pEdActive
);
145 ScAddress aAdr
= rRef
.aStart
;
146 ScRefFlags nFmt
= ( aAdr
.Tab() == nCurTab
)
147 ? ScRefFlags::ADDR_ABS
148 : ScRefFlags::ADDR_ABS_3D
;
150 OUString
aStr(aAdr
.Format(nFmt
, &rDocP
, rDocP
.GetAddressConvention()));
151 m_pEdActive
->SetRefString( aStr
);
153 if (m_pEdActive
== m_xEdFormulaCell
.get())
154 theFormulaCell
= aAdr
;
155 else if (m_pEdActive
== m_xEdVariableCell
.get())
156 theVariableCell
= aAdr
;
159 void ScSolverDlg::RaiseError( ScSolverErr eError
)
165 case SOLVERR_NOFORMULA
:
166 sMessage
= errMsgNoFormula
;
168 case SOLVERR_INVALID_FORMULA
:
169 sMessage
= errMsgInvalidForm
;
171 case SOLVERR_INVALID_VARIABLE
:
172 sMessage
= errMsgInvalidVar
;
174 case SOLVERR_INVALID_TARGETVALUE
:
175 sMessage
= errMsgInvalidVal
;
179 m_xMessageBox
.reset(Application::CreateMessageDialog(m_xDialog
.get(),
180 VclMessageType::Warning
, VclButtonsType::Ok
,
182 m_xMessageBox
->runAsync(m_xMessageBox
, [this](sal_Int32
/*nResult*/) {
183 m_xEdTargetVal
->grab_focus();
184 m_xMessageBox
.reset();
188 bool ScSolverDlg::IsRefInputMode() const
190 return m_pEdActive
!= nullptr;
193 bool ScSolverDlg::CheckTargetValue( const OUString
& rStrVal
)
198 return pDoc
->GetFormatTable()->IsNumberFormat( rStrVal
, n1
, n2
);
203 IMPL_LINK(ScSolverDlg
, BtnHdl
, weld::Button
&, rBtn
, void)
205 if (&rBtn
== m_xBtnOk
.get())
207 theTargetValStr
= m_xEdTargetVal
->get_text();
209 // The following code checks:
210 // 1. do the strings contain correct references / defined names?
211 // 2. does the formula coordinate refer to a cell containing a formula?
212 // 3. has a valid target value been entered?
214 const formula::FormulaGrammar::AddressConvention eConv
= pDoc
->GetAddressConvention();
215 ScRefFlags nRes1
= theFormulaCell
.Parse( m_xEdFormulaCell
->GetText(), *pDoc
, eConv
);
216 ScRefFlags nRes2
= theVariableCell
.Parse( m_xEdVariableCell
->GetText(), *pDoc
, eConv
);
218 // Remember Goal Seek settings for the next time the dialog opens
219 ScGoalSeekSettings aSettings
;
220 aSettings
.bDefined
= true;
221 aSettings
.aFormulaCell
= theFormulaCell
;
222 aSettings
.aVariableCell
= theVariableCell
;
223 aSettings
.sTargetValue
= theTargetValStr
;
224 pDoc
->SetGoalSeekSettings(aSettings
);
226 if ( (nRes1
& ScRefFlags::VALID
) == ScRefFlags::VALID
)
228 if ( (nRes2
& ScRefFlags::VALID
) == ScRefFlags::VALID
)
230 if ( CheckTargetValue( theTargetValStr
) )
232 CellType eType
= pDoc
->GetCellType( theFormulaCell
.Col(),
233 theFormulaCell
.Row(),
234 theFormulaCell
.Tab());
236 if ( CELLTYPE_FORMULA
== eType
)
238 ScSolveParam
aOutParam( theFormulaCell
,
241 ScSolveItem
aOutItem( SCITEM_SOLVEDATA
, &aOutParam
);
243 SetDispatcherLock( false );
246 GetBindings().GetDispatcher()->ExecuteList(SID_SOLVE
,
247 SfxCallMode::SLOT
| SfxCallMode::RECORD
,
251 else RaiseError( SOLVERR_NOFORMULA
);
253 else RaiseError( SOLVERR_INVALID_TARGETVALUE
);
255 else RaiseError( SOLVERR_INVALID_VARIABLE
);
257 else RaiseError( SOLVERR_INVALID_FORMULA
);
259 else if (&rBtn
== m_xBtnCancel
.get())
261 response(RET_CANCEL
);
265 IMPL_LINK(ScSolverDlg
, GetEditFocusHdl
, formula::RefEdit
&, rCtrl
, void)
267 if (&rCtrl
== m_xEdFormulaCell
.get())
268 m_pEdActive
= m_xEdFormulaCell
.get();
269 else if (&rCtrl
== m_xEdVariableCell
.get())
270 m_pEdActive
= m_xEdVariableCell
.get();
273 m_pEdActive
->SelectAll();
276 IMPL_LINK_NOARG(ScSolverDlg
, GetFocusHdl
, weld::Widget
&, void)
278 m_pEdActive
= nullptr;
279 m_xEdTargetVal
->select_region(0, -1);
282 IMPL_LINK(ScSolverDlg
, GetButtonFocusHdl
, formula::RefButton
&, rCtrl
, void)
284 if (&rCtrl
== m_xRBFormulaCell
.get())
285 m_pEdActive
= m_xEdFormulaCell
.get();
286 else if (&rCtrl
== m_xRBVariableCell
.get())
287 m_pEdActive
= m_xEdVariableCell
.get();
290 m_pEdActive
->SelectAll();
293 IMPL_LINK_NOARG(ScSolverDlg
, LoseEditFocusHdl
, formula::RefEdit
&, void)
295 bDlgLostFocus
= !m_xDialog
->has_toplevel_focus();
298 IMPL_LINK_NOARG(ScSolverDlg
, LoseButtonFocusHdl
, formula::RefButton
&, void)
300 bDlgLostFocus
= !m_xDialog
->has_toplevel_focus();
304 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */