1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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/.
10 #include <jsdialog/jsdialogbuilder.hxx>
11 #include <sal/log.hxx>
12 #include <comphelper/lok.hxx>
13 #include <vcl/tabpage.hxx>
14 #include <vcl/toolkit/button.hxx>
15 #include <vcl/toolkit/dialog.hxx>
16 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
17 #include <vcl/toolkit/combobox.hxx>
18 #include <messagedialog.hxx>
19 #include <tools/json_writer.hxx>
20 #include <o3tl/deleter.hxx>
22 #include <vcl/toolbox.hxx>
23 #include <vcl/toolkit/vclmedit.hxx>
24 #include <boost/property_tree/json_parser.hpp>
26 JSDialogNotifyIdle::JSDialogNotifyIdle(VclPtr
<vcl::Window
> aWindow
)
27 : Idle("JSDialog notify")
29 , m_LastNotificationMessage()
32 SetPriority(TaskPriority::POST_PAINT
);
35 void JSDialogNotifyIdle::ForceUpdate() { m_bForce
= true; }
37 void JSDialogNotifyIdle::Invoke()
44 const vcl::ILibreOfficeKitNotifier
* pNotifier
= m_aWindow
->GetLOKNotifier();
47 tools::JsonWriter aJsonWriter
;
48 m_aWindow
->DumpAsPropertyTree(aJsonWriter
);
49 aJsonWriter
.put("id", m_aWindow
->GetLOKWindowId());
50 if (m_bForce
|| !aJsonWriter
.isDataEquals(m_LastNotificationMessage
))
53 m_LastNotificationMessage
= aJsonWriter
.extractAsStdString();
54 pNotifier
->libreOfficeKitViewCallback(LOK_CALLBACK_JSDIALOG
,
55 m_LastNotificationMessage
.c_str());
59 catch (boost::property_tree::json_parser::json_parser_error
& rError
)
61 SAL_WARN("vcl", rError
.message());
65 void JSDialogSender::notifyDialogState(bool bForce
)
68 mpIdleNotify
->ForceUpdate();
69 mpIdleNotify
->Start();
74 vcl::Window
* extract_sal_widget(weld::Widget
* pParent
)
76 SalInstanceWidget
* pInstanceWidget
= dynamic_cast<SalInstanceWidget
*>(pParent
);
77 return pInstanceWidget
? pInstanceWidget
->getWidget() : nullptr;
81 JSInstanceBuilder::JSInstanceBuilder(weld::Widget
* pParent
, const OUString
& rUIRoot
,
82 const OUString
& rUIFile
)
83 : SalInstanceBuilder(extract_sal_widget(pParent
), rUIRoot
, rUIFile
)
85 , m_aParentDialog(nullptr)
86 , m_bHasTopLevelDialog(false)
87 , m_bIsNotebookbar(false)
89 vcl::Window
* pRoot
= m_xBuilder
->get_widget_root();
90 if (pRoot
&& pRoot
->GetParent())
92 m_aParentDialog
= pRoot
->GetParent()->GetParentWithLOKNotifier();
94 m_nWindowId
= m_aParentDialog
->GetLOKWindowId();
95 InsertWindowToMap(m_nWindowId
);
99 JSInstanceBuilder::JSInstanceBuilder(vcl::Window
* pParent
, const OUString
& rUIRoot
,
100 const OUString
& rUIFile
,
101 const css::uno::Reference
<css::frame::XFrame
>& rFrame
,
102 sal_uInt64 nWindowId
)
103 : SalInstanceBuilder(pParent
, rUIRoot
, rUIFile
, rFrame
)
105 , m_aParentDialog(nullptr)
106 , m_bHasTopLevelDialog(false)
107 , m_bIsNotebookbar(false)
109 vcl::Window
* pRoot
= m_xBuilder
->get_widget_root();
110 if (pRoot
&& pRoot
->GetParent())
112 m_aParentDialog
= pRoot
->GetParent()->GetParentWithLOKNotifier();
114 m_nWindowId
= m_aParentDialog
->GetLOKWindowId();
115 if (!m_nWindowId
&& nWindowId
)
117 m_nWindowId
= nWindowId
;
118 m_bIsNotebookbar
= true;
120 InsertWindowToMap(m_nWindowId
);
124 JSInstanceBuilder::~JSInstanceBuilder()
126 if (m_nWindowId
&& (m_bHasTopLevelDialog
|| m_bIsNotebookbar
))
127 GetLOKWeldWidgetsMap().erase(m_nWindowId
);
130 std::map
<sal_uInt64
, WidgetMap
>& JSInstanceBuilder::GetLOKWeldWidgetsMap()
132 // Map to remember the LOKWindowId <-> weld widgets binding.
133 static std::map
<sal_uInt64
, WidgetMap
> s_aLOKWeldBuildersMap
;
135 return s_aLOKWeldBuildersMap
;
138 weld::Widget
* JSInstanceBuilder::FindWeldWidgetsMap(sal_uInt64 nWindowId
, const OString
& rWidget
)
140 const auto it
= GetLOKWeldWidgetsMap().find(nWindowId
);
142 if (it
!= GetLOKWeldWidgetsMap().end())
144 auto widgetIt
= it
->second
.find(rWidget
);
145 if (widgetIt
!= it
->second
.end())
146 return widgetIt
->second
;
152 void JSInstanceBuilder::InsertWindowToMap(sal_uInt64 nWindowId
)
155 auto it
= GetLOKWeldWidgetsMap().find(nWindowId
);
156 if (it
== GetLOKWeldWidgetsMap().end())
157 GetLOKWeldWidgetsMap().insert(std::map
<sal_uInt64
, WidgetMap
>::value_type(nWindowId
, map
));
160 void JSInstanceBuilder::RememberWidget(const OString
& id
, weld::Widget
* pWidget
)
162 auto it
= GetLOKWeldWidgetsMap().find(m_nWindowId
);
163 if (it
!= GetLOKWeldWidgetsMap().end())
165 it
->second
.erase(id
);
166 it
->second
.insert(WidgetMap::value_type(id
, pWidget
));
170 std::unique_ptr
<weld::Dialog
> JSInstanceBuilder::weld_dialog(const OString
& id
)
172 ::Dialog
* pDialog
= m_xBuilder
->get
<::Dialog
>(id
);
173 m_nWindowId
= pDialog
->GetLOKWindowId();
175 InsertWindowToMap(m_nWindowId
);
177 std::unique_ptr
<weld::Dialog
> pRet(
178 pDialog
? new JSDialog(m_aOwnedToplevel
, pDialog
, this, false) : nullptr);
181 assert(!m_aOwnedToplevel
&& "only one toplevel per .ui allowed");
182 m_aOwnedToplevel
.set(pDialog
);
183 m_xBuilder
->drop_ownership(pDialog
);
184 m_bHasTopLevelDialog
= true;
187 const vcl::ILibreOfficeKitNotifier
* pNotifier
= pDialog
->GetLOKNotifier();
190 tools::JsonWriter aJsonWriter
;
191 m_aOwnedToplevel
->DumpAsPropertyTree(aJsonWriter
);
192 aJsonWriter
.put("id", m_aOwnedToplevel
->GetLOKWindowId());
193 pNotifier
->libreOfficeKitViewCallback(LOK_CALLBACK_JSDIALOG
, aJsonWriter
.extractData());
199 std::unique_ptr
<weld::Label
> JSInstanceBuilder::weld_label(const OString
& id
)
201 ::FixedText
* pLabel
= m_xBuilder
->get
<FixedText
>(id
);
202 auto pWeldWidget
= std::make_unique
<JSLabel
>(
203 m_bHasTopLevelDialog
? m_aOwnedToplevel
: m_aParentDialog
, pLabel
, this, false);
206 RememberWidget(id
, pWeldWidget
.get());
211 std::unique_ptr
<weld::Button
> JSInstanceBuilder::weld_button(const OString
& id
)
213 ::Button
* pButton
= m_xBuilder
->get
<::Button
>(id
);
214 auto pWeldWidget
= pButton
? std::make_unique
<JSButton
>(m_bHasTopLevelDialog
? m_aOwnedToplevel
216 pButton
, this, false)
220 RememberWidget(id
, pWeldWidget
.get());
225 std::unique_ptr
<weld::Entry
> JSInstanceBuilder::weld_entry(const OString
& id
)
227 Edit
* pEntry
= m_xBuilder
->get
<Edit
>(id
);
228 auto pWeldWidget
= pEntry
? std::make_unique
<JSEntry
>(m_bHasTopLevelDialog
? m_aOwnedToplevel
234 RememberWidget(id
, pWeldWidget
.get());
239 std::unique_ptr
<weld::ComboBox
> JSInstanceBuilder::weld_combo_box(const OString
& id
)
241 vcl::Window
* pWidget
= m_xBuilder
->get
<vcl::Window
>(id
);
242 ::ComboBox
* pComboBox
= dynamic_cast<::ComboBox
*>(pWidget
);
243 std::unique_ptr
<weld::ComboBox
> pWeldWidget
;
247 pWeldWidget
= std::make_unique
<JSComboBox
>(
248 m_bHasTopLevelDialog
? m_aOwnedToplevel
: m_aParentDialog
, pComboBox
, this, false);
252 ListBox
* pListBox
= dynamic_cast<ListBox
*>(pWidget
);
253 pWeldWidget
= pListBox
? std::make_unique
<JSListBox
>(m_bHasTopLevelDialog
? m_aOwnedToplevel
255 pListBox
, this, false)
260 RememberWidget(id
, pWeldWidget
.get());
265 std::unique_ptr
<weld::Notebook
> JSInstanceBuilder::weld_notebook(const OString
& id
)
267 TabControl
* pNotebook
= m_xBuilder
->get
<TabControl
>(id
);
268 auto pWeldWidget
= pNotebook
? std::make_unique
<JSNotebook
>(
269 m_bHasTopLevelDialog
? m_aOwnedToplevel
: m_aParentDialog
,
270 pNotebook
, this, false)
274 RememberWidget(id
, pWeldWidget
.get());
279 std::unique_ptr
<weld::SpinButton
> JSInstanceBuilder::weld_spin_button(const OString
& id
)
281 FormattedField
* pSpinButton
= m_xBuilder
->get
<FormattedField
>(id
);
282 auto pWeldWidget
= pSpinButton
? std::make_unique
<JSSpinButton
>(
283 m_bHasTopLevelDialog
? m_aOwnedToplevel
: m_aParentDialog
,
284 pSpinButton
, this, false)
288 RememberWidget(id
, pWeldWidget
.get());
293 std::unique_ptr
<weld::CheckButton
> JSInstanceBuilder::weld_check_button(const OString
& id
)
295 CheckBox
* pCheckButton
= m_xBuilder
->get
<CheckBox
>(id
);
296 auto pWeldWidget
= pCheckButton
? std::make_unique
<JSCheckButton
>(
297 m_bHasTopLevelDialog
? m_aOwnedToplevel
: m_aParentDialog
,
298 pCheckButton
, this, false)
302 RememberWidget(id
, pWeldWidget
.get());
307 std::unique_ptr
<weld::DrawingArea
>
308 JSInstanceBuilder::weld_drawing_area(const OString
& id
, const a11yref
& rA11yImpl
,
309 FactoryFunction pUITestFactoryFunction
, void* pUserData
)
311 VclDrawingArea
* pArea
= m_xBuilder
->get
<VclDrawingArea
>(id
);
312 auto pWeldWidget
= pArea
? std::make_unique
<JSDrawingArea
>(
313 m_bHasTopLevelDialog
? m_aOwnedToplevel
: m_aParentDialog
, pArea
,
314 this, rA11yImpl
, pUITestFactoryFunction
, pUserData
)
318 RememberWidget(id
, pWeldWidget
.get());
323 std::unique_ptr
<weld::Toolbar
> JSInstanceBuilder::weld_toolbar(const OString
& id
)
325 ToolBox
* pToolBox
= m_xBuilder
->get
<ToolBox
>(id
);
326 auto pWeldWidget
= pToolBox
? std::make_unique
<JSToolbar
>(
327 m_bHasTopLevelDialog
? m_aOwnedToplevel
: m_aParentDialog
,
328 pToolBox
, this, false)
332 RememberWidget(id
, pWeldWidget
.get());
337 std::unique_ptr
<weld::TextView
> JSInstanceBuilder::weld_text_view(const OString
& id
)
339 VclMultiLineEdit
* pTextView
= m_xBuilder
->get
<VclMultiLineEdit
>(id
);
340 auto pWeldWidget
= pTextView
? std::make_unique
<JSTextView
>(
341 m_bHasTopLevelDialog
? m_aOwnedToplevel
: m_aParentDialog
,
342 pTextView
, this, false)
346 RememberWidget(id
, pWeldWidget
.get());
351 weld::MessageDialog
* JSInstanceBuilder::CreateMessageDialog(weld::Widget
* pParent
,
352 VclMessageType eMessageType
,
353 VclButtonsType eButtonType
,
354 const OUString
& rPrimaryMessage
)
356 SalInstanceWidget
* pParentInstance
= dynamic_cast<SalInstanceWidget
*>(pParent
);
357 SystemWindow
* pParentWidget
= pParentInstance
? pParentInstance
->getSystemWindow() : nullptr;
358 VclPtrInstance
<::MessageDialog
> xMessageDialog(pParentWidget
, rPrimaryMessage
, eMessageType
,
361 const vcl::ILibreOfficeKitNotifier
* pNotifier
= xMessageDialog
->GetLOKNotifier();
364 tools::JsonWriter aJsonWriter
;
365 xMessageDialog
->DumpAsPropertyTree(aJsonWriter
);
366 aJsonWriter
.put("id", xMessageDialog
->GetLOKWindowId());
367 std::unique_ptr
<char[], o3tl::free_delete
> message(aJsonWriter
.extractData());
368 pNotifier
->libreOfficeKitViewCallback(LOK_CALLBACK_JSDIALOG
, message
.get());
371 return new JSMessageDialog(xMessageDialog
, nullptr, true);
374 JSDialog::JSDialog(VclPtr
<vcl::Window
> aOwnedToplevel
, ::Dialog
* pDialog
,
375 SalInstanceBuilder
* pBuilder
, bool bTakeOwnership
)
376 : JSWidget
<SalInstanceDialog
, ::Dialog
>(aOwnedToplevel
, pDialog
, pBuilder
, bTakeOwnership
)
380 void JSDialog::collapse(weld::Widget
* pEdit
, weld::Widget
* pButton
)
382 SalInstanceDialog::collapse(pEdit
, pButton
);
386 void JSDialog::undo_collapse()
388 SalInstanceDialog::undo_collapse();
392 JSLabel::JSLabel(VclPtr
<vcl::Window
> aOwnedToplevel
, FixedText
* pLabel
,
393 SalInstanceBuilder
* pBuilder
, bool bTakeOwnership
)
394 : JSWidget
<SalInstanceLabel
, FixedText
>(aOwnedToplevel
, pLabel
, pBuilder
, bTakeOwnership
)
398 void JSLabel::set_label(const OUString
& rText
)
400 SalInstanceLabel::set_label(rText
);
404 JSButton::JSButton(VclPtr
<vcl::Window
> aOwnedToplevel
, ::Button
* pButton
,
405 SalInstanceBuilder
* pBuilder
, bool bTakeOwnership
)
406 : JSWidget
<SalInstanceButton
, ::Button
>(aOwnedToplevel
, pButton
, pBuilder
, bTakeOwnership
)
410 JSEntry::JSEntry(VclPtr
<vcl::Window
> aOwnedToplevel
, ::Edit
* pEntry
, SalInstanceBuilder
* pBuilder
,
412 : JSWidget
<SalInstanceEntry
, ::Edit
>(aOwnedToplevel
, pEntry
, pBuilder
, bTakeOwnership
)
416 void JSEntry::set_text(const OUString
& rText
)
418 SalInstanceEntry::set_text(rText
);
422 JSListBox::JSListBox(VclPtr
<vcl::Window
> aOwnedToplevel
, ::ListBox
* pListBox
,
423 SalInstanceBuilder
* pBuilder
, bool bTakeOwnership
)
424 : JSWidget
<SalInstanceComboBoxWithoutEdit
, ::ListBox
>(aOwnedToplevel
, pListBox
, pBuilder
,
429 void JSListBox::insert(int pos
, const OUString
& rStr
, const OUString
* pId
,
430 const OUString
* pIconName
, VirtualDevice
* pImageSurface
)
432 SalInstanceComboBoxWithoutEdit::insert(pos
, rStr
, pId
, pIconName
, pImageSurface
);
436 void JSListBox::remove(int pos
)
438 SalInstanceComboBoxWithoutEdit::remove(pos
);
442 void JSListBox::set_active(int pos
)
444 SalInstanceComboBoxWithoutEdit::set_active(pos
);
448 JSComboBox::JSComboBox(VclPtr
<vcl::Window
> aOwnedToplevel
, ::ComboBox
* pComboBox
,
449 SalInstanceBuilder
* pBuilder
, bool bTakeOwnership
)
450 : JSWidget
<SalInstanceComboBoxWithEdit
, ::ComboBox
>(aOwnedToplevel
, pComboBox
, pBuilder
,
455 void JSComboBox::insert(int pos
, const OUString
& rStr
, const OUString
* pId
,
456 const OUString
* pIconName
, VirtualDevice
* pImageSurface
)
458 SalInstanceComboBoxWithEdit::insert(pos
, rStr
, pId
, pIconName
, pImageSurface
);
462 void JSComboBox::remove(int pos
)
464 SalInstanceComboBoxWithEdit::remove(pos
);
468 void JSComboBox::set_entry_text(const OUString
& rText
)
470 SalInstanceComboBoxWithEdit::set_entry_text(rText
);
474 void JSComboBox::set_active(int pos
)
476 SalInstanceComboBoxWithEdit::set_active(pos
);
480 JSNotebook::JSNotebook(VclPtr
<vcl::Window
> aOwnedToplevel
, ::TabControl
* pControl
,
481 SalInstanceBuilder
* pBuilder
, bool bTakeOwnership
)
482 : JSWidget
<SalInstanceNotebook
, ::TabControl
>(aOwnedToplevel
, pControl
, pBuilder
,
487 void JSNotebook::set_current_page(int nPage
)
490 int nCurrent
= get_current_page();
491 if (nCurrent
== nPage
)
494 SalInstanceNotebook::set_current_page(nPage
);
495 notifyDialogState(bForce
);
498 void JSNotebook::set_current_page(const OString
& rIdent
)
501 OString sCurrent
= get_current_page_ident();
502 if (sCurrent
== rIdent
)
505 SalInstanceNotebook::set_current_page(rIdent
);
506 notifyDialogState(bForce
);
509 void JSNotebook::remove_page(const OString
& rIdent
)
511 SalInstanceNotebook::remove_page(rIdent
);
515 void JSNotebook::insert_page(const OString
& rIdent
, const OUString
& rLabel
, int nPos
)
517 SalInstanceNotebook::insert_page(rIdent
, rLabel
, nPos
);
521 JSSpinButton::JSSpinButton(VclPtr
<vcl::Window
> aOwnedToplevel
, ::FormattedField
* pSpin
,
522 SalInstanceBuilder
* pBuilder
, bool bTakeOwnership
)
523 : JSWidget
<SalInstanceSpinButton
, ::FormattedField
>(aOwnedToplevel
, pSpin
, pBuilder
,
528 void JSSpinButton::set_value(int value
)
530 SalInstanceSpinButton::set_value(value
);
534 JSMessageDialog::JSMessageDialog(::MessageDialog
* pDialog
, SalInstanceBuilder
* pBuilder
,
536 : SalInstanceMessageDialog(pDialog
, pBuilder
, bTakeOwnership
)
537 , JSDialogSender(m_xMessageDialog
)
541 void JSMessageDialog::set_primary_text(const OUString
& rText
)
543 SalInstanceMessageDialog::set_primary_text(rText
);
547 void JSMessageDialog::set_secondary_text(const OUString
& rText
)
549 SalInstanceMessageDialog::set_secondary_text(rText
);
553 JSCheckButton::JSCheckButton(VclPtr
<vcl::Window
> aOwnedToplevel
, ::CheckBox
* pCheckBox
,
554 SalInstanceBuilder
* pBuilder
, bool bTakeOwnership
)
555 : JSWidget
<SalInstanceCheckButton
, ::CheckBox
>(aOwnedToplevel
, pCheckBox
, pBuilder
,
560 void JSCheckButton::set_active(bool active
)
562 SalInstanceCheckButton::set_active(active
);
566 JSDrawingArea::JSDrawingArea(VclPtr
<vcl::Window
> aOwnedToplevel
, VclDrawingArea
* pDrawingArea
,
567 SalInstanceBuilder
* pBuilder
, const a11yref
& rAlly
,
568 FactoryFunction pUITestFactoryFunction
, void* pUserData
)
569 : SalInstanceDrawingArea(pDrawingArea
, pBuilder
, rAlly
, pUITestFactoryFunction
, pUserData
,
571 , JSDialogSender(aOwnedToplevel
)
575 void JSDrawingArea::queue_draw()
577 SalInstanceDrawingArea::queue_draw();
581 void JSDrawingArea::queue_draw_area(int x
, int y
, int width
, int height
)
583 SalInstanceDrawingArea::queue_draw_area(x
, y
, width
, height
);
587 JSToolbar::JSToolbar(VclPtr
<vcl::Window
> aOwnedToplevel
, ::ToolBox
* pToolbox
,
588 SalInstanceBuilder
* pBuilder
, bool bTakeOwnership
)
589 : JSWidget
<SalInstanceToolbar
, ::ToolBox
>(aOwnedToplevel
, pToolbox
, pBuilder
, bTakeOwnership
)
593 void JSToolbar::signal_clicked(const OString
& rIdent
)
595 SalInstanceToolbar::signal_clicked(rIdent
);
599 JSTextView::JSTextView(VclPtr
<vcl::Window
> aOwnedToplevel
, ::VclMultiLineEdit
* pTextView
,
600 SalInstanceBuilder
* pBuilder
, bool bTakeOwnership
)
601 : JSWidget
<SalInstanceTextView
, ::VclMultiLineEdit
>(aOwnedToplevel
, pTextView
, pBuilder
,
606 void JSTextView::set_text(const OUString
& rText
)
608 SalInstanceTextView::set_text(rText
);
612 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */