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 <comphelper/string.hxx>
21 #include <vcl/svapp.hxx>
22 #include <sal/log.hxx>
24 #include "parawin.hxx"
25 #include <formula/IFunctionDescription.hxx>
26 #include <formula/funcvarargs.h>
27 #include <strings.hrc>
28 #include <bitmaps.hlst>
29 #include <core_resource.hxx>
30 #include <rtl/math.hxx>
35 // Formula token argument count is sal_uInt8, max 255, edit offset 254.
36 constexpr sal_uInt16 kMaxArgCount
= 255;
37 constexpr sal_uInt16 kMaxArgOffset
= kMaxArgCount
- 1;
39 ParaWin::ParaWin(weld::Container
* pParent
,IControlReferenceHandler
* _pDlg
)
42 , m_sOptional(ForResId(STR_OPTIONAL
))
43 , m_sRequired(ForResId(STR_REQUIRED
))
44 , m_xBuilder(Application::CreateBuilder(pParent
, u
"formula/ui/parameter.ui"_ustr
))
45 , m_xContainer(m_xBuilder
->weld_container(u
"ParameterPage"_ustr
))
46 , m_xSlider(m_xBuilder
->weld_scrolled_window(u
"scrollbar"_ustr
, true))
47 , m_xParamGrid(m_xBuilder
->weld_widget(u
"paramgrid"_ustr
))
48 , m_xGrid(m_xBuilder
->weld_widget(u
"grid"_ustr
))
49 , m_xFtEditDesc(m_xBuilder
->weld_label(u
"editdesc"_ustr
))
50 , m_xFtArgName(m_xBuilder
->weld_label(u
"parname"_ustr
))
51 , m_xFtArgDesc(m_xBuilder
->weld_label(u
"pardesc"_ustr
))
52 , m_xBtnFx1(m_xBuilder
->weld_button(u
"FX1"_ustr
))
53 , m_xBtnFx2(m_xBuilder
->weld_button(u
"FX2"_ustr
))
54 , m_xBtnFx3(m_xBuilder
->weld_button(u
"FX3"_ustr
))
55 , m_xBtnFx4(m_xBuilder
->weld_button(u
"FX4"_ustr
))
56 , m_xFtArg1(m_xBuilder
->weld_label(u
"FT_ARG1"_ustr
))
57 , m_xFtArg2(m_xBuilder
->weld_label(u
"FT_ARG2"_ustr
))
58 , m_xFtArg3(m_xBuilder
->weld_label(u
"FT_ARG3"_ustr
))
59 , m_xFtArg4(m_xBuilder
->weld_label(u
"FT_ARG4"_ustr
))
60 , m_xEdArg1(new ArgEdit(m_xBuilder
->weld_entry(u
"ED_ARG1"_ustr
)))
61 , m_xEdArg2(new ArgEdit(m_xBuilder
->weld_entry(u
"ED_ARG2"_ustr
)))
62 , m_xEdArg3(new ArgEdit(m_xBuilder
->weld_entry(u
"ED_ARG3"_ustr
)))
63 , m_xEdArg4(new ArgEdit(m_xBuilder
->weld_entry(u
"ED_ARG4"_ustr
)))
64 , m_xRefBtn1(new RefButton(m_xBuilder
->weld_button(u
"RB_ARG1"_ustr
)))
65 , m_xRefBtn2(new RefButton(m_xBuilder
->weld_button(u
"RB_ARG2"_ustr
)))
66 , m_xRefBtn3(new RefButton(m_xBuilder
->weld_button(u
"RB_ARG3"_ustr
)))
67 , m_xRefBtn4(new RefButton(m_xBuilder
->weld_button(u
"RB_ARG4"_ustr
)))
69 // Space for three lines of text in function description.
70 m_xFtEditDesc
->set_label(u
"X\nX\nX\n"_ustr
);
71 auto nEditHeight
= m_xFtEditDesc
->get_preferred_size().Height();
72 m_xFtEditDesc
->set_size_request(-1, nEditHeight
);
73 m_xFtEditDesc
->set_label(u
""_ustr
);
74 // Space for two lines of text in parameter description.
75 m_xFtArgDesc
->set_label(u
"X\nX\n"_ustr
);
76 auto nArgHeight
= m_xFtArgDesc
->get_preferred_size().Height();
77 m_xFtArgDesc
->set_size_request(-1, nArgHeight
);
78 m_xFtArgDesc
->set_label(u
""_ustr
);
80 m_xBtnFx1
->set_from_icon_name(BMP_FX
);
81 m_xBtnFx2
->set_from_icon_name(BMP_FX
);
82 m_xBtnFx3
->set_from_icon_name(BMP_FX
);
83 m_xBtnFx4
->set_from_icon_name(BMP_FX
);
85 //lock down initial preferences
86 m_xParamGrid
->set_size_request(-1, m_xParamGrid
->get_preferred_size().Height());
87 Size
aSize(m_xContainer
->get_preferred_size());
88 m_xContainer
->set_size_request(aSize
.Width(), aSize
.Height());
90 aDefaultString
= m_xFtEditDesc
->get_label();
94 m_xSlider
->connect_vadjustment_changed(LINK(this, ParaWin
, ScrollHdl
));
96 InitArgInput( 0, *m_xFtArg1
, *m_xBtnFx1
, *m_xEdArg1
, *m_xRefBtn1
);
97 InitArgInput( 1, *m_xFtArg2
, *m_xBtnFx2
, *m_xEdArg2
, *m_xRefBtn2
);
98 InitArgInput( 2, *m_xFtArg3
, *m_xBtnFx3
, *m_xEdArg3
, *m_xRefBtn3
);
99 InitArgInput( 3, *m_xFtArg4
, *m_xBtnFx4
, *m_xEdArg4
, *m_xRefBtn4
);
103 void ParaWin::UpdateArgDesc( sal_uInt16 nArg
)
105 if (nArg
== NOT_FOUND
)
109 nArg
= sal::static_int_cast
<sal_uInt16
>( nArg
+ GetSliderPos() );
111 if ((nMaxArgs
<= 0) || (nArg
>= nMaxArgs
))
117 SetArgumentDesc( OUString() );
118 SetArgumentText( OUString() );
120 if ( nArgs
< VAR_ARGS
)
122 sal_uInt16 nRealArg
= (nArg
< aVisibleArgMapping
.size()) ? aVisibleArgMapping
[nArg
] : nArg
;
123 aArgDesc
= pFuncDesc
->getParameterDescription(nRealArg
);
124 aArgName
= pFuncDesc
->getParameterName(nRealArg
) + " " +
125 ((pFuncDesc
->isParameterOptional(nRealArg
)) ? m_sOptional
: m_sRequired
);
127 else if ( nArgs
< PAIRED_VAR_ARGS
)
129 sal_uInt16 nFix
= nArgs
- VAR_ARGS
;
130 sal_uInt16 nPos
= std::min( nArg
, nFix
);
131 sal_uInt16 nRealArg
= (nPos
< aVisibleArgMapping
.size() ?
132 aVisibleArgMapping
[nPos
] : aVisibleArgMapping
.back());
133 aArgDesc
= pFuncDesc
->getParameterDescription(nRealArg
);
134 aArgName
= pFuncDesc
->getParameterName(nRealArg
);
135 sal_uInt16 nVarArgsStart
= pFuncDesc
->getVarArgsStart();
136 if ( nArg
>= nVarArgsStart
)
137 aArgName
+= OUString::number( nArg
-nVarArgsStart
+1 );
138 aArgName
+= " " + ((nArg
> nFix
|| pFuncDesc
->isParameterOptional(nRealArg
)) ? m_sOptional
: m_sRequired
) ;
142 sal_uInt16 nFix
= nArgs
- PAIRED_VAR_ARGS
;
147 nPos
= nFix
+ ( (nArg
-nFix
) % 2);
148 sal_uInt16 nRealArg
= (nPos
< aVisibleArgMapping
.size() ?
149 aVisibleArgMapping
[nPos
] : aVisibleArgMapping
.back());
150 aArgDesc
= pFuncDesc
->getParameterDescription(nRealArg
);
151 aArgName
= pFuncDesc
->getParameterName(nRealArg
);
152 sal_uInt16 nVarArgsStart
= pFuncDesc
->getVarArgsStart();
153 if ( nArg
>= nVarArgsStart
)
155 sal_Int16 nShifted
= pFuncDesc
->getFunctionName().equalsIgnoreAsciiCase(u
"LET") ? nPos
/ 2 : 0;
156 aArgName
+= OUString::number( (nArg
-nVarArgsStart
)/2 + 1 + nShifted
);
158 aArgName
+= " " + ((nArg
> (nFix
+1) || pFuncDesc
->isParameterOptional(nRealArg
)) ? m_sOptional
: m_sRequired
) ;
161 SetArgumentDesc(aArgDesc
);
162 SetArgumentText(aArgName
);
165 void ParaWin::UpdateArgInput( sal_uInt16 nOffset
, sal_uInt16 i
)
167 sal_uInt16 nArg
= nOffset
+ i
;
168 if (nArg
> kMaxArgOffset
)
171 if ( nArgs
< VAR_ARGS
)
175 sal_uInt16 nRealArg
= aVisibleArgMapping
[nArg
];
176 SetArgNameFont (i
,(pFuncDesc
->isParameterOptional(nRealArg
))
177 ? aFntLight
: aFntBold
);
178 SetArgName (i
,pFuncDesc
->getParameterName(nRealArg
));
181 else if ( nArgs
< PAIRED_VAR_ARGS
)
183 sal_uInt16 nFix
= nArgs
- VAR_ARGS
;
184 sal_uInt16 nPos
= std::min( nArg
, nFix
);
185 sal_uInt16 nRealArg
= (nPos
< aVisibleArgMapping
.size() ?
186 aVisibleArgMapping
[nPos
] : aVisibleArgMapping
.back());
188 (nArg
> nFix
|| pFuncDesc
->isParameterOptional(nRealArg
)) ?
189 aFntLight
: aFntBold
);
190 sal_uInt16 nVarArgsStart
= pFuncDesc
->getVarArgsStart();
191 if ( nArg
>= nVarArgsStart
)
193 OUString aArgName
= pFuncDesc
->getParameterName(nRealArg
) +
194 OUString::number(nArg
-nVarArgsStart
+1);
195 SetArgName( i
, aArgName
);
198 SetArgName( i
, pFuncDesc
->getParameterName(nRealArg
) );
202 sal_uInt16 nFix
= nArgs
- PAIRED_VAR_ARGS
;
207 nPos
= nFix
+ ( (nArg
-nFix
) % 2);
208 sal_uInt16 nRealArg
= (nPos
< aVisibleArgMapping
.size() ?
209 aVisibleArgMapping
[nPos
] : aVisibleArgMapping
.back());
211 (nArg
> (nFix
+1) || pFuncDesc
->isParameterOptional(nRealArg
)) ?
212 aFntLight
: aFntBold
);
213 sal_uInt16 nVarArgsStart
= pFuncDesc
->getVarArgsStart();
214 if ( nArg
>= nVarArgsStart
)
216 sal_Int16 nShifted
= pFuncDesc
->getFunctionName().equalsIgnoreAsciiCase(u
"LET") ? nPos
/ 2 : 0;
217 OUString aArgName
= pFuncDesc
->getParameterName(nRealArg
) +
218 OUString::number( (nArg
-nVarArgsStart
)/2 + 1 + nShifted
);
219 SetArgName( i
, aArgName
);
222 SetArgName( i
, pFuncDesc
->getParameterName(nRealArg
) );
225 aArgInput
[i
].SetArgVal(aParaArray
[nArg
]);
230 // #i66422# if the focus changes during destruction of the controls,
231 // don't call the focus handlers
232 Link
<weld::Widget
&,void> aEmptyLink
;
233 m_xBtnFx1
->connect_focus_in(aEmptyLink
);
234 m_xBtnFx2
->connect_focus_in(aEmptyLink
);
235 m_xBtnFx3
->connect_focus_in(aEmptyLink
);
236 m_xBtnFx4
->connect_focus_in(aEmptyLink
);
239 void ParaWin::SetActiveLine(sal_uInt16 no
)
244 tools::Long nOffset
= GetSliderPos();
246 tools::Long nNewEdPos
=static_cast<tools::Long
>(nActiveLine
)-nOffset
;
247 if(nNewEdPos
<0 || nNewEdPos
>3)
250 SetSliderPos(static_cast<sal_uInt16
>(nOffset
));
251 nOffset
=GetSliderPos();
253 nEdFocus
=no
-static_cast<sal_uInt16
>(nOffset
);
254 UpdateArgDesc( nEdFocus
);
257 RefEdit
* ParaWin::GetActiveEdit()
259 if (nMaxArgs
> 0 && nEdFocus
!= NOT_FOUND
)
261 return aArgInput
[nEdFocus
].GetArgEdPtr();
270 OUString
ParaWin::GetArgument(sal_uInt16 no
)
273 if(no
<aParaArray
.size())
276 if(no
==nActiveLine
&& aStr
.isEmpty())
282 OUString
ParaWin::GetActiveArgName() const
285 if (nMaxArgs
> 0 && nEdFocus
!= NOT_FOUND
)
287 aStr
=aArgInput
[nEdFocus
].GetArgName();
293 void ParaWin::SetArgument(sal_uInt16 no
, std::u16string_view aString
)
295 if (no
< aParaArray
.size())
296 aParaArray
[no
] = comphelper::string::stripStart(aString
, ' ');
299 void ParaWin::SetArgumentFonts(const vcl::Font
&aBoldFont
,const vcl::Font
&aLightFont
)
302 aFntLight
=aLightFont
;
305 void ParaWin::SetFunctionDesc(const IFunctionDescription
* pFDesc
)
309 SetArgumentDesc( OUString() );
310 SetArgumentText( OUString() );
311 SetEditDesc( OUString() );
312 nMaxArgs
= nArgs
= 0;
313 if ( pFuncDesc
!=nullptr)
315 if ( !pFuncDesc
->getDescription().isEmpty() )
317 SetEditDesc(pFuncDesc
->getDescription());
321 SetEditDesc(aDefaultString
);
323 nArgs
= pFuncDesc
->getSuppressedArgumentCount();
324 nMaxArgs
= std::min( nArgs
, kMaxArgCount
);
325 if (sal_uInt16 nVarArgsLimit
= pFuncDesc
->getVarArgsLimit())
326 nMaxArgs
= std::min( nVarArgsLimit
, nMaxArgs
);
327 pFuncDesc
->fillVisibleArgumentMapping(aVisibleArgMapping
);
328 m_xSlider
->set_vpolicy(VclPolicyType::NEVER
);
329 m_xSlider
->set_size_request(-1, -1);
330 OUString sHelpId
= pFuncDesc
->getHelpId();
331 m_xContainer
->set_help_id(sHelpId
);
332 m_xEdArg1
->GetWidget()->set_help_id(sHelpId
);
333 m_xEdArg2
->GetWidget()->set_help_id(sHelpId
);
334 m_xEdArg3
->GetWidget()->set_help_id(sHelpId
);
335 m_xEdArg4
->GetWidget()->set_help_id(sHelpId
);
346 void ParaWin::SetArgumentText(const OUString
& aText
)
348 m_xFtArgName
->set_label(aText
);
351 void ParaWin::SetArgumentDesc(const OUString
& aText
)
353 m_xFtArgDesc
->set_label(aText
);
356 void ParaWin::SetEditDesc(const OUString
& aText
)
358 m_xFtEditDesc
->set_label(aText
);
361 void ParaWin::SetArgName(sal_uInt16 no
,const OUString
& aText
)
363 aArgInput
[no
].SetArgName(aText
);
364 aArgInput
[no
].UpdateAccessibleNames();
367 void ParaWin::SetArgNameFont(sal_uInt16 no
,const vcl::Font
& aFont
)
369 aArgInput
[no
].SetArgNameFont(aFont
);
372 void ParaWin::SetEdFocus()
375 if(!aParaArray
.empty())
376 aArgInput
[0].GetArgEdPtr()->GrabFocus();
379 void ParaWin::InitArgInput(sal_uInt16 nPos
, weld::Label
& rFtArg
, weld::Button
& rBtnFx
,
380 ArgEdit
& rEdArg
, RefButton
& rRefBtn
)
383 rRefBtn
.SetReferences(pMyParent
, &rEdArg
);
384 rEdArg
.SetReferences(pMyParent
, &rFtArg
);
386 aArgInput
[nPos
].InitArgInput (&rFtArg
,&rBtnFx
,&rEdArg
,&rRefBtn
);
388 aArgInput
[nPos
].Hide();
390 aArgInput
[nPos
].SetFxClickHdl ( LINK( this, ParaWin
, GetFxHdl
) );
391 aArgInput
[nPos
].SetFxFocusHdl ( LINK( this, ParaWin
, GetFxFocusHdl
) );
392 aArgInput
[nPos
].SetEdFocusHdl ( LINK( this, ParaWin
, GetEdFocusHdl
) );
393 aArgInput
[nPos
].SetEdModifyHdl ( LINK( this, ParaWin
, ModifyHdl
) );
394 aArgInput
[nPos
].UpdateAccessibleNames();
397 void ParaWin::ClearAll()
399 SetFunctionDesc(nullptr);
400 SetArgumentOffset(0);
403 void ParaWin::SetArgumentOffset(sal_uInt16 nOffset
)
406 m_xSlider
->vadjustment_set_value(0);
408 aParaArray
.resize(nMaxArgs
);
412 for ( int i
=0; i
<4 && i
<nMaxArgs
; i
++ )
414 aArgInput
[i
].SetArgVal(OUString());
415 aArgInput
[i
].GetArgEdPtr()->Init(
416 (i
==0) ? nullptr : aArgInput
[i
-1].GetArgEdPtr(),
417 (i
==3 || i
==nMaxArgs
-1) ? nullptr : aArgInput
[i
+1].GetArgEdPtr(),
418 *m_xSlider
, *this, nMaxArgs
);
426 m_xSlider
->set_vpolicy(VclPolicyType::NEVER
);
427 m_xSlider
->set_size_request(-1, -1);
431 m_xSlider
->vadjustment_configure(nOffset
, 0, nMaxArgs
, 1, 4, 4);
432 m_xSlider
->set_vpolicy(VclPolicyType::ALWAYS
);
433 Size
aPrefSize(m_xGrid
->get_preferred_size());
434 m_xSlider
->set_size_request(aPrefSize
.Width(), aPrefSize
.Height());
438 void ParaWin::UpdateParas()
441 sal_uInt16 nOffset
= GetSliderPos();
445 for ( i
=0; (i
<nMaxArgs
) && (i
<4); i
++ )
447 UpdateArgInput( nOffset
, i
);
452 for ( i
=nMaxArgs
; i
<4; i
++ )
457 sal_uInt16
ParaWin::GetSliderPos() const
459 return static_cast<sal_uInt16
>(m_xSlider
->vadjustment_get_value());
462 void ParaWin::SetSliderPos(sal_uInt16 nSliderPos
)
464 sal_uInt16 nOffset
= GetSliderPos();
466 if(m_xSlider
->get_visible() && nOffset
!=nSliderPos
)
468 m_xSlider
->vadjustment_set_value(nSliderPos
);
469 for ( sal_uInt16 i
=0; i
<4; i
++ )
471 UpdateArgInput( nSliderPos
, i
);
476 void ParaWin::SliderMoved()
478 sal_uInt16 nOffset
= GetSliderPos();
480 for ( sal_uInt16 i
=0; i
<4; i
++ )
482 UpdateArgInput( nOffset
, i
);
484 if(nEdFocus
!=NOT_FOUND
)
486 UpdateArgDesc( nEdFocus
);
487 aArgInput
[nEdFocus
].SelectAll();
488 nActiveLine
=nEdFocus
+nOffset
;
490 aArgInput
[nEdFocus
].SelectAll(); // ensure all is still selected
491 aArgInput
[nEdFocus
].UpdateAccessibleNames();
495 void ParaWin::ArgumentModified()
497 aArgModifiedLink
.Call(*this);
500 IMPL_LINK( ParaWin
, GetFxHdl
, ArgInput
&, rPtr
, void )
502 sal_uInt16 nOffset
= GetSliderPos();
504 for (size_t nPos
=0; nPos
< std::size(aArgInput
); ++nPos
)
506 if(&rPtr
== &aArgInput
[nPos
])
513 if(nEdFocus
!=NOT_FOUND
)
515 aArgInput
[nEdFocus
].SelectAll();
516 nActiveLine
=nEdFocus
+nOffset
;
521 IMPL_LINK( ParaWin
, GetFxFocusHdl
, ArgInput
&, rPtr
, void )
523 sal_uInt16 nOffset
= GetSliderPos();
525 for (size_t nPos
=0; nPos
< SAL_N_ELEMENTS(aArgInput
); ++nPos
)
527 if(&rPtr
== &aArgInput
[nPos
])
534 if(nEdFocus
!=NOT_FOUND
)
536 aArgInput
[nEdFocus
].SelectAll();
537 UpdateArgDesc( nEdFocus
);
538 nActiveLine
=nEdFocus
+nOffset
;
542 IMPL_LINK( ParaWin
, GetEdFocusHdl
, ArgInput
&, rPtr
, void )
544 sal_uInt16 nOffset
= GetSliderPos();
546 for (size_t nPos
=0; nPos
< SAL_N_ELEMENTS(aArgInput
); ++nPos
)
548 if(&rPtr
== &aArgInput
[nPos
])
555 if(nEdFocus
!=NOT_FOUND
)
557 aArgInput
[nEdFocus
].SelectAll();
558 UpdateArgDesc( nEdFocus
);
559 nActiveLine
=nEdFocus
+nOffset
;
561 aArgInput
[nEdFocus
].SelectAll(); // ensure all is still selected
562 aArgInput
[nEdFocus
].UpdateAccessibleNames();
566 IMPL_LINK_NOARG(ParaWin
, ScrollHdl
, weld::ScrolledWindow
&, void)
571 IMPL_LINK( ParaWin
, ModifyHdl
, ArgInput
&, rPtr
, void )
573 sal_uInt16 nOffset
= GetSliderPos();
575 for (size_t nPos
=0; nPos
< SAL_N_ELEMENTS(aArgInput
); ++nPos
)
577 if(&rPtr
== &aArgInput
[nPos
])
583 if(nEdFocus
!=NOT_FOUND
)
585 size_t nPara
= nEdFocus
+ nOffset
;
586 if (nPara
< aParaArray
.size())
587 aParaArray
[nPara
] = aArgInput
[nEdFocus
].GetArgVal();
590 SAL_WARN("formula.ui","ParaWin::ModifyHdl - shot in foot: nPara " <<
591 nPara
<< " >= aParaArray.size() " << aParaArray
.size() <<
592 " with nEdFocus " << nEdFocus
<<
593 " and aArgInput[nEdFocus].GetArgVal() '" << aArgInput
[nEdFocus
].GetArgVal() << "'");
595 UpdateArgDesc( nEdFocus
);
596 nActiveLine
= static_cast<sal_uInt16
>(nPara
);
605 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */