bump product version to 7.6.3.2-android
[LibreOffice.git] / vcl / jsdialog / executor.cxx
blobaf514bc70dde40e04b8aed5efd2866b8c6555cf5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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/.
8 */
10 #include <jsdialog/jsdialogbuilder.hxx>
11 #include <o3tl/string_view.hxx>
12 #include <vcl/weld.hxx>
13 #include <vcl/jsdialog/executor.hxx>
14 #include <sal/log.hxx>
15 #include <rtl/uri.hxx>
16 #include <boost/property_tree/json_parser.hpp>
18 namespace jsdialog
20 StringMap jsonToStringMap(const char* pJSON)
22 StringMap aArgs;
23 if (pJSON && pJSON[0] != '\0')
25 std::stringstream aStream(pJSON);
26 boost::property_tree::ptree aTree;
27 boost::property_tree::read_json(aStream, aTree);
29 for (const auto& rPair : aTree)
31 aArgs[OUString::fromUtf8(rPair.first)]
32 = OUString::fromUtf8(rPair.second.get_value<std::string>("."));
35 return aArgs;
38 void SendFullUpdate(const OUString& nWindowId, const OUString& rWidget)
40 weld::Widget* pWidget = JSInstanceBuilder::FindWeldWidgetsMap(nWindowId, rWidget);
41 if (auto pJSWidget = dynamic_cast<BaseJSWidget*>(pWidget))
42 pJSWidget->sendFullUpdate();
45 void SendAction(const OUString& nWindowId, const OUString& rWidget,
46 std::unique_ptr<ActionDataMap> pData)
48 weld::Widget* pWidget = JSInstanceBuilder::FindWeldWidgetsMap(nWindowId, rWidget);
49 if (auto pJSWidget = dynamic_cast<BaseJSWidget*>(pWidget))
50 pJSWidget->sendAction(std::move(pData));
53 bool ExecuteAction(const OUString& nWindowId, const OUString& rWidget, StringMap& rData)
55 weld::Widget* pWidget = JSInstanceBuilder::FindWeldWidgetsMap(nWindowId, rWidget);
57 OUString sControlType = rData["type"];
58 OUString sAction = rData["cmd"];
60 if (sControlType == "responsebutton")
62 auto pButton = dynamic_cast<weld::Button*>(pWidget);
63 if (pWidget == nullptr || (pButton && !pButton->is_custom_handler_set()))
65 // welded wrapper not found - use response code instead
66 pWidget = JSInstanceBuilder::FindWeldWidgetsMap(nWindowId, "__DIALOG__");
67 sControlType = "dialog";
68 sAction = "response";
70 else
72 // welded wrapper for button found - use it
73 sControlType = "pushbutton";
77 if (pWidget != nullptr)
79 if (sAction == "grab_focus")
81 pWidget->grab_focus();
82 return true;
85 if (sControlType == "tabcontrol")
87 auto pNotebook = dynamic_cast<weld::Notebook*>(pWidget);
88 if (pNotebook)
90 if (sAction == "selecttab")
92 sal_Int32 page = o3tl::toInt32(rData["data"]);
94 OUString aCurrentPage = pNotebook->get_current_page_ident();
95 LOKTrigger::leave_page(*pNotebook, aCurrentPage);
96 pNotebook->set_current_page(page);
97 LOKTrigger::enter_page(*pNotebook, pNotebook->get_page_ident(page));
99 return true;
103 else if (sControlType == "combobox")
105 auto pCombobox = dynamic_cast<weld::ComboBox*>(pWidget);
106 if (pCombobox)
108 if (sAction == "selected")
110 OUString sSelectedData = rData["data"];
111 int separatorPos = sSelectedData.indexOf(';');
112 if (separatorPos > 0)
114 std::u16string_view entryPos = sSelectedData.subView(0, separatorPos);
115 sal_Int32 pos = o3tl::toInt32(entryPos);
116 pCombobox->set_active(pos);
117 LOKTrigger::trigger_changed(*pCombobox);
118 return true;
121 else if (sAction == "change")
123 // it might be other class than JSComboBox
124 auto pJSCombobox = dynamic_cast<JSComboBox*>(pWidget);
125 if (pJSCombobox)
126 pJSCombobox->set_entry_text_without_notify(rData["data"]);
127 else
128 pCombobox->set_entry_text(rData["data"]);
129 LOKTrigger::trigger_changed(*pCombobox);
130 return true;
134 else if (sControlType == "pushbutton")
136 auto pButton = dynamic_cast<weld::Button*>(pWidget);
137 if (pButton)
139 if (sAction == "click")
141 pButton->clicked();
142 return true;
144 else if (sAction == "toggle")
146 LOKTrigger::trigger_toggled(dynamic_cast<weld::Toggleable&>(*pWidget));
147 return true;
151 else if (sControlType == "menubutton")
153 auto pButton = dynamic_cast<weld::MenuButton*>(pWidget);
154 if (pButton)
156 if (sAction == "toggle")
158 if (pButton->get_active())
159 pButton->set_active(false);
160 else
161 pButton->set_active(true);
163 BaseJSWidget* pMenuButton = dynamic_cast<BaseJSWidget*>(pButton);
164 if (pMenuButton)
165 pMenuButton->sendUpdate(true);
167 return true;
169 else if (sAction == "select")
171 LOKTrigger::trigger_selected(*pButton, rData["data"]);
172 return true;
176 else if (sControlType == "checkbox")
178 auto pCheckButton = dynamic_cast<weld::CheckButton*>(pWidget);
179 if (pCheckButton)
181 if (sAction == "change")
183 bool bChecked = rData["data"] == "true";
184 pCheckButton->set_state(bChecked ? TRISTATE_TRUE : TRISTATE_FALSE);
185 LOKTrigger::trigger_toggled(*static_cast<weld::Toggleable*>(pCheckButton));
186 return true;
190 else if (sControlType == "drawingarea")
192 auto pArea = dynamic_cast<weld::DrawingArea*>(pWidget);
193 if (pArea)
195 if (sAction == "click" || sAction == "dblclick" || sAction == "mousemove"
196 || sAction == "mousedown" || sAction == "mouseup")
198 OUString sClickData = rData["data"];
199 int nSeparatorPos = sClickData.indexOf(';');
200 if (nSeparatorPos > 0)
202 // x;y
203 std::u16string_view nClickPosX = sClickData.subView(0, nSeparatorPos);
204 std::u16string_view nClickPosY = sClickData.subView(nSeparatorPos + 1);
206 if (nClickPosX.empty() || nClickPosY.empty())
207 return true;
209 double fPosX = o3tl::toDouble(nClickPosX);
210 double fPosY = o3tl::toDouble(nClickPosY);
211 OutputDevice& rRefDevice = pArea->get_ref_device();
212 // We send OutPutSize for the drawing area bitmap
213 // get_size_request is not necessarily updated
214 // therefore it may be incorrect.
215 Size size = rRefDevice.GetOutputSizePixel();
216 fPosX = fPosX * size.Width();
217 fPosY = fPosY * size.Height();
219 if (sAction == "click")
220 LOKTrigger::trigger_click(*pArea, Point(fPosX, fPosY));
221 else if (sAction == "dblclick")
222 LOKTrigger::trigger_dblclick(*pArea, Point(fPosX, fPosY));
223 else if (sAction == "mouseup")
224 LOKTrigger::trigger_mouse_up(*pArea, Point(fPosX, fPosY));
225 else if (sAction == "mousedown")
226 LOKTrigger::trigger_mouse_down(*pArea, Point(fPosX, fPosY));
227 else if (sAction == "mousemove")
228 LOKTrigger::trigger_mouse_move(*pArea, Point(fPosX, fPosY));
231 return true;
233 else if (sAction == "keypress")
235 sal_uInt32 nKeyNo = rData["data"].toUInt32();
236 LOKTrigger::trigger_key_press(*pArea, KeyEvent(nKeyNo, vcl::KeyCode(nKeyNo)));
237 LOKTrigger::trigger_key_release(*pArea, KeyEvent(nKeyNo, vcl::KeyCode(nKeyNo)));
238 return true;
240 else if (sAction == "textselection")
242 OUString sTextData = rData["data"];
243 int nSeparatorPos = sTextData.indexOf(';');
244 if (nSeparatorPos <= 0)
245 return true;
247 int nSeparator2Pos = sTextData.indexOf(';', nSeparatorPos + 1);
248 int nSeparator3Pos = 0;
250 if (nSeparator2Pos > 0)
252 // start;end;startPara;endPara
253 nSeparator3Pos = sTextData.indexOf(';', nSeparator2Pos + 1);
254 if (nSeparator3Pos <= 0)
255 return true;
257 else
259 // start;end
260 nSeparator2Pos = 0;
261 nSeparator3Pos = 0;
264 std::u16string_view aStartPos = sTextData.subView(0, nSeparatorPos);
265 std::u16string_view aEndPos
266 = sTextData.subView(nSeparatorPos + 1, nSeparator2Pos - nSeparatorPos + 1);
268 if (aStartPos.empty() || aEndPos.empty())
269 return true;
271 sal_Int32 nStart = o3tl::toInt32(aStartPos);
272 sal_Int32 nEnd = o3tl::toInt32(aEndPos);
273 sal_Int32 nStartPara = 0;
274 sal_Int32 nEndPara = 0;
276 // multiline case
277 if (nSeparator2Pos && nSeparator3Pos)
279 std::u16string_view aStartPara = sTextData.subView(
280 nSeparator2Pos + 1, nSeparator3Pos - nSeparator2Pos + 1);
281 std::u16string_view aEndPara = sTextData.subView(nSeparator3Pos + 1);
283 if (aStartPara.empty() || aEndPara.empty())
284 return true;
286 nStartPara = o3tl::toInt32(aStartPara);
287 nEndPara = o3tl::toInt32(aEndPara);
290 // pass information about paragraph number in the additional data
291 // handled in sc/source/ui/app/inputwin.cxx
292 Point* pParaPoint = new Point(nStartPara, nEndPara);
293 const void* pCmdData = pParaPoint;
295 Point aPos(nStart, nEnd);
296 CommandEvent aCEvt(aPos, CommandEventId::CursorPos, false, pCmdData);
297 LOKTrigger::command(*pArea, aCEvt);
299 return true;
303 else if (sControlType == "spinfield")
305 auto pSpinField = dynamic_cast<weld::SpinButton*>(pWidget);
306 if (pSpinField)
308 if (sAction == "change" || sAction == "value")
310 if (rData["data"] == "undefined")
311 return true;
313 // The Document will not scroll if that is in focus
314 // maybe we could send a message with: sAction == "grab_focus"
315 pWidget->grab_focus();
317 double nValue = o3tl::toDouble(rData["data"]);
318 pSpinField->set_value(nValue
319 * weld::SpinButton::Power10(pSpinField->get_digits()));
320 LOKTrigger::trigger_value_changed(*pSpinField);
321 return true;
323 if (sAction == "plus")
325 pSpinField->set_value(pSpinField->get_value() + 1);
326 LOKTrigger::trigger_value_changed(*pSpinField);
327 return true;
329 else if (sAction == "minus")
331 pSpinField->set_value(pSpinField->get_value() - 1);
332 LOKTrigger::trigger_value_changed(*pSpinField);
333 return true;
337 else if (sControlType == "toolbox")
339 auto pToolbar = dynamic_cast<weld::Toolbar*>(pWidget);
340 if (pToolbar)
342 if (sAction == "click")
344 LOKTrigger::trigger_clicked(*pToolbar, rData["data"]);
345 return true;
347 else if (sAction == "togglemenu")
349 const OUString& sId = rData["data"];
350 bool bIsActive = pToolbar->get_menu_item_active(sId);
351 pToolbar->set_menu_item_active(sId, !bIsActive);
352 return true;
354 else if (sAction == "closemenu")
356 pToolbar->set_menu_item_active(rData["data"], false);
357 return true;
359 else if (sAction == "openmenu")
361 pToolbar->set_menu_item_active(rData["data"], true);
362 return true;
366 else if (sControlType == "edit")
368 auto pEdit = dynamic_cast<JSEntry*>(pWidget);
369 if (pEdit)
371 if (sAction == "change")
373 pEdit->set_text_without_notify(rData["data"]);
374 LOKTrigger::trigger_changed(*pEdit);
375 return true;
379 auto pTextView = dynamic_cast<JSTextView*>(pWidget);
380 if (pTextView)
382 if (sAction == "change")
384 int rStartPos, rEndPos;
385 pTextView->get_selection_bounds(rStartPos, rEndPos);
386 pTextView->set_text_without_notify(rData["data"]);
387 pTextView->select_region(rStartPos, rEndPos);
388 LOKTrigger::trigger_changed(*pTextView);
389 return true;
391 else if (sAction == "textselection")
393 // start;end
394 OUString sTextData = rData["data"];
395 int nSeparatorPos = sTextData.indexOf(';');
396 if (nSeparatorPos <= 0)
397 return true;
399 std::u16string_view aStartPos = sTextData.subView(0, nSeparatorPos);
400 std::u16string_view aEndPos = sTextData.subView(nSeparatorPos + 1);
402 if (aStartPos.empty() || aEndPos.empty())
403 return true;
405 sal_Int32 nStart = o3tl::toInt32(aStartPos);
406 sal_Int32 nEnd = o3tl::toInt32(aEndPos);
408 pTextView->select_region(nStart, nEnd);
409 LOKTrigger::trigger_changed(*pTextView);
411 return true;
415 else if (sControlType == "treeview")
417 auto pTreeView = dynamic_cast<JSTreeView*>(pWidget);
418 if (pTreeView)
420 if (sAction == "change")
422 OUString sDataJSON = rtl::Uri::decode(
423 rData["data"], rtl_UriDecodeMechanism::rtl_UriDecodeWithCharset,
424 RTL_TEXTENCODING_UTF8);
425 StringMap aMap(jsonToStringMap(
426 OUStringToOString(sDataJSON, RTL_TEXTENCODING_ASCII_US).getStr()));
428 sal_Int32 nRow = o3tl::toInt32(aMap["row"]);
429 bool bValue = aMap["value"] == "true";
431 pTreeView->set_toggle(nRow, bValue ? TRISTATE_TRUE : TRISTATE_FALSE);
433 return true;
435 else if (sAction == "select")
437 sal_Int32 nAbsPos = o3tl::toInt32(rData["data"]);
439 pTreeView->unselect_all();
441 std::unique_ptr<weld::TreeIter> itEntry(pTreeView->make_iterator());
442 pTreeView->get_iter_abs_pos(*itEntry, nAbsPos);
443 pTreeView->select(*itEntry);
444 pTreeView->set_cursor_without_notify(*itEntry);
445 pTreeView->grab_focus();
446 LOKTrigger::trigger_changed(*pTreeView);
447 return true;
449 else if (sAction == "activate")
451 sal_Int32 nRow = o3tl::toInt32(rData["data"]);
453 pTreeView->unselect_all();
454 std::unique_ptr<weld::TreeIter> itEntry(pTreeView->make_iterator());
455 pTreeView->get_iter_abs_pos(*itEntry, nRow);
456 pTreeView->select(nRow);
457 pTreeView->set_cursor_without_notify(*itEntry);
458 pTreeView->grab_focus();
459 LOKTrigger::trigger_changed(*pTreeView);
460 LOKTrigger::trigger_row_activated(*pTreeView);
461 return true;
463 else if (sAction == "expand")
465 sal_Int32 nAbsPos = o3tl::toInt32(rData["data"]);
466 std::unique_ptr<weld::TreeIter> itEntry(pTreeView->make_iterator());
467 pTreeView->get_iter_abs_pos(*itEntry, nAbsPos);
468 pTreeView->set_cursor_without_notify(*itEntry);
469 pTreeView->grab_focus();
470 pTreeView->expand_row(*itEntry);
471 return true;
473 else if (sAction == "dragstart")
475 sal_Int32 nRow = o3tl::toInt32(rData["data"]);
477 pTreeView->select(nRow);
478 pTreeView->drag_start();
480 return true;
482 else if (sAction == "dragend")
484 pTreeView->drag_end();
485 return true;
489 else if (sControlType == "iconview")
491 auto pIconView = dynamic_cast<weld::IconView*>(pWidget);
492 if (pIconView)
494 if (sAction == "select")
496 sal_Int32 nPos = o3tl::toInt32(rData["data"]);
498 pIconView->select(nPos);
499 LOKTrigger::trigger_changed(*pIconView);
501 return true;
503 else if (sAction == "activate")
505 sal_Int32 nPos = o3tl::toInt32(rData["data"]);
507 pIconView->select(nPos);
508 LOKTrigger::trigger_changed(*pIconView);
509 LOKTrigger::trigger_item_activated(*pIconView);
511 return true;
515 else if (sControlType == "expander")
517 auto pExpander = dynamic_cast<weld::Expander*>(pWidget);
518 if (pExpander)
520 if (sAction == "toggle")
522 pExpander->set_expanded(!pExpander->get_expanded());
523 return true;
527 else if (sControlType == "dialog")
529 auto pDialog = dynamic_cast<weld::Dialog*>(pWidget);
530 if (pDialog)
532 if (sAction == "close")
534 pDialog->response(RET_CANCEL);
535 return true;
537 else if (sAction == "response")
539 sal_Int32 nResponse = o3tl::toInt32(rData["data"]);
540 pDialog->response(nResponse);
541 return true;
545 else if (sControlType == "popover")
547 auto pPopover = dynamic_cast<weld::Popover*>(pWidget);
548 if (pPopover)
550 if (sAction == "close")
552 LOKTrigger::trigger_closed(*pPopover);
553 return true;
557 else if (sControlType == "radiobutton")
559 auto pRadioButton = dynamic_cast<weld::RadioButton*>(pWidget);
560 if (pRadioButton)
562 if (sAction == "change")
564 bool bChecked = rData["data"] == "true";
565 pRadioButton->set_state(bChecked ? TRISTATE_TRUE : TRISTATE_FALSE);
566 LOKTrigger::trigger_toggled(*static_cast<weld::Toggleable*>(pRadioButton));
567 return true;
571 else if (sControlType == "scrolledwindow")
573 auto pScrolledWindow = dynamic_cast<JSScrolledWindow*>(pWidget);
574 if (pScrolledWindow)
576 if (sAction == "scrollv")
578 sal_Int32 nValue = o3tl::toInt32(rData["data"]);
579 pScrolledWindow->vadjustment_set_value_no_notification(nValue);
580 LOKTrigger::trigger_scrollv(*pScrolledWindow);
581 return true;
583 else if (sAction == "scrollh")
585 sal_Int32 nValue = o3tl::toInt32(rData["data"]);
586 pScrolledWindow->hadjustment_set_value_no_notification(nValue);
587 LOKTrigger::trigger_scrollh(*pScrolledWindow);
588 return true;
594 return false;
598 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */