/src/libreoffice/formula/source/ui/dlg/funcutl.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <vcl/event.hxx> |
21 | | |
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> |
30 | | |
31 | | namespace formula |
32 | | { |
33 | | |
34 | | ArgEdit::ArgEdit(std::unique_ptr<weld::Entry> xControl) |
35 | 0 | : RefEdit(std::move(xControl)) |
36 | 0 | , pEdPrev(nullptr) |
37 | 0 | , pEdNext(nullptr) |
38 | 0 | , pSlider(nullptr) |
39 | 0 | , pParaWin(nullptr) |
40 | 0 | , nArgs(0) |
41 | 0 | { |
42 | 0 | } |
43 | | |
44 | | void ArgEdit::Init(ArgEdit* pPrevEdit, ArgEdit* pNextEdit, |
45 | | weld::ScrolledWindow& rArgSlider, |
46 | | ParaWin& rParaWin, sal_uInt16 nArgCount) |
47 | 0 | { |
48 | 0 | pEdPrev = pPrevEdit; |
49 | 0 | pEdNext = pNextEdit; |
50 | 0 | pSlider = &rArgSlider; |
51 | 0 | pParaWin = &rParaWin; |
52 | 0 | nArgs = nArgCount; |
53 | 0 | } |
54 | | |
55 | | // Cursor control for Edit Fields in Argument Dialog |
56 | | bool ArgEdit::KeyInput(const KeyEvent& rKEvt) |
57 | 0 | { |
58 | 0 | vcl::KeyCode aCode = rKEvt.GetKeyCode(); |
59 | 0 | bool bUp = (aCode.GetCode() == KEY_UP); |
60 | 0 | bool bDown = (aCode.GetCode() == KEY_DOWN); |
61 | |
|
62 | 0 | if ( pSlider |
63 | 0 | && ( !aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() ) |
64 | 0 | && ( bUp || bDown ) ) |
65 | 0 | { |
66 | 0 | if ( nArgs > 1 ) |
67 | 0 | { |
68 | 0 | ArgEdit* pEd = nullptr; |
69 | 0 | int nThumb = pSlider->vadjustment_get_value(); |
70 | 0 | bool bDoScroll = false; |
71 | 0 | bool bChangeFocus = false; |
72 | |
|
73 | 0 | if ( bDown ) |
74 | 0 | { |
75 | 0 | if ( nArgs > 4 ) |
76 | 0 | { |
77 | 0 | if ( !pEdNext ) |
78 | 0 | { |
79 | 0 | nThumb++; |
80 | 0 | bDoScroll = ( nThumb+3 < static_cast<tools::Long>(nArgs) ); |
81 | 0 | } |
82 | 0 | else |
83 | 0 | { |
84 | 0 | pEd = pEdNext; |
85 | 0 | bChangeFocus = true; |
86 | 0 | } |
87 | 0 | } |
88 | 0 | else if ( pEdNext ) |
89 | 0 | { |
90 | 0 | pEd = pEdNext; |
91 | 0 | bChangeFocus = true; |
92 | 0 | } |
93 | 0 | } |
94 | 0 | else // if ( bUp ) |
95 | 0 | { |
96 | 0 | if ( nArgs > 4 ) |
97 | 0 | { |
98 | 0 | if ( !pEdPrev ) |
99 | 0 | { |
100 | 0 | nThumb--; |
101 | 0 | bDoScroll = ( nThumb >= 0 ); |
102 | 0 | } |
103 | 0 | else |
104 | 0 | { |
105 | 0 | pEd = pEdPrev; |
106 | 0 | bChangeFocus = true; |
107 | 0 | } |
108 | 0 | } |
109 | 0 | else if ( pEdPrev ) |
110 | 0 | { |
111 | 0 | pEd = pEdPrev; |
112 | 0 | bChangeFocus = true; |
113 | 0 | } |
114 | 0 | } |
115 | |
|
116 | 0 | if ( bDoScroll ) |
117 | 0 | { |
118 | 0 | pSlider->vadjustment_set_value( nThumb ); |
119 | 0 | pParaWin->SliderMoved(); |
120 | 0 | } |
121 | 0 | else if ( bChangeFocus ) |
122 | 0 | { |
123 | 0 | pEd->GrabFocus(); |
124 | 0 | } |
125 | 0 | } |
126 | 0 | return true; |
127 | 0 | } |
128 | 0 | return RefEdit::KeyInput(rKEvt); |
129 | 0 | } |
130 | | |
131 | | ArgInput::ArgInput() |
132 | 0 | { |
133 | 0 | pFtArg=nullptr; |
134 | 0 | pBtnFx=nullptr; |
135 | 0 | pEdArg=nullptr; |
136 | 0 | pRefBtn=nullptr; |
137 | 0 | } |
138 | | |
139 | | void ArgInput::InitArgInput(weld::Label* pftArg, weld::Button* pbtnFx, |
140 | | ArgEdit* pedArg, RefButton* prefBtn) |
141 | 0 | { |
142 | 0 | pFtArg =pftArg; |
143 | 0 | pBtnFx =pbtnFx; |
144 | 0 | pEdArg =pedArg; |
145 | 0 | pRefBtn=prefBtn; |
146 | |
|
147 | 0 | if(pBtnFx!=nullptr) |
148 | 0 | { |
149 | 0 | pBtnFx->connect_clicked( LINK( this, ArgInput, FxBtnClickHdl ) ); |
150 | 0 | pBtnFx->connect_focus_in( LINK( this, ArgInput, FxBtnFocusHdl ) ); |
151 | 0 | } |
152 | 0 | if(pEdArg!=nullptr) |
153 | 0 | { |
154 | 0 | pEdArg->SetGetFocusHdl ( LINK( this, ArgInput, EdFocusHdl ) ); |
155 | 0 | pEdArg->SetModifyHdl ( LINK( this, ArgInput, EdModifyHdl ) ); |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | // Sets the Name for the Argument |
160 | | void ArgInput::SetArgName(const OUString &aArg) |
161 | 0 | { |
162 | 0 | if (pFtArg) |
163 | 0 | pFtArg->set_label(aArg ); |
164 | 0 | } |
165 | | |
166 | | // Returns the Name for the Argument |
167 | | OUString ArgInput::GetArgName() const |
168 | 0 | { |
169 | 0 | OUString aPrivArgName; |
170 | 0 | if (pFtArg) |
171 | 0 | aPrivArgName = pFtArg->get_label(); |
172 | 0 | return aPrivArgName; |
173 | 0 | } |
174 | | |
175 | | //Sets the Name for the Argument |
176 | | void ArgInput::SetArgNameFont(const vcl::Font &aFont) |
177 | 0 | { |
178 | 0 | if (pFtArg) |
179 | 0 | pFtArg->set_font(aFont); |
180 | 0 | } |
181 | | |
182 | | //Sets up the Selection for the EditBox. |
183 | | void ArgInput::SelectAll() |
184 | 0 | { |
185 | 0 | if (pEdArg) |
186 | 0 | pEdArg->SelectAll(); |
187 | 0 | } |
188 | | |
189 | | //Sets the Value for the Argument |
190 | | void ArgInput::SetArgVal(const OUString &rVal) |
191 | 0 | { |
192 | 0 | if (pEdArg) |
193 | 0 | pEdArg->SetRefString(rVal); |
194 | 0 | } |
195 | | |
196 | | //Returns the Value for the Argument |
197 | | OUString ArgInput::GetArgVal() const |
198 | 0 | { |
199 | 0 | OUString aResult; |
200 | 0 | if (pEdArg) |
201 | 0 | aResult=pEdArg->GetText(); |
202 | 0 | return aResult; |
203 | 0 | } |
204 | | |
205 | | //Hides the Controls |
206 | | void ArgInput::Hide() |
207 | 0 | { |
208 | 0 | if (pFtArg && pBtnFx && pEdArg && pRefBtn) |
209 | 0 | { |
210 | 0 | pFtArg->hide(); |
211 | 0 | pBtnFx->hide(); |
212 | 0 | pEdArg->GetWidget()->hide(); |
213 | 0 | pRefBtn->GetWidget()->hide(); |
214 | 0 | } |
215 | 0 | } |
216 | | |
217 | | //Casts the Controls again. |
218 | | void ArgInput::Show() |
219 | 0 | { |
220 | 0 | if (pFtArg && pBtnFx && pEdArg && pRefBtn) |
221 | 0 | { |
222 | 0 | pFtArg->show(); |
223 | 0 | pBtnFx->show(); |
224 | 0 | pEdArg->GetWidget()->show(); |
225 | 0 | pRefBtn->GetWidget()->show(); |
226 | 0 | } |
227 | 0 | } |
228 | | |
229 | | void ArgInput::UpdateAccessibleNames() |
230 | 0 | { |
231 | 0 | OUString aArgName = ":" + pFtArg->get_label(); |
232 | |
|
233 | 0 | OUString aName = pBtnFx->get_tooltip_text() + aArgName; |
234 | 0 | pBtnFx->set_accessible_name(aName); |
235 | |
|
236 | 0 | aName = pRefBtn->GetWidget()->get_tooltip_text() + aArgName; |
237 | 0 | pRefBtn->GetWidget()->set_accessible_name(aName); |
238 | 0 | } |
239 | | |
240 | | IMPL_LINK(ArgInput, FxBtnClickHdl, weld::Button&, rBtn, void) |
241 | 0 | { |
242 | 0 | if (&rBtn == pBtnFx) |
243 | 0 | aFxClickLink.Call(*this); |
244 | 0 | } |
245 | | |
246 | | IMPL_LINK( ArgInput, FxBtnFocusHdl, weld::Widget&, rControl, void ) |
247 | 0 | { |
248 | 0 | if (&rControl == pBtnFx) |
249 | 0 | aFxFocusLink.Call(*this); |
250 | 0 | } |
251 | | |
252 | | IMPL_LINK( ArgInput, EdFocusHdl, RefEdit&, rControl, void ) |
253 | 0 | { |
254 | 0 | if (&rControl == pEdArg) |
255 | 0 | aEdFocusLink.Call(*this); |
256 | 0 | } |
257 | | |
258 | | IMPL_LINK( ArgInput, EdModifyHdl, RefEdit&, rEdit, void ) |
259 | 0 | { |
260 | 0 | if (&rEdit == pEdArg) |
261 | 0 | aEdModifyLink.Call(*this); |
262 | 0 | } |
263 | | |
264 | | RefEdit::RefEdit(std::unique_ptr<weld::Entry> xControl) |
265 | 0 | : mxEntry(std::move(xControl)) |
266 | 0 | , maIdle("formula RefEdit Idle") |
267 | 0 | , mpAnyRefDlg(nullptr) |
268 | 0 | , mpFocusInEvent(nullptr) |
269 | 0 | , mpFocusOutEvent(nullptr) |
270 | 0 | { |
271 | 0 | mxEntry->connect_focus_in(LINK(this, RefEdit, GetFocusHdl)); |
272 | 0 | mxEntry->connect_focus_out(LINK(this, RefEdit, LoseFocusHdl)); |
273 | 0 | mxEntry->connect_key_press(LINK(this, RefEdit, KeyInputHdl)); |
274 | 0 | mxEntry->connect_changed(LINK(this, RefEdit, Modify)); |
275 | 0 | maIdle.SetInvokeHandler(LINK(this, RefEdit, UpdateHdl)); |
276 | 0 | } |
277 | | |
278 | | RefEdit::~RefEdit() |
279 | 0 | { |
280 | 0 | if (mpFocusInEvent) |
281 | 0 | Application::RemoveUserEvent(mpFocusInEvent); |
282 | 0 | if (mpFocusOutEvent) |
283 | 0 | Application::RemoveUserEvent(mpFocusOutEvent); |
284 | 0 | maIdle.ClearInvokeHandler(); |
285 | 0 | maIdle.Stop(); |
286 | 0 | } |
287 | | |
288 | | void RefEdit::SetRefString( const OUString& rStr ) |
289 | 0 | { |
290 | | // Prevent unwanted side effects by setting only a differing string. |
291 | | // See commit message for reasons. |
292 | 0 | if (mxEntry->get_text() != rStr) |
293 | 0 | mxEntry->set_text(rStr); |
294 | 0 | } |
295 | | |
296 | | void RefEdit::SetRefValid(bool bValid) |
297 | 0 | { |
298 | 0 | mxEntry->set_message_type(bValid ? weld::EntryMessageType::Normal |
299 | 0 | : weld::EntryMessageType::Error); |
300 | 0 | } |
301 | | |
302 | | void RefEdit::SetText(const OUString& rStr) |
303 | 0 | { |
304 | 0 | mxEntry->set_text(rStr); |
305 | 0 | UpdateHdl(&maIdle); |
306 | 0 | } |
307 | | |
308 | | void RefEdit::StartUpdateData() |
309 | 0 | { |
310 | 0 | maIdle.Start(); |
311 | 0 | } |
312 | | |
313 | | void RefEdit::SetReferences(IControlReferenceHandler* pDlg, weld::Label* pLabel) |
314 | 0 | { |
315 | 0 | mpAnyRefDlg = pDlg; |
316 | 0 | if (pLabel) |
317 | 0 | maGetLabelTextForShrinkModeFunc = [pLabel] { return pLabel->get_label(); }; |
318 | 0 | else |
319 | 0 | maGetLabelTextForShrinkModeFunc = nullptr; |
320 | |
|
321 | 0 | if( pDlg ) |
322 | 0 | { |
323 | 0 | maIdle.SetInvokeHandler(LINK(this, RefEdit, UpdateHdl)); |
324 | 0 | } |
325 | 0 | else |
326 | 0 | { |
327 | 0 | maIdle.ClearInvokeHandler(); |
328 | 0 | maIdle.Stop(); |
329 | 0 | } |
330 | 0 | } |
331 | | |
332 | | void RefEdit::SetReferences(IControlReferenceHandler* pDlg, weld::Frame* pFrame) |
333 | 0 | { |
334 | 0 | SetReferences(pDlg); |
335 | |
|
336 | 0 | if (pFrame) |
337 | 0 | maGetLabelTextForShrinkModeFunc = [pFrame] { return pFrame->get_label(); }; |
338 | 0 | } |
339 | | |
340 | | OUString RefEdit::GetLabelTextForShrinkMode() |
341 | 0 | { |
342 | 0 | if (maGetLabelTextForShrinkModeFunc) |
343 | 0 | return maGetLabelTextForShrinkModeFunc(); |
344 | | |
345 | 0 | return OUString(); |
346 | 0 | } |
347 | | |
348 | | IMPL_LINK_NOARG(RefEdit, Modify, weld::Entry&, void) |
349 | 0 | { |
350 | 0 | maModifyHdl.Call(*this); |
351 | 0 | if (mpAnyRefDlg) |
352 | 0 | mpAnyRefDlg->HideReference(); |
353 | 0 | } |
354 | | |
355 | | IMPL_LINK(RefEdit, KeyInputHdl, const KeyEvent&, rKEvt, bool) |
356 | 0 | { |
357 | 0 | return KeyInput(rKEvt); |
358 | 0 | } |
359 | | |
360 | | bool RefEdit::KeyInput(const KeyEvent& rKEvt) |
361 | 0 | { |
362 | 0 | const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); |
363 | 0 | if (mpAnyRefDlg && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_F2) |
364 | 0 | { |
365 | 0 | mpAnyRefDlg->ReleaseFocus(this); |
366 | 0 | return true; |
367 | 0 | } |
368 | | |
369 | 0 | switch (rKeyCode.GetCode()) |
370 | 0 | { |
371 | 0 | case KEY_RETURN: |
372 | 0 | case KEY_ESCAPE: |
373 | 0 | return maActivateHdl.Call(*GetWidget()); |
374 | 0 | } |
375 | | |
376 | 0 | return false; |
377 | 0 | } |
378 | | |
379 | | void RefEdit::GetFocus() |
380 | 0 | { |
381 | 0 | maGetFocusHdl.Call(*this); |
382 | 0 | StartUpdateData(); |
383 | 0 | } |
384 | | |
385 | | void RefEdit::LoseFocus() |
386 | 0 | { |
387 | 0 | maLoseFocusHdl.Call(*this); |
388 | 0 | if (mpAnyRefDlg) |
389 | 0 | mpAnyRefDlg->HideReference(); |
390 | 0 | } |
391 | | |
392 | | IMPL_LINK_NOARG(RefEdit, GetFocusHdl, weld::Widget&, void) |
393 | 0 | { |
394 | | // in e.g. function wizard RefEdits we want to select all when we get focus |
395 | | // but in the gtk case there are pending gtk handlers which change selection |
396 | | // after our handler, so post our focus in event to happen after those complete |
397 | 0 | if (mpFocusInEvent) |
398 | 0 | Application::RemoveUserEvent(mpFocusInEvent); |
399 | 0 | mpFocusInEvent = Application::PostUserEvent(LINK(this, RefEdit, AsyncFocusInHdl)); |
400 | 0 | } |
401 | | |
402 | | IMPL_LINK_NOARG(RefEdit, LoseFocusHdl, weld::Widget&, void) |
403 | 0 | { |
404 | | // tdf#127262 because focus in is async, focus out must not appear out |
405 | | // of sequence to focus in |
406 | 0 | if (mpFocusOutEvent) |
407 | 0 | Application::RemoveUserEvent(mpFocusOutEvent); |
408 | 0 | mpFocusOutEvent = Application::PostUserEvent(LINK(this, RefEdit, AsyncFocusOutHdl)); |
409 | 0 | } |
410 | | |
411 | | IMPL_LINK_NOARG(RefEdit, AsyncFocusInHdl, void*, void) |
412 | 0 | { |
413 | 0 | mpFocusInEvent = nullptr; |
414 | 0 | GetFocus(); |
415 | 0 | } |
416 | | |
417 | | IMPL_LINK_NOARG(RefEdit, AsyncFocusOutHdl, void*, void) |
418 | 0 | { |
419 | 0 | mpFocusOutEvent = nullptr; |
420 | 0 | LoseFocus(); |
421 | 0 | } |
422 | | |
423 | | IMPL_LINK_NOARG(RefEdit, UpdateHdl, Timer *, void) |
424 | 0 | { |
425 | 0 | if (mpAnyRefDlg) |
426 | 0 | mpAnyRefDlg->ShowReference(mxEntry->get_text()); |
427 | 0 | } |
428 | | |
429 | | RefButton::RefButton(std::unique_ptr<weld::Button> xControl) |
430 | 0 | : xButton(std::move(xControl)) |
431 | 0 | , pAnyRefDlg( nullptr ) |
432 | 0 | , pRefEdit( nullptr ) |
433 | 0 | { |
434 | 0 | xButton->connect_focus_in(LINK(this, RefButton, GetFocus)); |
435 | 0 | xButton->connect_focus_out(LINK(this, RefButton, LoseFocus)); |
436 | 0 | xButton->connect_key_press(LINK(this, RefButton, KeyInput)); |
437 | 0 | xButton->connect_clicked(LINK(this, RefButton, Click)); |
438 | 0 | SetStartImage(); |
439 | 0 | } |
440 | | |
441 | | RefButton::~RefButton() |
442 | 0 | { |
443 | 0 | } |
444 | | |
445 | | void RefButton::SetStartImage() |
446 | 0 | { |
447 | 0 | xButton->set_from_icon_name(RID_BMP_REFBTN1); |
448 | 0 | xButton->set_tooltip_text(ForResId(RID_STR_SHRINK)); |
449 | 0 | } |
450 | | |
451 | | void RefButton::SetEndImage() |
452 | 0 | { |
453 | 0 | xButton->set_from_icon_name(RID_BMP_REFBTN2); |
454 | 0 | xButton->set_tooltip_text(ForResId(RID_STR_EXPAND)); |
455 | 0 | } |
456 | | |
457 | | void RefButton::SetReferences( IControlReferenceHandler* pDlg, RefEdit* pEdit ) |
458 | 0 | { |
459 | 0 | pAnyRefDlg = pDlg; |
460 | 0 | pRefEdit = pEdit; |
461 | 0 | } |
462 | | |
463 | | IMPL_LINK_NOARG(RefButton, Click, weld::Button&, void) |
464 | 0 | { |
465 | 0 | maClickHdl.Call(*this); |
466 | 0 | if( pAnyRefDlg ) |
467 | 0 | pAnyRefDlg->ToggleCollapsed( pRefEdit, this ); |
468 | 0 | } |
469 | | |
470 | | IMPL_LINK(RefButton, KeyInput, const KeyEvent&, rKEvt, bool) |
471 | 0 | { |
472 | 0 | const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); |
473 | 0 | if (pAnyRefDlg && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_F2) |
474 | 0 | { |
475 | 0 | pAnyRefDlg->ReleaseFocus( pRefEdit ); |
476 | 0 | return true; |
477 | 0 | } |
478 | | |
479 | 0 | switch (rKeyCode.GetCode()) |
480 | 0 | { |
481 | 0 | case KEY_RETURN: |
482 | 0 | case KEY_ESCAPE: |
483 | 0 | return maActivateHdl.Call(*GetWidget()); |
484 | 0 | } |
485 | | |
486 | 0 | return false; |
487 | 0 | } |
488 | | |
489 | | IMPL_LINK_NOARG(RefButton, GetFocus, weld::Widget&, void) |
490 | 0 | { |
491 | 0 | maGetFocusHdl.Call(*this); |
492 | 0 | if (pRefEdit) |
493 | 0 | pRefEdit->StartUpdateData(); |
494 | 0 | } |
495 | | |
496 | | IMPL_LINK_NOARG(RefButton, LoseFocus, weld::Widget&, void) |
497 | 0 | { |
498 | 0 | maLoseFocusHdl.Call(*this); |
499 | 0 | if (pRefEdit) |
500 | 0 | pRefEdit->DoModify(); |
501 | 0 | } |
502 | | |
503 | | } // formula |
504 | | |
505 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |