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>
34 // Formula token argument count is sal_uInt8, max 255, edit offset 254.
35 constexpr sal_uInt16 kMaxArgCount
= 255;
36 constexpr sal_uInt16 kMaxArgOffset
= kMaxArgCount
- 1;
38 ParaWin::ParaWin(weld::Container
* pParent
,IControlReferenceHandler
* _pDlg
)
41 , m_sOptional(ForResId(STR_OPTIONAL
))
42 , m_sRequired(ForResId(STR_REQUIRED
))
43 , m_xBuilder(Application::CreateBuilder(pParent
, "formula/ui/parameter.ui"))
44 , m_xContainer(m_xBuilder
->weld_container("ParameterPage"))
45 , m_xSlider(m_xBuilder
->weld_scrolled_window("scrollbar", true))
46 , m_xParamGrid(m_xBuilder
->weld_widget("paramgrid"))
47 , m_xGrid(m_xBuilder
->weld_widget("grid"))
48 , m_xFtEditDesc(m_xBuilder
->weld_label("editdesc"))
49 , m_xFtArgName(m_xBuilder
->weld_label("parname"))
50 , m_xFtArgDesc(m_xBuilder
->weld_label("pardesc"))
51 , m_xBtnFx1(m_xBuilder
->weld_button("FX1"))
52 , m_xBtnFx2(m_xBuilder
->weld_button("FX2"))
53 , m_xBtnFx3(m_xBuilder
->weld_button("FX3"))
54 , m_xBtnFx4(m_xBuilder
->weld_button("FX4"))
55 , m_xFtArg1(m_xBuilder
->weld_label("FT_ARG1"))
56 , m_xFtArg2(m_xBuilder
->weld_label("FT_ARG2"))
57 , m_xFtArg3(m_xBuilder
->weld_label("FT_ARG3"))
58 , m_xFtArg4(m_xBuilder
->weld_label("FT_ARG4"))
59 , m_xEdArg1(new ArgEdit(m_xBuilder
->weld_entry("ED_ARG1")))
60 , m_xEdArg2(new ArgEdit(m_xBuilder
->weld_entry("ED_ARG2")))
61 , m_xEdArg3(new ArgEdit(m_xBuilder
->weld_entry("ED_ARG3")))
62 , m_xEdArg4(new ArgEdit(m_xBuilder
->weld_entry("ED_ARG4")))
63 , m_xRefBtn1(new RefButton(m_xBuilder
->weld_button("RB_ARG1")))
64 , m_xRefBtn2(new RefButton(m_xBuilder
->weld_button("RB_ARG2")))
65 , m_xRefBtn3(new RefButton(m_xBuilder
->weld_button("RB_ARG3")))
66 , m_xRefBtn4(new RefButton(m_xBuilder
->weld_button("RB_ARG4")))
68 // Space for three lines of text in function description.
69 m_xFtEditDesc
->set_label("X\nX\nX\n");
70 auto nEditHeight
= m_xFtEditDesc
->get_preferred_size().Height();
71 m_xFtEditDesc
->set_size_request(-1, nEditHeight
);
72 m_xFtEditDesc
->set_label("");
73 // Space for two lines of text in parameter description.
74 m_xFtArgDesc
->set_label("X\nX\n");
75 auto nArgHeight
= m_xFtArgDesc
->get_preferred_size().Height();
76 m_xFtArgDesc
->set_size_request(-1, nArgHeight
);
77 m_xFtArgDesc
->set_label("");
79 m_xBtnFx1
->set_from_icon_name(BMP_FX
);
80 m_xBtnFx2
->set_from_icon_name(BMP_FX
);
81 m_xBtnFx3
->set_from_icon_name(BMP_FX
);
82 m_xBtnFx4
->set_from_icon_name(BMP_FX
);
84 //lock down initial preferences
85 m_xParamGrid
->set_size_request(-1, m_xParamGrid
->get_preferred_size().Height());
86 Size
aSize(m_xContainer
->get_preferred_size());
87 m_xContainer
->set_size_request(aSize
.Width(), aSize
.Height());
89 aDefaultString
= m_xFtEditDesc
->get_label();
93 m_xSlider
->connect_vadjustment_changed(LINK(this, ParaWin
, ScrollHdl
));
95 InitArgInput( 0, *m_xFtArg1
, *m_xBtnFx1
, *m_xEdArg1
, *m_xRefBtn1
);
96 InitArgInput( 1, *m_xFtArg2
, *m_xBtnFx2
, *m_xEdArg2
, *m_xRefBtn2
);
97 InitArgInput( 2, *m_xFtArg3
, *m_xBtnFx3
, *m_xEdArg3
, *m_xRefBtn3
);
98 InitArgInput( 3, *m_xFtArg4
, *m_xBtnFx4
, *m_xEdArg4
, *m_xRefBtn4
);
102 void ParaWin::UpdateArgDesc( sal_uInt16 nArg
)
104 if (nArg
== NOT_FOUND
)
108 nArg
= sal::static_int_cast
<sal_uInt16
>( nArg
+ GetSliderPos() );
110 if ((nMaxArgs
<= 0) || (nArg
>= nMaxArgs
))
116 SetArgumentDesc( OUString() );
117 SetArgumentText( OUString() );
119 if ( nArgs
< VAR_ARGS
)
121 sal_uInt16 nRealArg
= (nArg
< aVisibleArgMapping
.size()) ? aVisibleArgMapping
[nArg
] : nArg
;
122 aArgDesc
= pFuncDesc
->getParameterDescription(nRealArg
);
123 aArgName
= pFuncDesc
->getParameterName(nRealArg
) + " " +
124 ((pFuncDesc
->isParameterOptional(nRealArg
)) ? m_sOptional
: m_sRequired
);
126 else if ( nArgs
< PAIRED_VAR_ARGS
)
128 sal_uInt16 nFix
= nArgs
- VAR_ARGS
;
129 sal_uInt16 nPos
= std::min( nArg
, nFix
);
130 sal_uInt16 nRealArg
= (nPos
< aVisibleArgMapping
.size() ?
131 aVisibleArgMapping
[nPos
] : aVisibleArgMapping
.back());
132 aArgDesc
= pFuncDesc
->getParameterDescription(nRealArg
);
133 aArgName
= pFuncDesc
->getParameterName(nRealArg
);
134 sal_uInt16 nVarArgsStart
= pFuncDesc
->getVarArgsStart();
135 if ( nArg
>= nVarArgsStart
)
136 aArgName
+= OUString::number( nArg
-nVarArgsStart
+1 );
137 aArgName
+= " " + ((nArg
> nFix
|| pFuncDesc
->isParameterOptional(nRealArg
)) ? m_sOptional
: m_sRequired
) ;
141 sal_uInt16 nFix
= nArgs
- PAIRED_VAR_ARGS
;
146 nPos
= nFix
+ ( (nArg
-nFix
) % 2);
147 sal_uInt16 nRealArg
= (nPos
< aVisibleArgMapping
.size() ?
148 aVisibleArgMapping
[nPos
] : aVisibleArgMapping
.back());
149 aArgDesc
= pFuncDesc
->getParameterDescription(nRealArg
);
150 aArgName
= pFuncDesc
->getParameterName(nRealArg
);
151 sal_uInt16 nVarArgsStart
= pFuncDesc
->getVarArgsStart();
152 if ( nArg
>= nVarArgsStart
)
153 aArgName
+= OUString::number( (nArg
-nVarArgsStart
)/2 + 1 );
154 aArgName
+= " " + ((nArg
> (nFix
+1) || pFuncDesc
->isParameterOptional(nRealArg
)) ? m_sOptional
: m_sRequired
) ;
157 SetArgumentDesc(aArgDesc
);
158 SetArgumentText(aArgName
);
161 void ParaWin::UpdateArgInput( sal_uInt16 nOffset
, sal_uInt16 i
)
163 sal_uInt16 nArg
= nOffset
+ i
;
164 if (nArg
> kMaxArgOffset
)
167 if ( nArgs
< VAR_ARGS
)
171 sal_uInt16 nRealArg
= aVisibleArgMapping
[nArg
];
172 SetArgNameFont (i
,(pFuncDesc
->isParameterOptional(nRealArg
))
173 ? aFntLight
: aFntBold
);
174 SetArgName (i
,pFuncDesc
->getParameterName(nRealArg
));
177 else if ( nArgs
< PAIRED_VAR_ARGS
)
179 sal_uInt16 nFix
= nArgs
- VAR_ARGS
;
180 sal_uInt16 nPos
= std::min( nArg
, nFix
);
181 sal_uInt16 nRealArg
= (nPos
< aVisibleArgMapping
.size() ?
182 aVisibleArgMapping
[nPos
] : aVisibleArgMapping
.back());
184 (nArg
> nFix
|| pFuncDesc
->isParameterOptional(nRealArg
)) ?
185 aFntLight
: aFntBold
);
186 sal_uInt16 nVarArgsStart
= pFuncDesc
->getVarArgsStart();
187 if ( nArg
>= nVarArgsStart
)
189 OUString aArgName
= pFuncDesc
->getParameterName(nRealArg
) +
190 OUString::number(nArg
-nVarArgsStart
+1);
191 SetArgName( i
, aArgName
);
194 SetArgName( i
, pFuncDesc
->getParameterName(nRealArg
) );
198 sal_uInt16 nFix
= nArgs
- PAIRED_VAR_ARGS
;
203 nPos
= nFix
+ ( (nArg
-nFix
) % 2);
204 sal_uInt16 nRealArg
= (nPos
< aVisibleArgMapping
.size() ?
205 aVisibleArgMapping
[nPos
] : aVisibleArgMapping
.back());
207 (nArg
> (nFix
+1) || pFuncDesc
->isParameterOptional(nRealArg
)) ?
208 aFntLight
: aFntBold
);
209 sal_uInt16 nVarArgsStart
= pFuncDesc
->getVarArgsStart();
210 if ( nArg
>= nVarArgsStart
)
212 OUString aArgName
= pFuncDesc
->getParameterName(nRealArg
) +
213 OUString::number( (nArg
-nVarArgsStart
)/2 + 1 );
214 SetArgName( i
, aArgName
);
217 SetArgName( i
, pFuncDesc
->getParameterName(nRealArg
) );
220 aArgInput
[i
].SetArgVal(aParaArray
[nArg
]);
225 // #i66422# if the focus changes during destruction of the controls,
226 // don't call the focus handlers
227 Link
<weld::Widget
&,void> aEmptyLink
;
228 m_xBtnFx1
->connect_focus_in(aEmptyLink
);
229 m_xBtnFx2
->connect_focus_in(aEmptyLink
);
230 m_xBtnFx3
->connect_focus_in(aEmptyLink
);
231 m_xBtnFx4
->connect_focus_in(aEmptyLink
);
234 void ParaWin::SetActiveLine(sal_uInt16 no
)
239 tools::Long nOffset
= GetSliderPos();
241 tools::Long nNewEdPos
=static_cast<tools::Long
>(nActiveLine
)-nOffset
;
242 if(nNewEdPos
<0 || nNewEdPos
>3)
245 SetSliderPos(static_cast<sal_uInt16
>(nOffset
));
246 nOffset
=GetSliderPos();
248 nEdFocus
=no
-static_cast<sal_uInt16
>(nOffset
);
249 UpdateArgDesc( nEdFocus
);
252 RefEdit
* ParaWin::GetActiveEdit()
254 if (nMaxArgs
> 0 && nEdFocus
!= NOT_FOUND
)
256 return aArgInput
[nEdFocus
].GetArgEdPtr();
265 OUString
ParaWin::GetArgument(sal_uInt16 no
)
268 if(no
<aParaArray
.size())
271 if(no
==nActiveLine
&& aStr
.isEmpty())
277 OUString
ParaWin::GetActiveArgName() const
280 if (nMaxArgs
> 0 && nEdFocus
!= NOT_FOUND
)
282 aStr
=aArgInput
[nEdFocus
].GetArgName();
288 void ParaWin::SetArgument(sal_uInt16 no
, std::u16string_view aString
)
290 if (no
< aParaArray
.size())
291 aParaArray
[no
] = comphelper::string::stripStart(aString
, ' ');
294 void ParaWin::SetArgumentFonts(const vcl::Font
&aBoldFont
,const vcl::Font
&aLightFont
)
297 aFntLight
=aLightFont
;
300 void ParaWin::SetFunctionDesc(const IFunctionDescription
* pFDesc
)
304 SetArgumentDesc( OUString() );
305 SetArgumentText( OUString() );
306 SetEditDesc( OUString() );
307 nMaxArgs
= nArgs
= 0;
308 if ( pFuncDesc
!=nullptr)
310 if ( !pFuncDesc
->getDescription().isEmpty() )
312 SetEditDesc(pFuncDesc
->getDescription());
316 SetEditDesc(aDefaultString
);
318 nArgs
= pFuncDesc
->getSuppressedArgumentCount();
319 nMaxArgs
= std::min( nArgs
, kMaxArgCount
);
320 if (sal_uInt16 nVarArgsLimit
= pFuncDesc
->getVarArgsLimit())
321 nMaxArgs
= std::min( nVarArgsLimit
, nMaxArgs
);
322 pFuncDesc
->fillVisibleArgumentMapping(aVisibleArgMapping
);
323 m_xSlider
->set_vpolicy(VclPolicyType::NEVER
);
324 m_xSlider
->set_size_request(-1, -1);
325 OUString sHelpId
= pFuncDesc
->getHelpId();
326 m_xContainer
->set_help_id(sHelpId
);
327 m_xEdArg1
->GetWidget()->set_help_id(sHelpId
);
328 m_xEdArg2
->GetWidget()->set_help_id(sHelpId
);
329 m_xEdArg3
->GetWidget()->set_help_id(sHelpId
);
330 m_xEdArg4
->GetWidget()->set_help_id(sHelpId
);
341 void ParaWin::SetArgumentText(const OUString
& aText
)
343 m_xFtArgName
->set_label(aText
);
346 void ParaWin::SetArgumentDesc(const OUString
& aText
)
348 m_xFtArgDesc
->set_label(aText
);
351 void ParaWin::SetEditDesc(const OUString
& aText
)
353 m_xFtEditDesc
->set_label(aText
);
356 void ParaWin::SetArgName(sal_uInt16 no
,const OUString
& aText
)
358 aArgInput
[no
].SetArgName(aText
);
359 aArgInput
[no
].UpdateAccessibleNames();
362 void ParaWin::SetArgNameFont(sal_uInt16 no
,const vcl::Font
& aFont
)
364 aArgInput
[no
].SetArgNameFont(aFont
);
367 void ParaWin::SetEdFocus()
370 if(!aParaArray
.empty())
371 aArgInput
[0].GetArgEdPtr()->GrabFocus();
374 void ParaWin::InitArgInput(sal_uInt16 nPos
, weld::Label
& rFtArg
, weld::Button
& rBtnFx
,
375 ArgEdit
& rEdArg
, RefButton
& rRefBtn
)
378 rRefBtn
.SetReferences(pMyParent
, &rEdArg
);
379 rEdArg
.SetReferences(pMyParent
, &rFtArg
);
381 aArgInput
[nPos
].InitArgInput (&rFtArg
,&rBtnFx
,&rEdArg
,&rRefBtn
);
383 aArgInput
[nPos
].Hide();
385 aArgInput
[nPos
].SetFxClickHdl ( LINK( this, ParaWin
, GetFxHdl
) );
386 aArgInput
[nPos
].SetFxFocusHdl ( LINK( this, ParaWin
, GetFxFocusHdl
) );
387 aArgInput
[nPos
].SetEdFocusHdl ( LINK( this, ParaWin
, GetEdFocusHdl
) );
388 aArgInput
[nPos
].SetEdModifyHdl ( LINK( this, ParaWin
, ModifyHdl
) );
389 aArgInput
[nPos
].UpdateAccessibleNames();
392 void ParaWin::ClearAll()
394 SetFunctionDesc(nullptr);
395 SetArgumentOffset(0);
398 void ParaWin::SetArgumentOffset(sal_uInt16 nOffset
)
401 m_xSlider
->vadjustment_set_value(0);
403 aParaArray
.resize(nMaxArgs
);
407 for ( int i
=0; i
<4 && i
<nMaxArgs
; i
++ )
409 aArgInput
[i
].SetArgVal(OUString());
410 aArgInput
[i
].GetArgEdPtr()->Init(
411 (i
==0) ? nullptr : aArgInput
[i
-1].GetArgEdPtr(),
412 (i
==3 || i
==nMaxArgs
-1) ? nullptr : aArgInput
[i
+1].GetArgEdPtr(),
413 *m_xSlider
, *this, nMaxArgs
);
421 m_xSlider
->set_vpolicy(VclPolicyType::NEVER
);
422 m_xSlider
->set_size_request(-1, -1);
426 m_xSlider
->vadjustment_configure(nOffset
, 0, nMaxArgs
, 1, 4, 4);
427 m_xSlider
->set_vpolicy(VclPolicyType::ALWAYS
);
428 Size
aPrefSize(m_xGrid
->get_preferred_size());
429 m_xSlider
->set_size_request(aPrefSize
.Width(), aPrefSize
.Height());
433 void ParaWin::UpdateParas()
436 sal_uInt16 nOffset
= GetSliderPos();
440 for ( i
=0; (i
<nMaxArgs
) && (i
<4); i
++ )
442 UpdateArgInput( nOffset
, i
);
447 for ( i
=nMaxArgs
; i
<4; i
++ )
452 sal_uInt16
ParaWin::GetSliderPos() const
454 return static_cast<sal_uInt16
>(m_xSlider
->vadjustment_get_value());
457 void ParaWin::SetSliderPos(sal_uInt16 nSliderPos
)
459 sal_uInt16 nOffset
= GetSliderPos();
461 if(m_xSlider
->get_visible() && nOffset
!=nSliderPos
)
463 m_xSlider
->vadjustment_set_value(nSliderPos
);
464 for ( sal_uInt16 i
=0; i
<4; i
++ )
466 UpdateArgInput( nSliderPos
, i
);
471 void ParaWin::SliderMoved()
473 sal_uInt16 nOffset
= GetSliderPos();
475 for ( sal_uInt16 i
=0; i
<4; i
++ )
477 UpdateArgInput( nOffset
, i
);
479 if(nEdFocus
!=NOT_FOUND
)
481 UpdateArgDesc( nEdFocus
);
482 aArgInput
[nEdFocus
].SelectAll();
483 nActiveLine
=nEdFocus
+nOffset
;
485 aArgInput
[nEdFocus
].SelectAll(); // ensure all is still selected
486 aArgInput
[nEdFocus
].UpdateAccessibleNames();
490 void ParaWin::ArgumentModified()
492 aArgModifiedLink
.Call(*this);
495 IMPL_LINK( ParaWin
, GetFxHdl
, ArgInput
&, rPtr
, void )
497 sal_uInt16 nOffset
= GetSliderPos();
499 for (size_t nPos
=0; nPos
< std::size(aArgInput
); ++nPos
)
501 if(&rPtr
== &aArgInput
[nPos
])
508 if(nEdFocus
!=NOT_FOUND
)
510 aArgInput
[nEdFocus
].SelectAll();
511 nActiveLine
=nEdFocus
+nOffset
;
516 IMPL_LINK( ParaWin
, GetFxFocusHdl
, ArgInput
&, rPtr
, void )
518 sal_uInt16 nOffset
= GetSliderPos();
520 for (size_t nPos
=0; nPos
< SAL_N_ELEMENTS(aArgInput
); ++nPos
)
522 if(&rPtr
== &aArgInput
[nPos
])
529 if(nEdFocus
!=NOT_FOUND
)
531 aArgInput
[nEdFocus
].SelectAll();
532 UpdateArgDesc( nEdFocus
);
533 nActiveLine
=nEdFocus
+nOffset
;
537 IMPL_LINK( ParaWin
, GetEdFocusHdl
, ArgInput
&, rPtr
, void )
539 sal_uInt16 nOffset
= GetSliderPos();
541 for (size_t nPos
=0; nPos
< SAL_N_ELEMENTS(aArgInput
); ++nPos
)
543 if(&rPtr
== &aArgInput
[nPos
])
550 if(nEdFocus
!=NOT_FOUND
)
552 aArgInput
[nEdFocus
].SelectAll();
553 UpdateArgDesc( nEdFocus
);
554 nActiveLine
=nEdFocus
+nOffset
;
556 aArgInput
[nEdFocus
].SelectAll(); // ensure all is still selected
557 aArgInput
[nEdFocus
].UpdateAccessibleNames();
561 IMPL_LINK_NOARG(ParaWin
, ScrollHdl
, weld::ScrolledWindow
&, void)
566 IMPL_LINK( ParaWin
, ModifyHdl
, ArgInput
&, rPtr
, void )
568 sal_uInt16 nOffset
= GetSliderPos();
570 for (size_t nPos
=0; nPos
< SAL_N_ELEMENTS(aArgInput
); ++nPos
)
572 if(&rPtr
== &aArgInput
[nPos
])
578 if(nEdFocus
!=NOT_FOUND
)
580 size_t nPara
= nEdFocus
+ nOffset
;
581 if (nPara
< aParaArray
.size())
582 aParaArray
[nPara
] = aArgInput
[nEdFocus
].GetArgVal();
585 SAL_WARN("formula.ui","ParaWin::ModifyHdl - shot in foot: nPara " <<
586 nPara
<< " >= aParaArray.size() " << aParaArray
.size() <<
587 " with nEdFocus " << nEdFocus
<<
588 " and aArgInput[nEdFocus].GetArgVal() '" << aArgInput
[nEdFocus
].GetArgVal() << "'");
590 UpdateArgDesc( nEdFocus
);
591 nActiveLine
= static_cast<sal_uInt16
>(nPara
);
600 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */