/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/// Used to disable callbacks. /// Needed to avoid recursion when switching views, /// which can cause clients to invoke LOKit API and /// implicitly set the view, which might cause an /// infinite recursion if not detected and prevented. class DisableCallbacks
{ public:
DisableCallbacks()
{
assert(m_nDisabled >= 0 && "Expected non-negative DisabledCallbacks state when disabling.");
++m_nDisabled;
}
~DisableCallbacks()
{
assert(m_nDisabled > 0 && "Expected positive DisabledCallbacks state when re-enabling.");
--m_nDisabled;
}
assert(pViewShell->GetDocId() == docId && "DocId must be already set!"); returnstatic_cast<sal_Int32>(pViewShell->GetViewShellId());
}
int SfxLokHelper::createView()
{ // Assumes a single document, or at least that the // current view belongs to the document on which the // view will be created.
SfxViewShell* pViewShell = SfxViewShell::Current(); if (pViewShell == nullptr) return -1;
int SfxLokHelper::createView(int nDocId)
{ const SfxApplication* pApp = SfxApplication::Get(); if (pApp == nullptr) return -1;
// Find a shell with the given DocId. const ViewShellDocId docId(nDocId); for (const SfxViewShell* pViewShell : pApp->GetViewShells_Impl())
{ if (pViewShell->GetDocId() == docId) return createView(pViewShell->GetViewFrame(), docId);
}
if (bIsCurrShell)
{ // If we wanted to set the SfxViewShell that is actually set, we could skip it. // But it looks like that the language can go wrong, so we have to fix that. // This can happen, when someone sets the language or SfxViewShell::Current() separately.
SAL_WARN("lok", "LANGUAGE mismatch at setView! ... old (wrong) lang:"
<< comphelper::LibreOfficeKit::getLanguageTag().getBcp47()
<< " new lang:" << pViewShell->GetLOKLanguageTag().getBcp47());
}
// update the current LOK language and locale for the dialog tunneling
comphelper::LibreOfficeKit::setLanguageTag(pViewShell->GetLOKLanguageTag());
comphelper::LibreOfficeKit::setLocale(pViewShell->GetLOKLocale());
// Make comphelper::dispatchCommand() find the correct frame.
uno::Reference<frame::XFrame> xFrame = rViewFrame.GetFrame().GetFrameInterface();
uno::Reference<frame::XDesktop2> xDesktop = frame::Desktop::create(comphelper::getProcessComponentContext());
xDesktop->setActiveFrame(xFrame);
}
SfxViewShell* SfxLokHelper::getViewOfId(int nId)
{
SfxApplication* pApp = SfxApplication::Get(); if (pApp == nullptr) return nullptr;
const ViewShellId nViewShellId(nId);
std::vector<SfxViewShell*>& rViewArr = pApp->GetViewShells_Impl(); for (SfxViewShell* pViewShell : rViewArr)
{ if (pViewShell->GetViewShellId() == nViewShellId) return pViewShell;
}
return nullptr;
}
int SfxLokHelper::getView(const SfxViewShell* pViewShell)
{ if (!pViewShell)
pViewShell = SfxViewShell::Current(); // Still no valid view shell? Then no idea. if (!pViewShell) return -1;
for (SfxViewShell* pViewShell : rViewArr)
{ if (pViewShell->GetViewShellId() == ViewShellId(nId))
{
pViewShell->SetLOKLanguageTag(rBcp47LanguageTag); // sync also global getter if we are the current view bool bIsCurrShell = (pViewShell == SfxViewShell::Current()); if (bIsCurrShell)
comphelper::LibreOfficeKit::setLanguageTag(LanguageTag(rBcp47LanguageTag)); return;
}
}
}
for (SfxViewShell* pViewShell : rViewArr)
{ if (pViewShell->GetViewShellId() == ViewShellId(nId))
{ return pViewShell->GetLOKTimezone();
}
}
return {};
}
/* * Used for putting a whole JSON string into a string value * e.g { key: "{JSON}" }
*/ static OString lcl_sanitizeJSONAsValue(const OString &rStr)
{ if (rStr.getLength() < 1) return rStr; // FIXME: need an optimized 'escape' method for O[U]String.
OStringBuffer aBuf(rStr.getLength() + 8); for (sal_Int32 i = 0; i < rStr.getLength(); ++i)
{ if (rStr[i] == '"' || rStr[i] == '\\')
aBuf.append('\\');
if (rStr[i] != '\n')
aBuf.append(rStr[i]);
} return aBuf.makeStringAndClear();
}
if (bInvalidateAll)
{ for (int i = 0; i < pDoc->getParts(); ++i)
{
tools::Rectangle aRectangle(0, 0, 1000000000, 1000000000); constint nMode = pThisView->getEditMode();
pThisView->libreOfficeKitViewInvalidateTilesCallback(&aRectangle, i, nMode);
}
}
pThisView->libreOfficeKitViewCallback(LOK_CALLBACK_DOCUMENT_SIZE_CHANGED, rPayload);
}
void SfxLokHelper::notifyDocumentSizeChangedAllViews(vcl::ITiledRenderable* pDoc, bool bInvalidateAll)
{ if (DisableCallbacks::disabled()) return;
// FIXME: Do we know whether it is the views for the document that is in the "current" view that has changed? const SfxViewShell* const pCurrentViewShell = SfxViewShell::Current();
SfxViewShell* pViewShell = SfxViewShell::GetFirst(); while (pViewShell)
{ // FIXME: What if SfxViewShell::Current() returned null? // Should we then do this for all views of all open documents // or not? if (pCurrentViewShell == nullptr || pViewShell->GetDocId() == pCurrentViewShell-> GetDocId())
{
SfxLokHelper::notifyDocumentSizeChanged(pViewShell, ""_ostr, pDoc, bInvalidateAll);
bInvalidateAll = false; // we direct invalidations to all views anyway.
}
pViewShell = SfxViewShell::GetNext(*pViewShell);
}
}
void SfxLokHelper::notifyPartSizeChangedAllViews(vcl::ITiledRenderable* pDoc, int nPart)
{ if (DisableCallbacks::disabled()) return;
SfxViewShell* pViewShell = SfxViewShell::GetFirst(); while (pViewShell)
{ if (// FIXME should really filter on pViewShell->GetDocId() too
pViewShell->getPart() == nPart)
SfxLokHelper::notifyDocumentSizeChanged(pViewShell, ""_ostr, pDoc, false);
pViewShell = SfxViewShell::GetNext(*pViewShell);
}
}
// Update the signature state, perhaps the signing certificate is now trusted.
SfxObjectShell* pObjectShell = SfxObjectShell::Current(); if (!pObjectShell)
{ return;
}
SfxObjectShell* pObjectShell = SfxObjectShell::Current(); if (!pObjectShell)
{ return;
}
svl::crypto::SigningContext aSigningContext;
std::map<OUString, OUString> aMap
= SfxLokHelper::parseCommandParameters(OUString::fromUtf8(rCommand)); auto it = aMap.find("signatureTime"); if (it != aMap.end())
{ // Signature time is provided: prefer it over the system time.
aSigningContext.m_nSignatureTime = it->second.toInt64();
}
pObjectShell->SignDocumentContentUsingCertificate(aSigningContext); // Set commandName, this is a reply to a request.
rJsonWriter.put("commandName", aSignature); auto aCommandValues = rJsonWriter.startNode("commandValues");
rJsonWriter.put("signatureTime", aSigningContext.m_nSignatureTime);
VclPtr<vcl::Window> pFocusWindow = pLOKEv->mpWindow->GetFocusedWindow(); if (!pFocusWindow)
pFocusWindow = pLOKEv->mpWindow;
if (pLOKEv->mpWindow->isDisposed()) return;
switch (pLOKEv->mnEvent)
{ case VclEventId::WindowKeyInput:
{
sal_uInt16 nRepeat = pLOKEv->maKeyEvent.GetRepeat();
KeyEvent singlePress(pLOKEv->maKeyEvent.GetCharCode(),
pLOKEv->maKeyEvent.GetKeyCode()); for (sal_uInt16 i = 0; i <= nRepeat; ++i) if (!pFocusWindow->isDisposed())
pFocusWindow->KeyInput(singlePress);
if (pLOKEv->maKeyEvent.GetKeyCode().GetCode() == KEY_CONTEXTMENU)
{ // later do use getCaretPosition probably, or get focused obj position, smt like that
Point aPos = pFocusWindow->GetPointerPosPixel();
CommandEvent aCEvt( aPos, CommandEventId::ContextMenu);
pFocusWindow->Command(aCEvt);
} break;
} case VclEventId::WindowKeyUp: if (!pFocusWindow->isDisposed())
pFocusWindow->KeyUp(pLOKEv->maKeyEvent); break; case VclEventId::WindowMouseButtonDown:
pLOKEv->mpWindow->SetLastMousePos(pLOKEv->maMouseEvent.GetPosPixel());
pLOKEv->mpWindow->MouseButtonDown(pLOKEv->maMouseEvent); // Invoke the context menu if (pLOKEv->maMouseEvent.GetButtons() & MOUSE_RIGHT)
{ const CommandEvent aCEvt(pLOKEv->maMouseEvent.GetPosPixel(), CommandEventId::ContextMenu, true, nullptr);
pLOKEv->mpWindow->Command(aCEvt);
} break; case VclEventId::WindowMouseButtonUp:
pLOKEv->mpWindow->SetLastMousePos(pLOKEv->maMouseEvent.GetPosPixel());
pLOKEv->mpWindow->MouseButtonUp(pLOKEv->maMouseEvent);
// sometimes MouseButtonDown captures mouse and starts tracking, and VCL // will not take care of releasing that with tiled rendering if (pLOKEv->mpWindow->IsTracking())
pLOKEv->mpWindow->EndTracking();
break; case VclEventId::WindowMouseMove:
pLOKEv->mpWindow->SetLastMousePos(pLOKEv->maMouseEvent.GetPosPixel());
pLOKEv->mpWindow->MouseMove(pLOKEv->maMouseEvent);
pLOKEv->mpWindow->RequestHelp(HelpEvent{
pLOKEv->mpWindow->OutputToScreenPixel(pLOKEv->maMouseEvent.GetPosPixel()),
HelpEventMode::QUICK }); // If needed, HelpEventMode should be taken from a config break; case VclEventId::ExtTextInput: case VclEventId::EndExtTextInput:
pLOKEv->mpWindow->PostExtTextInputEvent(pLOKEv->mnEvent, pLOKEv->maText); break; default:
assert(false); break;
}
}
void postEventAsync(LOKAsyncEventData *pEvent)
{ if (!pEvent->mpWindow || pEvent->mpWindow->isDisposed())
{
SAL_WARN("vcl", "Async event post - but no valid window as destination " << pEvent->mpWindow.get()); delete pEvent; return;
}
pEvent->mnView = SfxLokHelper::getView(nullptr); if (vcl::lok::isUnipoll())
{ if (!Application::IsMainThread())
SAL_WARN("lok", "Posting event directly but not called from main thread!");
LOKPostAsyncEvent(pEvent, nullptr);
} else
Application::PostUserEvent(LINK_NONMEMBER(pEvent, LOKPostAsyncEvent));
}
}
void SfxLokHelper::postKeyEventAsync(const VclPtr<vcl::Window> &xWindow, int nType, int nCharCode, int nKeyCode, int nRepeat)
{
LOKAsyncEventData* pLOKEv = new LOKAsyncEventData; switch (nType)
{ case LOK_KEYEVENT_KEYINPUT:
pLOKEv->mnEvent = VclEventId::WindowKeyInput; break; case LOK_KEYEVENT_KEYUP:
pLOKEv->mnEvent = VclEventId::WindowKeyUp; break; default:
assert(false);
}
pLOKEv->maKeyEvent = KeyEvent(nCharCode, nKeyCode, nRepeat);
pLOKEv->mpWindow = xWindow;
postEventAsync(pLOKEv);
}
bool SfxLokHelper::testInPlaceComponentMouseEventHit(SfxViewShell* pViewShell, int nType, int nX, int nY, int nCount, int nButtons, int nModifier, double fScaleX, double fScaleY, bool bNegativeX)
{ // In LOK RTL mode draw/svx operates in negative X coordinates // But the coordinates from client is always positive, so negate nX. if (bNegativeX)
nX = -nX;
// check if the user hit a chart/math object which is being edited by this view if (LokChartHelper aChartHelper(pViewShell, bNegativeX);
aChartHelper.postMouseEvent(nType, nX, nY, nCount, nButtons, nModifier, fScaleX, fScaleY)) returntrue;
// check if the user hit a chart which is being edited by someone else // and, if so, skip current mouse event if (nType != LOK_MOUSEEVENT_MOUSEMOVE)
{ if (LokChartHelper::HitAny({nX, nY}, bNegativeX)) returntrue;
}
// The current view ID is not the one that belongs to this frame, update // language/locale.
comphelper::LibreOfficeKit::setLanguageTag(pNewShell->GetLOKLanguageTag());
comphelper::LibreOfficeKit::setLocale(pNewShell->GetLOKLocale());
m_bSetLanguage = true;
}
SfxLokLanguageGuard::~SfxLokLanguageGuard()
{ if (!m_bSetLanguage || !m_pOldShell)
{ return;
}
void LOKEditViewHistory::Update(bool bRemove)
{ if (!comphelper::LibreOfficeKit::isActive()) return;
SfxViewShell* pViewShell = SfxViewShell::Current(); if (pViewShell)
{ int nDocId = pViewShell->GetDocId().get(); if (maEditViewHistory.find(nDocId) != maEditViewHistory.end())
maEditViewHistory[nDocId].remove(pViewShell); if (!bRemove)
{
maEditViewHistory[nDocId].push_back(pViewShell); if (maEditViewHistory[nDocId].size() > 10)
maEditViewHistory[nDocId].pop_front();
}
}
}
ViewShellList LOKEditViewHistory::GetHistoryForDoc(ViewShellDocId aDocId)
{ int nDocId = aDocId.get();
ViewShellList aResult; if (maEditViewHistory.find(nDocId) != maEditViewHistory.end())
aResult = maEditViewHistory.at(nDocId); return aResult;
}
ViewShellList LOKEditViewHistory::GetSortedViewsForDoc(ViewShellDocId aDocId)
{
ViewShellList aEditViewHistoryForDoc = LOKEditViewHistory::GetHistoryForDoc(aDocId); // all views where document is loaded
ViewShellList aCurrentDocViewList; // active views that are listed in the edit history
ViewShellList aEditedViewList;
// Populate aCurrentDocViewList and aEditedViewList
SfxViewShell* pViewShell = SfxViewShell::GetFirst(); while (pViewShell)
{ if (pViewShell->GetDocId() == aDocId)
{ if (aEditViewHistoryForDoc.empty() ||
std::find(aEditViewHistoryForDoc.begin(), aEditViewHistoryForDoc.end(),
pViewShell) == aEditViewHistoryForDoc.end())
{ // append views not listed in the edit history; // the edit history is limited to 10 views, // so it could miss some view where in place editing is occurring
aCurrentDocViewList.push_back(pViewShell);
} else
{ // view is listed in the edit history
aEditedViewList.push_back(pViewShell);
}
}
pViewShell = SfxViewShell::GetNext(*pViewShell);
}
// in case some no more active view needs to be removed from the history
aEditViewHistoryForDoc.remove_if(
[&aEditedViewList](SfxViewShell* pHistoryItem) { return std::find(aEditedViewList.begin(), aEditedViewList.end(), pHistoryItem) == aEditedViewList.end();
});
// place views belonging to the edit history at the end
aCurrentDocViewList.splice(aCurrentDocViewList.end(), aEditViewHistoryForDoc);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.