1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <sal/config.h>
13 #include <string_view>
17 #include <sfx2/lokcomponenthelpers.hxx>
18 #include <sfx2/lokhelper.hxx>
20 #include <com/sun/star/frame/Desktop.hpp>
21 #include <com/sun/star/ui/ContextChangeEventObject.hpp>
22 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
23 #include <com/sun/star/xml/crypto/XCertificateCreator.hpp>
25 #include <comphelper/processfactory.hxx>
26 #include <o3tl/string_view.hxx>
27 #include <rtl/strbuf.hxx>
28 #include <vcl/lok.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/commandevent.hxx>
31 #include <vcl/window.hxx>
32 #include <sal/log.hxx>
33 #include <sfx2/app.hxx>
34 #include <sfx2/msg.hxx>
35 #include <sfx2/viewsh.hxx>
36 #include <sfx2/request.hxx>
37 #include <sfx2/sfxsids.hrc>
38 #include <sfx2/viewfrm.hxx>
39 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
40 #include <comphelper/lok.hxx>
41 #include <sfx2/msgpool.hxx>
42 #include <comphelper/scopeguard.hxx>
43 #include <comphelper/base64.hxx>
44 #include <tools/json_writer.hxx>
45 #include <svl/cryptosign.hxx>
46 #include <tools/urlobj.hxx>
48 #include <boost/property_tree/json_parser.hpp>
50 using namespace com::sun::star
;
53 bool g_bSettingView(false);
55 /// Used to disable callbacks.
56 /// Needed to avoid recursion when switching views,
57 /// which can cause clients to invoke LOKit API and
58 /// implicitly set the view, which might cause an
59 /// infinite recursion if not detected and prevented.
60 class DisableCallbacks
65 assert(m_nDisabled
>= 0 && "Expected non-negative DisabledCallbacks state when disabling.");
71 assert(m_nDisabled
> 0 && "Expected positive DisabledCallbacks state when re-enabling.");
75 static inline bool disabled()
77 return !comphelper::LibreOfficeKit::isActive() || m_nDisabled
!= 0;
81 static int m_nDisabled
;
84 int DisableCallbacks::m_nDisabled
= 0;
89 LanguageTag
g_defaultLanguageTag(u
"en-US"_ustr
, true);
90 LanguageTag
g_loadLanguageTag(u
"en-US"_ustr
, true); //< The language used to load.
91 LOKDeviceFormFactor g_deviceFormFactor
= LOKDeviceFormFactor::UNKNOWN
;
92 bool g_isDefaultTimezoneSet
= false;
93 OUString g_DefaultTimezone
;
94 const std::size_t g_logNotifierCacheMaxSize
= 50;
95 ::std::list
<::std::string
> g_logNotifierCache
;
98 int SfxLokHelper::createView(SfxViewFrame
& rViewFrame
, ViewShellDocId docId
)
100 assert(docId
>= ViewShellDocId(0) && "Cannot createView for invalid (negative) DocId.");
102 SfxViewShell::SetCurrentDocId(docId
);
103 SfxRequest
aRequest(rViewFrame
, SID_NEWWINDOW
);
104 rViewFrame
.ExecView_Impl(aRequest
);
105 SfxViewShell
* pViewShell
= SfxViewShell::Current();
106 if (pViewShell
== nullptr)
109 assert(pViewShell
->GetDocId() == docId
&& "DocId must be already set!");
110 return static_cast<sal_Int32
>(pViewShell
->GetViewShellId());
113 int SfxLokHelper::createView()
115 // Assumes a single document, or at least that the
116 // current view belongs to the document on which the
117 // view will be created.
118 SfxViewShell
* pViewShell
= SfxViewShell::Current();
119 if (pViewShell
== nullptr)
122 return createView(pViewShell
->GetViewFrame(), pViewShell
->GetDocId());
125 std::unordered_map
<OUString
, css::uno::Reference
<css::ui::XAcceleratorConfiguration
>>& SfxLokHelper::getAcceleratorConfs()
127 return SfxApplication::GetOrCreate()->GetAcceleratorConfs_Impl();
130 int SfxLokHelper::createView(int nDocId
)
132 const SfxApplication
* pApp
= SfxApplication::Get();
136 // Find a shell with the given DocId.
137 const ViewShellDocId
docId(nDocId
);
138 for (const SfxViewShell
* pViewShell
: pApp
->GetViewShells_Impl())
140 if (pViewShell
->GetDocId() == docId
)
141 return createView(pViewShell
->GetViewFrame(), docId
);
144 // No frame with nDocId found.
148 void SfxLokHelper::setEditMode(int nMode
, vcl::ITiledRenderable
* pDoc
)
151 pDoc
->setEditMode(nMode
);
154 void SfxLokHelper::destroyView(int nId
)
156 const SfxApplication
* pApp
= SfxApplication::Get();
160 const ViewShellId
nViewShellId(nId
);
161 std::vector
<SfxViewShell
*>& rViewArr
= pApp
->GetViewShells_Impl();
163 for (SfxViewShell
* pViewShell
: rViewArr
)
165 if (pViewShell
->GetViewShellId() == nViewShellId
)
167 pViewShell
->SetLOKAccessibilityState(false);
168 SfxViewFrame
& rViewFrame
= pViewShell
->GetViewFrame();
169 SfxRequest
aRequest(rViewFrame
, SID_CLOSEWIN
);
170 rViewFrame
.Exec_Impl(aRequest
);
176 bool SfxLokHelper::isSettingView()
178 return g_bSettingView
;
181 void SfxLokHelper::setView(int nId
)
183 g_bSettingView
= true;
184 comphelper::ScopeGuard
g([] { g_bSettingView
= false; });
186 SfxApplication
* pApp
= SfxApplication::Get();
190 const ViewShellId
nViewShellId(nId
);
191 std::vector
<SfxViewShell
*>& rViewArr
= pApp
->GetViewShells_Impl();
193 const auto itViewShell
= std::find_if(rViewArr
.begin(), rViewArr
.end(), [nViewShellId
](SfxViewShell
* pViewShell
){ return pViewShell
->GetViewShellId() == nViewShellId
; });
194 if (itViewShell
== rViewArr
.end())
197 const SfxViewShell
* pViewShell
= *itViewShell
;
201 bool bIsCurrShell
= (pViewShell
== SfxViewShell::Current());
202 if (bIsCurrShell
&& comphelper::LibreOfficeKit::getLanguageTag().getBcp47() == pViewShell
->GetLOKLanguageTag().getBcp47())
207 // If we wanted to set the SfxViewShell that is actually set, we could skip it.
208 // But it looks like that the language can go wrong, so we have to fix that.
209 // This can happen, when someone sets the language or SfxViewShell::Current() separately.
210 SAL_WARN("lok", "LANGUAGE mismatch at setView! ... old (wrong) lang:"
211 << comphelper::LibreOfficeKit::getLanguageTag().getBcp47()
212 << " new lang:" << pViewShell
->GetLOKLanguageTag().getBcp47());
215 // update the current LOK language and locale for the dialog tunneling
216 comphelper::LibreOfficeKit::setLanguageTag(pViewShell
->GetLOKLanguageTag());
217 comphelper::LibreOfficeKit::setLocale(pViewShell
->GetLOKLocale());
222 SfxViewFrame
& rViewFrame
= pViewShell
->GetViewFrame();
223 rViewFrame
.MakeActive_Impl(false);
225 // Make comphelper::dispatchCommand() find the correct frame.
226 uno::Reference
<frame::XFrame
> xFrame
= rViewFrame
.GetFrame().GetFrameInterface();
227 uno::Reference
<frame::XDesktop2
> xDesktop
= frame::Desktop::create(comphelper::getProcessComponentContext());
228 xDesktop
->setActiveFrame(xFrame
);
231 SfxViewShell
* SfxLokHelper::getViewOfId(int nId
)
233 SfxApplication
* pApp
= SfxApplication::Get();
237 const ViewShellId
nViewShellId(nId
);
238 std::vector
<SfxViewShell
*>& rViewArr
= pApp
->GetViewShells_Impl();
239 for (SfxViewShell
* pViewShell
: rViewArr
)
241 if (pViewShell
->GetViewShellId() == nViewShellId
)
248 int SfxLokHelper::getView(const SfxViewShell
* pViewShell
)
251 pViewShell
= SfxViewShell::Current();
252 // Still no valid view shell? Then no idea.
256 return static_cast<sal_Int32
>(pViewShell
->GetViewShellId());
259 std::size_t SfxLokHelper::getViewsCount(int nDocId
)
261 assert(nDocId
!= -1 && "Cannot getViewsCount for invalid DocId -1");
263 SfxApplication
* pApp
= SfxApplication::Get();
267 const ViewShellDocId
nCurrentDocId(nDocId
);
269 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
272 if (pViewShell
->GetDocId() == nCurrentDocId
)
274 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
280 bool SfxLokHelper::getViewIds(int nDocId
, int* pArray
, size_t nSize
)
282 assert(nDocId
!= -1 && "Cannot getViewsIds for invalid DocId -1");
284 SfxApplication
* pApp
= SfxApplication::Get();
288 const ViewShellDocId
nCurrentDocId(nDocId
);
290 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
293 if (pViewShell
->GetDocId() == nCurrentDocId
)
298 pArray
[n
] = static_cast<sal_Int32
>(pViewShell
->GetViewShellId());
302 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
308 int SfxLokHelper::getDocumentIdOfView(int nViewId
)
310 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
313 if (pViewShell
->GetViewShellId() == ViewShellId(nViewId
))
314 return static_cast<int>(pViewShell
->GetDocId());
315 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
320 const LanguageTag
& SfxLokHelper::getDefaultLanguage()
322 return g_defaultLanguageTag
;
325 void SfxLokHelper::setDefaultLanguage(const OUString
& rBcp47LanguageTag
)
327 g_defaultLanguageTag
= LanguageTag(rBcp47LanguageTag
, true);
330 const LanguageTag
& SfxLokHelper::getLoadLanguage() { return g_loadLanguageTag
; }
332 void SfxLokHelper::setLoadLanguage(const OUString
& rBcp47LanguageTag
)
334 g_loadLanguageTag
= LanguageTag(rBcp47LanguageTag
, true);
337 void SfxLokHelper::setViewLanguage(int nId
, const OUString
& rBcp47LanguageTag
)
339 std::vector
<SfxViewShell
*>& rViewArr
= SfxGetpApp()->GetViewShells_Impl();
341 for (SfxViewShell
* pViewShell
: rViewArr
)
343 if (pViewShell
->GetViewShellId() == ViewShellId(nId
))
345 pViewShell
->SetLOKLanguageTag(rBcp47LanguageTag
);
346 // sync also global getter if we are the current view
347 bool bIsCurrShell
= (pViewShell
== SfxViewShell::Current());
349 comphelper::LibreOfficeKit::setLanguageTag(LanguageTag(rBcp47LanguageTag
));
355 void SfxLokHelper::setViewReadOnly(int nId
, bool readOnly
)
357 std::vector
<SfxViewShell
*>& rViewArr
= SfxGetpApp()->GetViewShells_Impl();
359 for (SfxViewShell
* pViewShell
: rViewArr
)
361 if (pViewShell
&& pViewShell
->GetViewShellId() == ViewShellId(nId
))
363 LOK_INFO("lok.readonlyview", "SfxLokHelper::setViewReadOnly: view id: " << nId
<< ", readOnly: " << readOnly
);
364 pViewShell
->SetLokReadOnlyView(readOnly
);
370 void SfxLokHelper::setAllowChangeComments(int nId
, bool allow
)
372 std::vector
<SfxViewShell
*>& rViewArr
= SfxGetpApp()->GetViewShells_Impl();
374 for (SfxViewShell
* pViewShell
: rViewArr
)
376 if (pViewShell
&& pViewShell
->GetViewShellId() == ViewShellId(nId
))
378 LOK_INFO("lok.readonlyview", "SfxLokHelper::setAllowChangeComments: view id: " << nId
<< ", allow: " << allow
);
379 pViewShell
->SetAllowChangeComments(allow
);
385 void SfxLokHelper::setAccessibilityState(int nId
, bool nEnabled
)
387 std::vector
<SfxViewShell
*>& rViewArr
= SfxGetpApp()->GetViewShells_Impl();
389 for (SfxViewShell
* pViewShell
: rViewArr
)
391 if (pViewShell
&& pViewShell
->GetViewShellId() == ViewShellId(nId
))
393 LOK_INFO("lok.a11y", "SfxLokHelper::setAccessibilityState: view id: " << nId
<< ", nEnabled: " << nEnabled
);
394 pViewShell
->SetLOKAccessibilityState(nEnabled
);
400 void SfxLokHelper::setViewLocale(int nId
, const OUString
& rBcp47LanguageTag
)
402 std::vector
<SfxViewShell
*>& rViewArr
= SfxGetpApp()->GetViewShells_Impl();
404 for (SfxViewShell
* pViewShell
: rViewArr
)
406 if (pViewShell
->GetViewShellId() == ViewShellId(nId
))
408 pViewShell
->SetLOKLocale(rBcp47LanguageTag
);
414 LOKDeviceFormFactor
SfxLokHelper::getDeviceFormFactor()
416 return g_deviceFormFactor
;
419 void SfxLokHelper::setDeviceFormFactor(std::u16string_view rDeviceFormFactor
)
421 if (rDeviceFormFactor
== u
"desktop")
422 g_deviceFormFactor
= LOKDeviceFormFactor::DESKTOP
;
423 else if (rDeviceFormFactor
== u
"tablet")
424 g_deviceFormFactor
= LOKDeviceFormFactor::TABLET
;
425 else if (rDeviceFormFactor
== u
"mobile")
426 g_deviceFormFactor
= LOKDeviceFormFactor::MOBILE
;
428 g_deviceFormFactor
= LOKDeviceFormFactor::UNKNOWN
;
431 void SfxLokHelper::setDefaultTimezone(bool isSet
, const OUString
& rTimezone
)
433 g_isDefaultTimezoneSet
= isSet
;
434 g_DefaultTimezone
= rTimezone
;
437 std::pair
<bool, OUString
> SfxLokHelper::getDefaultTimezone()
439 return { g_isDefaultTimezoneSet
, g_DefaultTimezone
};
442 void SfxLokHelper::setViewTimezone(int nId
, bool isSet
, const OUString
& rTimezone
)
444 std::vector
<SfxViewShell
*>& rViewArr
= SfxGetpApp()->GetViewShells_Impl();
446 for (SfxViewShell
* pViewShell
: rViewArr
)
448 if (pViewShell
->GetViewShellId() == ViewShellId(nId
))
450 pViewShell
->SetLOKTimezone(isSet
, rTimezone
);
456 std::pair
<bool, OUString
> SfxLokHelper::getViewTimezone(int nId
)
458 std::vector
<SfxViewShell
*>& rViewArr
= SfxGetpApp()->GetViewShells_Impl();
460 for (SfxViewShell
* pViewShell
: rViewArr
)
462 if (pViewShell
->GetViewShellId() == ViewShellId(nId
))
464 return pViewShell
->GetLOKTimezone();
472 * Used for putting a whole JSON string into a string value
473 * e.g { key: "{JSON}" }
475 static OString
lcl_sanitizeJSONAsValue(const OString
&rStr
)
477 if (rStr
.getLength() < 1)
479 // FIXME: need an optimized 'escape' method for O[U]String.
480 OStringBuffer
aBuf(rStr
.getLength() + 8);
481 for (sal_Int32 i
= 0; i
< rStr
.getLength(); ++i
)
483 if (rStr
[i
] == '"' || rStr
[i
] == '\\')
487 aBuf
.append(rStr
[i
]);
489 return aBuf
.makeStringAndClear();
492 static OString
lcl_generateJSON(const SfxViewShell
* pView
, const boost::property_tree::ptree
& rTree
)
494 assert(pView
!= nullptr && "pView must be valid");
495 boost::property_tree::ptree aMessageProps
= rTree
;
496 aMessageProps
.put("viewId", SfxLokHelper::getView(pView
));
497 aMessageProps
.put("part", pView
->getPart());
498 aMessageProps
.put("mode", pView
->getEditMode());
499 std::stringstream aStream
;
500 boost::property_tree::write_json(aStream
, aMessageProps
, false /* pretty */);
501 return OString(o3tl::trim(aStream
.str()));
504 static inline OString
lcl_generateJSON(const SfxViewShell
* pView
, int nViewId
, std::string_view rKey
,
505 const OString
& rPayload
)
507 assert(pView
!= nullptr && "pView must be valid");
508 return OString::Concat("{ \"viewId\": \"") + OString::number(nViewId
)
509 + "\", \"part\": \"" + OString::number(pView
->getPart()) + "\", \"mode\": \""
510 + OString::number(pView
->getEditMode()) + "\", \"" + rKey
+ "\": \""
511 + lcl_sanitizeJSONAsValue(rPayload
) + "\" }";
514 static inline OString
lcl_generateJSON(const SfxViewShell
* pView
, std::string_view rKey
,
515 const OString
& rPayload
)
517 return lcl_generateJSON(pView
, SfxLokHelper::getView(pView
), rKey
, rPayload
);
520 void SfxLokHelper::notifyOtherView(const SfxViewShell
* pThisView
, SfxViewShell
const* pOtherView
,
521 int nType
, std::string_view rKey
, const OString
& rPayload
)
523 assert(pThisView
!= nullptr && "pThisView must be valid");
524 if (DisableCallbacks::disabled())
527 const OString aPayload
= lcl_generateJSON(pThisView
, rKey
, rPayload
);
528 const int viewId
= SfxLokHelper::getView(pThisView
);
529 pOtherView
->libreOfficeKitViewCallbackWithViewId(nType
, aPayload
, viewId
);
532 void SfxLokHelper::notifyOtherView(const SfxViewShell
* pThisView
, SfxViewShell
const* pOtherView
,
533 int nType
, const boost::property_tree::ptree
& rTree
)
535 assert(pThisView
!= nullptr && "pThisView must be valid");
536 if (DisableCallbacks::disabled() || !pOtherView
)
539 const int viewId
= SfxLokHelper::getView(pThisView
);
540 pOtherView
->libreOfficeKitViewCallbackWithViewId(nType
, lcl_generateJSON(pThisView
, rTree
), viewId
);
543 void SfxLokHelper::notifyOtherViews(const SfxViewShell
* pThisView
, int nType
, std::string_view rKey
,
544 const OString
& rPayload
)
546 assert(pThisView
!= nullptr && "pThisView must be valid");
547 if (DisableCallbacks::disabled())
550 // Cache the payload so we only have to generate it once, at most.
554 const ViewShellDocId nCurrentDocId
= pThisView
->GetDocId();
555 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
558 if (pViewShell
!= pThisView
&& nCurrentDocId
== pViewShell
->GetDocId())
560 // Payload is only dependent on pThisView.
561 if (aPayload
.isEmpty())
563 aPayload
= lcl_generateJSON(pThisView
, rKey
, rPayload
);
564 viewId
= SfxLokHelper::getView(pThisView
);
567 pViewShell
->libreOfficeKitViewCallbackWithViewId(nType
, aPayload
, viewId
);
570 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
574 void SfxLokHelper::notifyOtherViews(const SfxViewShell
* pThisView
, int nType
,
575 const boost::property_tree::ptree
& rTree
)
577 assert(pThisView
!= nullptr && "pThisView must be valid");
578 if (!pThisView
|| DisableCallbacks::disabled())
581 // Cache the payload so we only have to generate it once, at most.
585 const ViewShellDocId nCurrentDocId
= pThisView
->GetDocId();
586 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
589 if (pViewShell
!= pThisView
&& nCurrentDocId
== pViewShell
->GetDocId())
591 // Payload is only dependent on pThisView.
592 if (aPayload
.isEmpty())
594 aPayload
= lcl_generateJSON(pThisView
, rTree
);
595 viewId
= SfxLokHelper::getView(pThisView
);
598 pViewShell
->libreOfficeKitViewCallbackWithViewId(nType
, aPayload
, viewId
);
601 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
605 OString
SfxLokHelper::makePayloadJSON(const SfxViewShell
* pThisView
, int nViewId
, std::string_view rKey
, const OString
& rPayload
)
607 return lcl_generateJSON(pThisView
, nViewId
, rKey
, rPayload
);
611 OUString
lcl_getNameForSlot(const SfxViewShell
* pShell
, sal_uInt16 nWhich
)
613 if (pShell
&& pShell
->GetFrame())
615 const SfxSlot
* pSlot
= SfxSlotPool::GetSlotPool(pShell
->GetFrame()).GetSlot(nWhich
);
618 if (!pSlot
->GetUnoName().isEmpty())
620 return pSlot
->GetCommand();
629 void SfxLokHelper::sendUnoStatus(const SfxViewShell
* pShell
, const SfxPoolItem
* pItem
)
631 if (!pShell
|| !pItem
|| IsInvalidItem(pItem
) || DisableCallbacks::disabled())
634 boost::property_tree::ptree aItem
= pItem
->dumpAsJSON();
636 if (aItem
.count("state"))
638 OUString sCommand
= lcl_getNameForSlot(pShell
, pItem
->Which());
639 if (!sCommand
.isEmpty())
640 aItem
.put("commandName", sCommand
);
642 std::stringstream aStream
;
643 boost::property_tree::write_json(aStream
, aItem
);
644 pShell
->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED
, OString(aStream
.str()));
648 void SfxLokHelper::notifyViewRenderState(const SfxViewShell
* pShell
, vcl::ITiledRenderable
* pDoc
)
650 pShell
->libreOfficeKitViewCallback(LOK_CALLBACK_VIEW_RENDER_STATE
, pDoc
->getViewRenderState());
653 void SfxLokHelper::notifyWindow(const SfxViewShell
* pThisView
,
654 vcl::LOKWindowId nLOKWindowId
,
655 std::u16string_view rAction
,
656 const std::vector
<vcl::LOKPayloadItem
>& rPayload
)
658 assert(pThisView
!= nullptr && "pThisView must be valid");
660 if (nLOKWindowId
== 0 || DisableCallbacks::disabled())
663 OStringBuffer aPayload
=
664 "{ \"id\": \"" + OString::number(nLOKWindowId
) + "\""
665 ", \"action\": \"" + OUStringToOString(rAction
, RTL_TEXTENCODING_UTF8
) + "\"";
667 for (const auto& rItem
: rPayload
)
669 if (!rItem
.first
.isEmpty() && !rItem
.second
.isEmpty())
671 auto aFirst
= rItem
.first
.replaceAll("\""_ostr
, "\\\""_ostr
);
672 auto aSecond
= rItem
.second
.replaceAll("\""_ostr
, "\\\""_ostr
);
673 aPayload
.append(", \"" + aFirst
+ "\": \"" + aSecond
+ "\"");
676 aPayload
.append('}');
678 const OString s
= aPayload
.makeStringAndClear();
679 pThisView
->libreOfficeKitViewCallback(LOK_CALLBACK_WINDOW
, s
);
682 void SfxLokHelper::notifyInvalidation(SfxViewShell
const* pThisView
, tools::Rectangle
const* pRect
)
684 // -1 means all parts
685 const int nPart
= comphelper::LibreOfficeKit::isPartInInvalidation() ? pThisView
->getPart() : INT_MIN
;
686 SfxLokHelper::notifyInvalidation(pThisView
, nPart
, pRect
);
689 void SfxLokHelper::notifyInvalidation(SfxViewShell
const* pThisView
, const int nInPart
, tools::Rectangle
const* pRect
)
691 if (DisableCallbacks::disabled())
694 // -1 means all parts
695 const int nPart
= comphelper::LibreOfficeKit::isPartInInvalidation() ? nInPart
: INT_MIN
;
696 const int nMode
= pThisView
->getEditMode();
697 pThisView
->libreOfficeKitViewInvalidateTilesCallback(pRect
, nPart
, nMode
);
700 void SfxLokHelper::notifyDocumentSizeChanged(SfxViewShell
const* pThisView
, const OString
& rPayload
, vcl::ITiledRenderable
* pDoc
, bool bInvalidateAll
)
702 if (!pDoc
|| pDoc
->isDisposed() || DisableCallbacks::disabled())
707 for (int i
= 0; i
< pDoc
->getParts(); ++i
)
709 tools::Rectangle
aRectangle(0, 0, 1000000000, 1000000000);
710 const int nMode
= pThisView
->getEditMode();
711 pThisView
->libreOfficeKitViewInvalidateTilesCallback(&aRectangle
, i
, nMode
);
714 pThisView
->libreOfficeKitViewCallback(LOK_CALLBACK_DOCUMENT_SIZE_CHANGED
, rPayload
);
717 void SfxLokHelper::notifyDocumentSizeChangedAllViews(vcl::ITiledRenderable
* pDoc
, bool bInvalidateAll
)
719 if (DisableCallbacks::disabled())
722 // FIXME: Do we know whether it is the views for the document that is in the "current" view that has changed?
723 const SfxViewShell
* const pCurrentViewShell
= SfxViewShell::Current();
724 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
727 // FIXME: What if SfxViewShell::Current() returned null?
728 // Should we then do this for all views of all open documents
730 if (pCurrentViewShell
== nullptr || pViewShell
->GetDocId() == pCurrentViewShell
-> GetDocId())
732 SfxLokHelper::notifyDocumentSizeChanged(pViewShell
, ""_ostr
, pDoc
, bInvalidateAll
);
733 bInvalidateAll
= false; // we direct invalidations to all views anyway.
735 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
739 void SfxLokHelper::notifyPartSizeChangedAllViews(vcl::ITiledRenderable
* pDoc
, int nPart
)
741 if (DisableCallbacks::disabled())
744 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
747 if (// FIXME should really filter on pViewShell->GetDocId() too
748 pViewShell
->getPart() == nPart
)
749 SfxLokHelper::notifyDocumentSizeChanged(pViewShell
, ""_ostr
, pDoc
, false);
750 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
754 OString
SfxLokHelper::makeVisCursorInvalidation(int nViewId
, const OString
& rRectangle
,
755 bool bMispelledWord
, const OString
& rHyperlink
)
757 if (comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
759 OString sHyperlink
= rHyperlink
.isEmpty() ? "{}"_ostr
: rHyperlink
;
760 return OString::Concat("{ \"viewId\": \"") + OString::number(nViewId
) +
761 "\", \"rectangle\": \"" + rRectangle
+
762 "\", \"mispelledWord\": \"" + OString::number(bMispelledWord
? 1 : 0) +
763 "\", \"hyperlink\": " + sHyperlink
+ " }";
771 void SfxLokHelper::notifyAllViews(int nType
, const OString
& rPayload
)
773 if (DisableCallbacks::disabled())
776 const auto payload
= rPayload
.getStr();
777 const SfxViewShell
* const pCurrentViewShell
= SfxViewShell::Current();
778 if (!pCurrentViewShell
)
780 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
783 if (pViewShell
->GetDocId() == pCurrentViewShell
->GetDocId())
784 pViewShell
->libreOfficeKitViewCallback(nType
, payload
);
785 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
789 void SfxLokHelper::notifyContextChange(const css::ui::ContextChangeEventObject
& rEvent
)
791 if (DisableCallbacks::disabled())
794 SfxViewShell
* pViewShell
= SfxViewShell::Get({ rEvent
.Source
, css::uno::UNO_QUERY
});
799 rEvent
.ApplicationName
.replace(' ', '_') +
801 rEvent
.ContextName
.replace(' ', '_');
802 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_CHANGED
, aBuffer
.toUtf8());
805 void SfxLokHelper::notifyLog(const std::ostringstream
& stream
)
807 if (DisableCallbacks::disabled())
810 SfxViewShell
* pViewShell
= SfxViewShell::Current();
813 if (pViewShell
->getLibreOfficeKitViewCallback())
815 if (!g_logNotifierCache
.empty())
817 for (const auto& msg
: g_logNotifierCache
)
819 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_CORE_LOG
, msg
.c_str());
821 g_logNotifierCache
.clear();
823 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_CORE_LOG
, stream
.str().c_str());
827 while (g_logNotifierCache
.size() >= g_logNotifierCacheMaxSize
)
828 g_logNotifierCache
.pop_front();
829 g_logNotifierCache
.push_back(stream
.str());
835 std::string
extractCertificateWithOffset(const std::string
& certificate
, size_t& rOffset
)
837 static constexpr std::string_view
header("-----BEGIN CERTIFICATE-----");
838 static constexpr std::string_view
footer("-----END CERTIFICATE-----");
842 size_t pos1
= certificate
.find(header
, rOffset
);
843 if (pos1
== std::string::npos
)
846 size_t pos2
= certificate
.find(footer
, pos1
+ 1);
847 if (pos2
== std::string::npos
)
850 pos1
= pos1
+ header
.length();
851 size_t len
= pos2
- pos1
;
854 return certificate
.substr(pos1
, len
);
858 std::string
SfxLokHelper::extractCertificate(const std::string
& certificate
)
861 return extractCertificateWithOffset(certificate
, nOffset
);
864 std::vector
<std::string
> SfxLokHelper::extractCertificates(const std::string
& rCerts
)
866 std::vector
<std::string
> aRet
;
870 std::string aNext
= extractCertificateWithOffset(rCerts
, nOffset
);
876 aRet
.push_back(aNext
);
883 std::string
extractKey(const std::string
& privateKey
)
885 static constexpr std::string_view
header("-----BEGIN PRIVATE KEY-----");
886 static constexpr std::string_view
footer("-----END PRIVATE KEY-----");
890 size_t pos1
= privateKey
.find(header
);
891 if (pos1
== std::string::npos
)
894 size_t pos2
= privateKey
.find(footer
, pos1
+ 1);
895 if (pos2
== std::string::npos
)
898 pos1
= pos1
+ header
.length();
901 return privateKey
.substr(pos1
, pos2
);
905 css::uno::Reference
<css::security::XCertificate
> SfxLokHelper::getSigningCertificate(const std::string
& rCert
, const std::string
& rKey
)
907 const uno::Reference
<uno::XComponentContext
>& xContext
= comphelper::getProcessComponentContext();
908 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
909 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
910 if (!xSecurityContext
.is())
915 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
916 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
918 if (!xCertificateCreator
.is())
923 uno::Sequence
<sal_Int8
> aCertificateSequence
;
925 std::string aCertificateBase64String
= extractCertificate(rCert
);
926 if (!aCertificateBase64String
.empty())
928 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
);
929 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
933 aCertificateSequence
.realloc(rCert
.size());
934 std::copy(rCert
.c_str(), rCert
.c_str() + rCert
.size(), aCertificateSequence
.getArray());
937 uno::Sequence
<sal_Int8
> aPrivateKeySequence
;
938 std::string aPrivateKeyBase64String
= extractKey(rKey
);
939 if (!aPrivateKeyBase64String
.empty())
941 OUString aBase64OUString
= OUString::createFromAscii(aPrivateKeyBase64String
);
942 comphelper::Base64::decode(aPrivateKeySequence
, aBase64OUString
);
946 aPrivateKeySequence
.realloc(rKey
.size());
947 std::copy(rKey
.c_str(), rKey
.c_str() + rKey
.size(), aPrivateKeySequence
.getArray());
950 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->createDERCertificateWithPrivateKey(aCertificateSequence
, aPrivateKeySequence
);
954 uno::Reference
<security::XCertificate
> SfxLokHelper::addCertificate(
955 const css::uno::Reference
<css::xml::crypto::XCertificateCreator
>& xCertificateCreator
,
956 const css::uno::Sequence
<sal_Int8
>& rCert
)
958 // Trust arg is handled by CERT_DecodeTrustString(), see 'man certutil'.
959 return xCertificateCreator
->addDERCertificateToTheDatabase(rCert
, u
"TCu,Cu,Tu"_ustr
);
962 void SfxLokHelper::addCertificates(const std::vector
<std::string
>& rCerts
)
964 const uno::Reference
<uno::XComponentContext
>& xContext
= comphelper::getProcessComponentContext();
965 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
966 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
967 if (!xSecurityContext
.is())
972 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
973 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
974 if (!xCertificateCreator
.is())
979 for (const auto& rCert
: rCerts
)
981 uno::Sequence
<sal_Int8
> aCertificateSequence
;
982 OUString aBase64OUString
= OUString::fromUtf8(rCert
);
983 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
984 addCertificate(xCertificateCreator
, aCertificateSequence
);
987 // Update the signature state, perhaps the signing certificate is now trusted.
988 SfxObjectShell
* pObjectShell
= SfxObjectShell::Current();
994 pObjectShell
->RecheckSignature(false);
997 bool SfxLokHelper::supportsCommand(std::u16string_view rCommand
)
999 static const std::initializer_list
<std::u16string_view
> vSupport
= { u
"Signature" };
1001 return std::find(vSupport
.begin(), vSupport
.end(), rCommand
) != vSupport
.end();
1004 std::map
<OUString
, OUString
> SfxLokHelper::parseCommandParameters(std::u16string_view rCommand
)
1006 std::map
<OUString
, OUString
> aMap
;
1008 INetURLObject
aParser(rCommand
);
1009 OUString aArguments
= aParser
.GetParam();
1010 sal_Int32 nParamIndex
= 0;
1013 std::u16string_view aParam
= o3tl::getToken(aArguments
, 0, '&', nParamIndex
);
1014 sal_Int32 nIndex
= 0;
1019 std::u16string_view aToken
= o3tl::getToken(aParam
, 0, '=', nIndex
);
1024 } while (nIndex
>= 0);
1025 aMap
[aKey
] = INetURLObject::decode(aValue
, INetURLObject::DecodeMechanism::WithCharset
);
1026 } while (nParamIndex
>= 0);
1031 void SfxLokHelper::getCommandValues(tools::JsonWriter
& rJsonWriter
, std::string_view rCommand
)
1033 static constexpr OString
aSignature(".uno:Signature"_ostr
);
1034 if (!o3tl::starts_with(rCommand
, aSignature
))
1039 SfxObjectShell
* pObjectShell
= SfxObjectShell::Current();
1045 svl::crypto::SigningContext aSigningContext
;
1046 std::map
<OUString
, OUString
> aMap
1047 = SfxLokHelper::parseCommandParameters(OUString::fromUtf8(rCommand
));
1048 auto it
= aMap
.find("signatureTime");
1049 if (it
!= aMap
.end())
1051 // Signature time is provided: prefer it over the system time.
1052 aSigningContext
.m_nSignatureTime
= it
->second
.toInt64();
1054 pObjectShell
->SignDocumentContentUsingCertificate(aSigningContext
);
1055 // Set commandName, this is a reply to a request.
1056 rJsonWriter
.put("commandName", aSignature
);
1057 auto aCommandValues
= rJsonWriter
.startNode("commandValues");
1058 rJsonWriter
.put("signatureTime", aSigningContext
.m_nSignatureTime
);
1060 uno::Sequence
<sal_Int8
> aDigest(reinterpret_cast<sal_Int8
*>(aSigningContext
.m_aDigest
.data()),
1061 aSigningContext
.m_aDigest
.size());
1062 OUStringBuffer aBuffer
;
1063 comphelper::Base64::encode(aBuffer
, aDigest
);
1064 rJsonWriter
.put("digest", aBuffer
.makeStringAndClear());
1067 void SfxLokHelper::notifyUpdate(SfxViewShell
const* pThisView
, int nType
)
1069 if (DisableCallbacks::disabled() || !pThisView
)
1072 pThisView
->libreOfficeKitViewUpdatedCallback(nType
);
1075 void SfxLokHelper::notifyUpdatePerViewId(SfxViewShell
const* pThisView
, int nType
)
1077 notifyUpdatePerViewId(pThisView
, pThisView
, pThisView
, nType
);
1080 void SfxLokHelper::notifyUpdatePerViewId(SfxViewShell
const* pTargetShell
, SfxViewShell
const* pViewShell
,
1081 SfxViewShell
const* pSourceShell
, int nType
)
1083 if (DisableCallbacks::disabled())
1086 int viewId
= SfxLokHelper::getView(pViewShell
);
1087 int sourceViewId
= SfxLokHelper::getView(pSourceShell
);
1088 pTargetShell
->libreOfficeKitViewUpdatedCallbackPerViewId(nType
, viewId
, sourceViewId
);
1091 void SfxLokHelper::notifyOtherViewsUpdatePerViewId(SfxViewShell
const* pThisView
, int nType
)
1093 if (DisableCallbacks::disabled() || !pThisView
)
1096 int viewId
= SfxLokHelper::getView(pThisView
);
1097 const ViewShellDocId nCurrentDocId
= pThisView
->GetDocId();
1098 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
1101 if (pViewShell
!= pThisView
&& nCurrentDocId
== pViewShell
->GetDocId())
1102 pViewShell
->libreOfficeKitViewUpdatedCallbackPerViewId(nType
, viewId
, viewId
);
1104 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
1110 struct LOKAsyncEventData
1112 int mnView
; // Window is not enough.
1113 VclPtr
<vcl::Window
> mpWindow
;
1115 MouseEvent maMouseEvent
;
1116 KeyEvent maKeyEvent
;
1120 void LOKPostAsyncEvent(void* pEv
, void*)
1122 std::unique_ptr
<LOKAsyncEventData
> pLOKEv(static_cast<LOKAsyncEventData
*>(pEv
));
1123 if (pLOKEv
->mpWindow
->isDisposed())
1126 int nView
= SfxLokHelper::getView(nullptr);
1127 if (nView
!= pLOKEv
->mnView
)
1129 SAL_INFO("sfx.view", "LOK - view mismatch " << nView
<< " vs. " << pLOKEv
->mnView
);
1130 SfxLokHelper::setView(pLOKEv
->mnView
);
1133 if (!pLOKEv
->mpWindow
->HasChildPathFocus(true))
1135 SAL_INFO("sfx.view", "LOK - focus mismatch, switching focus");
1136 pLOKEv
->mpWindow
->GrabFocus();
1139 VclPtr
<vcl::Window
> pFocusWindow
= pLOKEv
->mpWindow
->GetFocusedWindow();
1141 pFocusWindow
= pLOKEv
->mpWindow
;
1143 if (pLOKEv
->mpWindow
->isDisposed())
1146 switch (pLOKEv
->mnEvent
)
1148 case VclEventId::WindowKeyInput
:
1150 sal_uInt16 nRepeat
= pLOKEv
->maKeyEvent
.GetRepeat();
1151 KeyEvent
singlePress(pLOKEv
->maKeyEvent
.GetCharCode(),
1152 pLOKEv
->maKeyEvent
.GetKeyCode());
1153 for (sal_uInt16 i
= 0; i
<= nRepeat
; ++i
)
1154 if (!pFocusWindow
->isDisposed())
1155 pFocusWindow
->KeyInput(singlePress
);
1157 if (pLOKEv
->maKeyEvent
.GetKeyCode().GetCode() == KEY_CONTEXTMENU
)
1159 // later do use getCaretPosition probably, or get focused obj position, smt like that
1160 Point aPos
= pFocusWindow
->GetPointerPosPixel();
1161 CommandEvent
aCEvt( aPos
, CommandEventId::ContextMenu
);
1162 pFocusWindow
->Command(aCEvt
);
1166 case VclEventId::WindowKeyUp
:
1167 if (!pFocusWindow
->isDisposed())
1168 pFocusWindow
->KeyUp(pLOKEv
->maKeyEvent
);
1170 case VclEventId::WindowMouseButtonDown
:
1171 pLOKEv
->mpWindow
->SetLastMousePos(pLOKEv
->maMouseEvent
.GetPosPixel());
1172 pLOKEv
->mpWindow
->MouseButtonDown(pLOKEv
->maMouseEvent
);
1173 // Invoke the context menu
1174 if (pLOKEv
->maMouseEvent
.GetButtons() & MOUSE_RIGHT
)
1176 const CommandEvent
aCEvt(pLOKEv
->maMouseEvent
.GetPosPixel(), CommandEventId::ContextMenu
, true, nullptr);
1177 pLOKEv
->mpWindow
->Command(aCEvt
);
1180 case VclEventId::WindowMouseButtonUp
:
1181 pLOKEv
->mpWindow
->SetLastMousePos(pLOKEv
->maMouseEvent
.GetPosPixel());
1182 pLOKEv
->mpWindow
->MouseButtonUp(pLOKEv
->maMouseEvent
);
1184 // sometimes MouseButtonDown captures mouse and starts tracking, and VCL
1185 // will not take care of releasing that with tiled rendering
1186 if (pLOKEv
->mpWindow
->IsTracking())
1187 pLOKEv
->mpWindow
->EndTracking();
1190 case VclEventId::WindowMouseMove
:
1191 pLOKEv
->mpWindow
->SetLastMousePos(pLOKEv
->maMouseEvent
.GetPosPixel());
1192 pLOKEv
->mpWindow
->MouseMove(pLOKEv
->maMouseEvent
);
1193 pLOKEv
->mpWindow
->RequestHelp(HelpEvent
{
1194 pLOKEv
->mpWindow
->OutputToScreenPixel(pLOKEv
->maMouseEvent
.GetPosPixel()),
1195 HelpEventMode::QUICK
}); // If needed, HelpEventMode should be taken from a config
1197 case VclEventId::ExtTextInput
:
1198 case VclEventId::EndExtTextInput
:
1199 pLOKEv
->mpWindow
->PostExtTextInputEvent(pLOKEv
->mnEvent
, pLOKEv
->maText
);
1207 void postEventAsync(LOKAsyncEventData
*pEvent
)
1209 if (!pEvent
->mpWindow
|| pEvent
->mpWindow
->isDisposed())
1211 SAL_WARN("vcl", "Async event post - but no valid window as destination " << pEvent
->mpWindow
.get());
1216 pEvent
->mnView
= SfxLokHelper::getView(nullptr);
1217 if (vcl::lok::isUnipoll())
1219 if (!Application::IsMainThread())
1220 SAL_WARN("lok", "Posting event directly but not called from main thread!");
1221 LOKPostAsyncEvent(pEvent
, nullptr);
1224 Application::PostUserEvent(Link
<void*, void>(pEvent
, LOKPostAsyncEvent
));
1228 void SfxLokHelper::postKeyEventAsync(const VclPtr
<vcl::Window
> &xWindow
,
1229 int nType
, int nCharCode
, int nKeyCode
, int nRepeat
)
1231 LOKAsyncEventData
* pLOKEv
= new LOKAsyncEventData
;
1234 case LOK_KEYEVENT_KEYINPUT
:
1235 pLOKEv
->mnEvent
= VclEventId::WindowKeyInput
;
1237 case LOK_KEYEVENT_KEYUP
:
1238 pLOKEv
->mnEvent
= VclEventId::WindowKeyUp
;
1243 pLOKEv
->maKeyEvent
= KeyEvent(nCharCode
, nKeyCode
, nRepeat
);
1244 pLOKEv
->mpWindow
= xWindow
;
1245 postEventAsync(pLOKEv
);
1248 void SfxLokHelper::setBlockedCommandList(int nViewId
, const char* blockedCommandList
)
1250 SfxViewShell
* pViewShell
= SfxLokHelper::getViewOfId(nViewId
);
1254 pViewShell
->setBlockedCommandList(blockedCommandList
);
1258 void SfxLokHelper::postExtTextEventAsync(const VclPtr
<vcl::Window
> &xWindow
,
1259 int nType
, const OUString
&rText
)
1261 LOKAsyncEventData
* pLOKEv
= new LOKAsyncEventData
;
1264 case LOK_EXT_TEXTINPUT
:
1265 pLOKEv
->mnEvent
= VclEventId::ExtTextInput
;
1266 pLOKEv
->maText
= rText
;
1268 case LOK_EXT_TEXTINPUT_END
:
1269 pLOKEv
->mnEvent
= VclEventId::EndExtTextInput
;
1270 pLOKEv
->maText
= "";
1275 pLOKEv
->mpWindow
= xWindow
;
1276 postEventAsync(pLOKEv
);
1279 void SfxLokHelper::postMouseEventAsync(const VclPtr
<vcl::Window
> &xWindow
, LokMouseEventData
const & rLokMouseEventData
)
1281 LOKAsyncEventData
* pLOKEv
= new LOKAsyncEventData
;
1282 switch (rLokMouseEventData
.mnType
)
1284 case LOK_MOUSEEVENT_MOUSEBUTTONDOWN
:
1285 pLOKEv
->mnEvent
= VclEventId::WindowMouseButtonDown
;
1287 case LOK_MOUSEEVENT_MOUSEBUTTONUP
:
1288 pLOKEv
->mnEvent
= VclEventId::WindowMouseButtonUp
;
1290 case LOK_MOUSEEVENT_MOUSEMOVE
:
1291 pLOKEv
->mnEvent
= VclEventId::WindowMouseMove
;
1297 // no reason - just always true so far.
1298 assert (rLokMouseEventData
.meModifiers
== MouseEventModifiers::SIMPLECLICK
);
1300 pLOKEv
->maMouseEvent
= MouseEvent(rLokMouseEventData
.maPosition
, rLokMouseEventData
.mnCount
,
1301 rLokMouseEventData
.meModifiers
, rLokMouseEventData
.mnButtons
,
1302 rLokMouseEventData
.mnModifier
);
1303 if (rLokMouseEventData
.maLogicPosition
)
1305 pLOKEv
->maMouseEvent
.setLogicPosition(*rLokMouseEventData
.maLogicPosition
);
1307 pLOKEv
->mpWindow
= xWindow
;
1308 postEventAsync(pLOKEv
);
1311 void SfxLokHelper::dumpState(rtl::OStringBuffer
&rState
)
1313 SfxViewShell
* pShell
= SfxViewShell::Current();
1314 sal_Int32 nDocId
= pShell
? static_cast<sal_Int32
>(pShell
->GetDocId().get()) : -1;
1316 rState
.append("\n\tDocId:\t");
1317 rState
.append(nDocId
);
1322 rState
.append("\n\tViewCount:\t");
1323 rState
.append(static_cast<sal_Int32
>(getViewsCount(nDocId
)));
1325 const SfxViewShell
* const pCurrentViewShell
= SfxViewShell::Current();
1326 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
1329 if (pCurrentViewShell
== nullptr || pViewShell
->GetDocId() == pCurrentViewShell
-> GetDocId())
1330 pViewShell
->dumpLibreOfficeKitViewState(rState
);
1332 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
1336 bool SfxLokHelper::testInPlaceComponentMouseEventHit(SfxViewShell
* pViewShell
, int nType
, int nX
,
1337 int nY
, int nCount
, int nButtons
,
1338 int nModifier
, double fScaleX
, double fScaleY
,
1341 // In LOK RTL mode draw/svx operates in negative X coordinates
1342 // But the coordinates from client is always positive, so negate nX.
1346 // check if the user hit a chart/math object which is being edited by this view
1347 if (LokChartHelper
aChartHelper(pViewShell
, bNegativeX
);
1348 aChartHelper
.postMouseEvent(nType
, nX
, nY
, nCount
, nButtons
, nModifier
, fScaleX
, fScaleY
))
1351 if (LokStarMathHelper
aMathHelper(pViewShell
);
1352 aMathHelper
.postMouseEvent(nType
, nX
, nY
, nCount
, nButtons
, nModifier
, fScaleX
, fScaleY
))
1355 // check if the user hit a chart which is being edited by someone else
1356 // and, if so, skip current mouse event
1357 if (nType
!= LOK_MOUSEEVENT_MOUSEMOVE
)
1359 if (LokChartHelper::HitAny({nX
, nY
}, bNegativeX
))
1366 VclPtr
<vcl::Window
> SfxLokHelper::getInPlaceDocWindow(SfxViewShell
* pViewShell
)
1368 if (VclPtr
<vcl::Window
> pWindow
= LokChartHelper(pViewShell
).GetWindow())
1370 if (VclPtr
<vcl::Window
> pWindow
= LokStarMathHelper(pViewShell
).GetWidgetWindow())
1375 void SfxLokHelper::sendNetworkAccessError(std::string_view rAction
)
1377 tools::JsonWriter aWriter
;
1378 aWriter
.put("code", static_cast<sal_uInt32
>(
1379 ErrCode(ErrCodeArea::Inet
, sal_uInt16(ErrCodeClass::Access
))));
1380 aWriter
.put("kind", "network");
1381 aWriter
.put("cmd", rAction
);
1383 SfxViewShell
* pViewShell
= SfxViewShell::Current();
1386 pViewShell
->libreOfficeKitViewCallback(
1387 LOK_CALLBACK_ERROR
, aWriter
.finishAndGetAsOString());
1391 SfxLokLanguageGuard::SfxLokLanguageGuard(SfxViewShell
* pNewShell
)
1392 : m_bSetLanguage(false)
1393 , m_pOldShell(nullptr)
1395 m_pOldShell
= SfxViewShell::Current();
1396 if (!comphelper::LibreOfficeKit::isActive() || !pNewShell
|| pNewShell
== m_pOldShell
)
1401 // The current view ID is not the one that belongs to this frame, update
1403 comphelper::LibreOfficeKit::setLanguageTag(pNewShell
->GetLOKLanguageTag());
1404 comphelper::LibreOfficeKit::setLocale(pNewShell
->GetLOKLocale());
1405 m_bSetLanguage
= true;
1408 SfxLokLanguageGuard::~SfxLokLanguageGuard()
1410 if (!m_bSetLanguage
|| !m_pOldShell
)
1415 comphelper::LibreOfficeKit::setLanguageTag(m_pOldShell
->GetLOKLanguageTag());
1416 comphelper::LibreOfficeKit::setLocale(m_pOldShell
->GetLOKLocale());
1419 LOKEditViewHistory::EditViewHistoryMap
LOKEditViewHistory::maEditViewHistory
;
1422 void LOKEditViewHistory::Update(bool bRemove
)
1424 if (!comphelper::LibreOfficeKit::isActive())
1427 SfxViewShell
* pViewShell
= SfxViewShell::Current();
1430 int nDocId
= pViewShell
->GetDocId().get();
1431 if (maEditViewHistory
.find(nDocId
) != maEditViewHistory
.end())
1432 maEditViewHistory
[nDocId
].remove(pViewShell
);
1435 maEditViewHistory
[nDocId
].push_back(pViewShell
);
1436 if (maEditViewHistory
[nDocId
].size() > 10)
1437 maEditViewHistory
[nDocId
].pop_front();
1442 ViewShellList
LOKEditViewHistory::GetHistoryForDoc(ViewShellDocId aDocId
)
1444 int nDocId
= aDocId
.get();
1445 ViewShellList aResult
;
1446 if (maEditViewHistory
.find(nDocId
) != maEditViewHistory
.end())
1447 aResult
= maEditViewHistory
.at(nDocId
);
1451 ViewShellList
LOKEditViewHistory::GetSortedViewsForDoc(ViewShellDocId aDocId
)
1453 ViewShellList aEditViewHistoryForDoc
= LOKEditViewHistory::GetHistoryForDoc(aDocId
);
1454 // all views where document is loaded
1455 ViewShellList aCurrentDocViewList
;
1456 // active views that are listed in the edit history
1457 ViewShellList aEditedViewList
;
1459 // Populate aCurrentDocViewList and aEditedViewList
1460 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
1463 if (pViewShell
->GetDocId() == aDocId
)
1465 if (aEditViewHistoryForDoc
.empty() ||
1466 std::find(aEditViewHistoryForDoc
.begin(), aEditViewHistoryForDoc
.end(),
1467 pViewShell
) == aEditViewHistoryForDoc
.end())
1469 // append views not listed in the edit history;
1470 // the edit history is limited to 10 views,
1471 // so it could miss some view where in place editing is occurring
1472 aCurrentDocViewList
.push_back(pViewShell
);
1476 // view is listed in the edit history
1477 aEditedViewList
.push_back(pViewShell
);
1480 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
1483 // in case some no more active view needs to be removed from the history
1484 aEditViewHistoryForDoc
.remove_if(
1485 [&aEditedViewList
](SfxViewShell
* pHistoryItem
) {
1486 return std::find(aEditedViewList
.begin(), aEditedViewList
.end(), pHistoryItem
) == aEditedViewList
.end();
1489 // place views belonging to the edit history at the end
1490 aCurrentDocViewList
.splice(aCurrentDocViewList
.end(), aEditViewHistoryForDoc
);
1492 return aCurrentDocViewList
;
1495 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */