Avoid potential negative array index access to cached text.
[LibreOffice.git] / formula / source / ui / dlg / parawin.cxx
blobbcc1c2d1a962901701d684d8121a8a4d473c9c61
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
31 namespace formula
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)
39 : pFuncDesc(nullptr)
40 , pMyParent(_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();
90 nEdFocus = NOT_FOUND;
91 nActiveLine = 0;
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);
99 ClearAll();
102 void ParaWin::UpdateArgDesc( sal_uInt16 nArg )
104 if (nArg == NOT_FOUND)
105 return;
107 if (nMaxArgs > 4)
108 nArg = sal::static_int_cast<sal_uInt16>( nArg + GetSliderPos() );
110 if ((nMaxArgs <= 0) || (nArg >= nMaxArgs))
111 return;
113 OUString aArgDesc;
114 OUString aArgName;
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) ;
139 else
141 sal_uInt16 nFix = nArgs - PAIRED_VAR_ARGS;
142 sal_uInt16 nPos;
143 if ( nArg < nFix )
144 nPos = nArg;
145 else
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)
165 return;
167 if ( nArgs < VAR_ARGS)
169 if (nArg < nMaxArgs)
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());
183 SetArgNameFont( i,
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 );
193 else
194 SetArgName( i, pFuncDesc->getParameterName(nRealArg) );
196 else
198 sal_uInt16 nFix = nArgs - PAIRED_VAR_ARGS;
199 sal_uInt16 nPos;
200 if ( nArg < nFix )
201 nPos = nArg;
202 else
203 nPos = nFix + ( (nArg-nFix) % 2);
204 sal_uInt16 nRealArg = (nPos < aVisibleArgMapping.size() ?
205 aVisibleArgMapping[nPos] : aVisibleArgMapping.back());
206 SetArgNameFont( i,
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 );
216 else
217 SetArgName( i, pFuncDesc->getParameterName(nRealArg) );
219 if (nArg < nMaxArgs)
220 aArgInput[i].SetArgVal(aParaArray[nArg]);
223 ParaWin::~ParaWin()
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)
236 if (no >= nMaxArgs)
237 return;
239 tools::Long nOffset = GetSliderPos();
240 nActiveLine=no;
241 tools::Long nNewEdPos=static_cast<tools::Long>(nActiveLine)-nOffset;
242 if(nNewEdPos<0 || nNewEdPos>3)
244 nOffset+=nNewEdPos;
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();
258 else
260 return nullptr;
265 OUString ParaWin::GetArgument(sal_uInt16 no)
267 OUString aStr;
268 if(no<aParaArray.size())
270 aStr=aParaArray[no];
271 if(no==nActiveLine && aStr.isEmpty())
272 aStr += " ";
274 return aStr;
277 OUString ParaWin::GetActiveArgName() const
279 OUString aStr;
280 if (nMaxArgs > 0 && nEdFocus != NOT_FOUND)
282 aStr=aArgInput[nEdFocus].GetArgName();
284 return aStr;
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)
296 aFntBold=aBoldFont;
297 aFntLight=aLightFont;
300 void ParaWin::SetFunctionDesc(const IFunctionDescription* pFDesc)
302 pFuncDesc=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());
314 else
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);
332 SetActiveLine(0);
334 else
336 nActiveLine=0;
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()
369 UpdateArgDesc(0);
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)
400 aParaArray.clear();
401 m_xSlider->vadjustment_set_value(0);
403 aParaArray.resize(nMaxArgs);
405 if (nMaxArgs > 0)
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 );
417 UpdateParas();
419 if (nMaxArgs < 5)
421 m_xSlider->set_vpolicy(VclPolicyType::NEVER);
422 m_xSlider->set_size_request(-1, -1);
424 else
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()
435 sal_uInt16 i;
436 sal_uInt16 nOffset = GetSliderPos();
438 if ( nMaxArgs > 0 )
440 for ( i=0; (i<nMaxArgs) && (i<4); i++ )
442 UpdateArgInput( nOffset, i );
443 aArgInput[i].Show();
447 for ( i=nMaxArgs; i<4; i++ )
448 aArgInput[i].Hide();
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;
484 ArgumentModified();
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();
498 nEdFocus=NOT_FOUND;
499 for (size_t nPos=0; nPos < std::size(aArgInput); ++nPos)
501 if(&rPtr == &aArgInput[nPos])
503 nEdFocus=nPos;
504 break;
508 if(nEdFocus!=NOT_FOUND)
510 aArgInput[nEdFocus].SelectAll();
511 nActiveLine=nEdFocus+nOffset;
512 aFxLink.Call(*this);
516 IMPL_LINK( ParaWin, GetFxFocusHdl, ArgInput&, rPtr, void )
518 sal_uInt16 nOffset = GetSliderPos();
519 nEdFocus=NOT_FOUND;
520 for (size_t nPos=0; nPos < SAL_N_ELEMENTS(aArgInput); ++nPos)
522 if(&rPtr == &aArgInput[nPos])
524 nEdFocus=nPos;
525 break;
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();
540 nEdFocus=NOT_FOUND;
541 for (size_t nPos=0; nPos < SAL_N_ELEMENTS(aArgInput); ++nPos)
543 if(&rPtr == &aArgInput[nPos])
545 nEdFocus=nPos;
546 break;
550 if(nEdFocus!=NOT_FOUND)
552 aArgInput[nEdFocus].SelectAll();
553 UpdateArgDesc( nEdFocus );
554 nActiveLine=nEdFocus+nOffset;
555 ArgumentModified();
556 aArgInput[nEdFocus].SelectAll(); // ensure all is still selected
557 aArgInput[nEdFocus].UpdateAccessibleNames();
561 IMPL_LINK_NOARG(ParaWin, ScrollHdl, weld::ScrolledWindow&, void)
563 SliderMoved();
566 IMPL_LINK( ParaWin, ModifyHdl, ArgInput&, rPtr, void )
568 sal_uInt16 nOffset = GetSliderPos();
569 nEdFocus=NOT_FOUND;
570 for (size_t nPos=0; nPos < SAL_N_ELEMENTS(aArgInput); ++nPos)
572 if(&rPtr == &aArgInput[nPos])
574 nEdFocus=nPos;
575 break;
578 if(nEdFocus!=NOT_FOUND)
580 size_t nPara = nEdFocus + nOffset;
581 if (nPara < aParaArray.size())
582 aParaArray[nPara] = aArgInput[nEdFocus].GetArgVal();
583 else
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);
594 ArgumentModified();
598 } // formula
600 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */