Avoid potential negative array index access to cached text.
[LibreOffice.git] / formula / source / ui / dlg / funcutl.cxx
blob58c2492c5505856683bd67ccb8ed391acc0eda45
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 <vcl/event.hxx>
22 #include <formula/funcutl.hxx>
23 #include <formula/IControlReferenceHandler.hxx>
24 #include <vcl/svapp.hxx>
25 #include "ControlHelper.hxx"
26 #include "parawin.hxx"
27 #include <strings.hrc>
28 #include <bitmaps.hlst>
29 #include <core_resource.hxx>
31 namespace formula
34 ArgEdit::ArgEdit(std::unique_ptr<weld::Entry> xControl)
35 : RefEdit(std::move(xControl))
36 , pEdPrev(nullptr)
37 , pEdNext(nullptr)
38 , pSlider(nullptr)
39 , pParaWin(nullptr)
40 , nArgs(0)
44 void ArgEdit::Init(ArgEdit* pPrevEdit, ArgEdit* pNextEdit,
45 weld::ScrolledWindow& rArgSlider,
46 ParaWin& rParaWin, sal_uInt16 nArgCount)
48 pEdPrev = pPrevEdit;
49 pEdNext = pNextEdit;
50 pSlider = &rArgSlider;
51 pParaWin = &rParaWin;
52 nArgs = nArgCount;
55 // Cursor control for Edit Fields in Argument Dialog
56 bool ArgEdit::KeyInput(const KeyEvent& rKEvt)
58 vcl::KeyCode aCode = rKEvt.GetKeyCode();
59 bool bUp = (aCode.GetCode() == KEY_UP);
60 bool bDown = (aCode.GetCode() == KEY_DOWN);
62 if ( pSlider
63 && ( !aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() )
64 && ( bUp || bDown ) )
66 if ( nArgs > 1 )
68 ArgEdit* pEd = nullptr;
69 int nThumb = pSlider->vadjustment_get_value();
70 bool bDoScroll = false;
71 bool bChangeFocus = false;
73 if ( bDown )
75 if ( nArgs > 4 )
77 if ( !pEdNext )
79 nThumb++;
80 bDoScroll = ( nThumb+3 < static_cast<tools::Long>(nArgs) );
82 else
84 pEd = pEdNext;
85 bChangeFocus = true;
88 else if ( pEdNext )
90 pEd = pEdNext;
91 bChangeFocus = true;
94 else // if ( bUp )
96 if ( nArgs > 4 )
98 if ( !pEdPrev )
100 nThumb--;
101 bDoScroll = ( nThumb >= 0 );
103 else
105 pEd = pEdPrev;
106 bChangeFocus = true;
109 else if ( pEdPrev )
111 pEd = pEdPrev;
112 bChangeFocus = true;
116 if ( bDoScroll )
118 pSlider->vadjustment_set_value( nThumb );
119 pParaWin->SliderMoved();
121 else if ( bChangeFocus )
123 pEd->GrabFocus();
126 return true;
128 return RefEdit::KeyInput(rKEvt);
131 ArgInput::ArgInput()
133 pFtArg=nullptr;
134 pBtnFx=nullptr;
135 pEdArg=nullptr;
136 pRefBtn=nullptr;
139 void ArgInput::InitArgInput(weld::Label* pftArg, weld::Button* pbtnFx,
140 ArgEdit* pedArg, RefButton* prefBtn)
142 pFtArg =pftArg;
143 pBtnFx =pbtnFx;
144 pEdArg =pedArg;
145 pRefBtn=prefBtn;
147 if(pBtnFx!=nullptr)
149 pBtnFx->connect_clicked( LINK( this, ArgInput, FxBtnClickHdl ) );
150 pBtnFx->connect_focus_in( LINK( this, ArgInput, FxBtnFocusHdl ) );
152 if(pEdArg!=nullptr)
154 pEdArg->SetGetFocusHdl ( LINK( this, ArgInput, EdFocusHdl ) );
155 pEdArg->SetModifyHdl ( LINK( this, ArgInput, EdModifyHdl ) );
159 // Sets the Name for the Argument
160 void ArgInput::SetArgName(const OUString &aArg)
162 if (pFtArg)
163 pFtArg->set_label(aArg );
166 // Returns the Name for the Argument
167 OUString ArgInput::GetArgName() const
169 OUString aPrivArgName;
170 if (pFtArg)
171 aPrivArgName = pFtArg->get_label();
172 return aPrivArgName;
175 //Sets the Name for the Argument
176 void ArgInput::SetArgNameFont(const vcl::Font &aFont)
178 if (pFtArg)
179 pFtArg->set_font(aFont);
182 //Sets up the Selection for the EditBox.
183 void ArgInput::SelectAll()
185 if (pEdArg)
186 pEdArg->SelectAll();
189 //Sets the Value for the Argument
190 void ArgInput::SetArgVal(const OUString &rVal)
192 if (pEdArg)
193 pEdArg->SetRefString(rVal);
196 //Returns the Value for the Argument
197 OUString ArgInput::GetArgVal() const
199 OUString aResult;
200 if (pEdArg)
201 aResult=pEdArg->GetText();
202 return aResult;
205 //Hides the Controls
206 void ArgInput::Hide()
208 if (pFtArg && pBtnFx && pEdArg && pRefBtn)
210 pFtArg->hide();
211 pBtnFx->hide();
212 pEdArg->GetWidget()->hide();
213 pRefBtn->GetWidget()->hide();
217 //Casts the Controls again.
218 void ArgInput::Show()
220 if (pFtArg && pBtnFx && pEdArg && pRefBtn)
222 pFtArg->show();
223 pBtnFx->show();
224 pEdArg->GetWidget()->show();
225 pRefBtn->GetWidget()->show();
229 void ArgInput::UpdateAccessibleNames()
231 OUString aArgName = ":" + pFtArg->get_label();
233 OUString aName = pBtnFx->get_tooltip_text() + aArgName;
234 pBtnFx->set_accessible_name(aName);
236 aName = pRefBtn->GetWidget()->get_tooltip_text() + aArgName;
237 pRefBtn->GetWidget()->set_accessible_name(aName);
240 IMPL_LINK(ArgInput, FxBtnClickHdl, weld::Button&, rBtn, void)
242 if (&rBtn == pBtnFx)
243 aFxClickLink.Call(*this);
246 IMPL_LINK( ArgInput, FxBtnFocusHdl, weld::Widget&, rControl, void )
248 if (&rControl == pBtnFx)
249 aFxFocusLink.Call(*this);
252 IMPL_LINK( ArgInput, EdFocusHdl, RefEdit&, rControl, void )
254 if (&rControl == pEdArg)
255 aEdFocusLink.Call(*this);
258 IMPL_LINK( ArgInput, EdModifyHdl, RefEdit&, rEdit, void )
260 if (&rEdit == pEdArg)
261 aEdModifyLink.Call(*this);
264 RefEdit::RefEdit(std::unique_ptr<weld::Entry> xControl)
265 : xEntry(std::move(xControl))
266 , aIdle("formula RefEdit Idle")
267 , pAnyRefDlg(nullptr)
268 , pLabelWidget(nullptr)
269 , mpFocusInEvent(nullptr)
270 , mpFocusOutEvent(nullptr)
272 xEntry->connect_focus_in(LINK(this, RefEdit, GetFocusHdl));
273 xEntry->connect_focus_out(LINK(this, RefEdit, LoseFocusHdl));
274 xEntry->connect_key_press(LINK(this, RefEdit, KeyInputHdl));
275 xEntry->connect_changed(LINK(this, RefEdit, Modify));
276 aIdle.SetInvokeHandler( LINK( this, RefEdit, UpdateHdl ) );
279 RefEdit::~RefEdit()
281 if (mpFocusInEvent)
282 Application::RemoveUserEvent(mpFocusInEvent);
283 if (mpFocusOutEvent)
284 Application::RemoveUserEvent(mpFocusOutEvent);
285 aIdle.ClearInvokeHandler();
286 aIdle.Stop();
289 void RefEdit::SetRefString( const OUString& rStr )
291 // Prevent unwanted side effects by setting only a differing string.
292 // See commit message for reasons.
293 if (xEntry->get_text() != rStr)
294 xEntry->set_text(rStr);
297 void RefEdit::SetRefValid(bool bValid)
299 xEntry->set_message_type(bValid ? weld::EntryMessageType::Normal : weld::EntryMessageType::Error);
302 void RefEdit::SetText(const OUString& rStr)
304 xEntry->set_text(rStr);
305 UpdateHdl( &aIdle );
308 void RefEdit::StartUpdateData()
310 aIdle.Start();
313 void RefEdit::SetReferences(IControlReferenceHandler* pDlg, weld::Label* pLabel)
315 pAnyRefDlg = pDlg;
316 pLabelWidget = pLabel;
318 if( pDlg )
320 aIdle.SetInvokeHandler(LINK(this, RefEdit, UpdateHdl));
322 else
324 aIdle.ClearInvokeHandler();
325 aIdle.Stop();
329 IMPL_LINK_NOARG(RefEdit, Modify, weld::Entry&, void)
331 maModifyHdl.Call(*this);
332 if (pAnyRefDlg)
333 pAnyRefDlg->HideReference();
336 IMPL_LINK(RefEdit, KeyInputHdl, const KeyEvent&, rKEvt, bool)
338 return KeyInput(rKEvt);
341 bool RefEdit::KeyInput(const KeyEvent& rKEvt)
343 const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
344 if (pAnyRefDlg && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_F2)
346 pAnyRefDlg->ReleaseFocus( this );
347 return true;
350 switch (rKeyCode.GetCode())
352 case KEY_RETURN:
353 case KEY_ESCAPE:
354 return maActivateHdl.Call(*GetWidget());
357 return false;
360 void RefEdit::GetFocus()
362 maGetFocusHdl.Call(*this);
363 StartUpdateData();
366 void RefEdit::LoseFocus()
368 maLoseFocusHdl.Call(*this);
369 if( pAnyRefDlg )
370 pAnyRefDlg->HideReference();
373 IMPL_LINK_NOARG(RefEdit, GetFocusHdl, weld::Widget&, void)
375 // in e.g. function wizard RefEdits we want to select all when we get focus
376 // but in the gtk case there are pending gtk handlers which change selection
377 // after our handler, so post our focus in event to happen after those complete
378 if (mpFocusInEvent)
379 Application::RemoveUserEvent(mpFocusInEvent);
380 mpFocusInEvent = Application::PostUserEvent(LINK(this, RefEdit, AsyncFocusInHdl));
383 IMPL_LINK_NOARG(RefEdit, LoseFocusHdl, weld::Widget&, void)
385 // tdf#127262 because focus in is async, focus out must not appear out
386 // of sequence to focus in
387 if (mpFocusOutEvent)
388 Application::RemoveUserEvent(mpFocusOutEvent);
389 mpFocusOutEvent = Application::PostUserEvent(LINK(this, RefEdit, AsyncFocusOutHdl));
392 IMPL_LINK_NOARG(RefEdit, AsyncFocusInHdl, void*, void)
394 mpFocusInEvent = nullptr;
395 GetFocus();
398 IMPL_LINK_NOARG(RefEdit, AsyncFocusOutHdl, void*, void)
400 mpFocusOutEvent = nullptr;
401 LoseFocus();
404 IMPL_LINK_NOARG(RefEdit, UpdateHdl, Timer *, void)
406 if( pAnyRefDlg )
407 pAnyRefDlg->ShowReference(xEntry->get_text());
410 RefButton::RefButton(std::unique_ptr<weld::Button> xControl)
411 : xButton(std::move(xControl))
412 , pAnyRefDlg( nullptr )
413 , pRefEdit( nullptr )
415 xButton->connect_focus_in(LINK(this, RefButton, GetFocus));
416 xButton->connect_focus_out(LINK(this, RefButton, LoseFocus));
417 xButton->connect_key_press(LINK(this, RefButton, KeyInput));
418 xButton->connect_clicked(LINK(this, RefButton, Click));
419 SetStartImage();
422 RefButton::~RefButton()
426 void RefButton::SetStartImage()
428 xButton->set_from_icon_name(RID_BMP_REFBTN1);
429 xButton->set_tooltip_text(ForResId(RID_STR_SHRINK));
432 void RefButton::SetEndImage()
434 xButton->set_from_icon_name(RID_BMP_REFBTN2);
435 xButton->set_tooltip_text(ForResId(RID_STR_EXPAND));
438 void RefButton::SetReferences( IControlReferenceHandler* pDlg, RefEdit* pEdit )
440 pAnyRefDlg = pDlg;
441 pRefEdit = pEdit;
444 IMPL_LINK_NOARG(RefButton, Click, weld::Button&, void)
446 maClickHdl.Call(*this);
447 if( pAnyRefDlg )
448 pAnyRefDlg->ToggleCollapsed( pRefEdit, this );
451 IMPL_LINK(RefButton, KeyInput, const KeyEvent&, rKEvt, bool)
453 const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
454 if (pAnyRefDlg && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_F2)
456 pAnyRefDlg->ReleaseFocus( pRefEdit );
457 return true;
460 switch (rKeyCode.GetCode())
462 case KEY_RETURN:
463 case KEY_ESCAPE:
464 return maActivateHdl.Call(*GetWidget());
467 return false;
470 IMPL_LINK_NOARG(RefButton, GetFocus, weld::Widget&, void)
472 maGetFocusHdl.Call(*this);
473 if (pRefEdit)
474 pRefEdit->StartUpdateData();
477 IMPL_LINK_NOARG(RefButton, LoseFocus, weld::Widget&, void)
479 maLoseFocusHdl.Call(*this);
480 if (pRefEdit)
481 pRefEdit->DoModify();
484 } // formula
486 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */