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 <config_features.h>
19 #include <unicode/udata.h>
20 #include <unicode/ucnv.h>
22 #import <Foundation/Foundation.h>
23 #import <CoreGraphics/CoreGraphics.h>
28 #include <osl/detail/android-bootstrap.h>
34 #include <boost/property_tree/json_parser.hpp>
35 #include <boost/algorithm/string.hpp>
37 #include <LibreOfficeKit/LibreOfficeKit.h>
38 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
40 #include <sal/log.hxx>
41 #include <vcl/errinf.hxx>
42 #include <vcl/lok.hxx>
43 #include <o3tl/any.hxx>
44 #include <osl/file.hxx>
45 #include <osl/process.h>
46 #include <osl/thread.h>
47 #include <rtl/bootstrap.hxx>
48 #include <rtl/strbuf.hxx>
49 #include <rtl/uri.hxx>
50 #include <svl/zforlist.hxx>
51 #include <cppuhelper/bootstrap.hxx>
52 #include <comphelper/base64.hxx>
53 #include <comphelper/dispatchcommand.hxx>
54 #include <comphelper/lok.hxx>
55 #include <comphelper/processfactory.hxx>
56 #include <comphelper/string.hxx>
57 #include <comphelper/profilezone.hxx>
58 #include <comphelper/propertysequence.hxx>
59 #include <comphelper/scopeguard.hxx>
60 #include <comphelper/threadpool.hxx>
61 #include <comphelper/sequenceashashmap.hxx>
63 #include <com/sun/star/beans/XPropertySet.hpp>
64 #include <com/sun/star/container/XNameAccess.hpp>
65 #include <com/sun/star/frame/Desktop.hpp>
66 #include <com/sun/star/frame/DispatchResultEvent.hpp>
67 #include <com/sun/star/frame/DispatchResultState.hpp>
68 #include <com/sun/star/frame/XDispatchProvider.hpp>
69 #include <com/sun/star/frame/XDispatchResultListener.hpp>
70 #include <com/sun/star/frame/XSynchronousDispatch.hpp>
71 #include <com/sun/star/frame/XStorable.hpp>
72 #include <com/sun/star/lang/Locale.hpp>
73 #include <com/sun/star/lang/XComponent.hpp>
74 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
75 #include <com/sun/star/reflection/theCoreReflection.hpp>
76 #include <com/sun/star/reflection/XIdlClass.hpp>
77 #include <com/sun/star/reflection/XIdlReflection.hpp>
78 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
79 #include <com/sun/star/util/URLTransformer.hpp>
80 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
81 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
82 #include <com/sun/star/datatransfer/XTransferable2.hpp>
83 #include <com/sun/star/text/TextContentAnchorType.hpp>
84 #include <com/sun/star/document/XRedlinesSupplier.hpp>
85 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
87 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
88 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
89 #include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
90 #include <com/sun/star/xml/crypto/XCertificateCreator.hpp>
91 #include <com/sun/star/security/XCertificate.hpp>
93 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
94 #include <com/sun/star/linguistic2/XSpellChecker.hpp>
95 #include <com/sun/star/i18n/LocaleCalendar2.hpp>
96 #include <com/sun/star/i18n/ScriptType.hpp>
97 #include <com/sun/star/lang/DisposedException.hpp>
99 #include <editeng/flstitem.hxx>
101 #include <sfx2/app.hxx>
103 #include <sfx2/objsh.hxx>
104 #include <sfx2/docfilt.hxx>
105 #include <sfx2/docfile.hxx>
106 #include <sfx2/viewsh.hxx>
107 #include <sfx2/viewfrm.hxx>
108 #include <sfx2/msgpool.hxx>
109 #include <sfx2/dispatch.hxx>
110 #include <sfx2/lokcharthelper.hxx>
111 #include <sfx2/DocumentSigner.hxx>
112 #include <sfx2/sidebar/SidebarDockingWindow.hxx>
113 #include <sfx2/sidebar/SidebarController.hxx>
114 #include <svx/dialmgr.hxx>
115 #include <svx/strings.hrc>
116 #include <svx/svdview.hxx>
117 #include <svx/svxids.hrc>
118 #include <svx/ucsubset.hxx>
119 #include <vcl/vclevent.hxx>
120 #include <vcl/GestureEvent.hxx>
121 #include <vcl/svapp.hxx>
122 #include <unotools/resmgr.hxx>
123 #include <tools/fract.hxx>
124 #include <tools/json_writer.hxx>
125 #include <svtools/ctrltool.hxx>
126 #include <svtools/langtab.hxx>
127 #include <vcl/floatwin.hxx>
128 #include <vcl/fontcharmap.hxx>
129 #include <vcl/graphicfilter.hxx>
131 #include <vcl/sysdata.hxx>
133 #include <vcl/virdev.hxx>
134 #include <vcl/ImageTree.hxx>
135 #include <vcl/ITiledRenderable.hxx>
136 #include <vcl/dialoghelper.hxx>
137 #include <unicode/uchar.h>
138 #include <unotools/confignode.hxx>
139 #include <unotools/syslocaleoptions.hxx>
140 #include <unotools/mediadescriptor.hxx>
141 #include <unotools/pathoptions.hxx>
142 #include <unotools/tempfile.hxx>
143 #include <unotools/streamwrap.hxx>
144 #include <osl/module.hxx>
145 #include <comphelper/sequence.hxx>
146 #include <sfx2/sfxbasemodel.hxx>
147 #include <svl/undo.hxx>
148 #include <unotools/datetime.hxx>
149 #include <i18nlangtag/mslangid.hxx>
150 #include <i18nlangtag/languagetag.hxx>
151 #include <vcl/builder.hxx>
152 #include <vcl/abstdlg.hxx>
153 #include <tools/diagnose_ex.h>
154 #include <vcl/uitest/uiobject.hxx>
155 #include <vcl/jsdialog/executor.hxx>
157 // Needed for getUndoManager()
158 #include <com/sun/star/document/XUndoManager.hpp>
159 #include <com/sun/star/document/XUndoManagerSupplier.hpp>
160 #include <editeng/sizeitem.hxx>
161 #include <svx/rulritem.hxx>
162 #include <svx/pageitem.hxx>
166 #include "../app/cmdlineargs.hxx"
167 // We also need to hackily be able to start the main libreoffice thread:
168 #include "../app/sofficemain.h"
169 #include "../app/officeipcthread.hxx"
170 #include <lib/init.hxx>
172 #include "lokinteractionhandler.hxx"
173 #include "lokclipboard.hxx"
174 #include <officecfg/Office/Impress.hxx>
178 using namespace desktop
;
181 static LibLibreOffice_Impl
*gImpl
= nullptr;
182 static std::weak_ptr
< LibreOfficeKitClass
> gOfficeClass
;
183 static std::weak_ptr
< LibreOfficeKitDocumentClass
> gDocumentClass
;
185 static void SetLastExceptionMsg(const OUString
& s
= OUString())
187 SAL_WARN_IF(!s
.isEmpty(), "lok", "lok exception '" + s
+ "'");
189 gImpl
->maLastExceptionMsg
= s
;
197 const char *filterName
;
202 const ExtensionMap aWriterExtensionMap
[] =
204 { "doc", "MS Word 97" },
205 { "docm", "MS Word 2007 XML VBA" },
206 { "docx", "MS Word 2007 XML" },
207 { "fodt", "OpenDocument Text Flat XML" },
208 { "html", "HTML (StarWriter)" },
209 { "odt", "writer8" },
210 { "ott", "writer8_template" },
211 { "pdf", "writer_pdf_Export" },
213 { "rtf", "Rich Text Format" },
215 { "xhtml", "XHTML Writer File" },
216 { "png", "writer_png_Export" },
220 const ExtensionMap aCalcExtensionMap
[] =
222 { "csv", "Text - txt - csv (StarCalc)" },
223 { "fods", "OpenDocument Spreadsheet Flat XML" },
224 { "html", "HTML (StarCalc)" },
226 { "ots", "calc8_template" },
227 { "pdf", "calc_pdf_Export" },
228 { "xhtml", "XHTML Calc File" },
229 { "xls", "MS Excel 97" },
230 { "xlsm", "Calc MS Excel 2007 VBA XML" },
231 { "xlsx", "Calc MS Excel 2007 XML" },
232 { "png", "calc_png_Export" },
236 const ExtensionMap aImpressExtensionMap
[] =
238 { "fodp", "OpenDocument Presentation Flat XML" },
239 { "html", "impress_html_Export" },
240 { "odg", "impress8_draw" },
241 { "odp", "impress8" },
242 { "otp", "impress8_template" },
243 { "pdf", "impress_pdf_Export" },
244 { "potm", "Impress MS PowerPoint 2007 XML Template" },
245 { "pot", "MS PowerPoint 97 Vorlage" },
246 { "pptm", "Impress MS PowerPoint 2007 XML VBA" },
247 { "pptx", "Impress MS PowerPoint 2007 XML" },
248 { "pps", "MS PowerPoint 97 Autoplay" },
249 { "ppt", "MS PowerPoint 97" },
250 { "svg", "impress_svg_Export" },
251 { "xhtml", "XHTML Impress File" },
252 { "png", "impress_png_Export"},
256 const ExtensionMap aDrawExtensionMap
[] =
258 { "fodg", "draw_ODG_FlatXML" },
259 { "html", "draw_html_Export" },
261 { "pdf", "draw_pdf_Export" },
262 { "svg", "draw_svg_Export" },
263 { "xhtml", "XHTML Draw File" },
264 { "png", "draw_png_Export"},
268 static OUString
getUString(const char* pString
)
270 if (pString
== nullptr)
273 OString
sString(pString
, strlen(pString
));
274 return OStringToOUString(sString
, RTL_TEXTENCODING_UTF8
);
277 // Tolerate embedded \0s etc.
278 static char *convertOString(const OString
&rStr
)
280 char* pMemory
= static_cast<char*>(malloc(rStr
.getLength() + 1));
281 assert(pMemory
); // don't tolerate failed allocations.
282 memcpy(pMemory
, rStr
.getStr(), rStr
.getLength() + 1);
286 static char *convertOUString(const OUString
&aStr
)
288 return convertOString(OUStringToOString(aStr
, RTL_TEXTENCODING_UTF8
));
291 /// Try to convert a relative URL to an absolute one, unless it already looks like a URL.
292 static OUString
getAbsoluteURL(const char* pURL
)
294 OUString
aURL(getUString(pURL
));
298 // convert relative paths to absolute ones
299 OUString aWorkingDir
;
300 osl_getProcessWorkingDir(&aWorkingDir
.pData
);
301 if (!aWorkingDir
.endsWith("/"))
306 return rtl::Uri::convertRelToAbs(aWorkingDir
, aURL
);
308 catch (const rtl::MalformedUriException
&)
315 static uno::Any
jsonToUnoAny(const boost::property_tree::ptree
& aTree
)
320 uno::Reference
< reflection::XIdlField
> aField
;
321 boost::property_tree::ptree aNodeNull
, aNodeValue
, aNodeField
;
322 const std::string
& rType
= aTree
.get
<std::string
>("type", "");
323 const std::string
& rValue
= aTree
.get
<std::string
>("value", "");
324 uno::Sequence
< uno::Reference
< reflection::XIdlField
> > aFields
;
325 uno::Reference
< reflection:: XIdlClass
> xIdlClass
=
326 css::reflection::theCoreReflection::get(comphelper::getProcessComponentContext())->forName(OUString::fromUtf8(rType
.c_str()));
329 uno::TypeClass aTypeClass
= xIdlClass
->getTypeClass();
330 xIdlClass
->createObject(aAny
);
331 aFields
= xIdlClass
->getFields();
332 nFields
= aFields
.getLength();
333 aNodeValue
= aTree
.get_child("value", aNodeNull
);
334 if (nFields
> 0 && aNodeValue
!= aNodeNull
)
336 for (sal_Int32 itField
= 0; itField
< nFields
; ++itField
)
338 aField
= aFields
[itField
];
339 aNodeField
= aNodeValue
.get_child(aField
->getName().toUtf8().getStr(), aNodeNull
);
340 if (aNodeField
!= aNodeNull
)
342 aValue
= jsonToUnoAny(aNodeField
);
343 aField
->set(aAny
, aValue
);
347 else if (!rValue
.empty())
349 if (aTypeClass
== uno::TypeClass_VOID
)
351 else if (aTypeClass
== uno::TypeClass_BYTE
)
352 aAny
<<= static_cast<sal_Int8
>(OString(rValue
.c_str()).toInt32());
353 else if (aTypeClass
== uno::TypeClass_BOOLEAN
)
354 aAny
<<= OString(rValue
.c_str()).toBoolean();
355 else if (aTypeClass
== uno::TypeClass_SHORT
)
356 aAny
<<= static_cast<sal_Int16
>(OString(rValue
.c_str()).toInt32());
357 else if (aTypeClass
== uno::TypeClass_UNSIGNED_SHORT
)
358 aAny
<<= static_cast<sal_uInt16
>(OString(rValue
.c_str()).toUInt32());
359 else if (aTypeClass
== uno::TypeClass_LONG
)
360 aAny
<<= OString(rValue
.c_str()).toInt32();
361 else if (aTypeClass
== uno::TypeClass_UNSIGNED_LONG
)
362 aAny
<<= static_cast<sal_uInt32
>(OString(rValue
.c_str()).toInt32());
363 else if (aTypeClass
== uno::TypeClass_FLOAT
)
364 aAny
<<= OString(rValue
.c_str()).toFloat();
365 else if (aTypeClass
== uno::TypeClass_DOUBLE
)
366 aAny
<<= OString(rValue
.c_str()).toDouble();
367 else if (aTypeClass
== uno::TypeClass_STRING
)
368 aAny
<<= OUString::fromUtf8(rValue
.c_str());
374 std::vector
<beans::PropertyValue
> desktop::jsonToPropertyValuesVector(const char* pJSON
)
376 std::vector
<beans::PropertyValue
> aArguments
;
377 if (pJSON
&& pJSON
[0] != '\0')
379 boost::property_tree::ptree aTree
, aNodeNull
, aNodeValue
;
380 std::stringstream
aStream(pJSON
);
381 boost::property_tree::read_json(aStream
, aTree
);
383 for (const auto& rPair
: aTree
)
385 const std::string
& rType
= rPair
.second
.get
<std::string
>("type", "");
386 const std::string
& rValue
= rPair
.second
.get
<std::string
>("value", "");
388 beans::PropertyValue aValue
;
389 aValue
.Name
= OUString::fromUtf8(rPair
.first
.c_str());
390 if (rType
== "string")
391 aValue
.Value
<<= OUString::fromUtf8(rValue
.c_str());
392 else if (rType
== "boolean")
393 aValue
.Value
<<= OString(rValue
.c_str()).toBoolean();
394 else if (rType
== "float")
395 aValue
.Value
<<= OString(rValue
.c_str()).toFloat();
396 else if (rType
== "long")
397 aValue
.Value
<<= OString(rValue
.c_str()).toInt32();
398 else if (rType
== "short")
399 aValue
.Value
<<= sal_Int16(OString(rValue
.c_str()).toInt32());
400 else if (rType
== "unsigned short")
401 aValue
.Value
<<= sal_uInt16(OString(rValue
.c_str()).toUInt32());
402 else if (rType
== "int64")
403 aValue
.Value
<<= OString(rValue
.c_str()).toInt64();
404 else if (rType
== "int32")
405 aValue
.Value
<<= OString(rValue
.c_str()).toInt32();
406 else if (rType
== "int16")
407 aValue
.Value
<<= sal_Int16(OString(rValue
.c_str()).toInt32());
408 else if (rType
== "uint64")
409 aValue
.Value
<<= OString(rValue
.c_str()).toUInt64();
410 else if (rType
== "uint32")
411 aValue
.Value
<<= OString(rValue
.c_str()).toUInt32();
412 else if (rType
== "uint16")
413 aValue
.Value
<<= sal_uInt16(OString(rValue
.c_str()).toUInt32());
414 else if (rType
== "[]byte")
416 aNodeValue
= rPair
.second
.get_child("value", aNodeNull
);
417 if (aNodeValue
!= aNodeNull
&& aNodeValue
.size() == 0)
419 uno::Sequence
< sal_Int8
> aSeqByte(reinterpret_cast<const sal_Int8
*>(rValue
.c_str()), rValue
.size());
420 aValue
.Value
<<= aSeqByte
;
423 else if (rType
== "[]any")
425 aNodeValue
= rPair
.second
.get_child("value", aNodeNull
);
426 if (aNodeValue
!= aNodeNull
&& !aNodeValue
.empty())
429 uno::Sequence
< uno::Any
> aSeq(aNodeValue
.size());
430 for (const auto& rSeqPair
: aNodeValue
)
431 aSeq
[itSeq
++] = jsonToUnoAny(rSeqPair
.second
);
432 aValue
.Value
<<= aSeq
;
436 SAL_WARN("desktop.lib", "jsonToPropertyValuesVector: unhandled type '"<<rType
<<"'");
437 aArguments
.push_back(aValue
);
444 static StringMap
jsonToStringMap(const char* pJSON
)
447 if (pJSON
&& pJSON
[0] != '\0')
449 std::stringstream
aStream(pJSON
);
450 boost::property_tree::ptree aTree
;
451 boost::property_tree::read_json(aStream
, aTree
);
453 for (const auto& rPair
: aTree
)
455 aArgs
[OUString::fromUtf8(rPair
.first
.c_str())] = OUString::fromUtf8(rPair
.second
.get_value
<std::string
>(".").c_str());
462 static boost::property_tree::ptree
unoAnyToPropertyTree(const uno::Any
& anyItem
)
464 boost::property_tree::ptree aTree
;
465 OUString aType
= anyItem
.getValueTypeName();
466 aTree
.put("type", aType
.toUtf8().getStr());
468 if (aType
== "string")
469 aTree
.put("value", anyItem
.get
<OUString
>().toUtf8().getStr());
470 else if (aType
== "unsigned long")
471 aTree
.put("value", OString::number(anyItem
.get
<sal_uInt32
>()).getStr());
472 else if (aType
== "long")
473 aTree
.put("value", OString::number(anyItem
.get
<sal_Int32
>()).getStr());
474 else if (aType
== "[]any")
476 uno::Sequence
<uno::Any
> aSeq
;
477 if (anyItem
>>= aSeq
)
479 boost::property_tree::ptree aSubTree
;
481 for (auto i
= 0; i
< aSeq
.getLength(); ++i
)
483 aSubTree
.add_child(OString::number(i
).getStr(), unoAnyToPropertyTree(aSeq
[i
]));
485 aTree
.add_child("value", aSubTree
);
489 // TODO: Add more as required
496 RectangleAndPart
RectangleAndPart::Create(const std::string
& rPayload
)
498 RectangleAndPart aRet
;
499 if (rPayload
.compare(0, 5, "EMPTY") == 0) // payload starts with "EMPTY"
501 aRet
.m_aRectangle
= tools::Rectangle(0, 0, SfxLokHelper::MaxTwips
, SfxLokHelper::MaxTwips
);
502 if (comphelper::LibreOfficeKit::isPartInInvalidation())
503 aRet
.m_nPart
= std::stol(rPayload
.substr(6));
508 std::istringstream
aStream(rPayload
);
509 tools::Long nLeft
, nTop
, nWidth
, nHeight
;
510 tools::Long nPart
= INT_MIN
;
512 if (comphelper::LibreOfficeKit::isPartInInvalidation())
514 aStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
>> nComma
>> nPart
;
518 aStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
;
521 if (nWidth
> 0 && nHeight
> 0)
523 // The top-left corner starts at (0, 0).
524 // Anything negative is invalid.
537 if (nWidth
> 0 && nHeight
> 0)
539 aRet
.m_aRectangle
= tools::Rectangle(nLeft
, nTop
, nLeft
+ nWidth
, nTop
+ nHeight
);
542 // else leave empty rect.
544 aRet
.m_nPart
= nPart
;
548 RectangleAndPart
& CallbackFlushHandler::CallbackData::setRectangleAndPart(const std::string
& payload
)
550 setRectangleAndPart(RectangleAndPart::Create(payload
));
552 // Return reference to the cached object.
553 return boost::get
<RectangleAndPart
>(PayloadObject
);
556 void CallbackFlushHandler::CallbackData::setRectangleAndPart(const RectangleAndPart
& rRectAndPart
)
558 PayloadString
= rRectAndPart
.toString().getStr();
559 PayloadObject
= rRectAndPart
;
562 const RectangleAndPart
& CallbackFlushHandler::CallbackData::getRectangleAndPart() const
564 assert(PayloadObject
.which() == 1);
565 return boost::get
<RectangleAndPart
>(PayloadObject
);
568 boost::property_tree::ptree
& CallbackFlushHandler::CallbackData::setJson(const std::string
& payload
)
570 boost::property_tree::ptree aTree
;
571 std::stringstream
aStream(payload
);
572 boost::property_tree::read_json(aStream
, aTree
);
574 // Let boost normalize the payload so it always matches the cache.
577 // Return reference to the cached object.
578 return boost::get
<boost::property_tree::ptree
>(PayloadObject
);
581 void CallbackFlushHandler::CallbackData::setJson(const boost::property_tree::ptree
& rTree
)
583 std::stringstream aJSONStream
;
584 constexpr bool bPretty
= false; // Don't waste time and bloat logs.
585 boost::property_tree::write_json(aJSONStream
, rTree
, bPretty
);
586 PayloadString
= boost::trim_copy(aJSONStream
.str());
588 PayloadObject
= rTree
;
591 const boost::property_tree::ptree
& CallbackFlushHandler::CallbackData::getJson() const
593 assert(PayloadObject
.which() == 2);
594 return boost::get
<boost::property_tree::ptree
>(PayloadObject
);
597 bool CallbackFlushHandler::CallbackData::validate() const
599 switch (PayloadObject
.which())
607 return getRectangleAndPart().toString().getStr() == PayloadString
;
612 std::stringstream aJSONStream
;
613 boost::property_tree::write_json(aJSONStream
, getJson(), false);
614 const std::string aExpected
= boost::trim_copy(aJSONStream
.str());
615 return aExpected
== PayloadString
;
619 assert(!"Unknown variant type; please add an entry to validate.");
629 bool lcl_isViewCallbackType(const int type
)
633 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
634 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
635 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
636 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
637 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
645 int lcl_getViewId(const std::string
& payload
)
647 // this is a cheap way how to get the viewId from a JSON message; proper
648 // parsing is terribly expensive, and we just need the viewId here
649 size_t viewIdPos
= payload
.find("viewId");
650 if (viewIdPos
== std::string::npos
)
653 size_t numberPos
= payload
.find(":", viewIdPos
+ 6);
654 if (numberPos
== std::string::npos
)
657 for (++numberPos
; numberPos
< payload
.length(); ++numberPos
)
659 if (payload
[numberPos
] == ',' || payload
[numberPos
] == '}' || (payload
[numberPos
] >= '0' && payload
[numberPos
] <= '9'))
663 if (numberPos
< payload
.length() && payload
[numberPos
] >= '0' && payload
[numberPos
] <= '9')
664 return strtol(payload
.substr(numberPos
).c_str(), nullptr, 10);
669 int lcl_getViewId(const desktop::CallbackFlushHandler::CallbackData
& rCallbackData
)
671 if (rCallbackData
.isCached())
672 return rCallbackData
.getJson().get
<int>("viewId");
673 return lcl_getViewId(rCallbackData
.PayloadString
);
676 std::string
extractCertificate(const std::string
& certificate
)
678 const std::string
header("-----BEGIN CERTIFICATE-----");
679 const std::string
footer("-----END CERTIFICATE-----");
683 size_t pos1
= certificate
.find(header
);
684 if (pos1
== std::string::npos
)
687 size_t pos2
= certificate
.find(footer
, pos1
+ 1);
688 if (pos2
== std::string::npos
)
691 pos1
= pos1
+ header
.length();
694 return certificate
.substr(pos1
, pos2
);
697 std::string
extractPrivateKey(const std::string
& privateKey
)
699 const std::string
header("-----BEGIN PRIVATE KEY-----");
700 const std::string
footer("-----END PRIVATE KEY-----");
704 size_t pos1
= privateKey
.find(header
);
705 if (pos1
== std::string::npos
)
708 size_t pos2
= privateKey
.find(footer
, pos1
+ 1);
709 if (pos2
== std::string::npos
)
712 pos1
= pos1
+ header
.length();
715 return privateKey
.substr(pos1
, pos2
);
718 OUString
lcl_getCurrentDocumentMimeType(const LibLODocument_Impl
* pDocument
)
720 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
724 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
728 SfxMedium
* pMedium
= pObjectShell
->GetMedium();
732 auto pFilter
= pMedium
->GetFilter();
736 return pFilter
->GetMimeType();
739 // Gets an undo manager to enter and exit undo context. Needed by ToggleOrientation
740 css::uno::Reference
< css::document::XUndoManager
> getUndoManager( const css::uno::Reference
< css::frame::XFrame
>& rxFrame
)
742 const css::uno::Reference
< css::frame::XController
>& xController
= rxFrame
->getController();
743 if ( xController
.is() )
745 const css::uno::Reference
< css::frame::XModel
>& xModel
= xController
->getModel();
748 const css::uno::Reference
< css::document::XUndoManagerSupplier
> xSuppUndo( xModel
, css::uno::UNO_QUERY_THROW
);
749 return css::uno::Reference
< css::document::XUndoManager
>( xSuppUndo
->getUndoManager(), css::uno::UNO_SET_THROW
);
753 return css::uno::Reference
< css::document::XUndoManager
> ();
756 // Adjusts page margins for Writer doc. Needed by ToggleOrientation
757 void ExecuteMarginLRChange(
758 const tools::Long nPageLeftMargin
,
759 const tools::Long nPageRightMargin
,
760 SvxLongLRSpaceItem
* pPageLRMarginItem
)
762 pPageLRMarginItem
->SetLeft( nPageLeftMargin
);
763 pPageLRMarginItem
->SetRight( nPageRightMargin
);
764 SfxViewShell::Current()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_LRSPACE
,
765 SfxCallMode::RECORD
, { pPageLRMarginItem
});
768 // Adjusts page margins for Writer doc. Needed by ToggleOrientation
769 void ExecuteMarginULChange(
770 const tools::Long nPageTopMargin
,
771 const tools::Long nPageBottomMargin
,
772 SvxLongULSpaceItem
* pPageULMarginItem
)
774 pPageULMarginItem
->SetUpper( nPageTopMargin
);
775 pPageULMarginItem
->SetLower( nPageBottomMargin
);
776 SfxViewShell::Current()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_ULSPACE
,
777 SfxCallMode::RECORD
, { pPageULMarginItem
});
780 // Main function which toggles page orientation of the Writer doc. Needed by ToggleOrientation
781 void ExecuteOrientationChange()
783 std::unique_ptr
<SvxPageItem
> pPageItem(new SvxPageItem(SID_ATTR_PAGE
));
784 std::unique_ptr
<SvxSizeItem
> pPageSizeItem(new SvxSizeItem(SID_ATTR_PAGE_SIZE
));
785 std::unique_ptr
<SvxLongLRSpaceItem
> pPageLRMarginItem(new SvxLongLRSpaceItem( 0, 0, SID_ATTR_PAGE_LRSPACE
));
786 std::unique_ptr
<SvxLongULSpaceItem
> pPageULMarginItem(new SvxLongULSpaceItem( 0, 0, SID_ATTR_PAGE_ULSPACE
));
787 // 1mm in twips rounded
788 // This should be in sync with MINBODY in sw/source/uibase/sidebar/PageMarginControl.hxx
789 constexpr tools::Long MINBODY
= 56;
791 css::uno::Reference
< css::document::XUndoManager
> mxUndoManager(
792 getUndoManager( SfxViewFrame::Current()->GetFrame().GetFrameInterface() ) );
794 if ( mxUndoManager
.is() )
795 mxUndoManager
->enterUndoContext( "" );
798 const SfxPoolItem
* pItem
;
801 SfxViewFrame::Current()->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_SIZE
, pItem
);
802 pPageSizeItem
.reset( static_cast<SvxSizeItem
*>(pItem
->Clone()) );
806 SfxViewFrame::Current()->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_LRSPACE
, pItem
);
807 pPageLRMarginItem
.reset( static_cast<SvxLongLRSpaceItem
*>(pItem
->Clone()) );
811 SfxViewFrame::Current()->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PAGE_ULSPACE
, pItem
);
812 pPageULMarginItem
.reset( static_cast<SvxLongULSpaceItem
*>(pItem
->Clone()) );
816 bool bIsLandscape
= false;
817 if ( pPageSizeItem
->GetSize().Width() > pPageSizeItem
->GetSize().Height())
820 // toggle page orientation
821 pPageItem
->SetLandscape(!bIsLandscape
);
824 // swap the width and height of the page size
825 const tools::Long nRotatedWidth
= pPageSizeItem
->GetSize().Height();
826 const tools::Long nRotatedHeight
= pPageSizeItem
->GetSize().Width();
827 pPageSizeItem
->SetSize(Size(nRotatedWidth
, nRotatedHeight
));
830 // apply changed attributes
831 if (SfxViewShell::Current())
833 SfxViewShell::Current()->GetDispatcher()->ExecuteList(SID_ATTR_PAGE_SIZE
,
834 SfxCallMode::RECORD
, { pPageSizeItem
.get(), pPageItem
.get() });
839 // check, if margin values still fit to the changed page size.
840 // if not, adjust margin values
842 const tools::Long nML
= pPageLRMarginItem
->GetLeft();
843 const tools::Long nMR
= pPageLRMarginItem
->GetRight();
844 const tools::Long nTmpPW
= nML
+ nMR
+ MINBODY
;
846 const tools::Long nPW
= pPageSizeItem
->GetSize().Width();
852 ExecuteMarginLRChange( pPageLRMarginItem
->GetLeft(), nMR
- (nTmpPW
- nPW
), pPageLRMarginItem
.get() );
856 ExecuteMarginLRChange( nML
- (nTmpPW
- nPW
), pPageLRMarginItem
->GetRight(), pPageLRMarginItem
.get() );
860 const tools::Long nMT
= pPageULMarginItem
->GetUpper();
861 const tools::Long nMB
= pPageULMarginItem
->GetLower();
862 const tools::Long nTmpPH
= nMT
+ nMB
+ MINBODY
;
864 const tools::Long nPH
= pPageSizeItem
->GetSize().Height();
870 ExecuteMarginULChange( pPageULMarginItem
->GetUpper(), nMB
- ( nTmpPH
- nPH
), pPageULMarginItem
.get() );
874 ExecuteMarginULChange( nMT
- ( nTmpPH
- nPH
), pPageULMarginItem
->GetLower(), pPageULMarginItem
.get() );
879 if ( mxUndoManager
.is() )
880 mxUndoManager
->leaveUndoContext();
883 void setupSidebar(const OUString
& sidebarDeckId
= "")
885 SfxViewShell
* pViewShell
= SfxViewShell::Current();
886 SfxViewFrame
* pViewFrame
= pViewShell
? pViewShell
->GetViewFrame() : nullptr;
889 if (!pViewFrame
->GetChildWindow(SID_SIDEBAR
))
890 pViewFrame
->SetChildWindow(SID_SIDEBAR
, false /* create it */, true /* focus */);
892 pViewFrame
->ShowChildWindow(SID_SIDEBAR
, true);
894 // Force synchronous population of panels
895 SfxChildWindow
*pChild
= pViewFrame
->GetChildWindow(SID_SIDEBAR
);
899 auto pDockingWin
= dynamic_cast<sfx2::sidebar::SidebarDockingWindow
*>(pChild
->GetWindow());
903 OUString currentDeckId
= pDockingWin
->GetSidebarController()->GetCurrentDeckId();
905 // check if it is the chart deck id, if it is, don't switch to default deck
906 bool switchToDefault
= true;
908 if (currentDeckId
== "ChartDeck")
909 switchToDefault
= false;
911 if (!sidebarDeckId
.isEmpty())
913 pDockingWin
->GetSidebarController()->SwitchToDeck(sidebarDeckId
);
918 pDockingWin
->GetSidebarController()->SwitchToDefaultDeck();
921 pDockingWin
->SyncUpdate();
924 SetLastExceptionMsg("No view shell or sidebar");
929 SfxViewShell
* pViewShell
= SfxViewShell::Current();
930 SfxViewFrame
* pViewFrame
= pViewShell
? pViewShell
->GetViewFrame(): nullptr;
932 pViewFrame
->SetChildWindow(SID_SIDEBAR
, false , false );
934 SetLastExceptionMsg("No view shell or sidebar");
937 VclPtr
<Window
> getSidebarWindow()
942 SfxViewShell
* pViewShell
= SfxViewShell::Current();
943 SfxViewFrame
* pViewFrame
= pViewShell
? pViewShell
->GetViewFrame(): nullptr;
947 // really a SidebarChildWindow
948 SfxChildWindow
*pChild
= pViewFrame
->GetChildWindow(SID_SIDEBAR
);
952 // really a SidebarDockingWindow
953 vcl::Window
*pWin
= pChild
->GetWindow();
960 } // end anonymous namespace
962 // Could be anonymous in principle, but for the unit testing purposes, we
963 // declare it in init.hxx.
964 OUString
desktop::extractParameter(OUString
& rOptions
, const OUString
& rName
)
968 OUString
aNameEquals(rName
+ "=");
969 OUString
aCommaNameEquals("," + rName
+ "=");
972 if (rOptions
.startsWith(aNameEquals
))
974 size_t nLen
= aNameEquals
.getLength();
975 int nComma
= rOptions
.indexOf(",", nLen
);
978 aValue
= rOptions
.copy(nLen
, nComma
- nLen
);
979 rOptions
= rOptions
.copy(nComma
+ 1);
983 aValue
= rOptions
.copy(nLen
);
987 else if ((nIndex
= rOptions
.indexOf(aCommaNameEquals
)) >= 0)
989 size_t nLen
= aCommaNameEquals
.getLength();
990 int nComma
= rOptions
.indexOf(",", nIndex
+ nLen
);
993 aValue
= rOptions
.copy(nIndex
+ nLen
, nComma
- nIndex
- nLen
);
994 rOptions
= OUString::Concat(rOptions
.subView(0, nIndex
)) + rOptions
.subView(nComma
);
998 aValue
= rOptions
.copy(nIndex
+ nLen
);
999 rOptions
= rOptions
.copy(0, nIndex
);
1009 static void doc_destroy(LibreOfficeKitDocument
* pThis
);
1010 static int doc_saveAs(LibreOfficeKitDocument
* pThis
, const char* pUrl
, const char* pFormat
, const char* pFilterOptions
);
1011 static int doc_getDocumentType(LibreOfficeKitDocument
* pThis
);
1012 static int doc_getParts(LibreOfficeKitDocument
* pThis
);
1013 static char* doc_getPartPageRectangles(LibreOfficeKitDocument
* pThis
);
1014 static int doc_getPart(LibreOfficeKitDocument
* pThis
);
1015 static void doc_setPart(LibreOfficeKitDocument
* pThis
, int nPart
);
1016 static void doc_selectPart(LibreOfficeKitDocument
* pThis
, int nPart
, int nSelect
);
1017 static void doc_moveSelectedParts(LibreOfficeKitDocument
* pThis
, int nPosition
, bool bDuplicate
);
1018 static char* doc_getPartName(LibreOfficeKitDocument
* pThis
, int nPart
);
1019 static void doc_setPartMode(LibreOfficeKitDocument
* pThis
, int nPartMode
);
1020 static void doc_paintTile(LibreOfficeKitDocument
* pThis
,
1021 unsigned char* pBuffer
,
1022 const int nCanvasWidth
, const int nCanvasHeight
,
1023 const int nTilePosX
, const int nTilePosY
,
1024 const int nTileWidth
, const int nTileHeight
);
1026 static void doc_paintTileToCGContext(LibreOfficeKitDocument
* pThis
,
1028 const int nCanvasWidth
, const int nCanvasHeight
,
1029 const int nTilePosX
, const int nTilePosY
,
1030 const int nTileWidth
, const int nTileHeight
);
1032 static void doc_paintPartTile(LibreOfficeKitDocument
* pThis
,
1033 unsigned char* pBuffer
,
1035 const int nCanvasWidth
, const int nCanvasHeight
,
1036 const int nTilePosX
, const int nTilePosY
,
1037 const int nTileWidth
, const int nTileHeight
);
1038 static int doc_getTileMode(LibreOfficeKitDocument
* pThis
);
1039 static void doc_getDocumentSize(LibreOfficeKitDocument
* pThis
,
1042 static void doc_initializeForRendering(LibreOfficeKitDocument
* pThis
,
1043 const char* pArguments
);
1045 static void doc_registerCallback(LibreOfficeKitDocument
* pThis
,
1046 LibreOfficeKitCallback pCallback
,
1048 static void doc_postKeyEvent(LibreOfficeKitDocument
* pThis
,
1052 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument
* pThis
,
1056 static void doc_removeTextContext(LibreOfficeKitDocument
* pThis
,
1057 unsigned nLOKWindowId
,
1060 static void doc_sendDialogEvent(LibreOfficeKitDocument
* pThis
,
1061 unsigned long long int nLOKWindowId
,
1062 const char* pArguments
);
1063 static void doc_postWindowKeyEvent(LibreOfficeKitDocument
* pThis
,
1064 unsigned nLOKWindowId
,
1068 static void doc_postMouseEvent (LibreOfficeKitDocument
* pThis
,
1075 static void doc_postWindowMouseEvent (LibreOfficeKitDocument
* pThis
,
1076 unsigned nLOKWindowId
,
1083 static void doc_postWindowGestureEvent(LibreOfficeKitDocument
* pThis
,
1084 unsigned nLOKWindowId
,
1089 static void doc_postUnoCommand(LibreOfficeKitDocument
* pThis
,
1090 const char* pCommand
,
1091 const char* pArguments
,
1092 bool bNotifyWhenFinished
);
1093 static void doc_setWindowTextSelection(LibreOfficeKitDocument
* pThis
,
1094 unsigned nLOKWindowId
,
1098 static void doc_setTextSelection (LibreOfficeKitDocument
* pThis
,
1102 static char* doc_getTextSelection(LibreOfficeKitDocument
* pThis
,
1103 const char* pMimeType
,
1104 char** pUsedMimeType
);
1105 static int doc_getSelectionType(LibreOfficeKitDocument
* pThis
);
1106 static int doc_getClipboard (LibreOfficeKitDocument
* pThis
,
1107 const char **pMimeTypes
,
1109 char ***pOutMimeTypes
,
1111 char ***pOutStreams
);
1112 static int doc_setClipboard (LibreOfficeKitDocument
* pThis
,
1113 const size_t nInCount
,
1114 const char **pInMimeTypes
,
1115 const size_t *pInSizes
,
1116 const char **pInStreams
);
1117 static bool doc_paste(LibreOfficeKitDocument
* pThis
,
1118 const char* pMimeType
,
1121 static void doc_setGraphicSelection (LibreOfficeKitDocument
* pThis
,
1125 static void doc_resetSelection (LibreOfficeKitDocument
* pThis
);
1126 static char* doc_getCommandValues(LibreOfficeKitDocument
* pThis
, const char* pCommand
);
1127 static void doc_setClientZoom(LibreOfficeKitDocument
* pThis
,
1128 int nTilePixelWidth
,
1129 int nTilePixelHeight
,
1131 int nTileTwipHeight
);
1132 static void doc_setClientVisibleArea(LibreOfficeKitDocument
* pThis
, int nX
, int nY
, int nWidth
, int nHeight
);
1133 static void doc_setOutlineState(LibreOfficeKitDocument
* pThis
, bool bColumn
, int nLevel
, int nIndex
, bool bHidden
);
1134 static int doc_createView(LibreOfficeKitDocument
* pThis
);
1135 static int doc_createViewWithOptions(LibreOfficeKitDocument
* pThis
, const char* pOptions
);
1136 static void doc_destroyView(LibreOfficeKitDocument
* pThis
, int nId
);
1137 static void doc_setView(LibreOfficeKitDocument
* pThis
, int nId
);
1138 static int doc_getView(LibreOfficeKitDocument
* pThis
);
1139 static int doc_getViewsCount(LibreOfficeKitDocument
* pThis
);
1140 static bool doc_getViewIds(LibreOfficeKitDocument
* pThis
, int* pArray
, size_t nSize
);
1141 static void doc_setViewLanguage(LibreOfficeKitDocument
* pThis
, int nId
, const char* language
);
1142 static unsigned char* doc_renderFontOrientation(LibreOfficeKitDocument
* pThis
,
1143 const char *pFontName
,
1148 static unsigned char* doc_renderFont(LibreOfficeKitDocument
* pThis
,
1149 const char *pFontName
,
1153 static char* doc_getPartHash(LibreOfficeKitDocument
* pThis
, int nPart
);
1155 static void doc_paintWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
1156 const int nX
, const int nY
,
1157 const int nWidth
, const int nHeight
);
1159 static void doc_paintWindowDPI(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
1160 const int nX
, const int nY
,
1161 const int nWidth
, const int nHeight
,
1162 const double fDPIScale
);
1164 static void doc_paintWindowForView(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, unsigned char* pBuffer
,
1165 const int nX
, const int nY
,
1166 const int nWidth
, const int nHeight
,
1167 const double fDPIScale
, int viewId
);
1169 static void doc_postWindow(LibreOfficeKitDocument
* pThis
, unsigned
1170 nLOKWindowId
, int nAction
, const char* pData
);
1172 static char* doc_getPartInfo(LibreOfficeKitDocument
* pThis
, int nPart
);
1174 static bool doc_insertCertificate(LibreOfficeKitDocument
* pThis
,
1175 const unsigned char* pCertificateBinary
,
1176 const int nCertificateBinarySize
,
1177 const unsigned char* pPrivateKeyBinary
,
1178 const int nPrivateKeyBinarySize
);
1180 static bool doc_addCertificate(LibreOfficeKitDocument
* pThis
,
1181 const unsigned char* pCertificateBinary
,
1182 const int nCertificateBinarySize
);
1184 static int doc_getSignatureState(LibreOfficeKitDocument
* pThis
);
1186 static size_t doc_renderShapeSelection(LibreOfficeKitDocument
* pThis
, char** pOutput
);
1188 static void doc_resizeWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
1189 const int nWidth
, const int nHeight
);
1191 static void doc_completeFunction(LibreOfficeKitDocument
* pThis
, const char*);
1194 static void doc_sendFormFieldEvent(LibreOfficeKitDocument
* pThis
,
1195 const char* pArguments
);
1199 ITiledRenderable
* getTiledRenderable(LibreOfficeKitDocument
* pThis
)
1201 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
1202 return dynamic_cast<ITiledRenderable
*>(pDocument
->mxComponent
.get());
1208 * Unfortunately clipboard creation using UNO is insanely baroque.
1209 * we also need to ensure that this works for the first view which
1210 * has no clear 'createView' called for it (unfortunately).
1212 rtl::Reference
<LOKClipboard
> forceSetClipboardForCurrentView(LibreOfficeKitDocument
*pThis
)
1214 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
1215 rtl::Reference
<LOKClipboard
> xClip(LOKClipboardFactory::getClipboardForCurView());
1217 SAL_INFO("lok", "Set to clipboard for view " << xClip
.get());
1218 // FIXME: using a hammer here - should not be necessary if all tests used createView.
1219 pDoc
->setClipboard(uno::Reference
<datatransfer::clipboard::XClipboard
>(xClip
->getXI(), UNO_QUERY
));
1226 } // anonymous namespace
1228 LibLODocument_Impl::LibLODocument_Impl(const uno::Reference
<css::lang::XComponent
> &xComponent
, int nDocumentId
)
1229 : mxComponent(xComponent
)
1230 , mnDocumentId(nDocumentId
)
1232 assert(nDocumentId
!= -1 && "Cannot set mnDocumentId to -1");
1234 m_pDocumentClass
= gDocumentClass
.lock();
1235 if (!m_pDocumentClass
)
1237 m_pDocumentClass
= std::make_shared
<LibreOfficeKitDocumentClass
>();
1239 m_pDocumentClass
->nSize
= sizeof(LibreOfficeKitDocumentClass
);
1241 m_pDocumentClass
->destroy
= doc_destroy
;
1242 m_pDocumentClass
->saveAs
= doc_saveAs
;
1243 m_pDocumentClass
->getDocumentType
= doc_getDocumentType
;
1244 m_pDocumentClass
->getParts
= doc_getParts
;
1245 m_pDocumentClass
->getPartPageRectangles
= doc_getPartPageRectangles
;
1246 m_pDocumentClass
->getPart
= doc_getPart
;
1247 m_pDocumentClass
->setPart
= doc_setPart
;
1248 m_pDocumentClass
->selectPart
= doc_selectPart
;
1249 m_pDocumentClass
->moveSelectedParts
= doc_moveSelectedParts
;
1250 m_pDocumentClass
->getPartName
= doc_getPartName
;
1251 m_pDocumentClass
->setPartMode
= doc_setPartMode
;
1252 m_pDocumentClass
->paintTile
= doc_paintTile
;
1254 m_pDocumentClass
->paintTileToCGContext
= doc_paintTileToCGContext
;
1256 m_pDocumentClass
->paintPartTile
= doc_paintPartTile
;
1257 m_pDocumentClass
->getTileMode
= doc_getTileMode
;
1258 m_pDocumentClass
->getDocumentSize
= doc_getDocumentSize
;
1259 m_pDocumentClass
->initializeForRendering
= doc_initializeForRendering
;
1260 m_pDocumentClass
->registerCallback
= doc_registerCallback
;
1261 m_pDocumentClass
->postKeyEvent
= doc_postKeyEvent
;
1262 m_pDocumentClass
->postWindowExtTextInputEvent
= doc_postWindowExtTextInputEvent
;
1263 m_pDocumentClass
->removeTextContext
= doc_removeTextContext
;
1264 m_pDocumentClass
->postWindowKeyEvent
= doc_postWindowKeyEvent
;
1265 m_pDocumentClass
->postMouseEvent
= doc_postMouseEvent
;
1266 m_pDocumentClass
->postWindowMouseEvent
= doc_postWindowMouseEvent
;
1267 m_pDocumentClass
->sendDialogEvent
= doc_sendDialogEvent
;
1268 m_pDocumentClass
->postUnoCommand
= doc_postUnoCommand
;
1269 m_pDocumentClass
->setTextSelection
= doc_setTextSelection
;
1270 m_pDocumentClass
->setWindowTextSelection
= doc_setWindowTextSelection
;
1271 m_pDocumentClass
->getTextSelection
= doc_getTextSelection
;
1272 m_pDocumentClass
->getSelectionType
= doc_getSelectionType
;
1273 m_pDocumentClass
->getClipboard
= doc_getClipboard
;
1274 m_pDocumentClass
->setClipboard
= doc_setClipboard
;
1275 m_pDocumentClass
->paste
= doc_paste
;
1276 m_pDocumentClass
->setGraphicSelection
= doc_setGraphicSelection
;
1277 m_pDocumentClass
->resetSelection
= doc_resetSelection
;
1278 m_pDocumentClass
->getCommandValues
= doc_getCommandValues
;
1279 m_pDocumentClass
->setClientZoom
= doc_setClientZoom
;
1280 m_pDocumentClass
->setClientVisibleArea
= doc_setClientVisibleArea
;
1281 m_pDocumentClass
->setOutlineState
= doc_setOutlineState
;
1283 m_pDocumentClass
->createView
= doc_createView
;
1284 m_pDocumentClass
->destroyView
= doc_destroyView
;
1285 m_pDocumentClass
->setView
= doc_setView
;
1286 m_pDocumentClass
->getView
= doc_getView
;
1287 m_pDocumentClass
->getViewsCount
= doc_getViewsCount
;
1288 m_pDocumentClass
->getViewIds
= doc_getViewIds
;
1290 m_pDocumentClass
->renderFont
= doc_renderFont
;
1291 m_pDocumentClass
->renderFontOrientation
= doc_renderFontOrientation
;
1292 m_pDocumentClass
->getPartHash
= doc_getPartHash
;
1294 m_pDocumentClass
->paintWindow
= doc_paintWindow
;
1295 m_pDocumentClass
->paintWindowDPI
= doc_paintWindowDPI
;
1296 m_pDocumentClass
->paintWindowForView
= doc_paintWindowForView
;
1297 m_pDocumentClass
->postWindow
= doc_postWindow
;
1298 m_pDocumentClass
->resizeWindow
= doc_resizeWindow
;
1300 m_pDocumentClass
->setViewLanguage
= doc_setViewLanguage
;
1302 m_pDocumentClass
->getPartInfo
= doc_getPartInfo
;
1304 m_pDocumentClass
->insertCertificate
= doc_insertCertificate
;
1305 m_pDocumentClass
->addCertificate
= doc_addCertificate
;
1306 m_pDocumentClass
->getSignatureState
= doc_getSignatureState
;
1308 m_pDocumentClass
->renderShapeSelection
= doc_renderShapeSelection
;
1309 m_pDocumentClass
->postWindowGestureEvent
= doc_postWindowGestureEvent
;
1311 m_pDocumentClass
->createViewWithOptions
= doc_createViewWithOptions
;
1312 m_pDocumentClass
->completeFunction
= doc_completeFunction
;
1314 m_pDocumentClass
->sendFormFieldEvent
= doc_sendFormFieldEvent
;
1316 gDocumentClass
= m_pDocumentClass
;
1318 pClass
= m_pDocumentClass
.get();
1321 forceSetClipboardForCurrentView(this);
1325 LibLODocument_Impl::~LibLODocument_Impl()
1329 mxComponent
->dispose();
1331 catch (const css::lang::DisposedException
&)
1333 TOOLS_WARN_EXCEPTION("lok", "failed to dispose document");
1337 static OUString
getGenerator()
1339 OUString
sGenerator(
1340 Translate::ExpandVariables("%PRODUCTNAME %PRODUCTVERSION%PRODUCTEXTENSION (%1)"));
1341 OUString
os("$_OS");
1342 ::rtl::Bootstrap::expandMacros(os
);
1343 return sGenerator
.replaceFirst("%1", os
);
1348 CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument
* pDocument
, LibreOfficeKitCallback pCallback
, void* pData
)
1349 : Idle( "lokit timer callback" ),
1350 m_pDocument(pDocument
),
1351 m_pCallback(pCallback
),
1353 m_nDisableCallbacks(0)
1355 SetPriority(TaskPriority::POST_PAINT
);
1357 // Add the states that are safe to skip duplicates on, even when
1358 // not consequent (i.e. do no emit them if unchanged from last).
1359 m_states
.emplace(LOK_CALLBACK_TEXT_SELECTION
, "NIL");
1360 m_states
.emplace(LOK_CALLBACK_GRAPHIC_SELECTION
, "NIL");
1361 m_states
.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
, "NIL");
1362 m_states
.emplace(LOK_CALLBACK_STATE_CHANGED
, "NIL");
1363 m_states
.emplace(LOK_CALLBACK_MOUSE_POINTER
, "NIL");
1364 m_states
.emplace(LOK_CALLBACK_CELL_CURSOR
, "NIL");
1365 m_states
.emplace(LOK_CALLBACK_CELL_FORMULA
, "NIL");
1366 m_states
.emplace(LOK_CALLBACK_CELL_ADDRESS
, "NIL");
1367 m_states
.emplace(LOK_CALLBACK_CURSOR_VISIBLE
, "NIL");
1368 m_states
.emplace(LOK_CALLBACK_SET_PART
, "NIL");
1373 CallbackFlushHandler::~CallbackFlushHandler()
1378 void CallbackFlushHandler::callback(const int type
, const char* payload
, void* data
)
1380 CallbackFlushHandler
* self
= static_cast<CallbackFlushHandler
*>(data
);
1383 self
->queue(type
, payload
);
1387 void CallbackFlushHandler::queue(const int type
, const char* data
)
1389 comphelper::ProfileZone
aZone("CallbackFlushHandler::queue");
1391 CallbackData
aCallbackData(type
, (data
? data
: "(nil)"));
1392 const std::string
& payload
= aCallbackData
.PayloadString
;
1393 SAL_INFO("lok", "Queue: [" << type
<< "]: [" << payload
<< "] on " << m_queue
.size() << " entries.");
1395 bool bIsChartActive
= false;
1396 if (type
== LOK_CALLBACK_GRAPHIC_SELECTION
)
1398 LokChartHelper
aChartHelper(SfxViewShell::Current());
1399 bIsChartActive
= aChartHelper
.GetWindow() != nullptr;
1402 if (callbacksDisabled() && !bIsChartActive
)
1404 // We drop notifications when this is set, except for important ones.
1405 // When we issue a complex command (such as .uno:InsertAnnotation)
1406 // there will be multiple notifications. On the first invalidation
1407 // we will start painting, but other events will get fired
1408 // while the complex command in question executes.
1409 // We don't want to suppress everything here on the wrong assumption
1410 // that no new events are fired during painting.
1411 if (type
!= LOK_CALLBACK_STATE_CHANGED
&&
1412 type
!= LOK_CALLBACK_INVALIDATE_TILES
&&
1413 type
!= LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
1414 type
!= LOK_CALLBACK_CURSOR_VISIBLE
&&
1415 type
!= LOK_CALLBACK_VIEW_CURSOR_VISIBLE
&&
1416 type
!= LOK_CALLBACK_TEXT_SELECTION
&&
1417 type
!= LOK_CALLBACK_TEXT_SELECTION_START
&&
1418 type
!= LOK_CALLBACK_TEXT_SELECTION_END
&&
1419 type
!= LOK_CALLBACK_REFERENCE_MARKS
)
1421 SAL_INFO("lok", "Skipping while painting [" << type
<< "]: [" << payload
<< "].");
1425 // In Writer we drop all notifications during painting.
1426 if (doc_getDocumentType(m_pDocument
) == LOK_DOCTYPE_TEXT
)
1430 // Suppress invalid payloads.
1431 if (type
== LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
1432 payload
.find(", 0, 0, ") != std::string::npos
)
1434 // The cursor position is often the relative coordinates of the widget
1435 // issuing it, instead of the absolute one that we expect.
1436 // This is temporary however, and, once the control is created and initialized
1437 // correctly, it eventually emits the correct absolute coordinates.
1438 SAL_INFO("lok", "Skipping invalid event [" << type
<< "]: [" << payload
<< "].");
1442 std::unique_lock
<std::mutex
> lock(m_mutex
);
1444 // drop duplicate callbacks for the listed types
1447 case LOK_CALLBACK_TEXT_SELECTION_START
:
1448 case LOK_CALLBACK_TEXT_SELECTION_END
:
1449 case LOK_CALLBACK_TEXT_SELECTION
:
1450 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1451 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
1452 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1453 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
1454 case LOK_CALLBACK_STATE_CHANGED
:
1455 case LOK_CALLBACK_MOUSE_POINTER
:
1456 case LOK_CALLBACK_CELL_CURSOR
:
1457 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
1458 case LOK_CALLBACK_CELL_FORMULA
:
1459 case LOK_CALLBACK_CELL_ADDRESS
:
1460 case LOK_CALLBACK_CURSOR_VISIBLE
:
1461 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
1462 case LOK_CALLBACK_SET_PART
:
1463 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
1464 case LOK_CALLBACK_INVALIDATE_HEADER
:
1465 case LOK_CALLBACK_WINDOW
:
1466 case LOK_CALLBACK_CALC_FUNCTION_LIST
:
1467 case LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY
:
1469 const auto& pos
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1470 [type
] (const queue_type::value_type
& elem
) { return (elem
.Type
== type
); });
1472 if (pos
!= m_queue
.rend() && pos
->PayloadString
== payload
)
1474 SAL_INFO("lok", "Skipping queue duplicate [" << type
<< + "]: [" << payload
<< "].");
1481 if (type
== LOK_CALLBACK_TEXT_SELECTION
&& payload
.empty())
1483 const auto& posStart
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1484 [] (const queue_type::value_type
& elem
) { return (elem
.Type
== LOK_CALLBACK_TEXT_SELECTION_START
); });
1485 if (posStart
!= m_queue
.rend())
1486 posStart
->PayloadString
.clear();
1488 const auto& posEnd
= std::find_if(m_queue
.rbegin(), m_queue
.rend(),
1489 [] (const queue_type::value_type
& elem
) { return (elem
.Type
== LOK_CALLBACK_TEXT_SELECTION_END
); });
1490 if (posEnd
!= m_queue
.rend())
1491 posEnd
->PayloadString
.clear();
1494 // When payload is empty discards any previous state.
1495 if (payload
.empty())
1499 case LOK_CALLBACK_TEXT_SELECTION_START
:
1500 case LOK_CALLBACK_TEXT_SELECTION_END
:
1501 case LOK_CALLBACK_TEXT_SELECTION
:
1502 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1503 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1504 case LOK_CALLBACK_INVALIDATE_TILES
:
1506 [type
](const queue_type::value_type
& elem
) { return (elem
.Type
== type
); }))
1507 SAL_INFO("lok", "Removed dups of [" << type
<< "]: [" << payload
<< "].");
1515 // These are safe to use the latest state and ignore previous
1516 // ones (if any) since the last overrides previous ones.
1517 case LOK_CALLBACK_TEXT_SELECTION_START
:
1518 case LOK_CALLBACK_TEXT_SELECTION_END
:
1519 case LOK_CALLBACK_TEXT_SELECTION
:
1520 case LOK_CALLBACK_MOUSE_POINTER
:
1521 case LOK_CALLBACK_CELL_CURSOR
:
1522 case LOK_CALLBACK_CELL_FORMULA
:
1523 case LOK_CALLBACK_CELL_ADDRESS
:
1524 case LOK_CALLBACK_CURSOR_VISIBLE
:
1525 case LOK_CALLBACK_SET_PART
:
1526 case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
:
1527 case LOK_CALLBACK_RULER_UPDATE
:
1530 [type
](const queue_type::value_type
& elem
) { return (elem
.Type
== type
); }))
1531 SAL_INFO("lok", "Removed dups of [" << type
<< "]: [" << payload
<< "].");
1535 // These are safe to use the latest state and ignore previous
1536 // ones (if any) since the last overrides previous ones,
1537 // but only if the view is the same.
1538 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
1539 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
1540 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
1541 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1542 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
1543 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
1544 case LOK_CALLBACK_CALC_FUNCTION_LIST
:
1545 case LOK_CALLBACK_JSDIALOG
:
1547 // deleting the duplicate of visible cursor message can cause hyperlink popup not to show up on second/or more click on the same place.
1548 // If the hyperlink is not empty we can bypass that to show the popup
1549 const bool hyperLinkException
= type
== LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
&&
1550 payload
.find("\"hyperlink\":\"\"") == std::string::npos
&&
1551 payload
.find("\"hyperlink\": {}") == std::string::npos
;
1552 const int nViewId
= lcl_getViewId(payload
);
1554 [type
, nViewId
, hyperLinkException
] (const queue_type::value_type
& elem
) {
1555 return (elem
.Type
== type
&& nViewId
== lcl_getViewId(elem
) && !hyperLinkException
);
1561 case LOK_CALLBACK_INVALIDATE_TILES
:
1562 if (processInvalidateTilesEvent(aCallbackData
))
1566 // State changes with same name override previous ones with a different value.
1567 // Ex. ".uno:PageStatus=Slide 20 of 83" overwrites any previous PageStatus.
1568 case LOK_CALLBACK_STATE_CHANGED
:
1570 // Compare the state name=value and overwrite earlier entries with same name.
1571 const auto pos
= payload
.find('=');
1572 if (pos
!= std::string::npos
)
1574 const std::string name
= payload
.substr(0, pos
+ 1);
1575 // This is needed because otherwise it creates some problems when
1576 // a save occurs while a cell is still edited in Calc.
1577 if (name
!= ".uno:ModifiedStatus=")
1580 [type
, &name
] (const queue_type::value_type
& elem
) {
1581 return (elem
.Type
== type
) && (elem
.PayloadString
.compare(0, name
.size(), name
) == 0);
1589 case LOK_CALLBACK_WINDOW
:
1590 if (processWindowEvent(aCallbackData
))
1594 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1596 // remove only selection ranges and 'EMPTY' messages
1597 // always send 'INPLACE' and 'INPLACE EXIT' messages
1598 removeAll([type
, payload
] (const queue_type::value_type
& elem
)
1599 { return (elem
.Type
== type
&& elem
.PayloadString
[0] != 'I'); });
1605 // Validate that the cached data and the payload string are identical.
1606 assert(aCallbackData
.validate() && "Cached callback payload object and string mismatch!");
1607 m_queue
.emplace_back(aCallbackData
);
1608 SAL_INFO("lok", "Queued #" << (m_queue
.size() - 1) <<
1609 " [" << type
<< "]: [" << payload
<< "] to have " << m_queue
.size() << " entries.");
1613 // Dump the queue state and validate cached data.
1615 std::ostringstream oss
;
1616 if (m_queue
.empty())
1619 oss
<< m_queue
.size() << " items\n";
1620 for (const CallbackData
& c
: m_queue
)
1621 oss
<< i
++ << ": [" << c
.Type
<< "] [" << c
.PayloadString
<< "].\n";
1622 SAL_INFO("lok", "Current Queue: " << oss
.str());
1625 m_queue
.begin(), m_queue
.end(),
1626 [](const CallbackData
& c
) { return c
.validate(); }));
1637 bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData
& aCallbackData
)
1639 const std::string
& payload
= aCallbackData
.PayloadString
;
1640 const int type
= aCallbackData
.Type
;
1642 RectangleAndPart
& rcNew
= aCallbackData
.setRectangleAndPart(payload
);
1643 if (rcNew
.isEmpty())
1645 SAL_INFO("lok", "Skipping invalid event [" << type
<< "]: [" << payload
<< "].");
1649 // If we have to invalidate all tiles, we can skip any new tile invalidation.
1650 // Find the last INVALIDATE_TILES entry, if any to see if it's invalidate-all.
1652 = std::find_if(m_queue
.rbegin(), m_queue
.rend(), [](const queue_type::value_type
& elem
) {
1653 return (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
);
1655 if (pos
!= m_queue
.rend())
1657 const RectangleAndPart
& rcOld
= pos
->getRectangleAndPart();
1658 if (rcOld
.isInfinite() && (rcOld
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
))
1660 SAL_INFO("lok", "Skipping queue [" << type
<< "]: [" << payload
1661 << "] since all tiles need to be invalidated.");
1665 if (rcOld
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
)
1667 // If fully overlapping.
1668 if (rcOld
.m_aRectangle
.IsInside(rcNew
.m_aRectangle
))
1670 SAL_INFO("lok", "Skipping queue [" << type
<< "]: [" << payload
1671 << "] since overlaps existing all-parts.");
1677 if (rcNew
.isInfinite())
1679 SAL_INFO("lok", "Have Empty [" << type
<< "]: [" << payload
1680 << "] so removing all with part " << rcNew
.m_nPart
<< ".");
1681 removeAll([&rcNew
](const queue_type::value_type
& elem
) {
1682 if (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
)
1684 // Remove exiting if new is all-encompassing, or if of the same part.
1685 const RectangleAndPart rcOld
= RectangleAndPart::Create(elem
.PayloadString
);
1686 return (rcNew
.m_nPart
== -1 || rcOld
.m_nPart
== rcNew
.m_nPart
);
1695 const auto rcOrig
= rcNew
;
1697 SAL_INFO("lok", "Have [" << type
<< "]: [" << payload
<< "] so merging overlapping.");
1698 removeAll([&rcNew
](const queue_type::value_type
& elem
) {
1699 if (elem
.Type
== LOK_CALLBACK_INVALIDATE_TILES
)
1701 const RectangleAndPart
& rcOld
= elem
.getRectangleAndPart();
1702 if (rcNew
.m_nPart
!= -1 && rcOld
.m_nPart
!= -1 && rcOld
.m_nPart
!= rcNew
.m_nPart
)
1704 SAL_INFO("lok", "Nothing to merge between new: "
1705 << rcNew
.toString() << ", and old: " << rcOld
.toString());
1709 if (rcNew
.m_nPart
== -1)
1711 // Don't merge unless fully overlapped.
1712 SAL_INFO("lok", "New " << rcNew
.toString() << " has " << rcOld
.toString()
1714 if (rcNew
.m_aRectangle
.IsInside(rcOld
.m_aRectangle
))
1716 SAL_INFO("lok", "New " << rcNew
.toString() << " engulfs old "
1717 << rcOld
.toString() << ".");
1721 else if (rcOld
.m_nPart
== -1)
1723 // Don't merge unless fully overlapped.
1724 SAL_INFO("lok", "Old " << rcOld
.toString() << " has " << rcNew
.toString()
1726 if (rcOld
.m_aRectangle
.IsInside(rcNew
.m_aRectangle
))
1728 SAL_INFO("lok", "New " << rcNew
.toString() << " engulfs old "
1729 << rcOld
.toString() << ".");
1735 const tools::Rectangle rcOverlap
1736 = rcNew
.m_aRectangle
.GetIntersection(rcOld
.m_aRectangle
);
1737 const bool bOverlap
= !rcOverlap
.IsEmpty();
1738 SAL_INFO("lok", "Merging " << rcNew
.toString() << " & " << rcOld
.toString()
1739 << " => " << rcOverlap
.toString()
1740 << " Overlap: " << bOverlap
);
1743 rcNew
.m_aRectangle
.Union(rcOld
.m_aRectangle
);
1744 SAL_INFO("lok", "Merged: " << rcNew
.toString());
1754 if (rcNew
.m_aRectangle
!= rcOrig
.m_aRectangle
)
1756 SAL_INFO("lok", "Replacing: " << rcOrig
.toString() << " by " << rcNew
.toString());
1757 if (rcNew
.m_aRectangle
.GetWidth() < rcOrig
.m_aRectangle
.GetWidth()
1758 || rcNew
.m_aRectangle
.GetHeight() < rcOrig
.m_aRectangle
.GetHeight())
1760 SAL_WARN("lok", "Error: merged rect smaller.");
1765 aCallbackData
.setRectangleAndPart(rcNew
);
1770 bool CallbackFlushHandler::processWindowEvent(CallbackData
& aCallbackData
)
1772 const std::string
& payload
= aCallbackData
.PayloadString
;
1773 const int type
= aCallbackData
.Type
;
1775 boost::property_tree::ptree
& aTree
= aCallbackData
.setJson(payload
);
1776 const unsigned nLOKWindowId
= aTree
.get
<unsigned>("id", 0);
1777 const std::string aAction
= aTree
.get
<std::string
>("action", "");
1778 if (aAction
== "invalidate")
1780 std::string aRectStr
= aTree
.get
<std::string
>("rectangle", "");
1781 // no 'rectangle' field => invalidate all of the window =>
1782 // remove all previous window part invalidations
1783 if (aRectStr
.empty())
1785 removeAll([&nLOKWindowId
](const queue_type::value_type
& elem
) {
1786 if (elem
.Type
== LOK_CALLBACK_WINDOW
)
1788 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1789 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0)
1790 && aOldTree
.get
<std::string
>("action", "") == "invalidate")
1800 // if we have to invalidate all of the window, ignore
1801 // any part invalidation message
1802 const auto invAllExist
= std::any_of(m_queue
.rbegin(), m_queue
.rend(),
1803 [&nLOKWindowId
] (const queue_type::value_type
& elem
)
1805 if (elem
.Type
!= LOK_CALLBACK_WINDOW
)
1808 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1809 return nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0)
1810 && aOldTree
.get
<std::string
>("action", "") == "invalidate"
1811 && aOldTree
.get
<std::string
>("rectangle", "").empty();
1814 // we found a invalidate-all window callback
1817 SAL_INFO("lok.dialog", "Skipping queue ["
1818 << type
<< "]: [" << payload
1819 << "] since whole window needs to be invalidated.");
1823 std::istringstream
aRectStream(aRectStr
);
1824 tools::Long nLeft
, nTop
, nWidth
, nHeight
;
1826 aRectStream
>> nLeft
>> nComma
>> nTop
>> nComma
>> nWidth
>> nComma
>> nHeight
;
1827 tools::Rectangle
aNewRect(nLeft
, nTop
, nLeft
+ nWidth
, nTop
+ nHeight
);
1828 bool currentIsRedundant
= false;
1829 removeAll([&aNewRect
, &nLOKWindowId
,
1830 ¤tIsRedundant
](const queue_type::value_type
& elem
) {
1831 if (elem
.Type
!= LOK_CALLBACK_WINDOW
)
1834 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1835 if (aOldTree
.get
<std::string
>("action", "") == "invalidate")
1837 // Not possible that we encounter an empty rectangle here; we already handled this case above.
1838 std::istringstream
aOldRectStream(aOldTree
.get
<std::string
>("rectangle", ""));
1839 tools::Long nOldLeft
, nOldTop
, nOldWidth
, nOldHeight
;
1841 aOldRectStream
>> nOldLeft
>> nOldComma
>> nOldTop
>> nOldComma
>> nOldWidth
1842 >> nOldComma
>> nOldHeight
;
1843 const tools::Rectangle aOldRect
= tools::Rectangle(
1844 nOldLeft
, nOldTop
, nOldLeft
+ nOldWidth
, nOldTop
+ nOldHeight
);
1846 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
1848 if (aNewRect
== aOldRect
)
1850 SAL_INFO("lok.dialog", "Duplicate rect [" << aNewRect
.toString()
1851 << "]. Skipping new.");
1852 // We have a rectangle in the queue already that makes the current Callback useless.
1853 currentIsRedundant
= true;
1856 // new one engulfs the old one?
1857 else if (aNewRect
.IsInside(aOldRect
))
1859 SAL_INFO("lok.dialog",
1860 "New rect [" << aNewRect
.toString() << "] engulfs old ["
1861 << aOldRect
.toString() << "]. Replacing old.");
1864 // old one engulfs the new one?
1865 else if (aOldRect
.IsInside(aNewRect
))
1867 SAL_INFO("lok.dialog",
1868 "Old rect [" << aOldRect
.toString() << "] engulfs new ["
1869 << aNewRect
.toString() << "]. Skipping new.");
1870 // We have a rectangle in the queue already that makes the current Callback useless.
1871 currentIsRedundant
= true;
1876 // Overlapping rects.
1877 const tools::Rectangle aPreMergeRect
= aNewRect
;
1878 aNewRect
.Union(aOldRect
);
1879 SAL_INFO("lok.dialog", "Merging rects ["
1880 << aPreMergeRect
.toString() << "] & ["
1881 << aOldRect
.toString() << "] = ["
1882 << aNewRect
.toString()
1883 << "]. Replacing old.");
1893 // Do not enqueue if redundant.
1894 if (currentIsRedundant
)
1897 aTree
.put("rectangle", aNewRect
.toString().getStr());
1898 aCallbackData
.setJson(aTree
);
1899 assert(aCallbackData
.validate() && "Validation after setJson failed!");
1902 else if (aAction
== "created")
1904 // Remove all previous actions on same dialog, if we are creating it anew.
1905 removeAll([&nLOKWindowId
](const queue_type::value_type
& elem
) {
1906 if (elem
.Type
== LOK_CALLBACK_WINDOW
)
1908 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1909 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
1915 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
1918 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog rendering, or window not found.";
1923 auto xClip
= forceSetClipboardForCurrentView(m_pDocument
);
1925 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard(xClip
.get());
1926 pWindow
->SetClipboard(xClipboard
);
1929 else if (aAction
== "size_changed")
1931 // A size change is practically re-creation of the window.
1932 // But at a minimum it's a full invalidation.
1933 removeAll([&nLOKWindowId
](const queue_type::value_type
& elem
) {
1934 if (elem
.Type
== LOK_CALLBACK_WINDOW
)
1936 const boost::property_tree::ptree
& aOldTree
= elem
.getJson();
1937 if (nLOKWindowId
== aOldTree
.get
<unsigned>("id", 0))
1939 const std::string aOldAction
= aOldTree
.get
<std::string
>("action", "");
1940 if (aOldAction
== "invalidate")
1952 void CallbackFlushHandler::Invoke()
1954 comphelper::ProfileZone
aZone("CallbackFlushHandler::Invoke");
1959 std::scoped_lock
<std::mutex
> lock(m_mutex
);
1961 SAL_INFO("lok", "Flushing " << m_queue
.size() << " elements.");
1962 for (const auto& rCallbackData
: m_queue
)
1964 const int type
= rCallbackData
.Type
;
1965 const auto& payload
= rCallbackData
.PayloadString
;
1966 const int viewId
= lcl_isViewCallbackType(type
) ? lcl_getViewId(rCallbackData
) : -1;
1970 const auto stateIt
= m_states
.find(type
);
1971 if (stateIt
!= m_states
.end())
1973 // If the state didn't change, it's safe to ignore.
1974 if (stateIt
->second
== payload
)
1976 SAL_INFO("lok", "Skipping duplicate [" << type
<< "]: [" << payload
<< "].");
1980 stateIt
->second
= payload
;
1985 const auto statesIt
= m_viewStates
.find(viewId
);
1986 if (statesIt
!= m_viewStates
.end())
1988 auto& states
= statesIt
->second
;
1989 const auto stateIt
= states
.find(type
);
1990 if (stateIt
!= states
.end())
1992 // If the state didn't change, it's safe to ignore.
1993 if (stateIt
->second
== payload
)
1995 SAL_INFO("lok", "Skipping view duplicate [" << type
<< ',' << viewId
<< "]: [" << payload
<< "].");
1999 SAL_INFO("lok", "Replacing an element in view states [" << type
<< ',' << viewId
<< "]: [" << payload
<< "].");
2000 stateIt
->second
= payload
;
2004 SAL_INFO("lok", "Inserted a new element in view states: [" << type
<< ',' << viewId
<< "]: [" << payload
<< "]");
2005 states
.emplace(type
, payload
);
2011 m_pCallback(type
, payload
.c_str(), m_pData
);
2017 bool CallbackFlushHandler::removeAll(const std::function
<bool (const CallbackFlushHandler::queue_type::value_type
&)>& rTestFunc
)
2019 auto newEnd
= std::remove_if(m_queue
.begin(), m_queue
.end(), rTestFunc
);
2020 if (newEnd
!= m_queue
.end())
2022 m_queue
.erase(newEnd
, m_queue
.end());
2029 void CallbackFlushHandler::addViewStates(int viewId
)
2031 const auto& result
= m_viewStates
.emplace(viewId
, decltype(m_viewStates
)::mapped_type());
2032 if (!result
.second
&& result
.first
!= m_viewStates
.end())
2034 result
.first
->second
.clear();
2038 void CallbackFlushHandler::removeViewStates(int viewId
)
2040 m_viewStates
.erase(viewId
);
2044 static void doc_destroy(LibreOfficeKitDocument
*pThis
)
2046 comphelper::ProfileZone
aZone("doc_destroy");
2048 SolarMutexGuard aGuard
;
2050 LOKClipboardFactory::releaseClipboardForView(-1);
2052 LibLODocument_Impl
*pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2056 static void lo_destroy (LibreOfficeKit
* pThis
);
2057 static int lo_initialize (LibreOfficeKit
* pThis
, const char* pInstallPath
, const char* pUserProfilePath
);
2058 static LibreOfficeKitDocument
* lo_documentLoad (LibreOfficeKit
* pThis
, const char* pURL
);
2059 static char * lo_getError (LibreOfficeKit
* pThis
);
2060 static void lo_freeError (char* pFree
);
2061 static LibreOfficeKitDocument
* lo_documentLoadWithOptions (LibreOfficeKit
* pThis
,
2063 const char* pOptions
);
2064 static void lo_registerCallback (LibreOfficeKit
* pThis
,
2065 LibreOfficeKitCallback pCallback
,
2067 static char* lo_getFilterTypes(LibreOfficeKit
* pThis
);
2068 static void lo_setOptionalFeatures(LibreOfficeKit
* pThis
, unsigned long long features
);
2069 static void lo_setDocumentPassword(LibreOfficeKit
* pThis
,
2071 const char* pPassword
);
2072 static char* lo_getVersionInfo(LibreOfficeKit
* pThis
);
2073 static int lo_runMacro (LibreOfficeKit
* pThis
, const char* pURL
);
2075 static bool lo_signDocument(LibreOfficeKit
* pThis
,
2077 const unsigned char* pCertificateBinary
,
2078 const int nCertificateBinarySize
,
2079 const unsigned char* pPrivateKeyBinary
,
2080 const int nPrivateKeyBinarySize
);
2082 static void lo_runLoop(LibreOfficeKit
* pThis
,
2083 LibreOfficeKitPollCallback pPollCallback
,
2084 LibreOfficeKitWakeCallback pWakeCallback
,
2087 LibLibreOffice_Impl::LibLibreOffice_Impl()
2088 : m_pOfficeClass( gOfficeClass
.lock() )
2090 , mpCallback(nullptr)
2091 , mpCallbackData(nullptr)
2092 , mOptionalFeatures(0)
2094 if(!m_pOfficeClass
) {
2095 m_pOfficeClass
= std::make_shared
<LibreOfficeKitClass
>();
2096 m_pOfficeClass
->nSize
= sizeof(LibreOfficeKitClass
);
2098 m_pOfficeClass
->destroy
= lo_destroy
;
2099 m_pOfficeClass
->documentLoad
= lo_documentLoad
;
2100 m_pOfficeClass
->getError
= lo_getError
;
2101 m_pOfficeClass
->freeError
= lo_freeError
;
2102 m_pOfficeClass
->documentLoadWithOptions
= lo_documentLoadWithOptions
;
2103 m_pOfficeClass
->registerCallback
= lo_registerCallback
;
2104 m_pOfficeClass
->getFilterTypes
= lo_getFilterTypes
;
2105 m_pOfficeClass
->setOptionalFeatures
= lo_setOptionalFeatures
;
2106 m_pOfficeClass
->setDocumentPassword
= lo_setDocumentPassword
;
2107 m_pOfficeClass
->getVersionInfo
= lo_getVersionInfo
;
2108 m_pOfficeClass
->runMacro
= lo_runMacro
;
2109 m_pOfficeClass
->signDocument
= lo_signDocument
;
2110 m_pOfficeClass
->runLoop
= lo_runLoop
;
2112 gOfficeClass
= m_pOfficeClass
;
2115 pClass
= m_pOfficeClass
.get();
2118 LibLibreOffice_Impl::~LibLibreOffice_Impl()
2126 void paintTileToCGContext(ITiledRenderable
* pDocument
,
2127 void* rCGContext
, const Size nCanvasSize
,
2128 const int nTilePosX
, const int nTilePosY
,
2129 const int nTileWidth
, const int nTileHeight
)
2131 SystemGraphicsData aData
;
2132 aData
.rCGContext
= reinterpret_cast<CGContextRef
>(rCGContext
);
2134 ScopedVclPtrInstance
<VirtualDevice
> pDevice(aData
, Size(1, 1), DeviceFormat::DEFAULT
);
2135 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
2136 pDevice
->SetOutputSizePixel(nCanvasSize
);
2137 pDocument
->paintTile(*pDevice
, nCanvasSize
.Width(), nCanvasSize
.Height(),
2138 nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2141 void paintTileIOS(LibreOfficeKitDocument
* pThis
,
2142 unsigned char* pBuffer
,
2143 const int nCanvasWidth
, const int nCanvasHeight
, const double fDPIScale
,
2144 const int nTilePosX
, const int nTilePosY
,
2145 const int nTileWidth
, const int nTileHeight
)
2147 CGContextRef pCGContext
= CGBitmapContextCreate(pBuffer
, nCanvasWidth
, nCanvasHeight
, 8,
2148 nCanvasWidth
* 4, CGColorSpaceCreateDeviceRGB(),
2149 kCGImageAlphaPremultipliedFirst
| kCGImageByteOrder32Little
);
2151 CGContextTranslateCTM(pCGContext
, 0, nCanvasHeight
);
2152 CGContextScaleCTM(pCGContext
, fDPIScale
, -fDPIScale
);
2154 doc_paintTileToCGContext(pThis
, (void*) pCGContext
, nCanvasWidth
, nCanvasHeight
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
2156 CGContextRelease(pCGContext
);
2160 void setLanguageAndLocale(OUString
const & aLangISO
)
2162 SvtSysLocaleOptions aLocalOptions
;
2163 aLocalOptions
.SetLocaleConfigString(aLangISO
);
2164 aLocalOptions
.SetUILocaleConfigString(aLangISO
);
2165 aLocalOptions
.Commit();
2168 void setFormatSpecificFilterData(OUString
const & sFormat
, comphelper::SequenceAsHashMap
& rFilterDataMap
)
2170 if (sFormat
== "pdf")
2172 // always export bookmarks, which is needed for annotations
2173 rFilterDataMap
["ExportBookmarks"] <<= true;
2177 } // anonymous namespace
2179 // Wonder global state ...
2180 static uno::Reference
<css::uno::XComponentContext
> xContext
;
2181 static uno::Reference
<css::lang::XMultiServiceFactory
> xSFactory
;
2182 static uno::Reference
<css::lang::XMultiComponentFactory
> xFactory
;
2184 static LibreOfficeKitDocument
* lo_documentLoad(LibreOfficeKit
* pThis
, const char* pURL
)
2186 return lo_documentLoadWithOptions(pThis
, pURL
, nullptr);
2189 static LibreOfficeKitDocument
* lo_documentLoadWithOptions(LibreOfficeKit
* pThis
, const char* pURL
, const char* pOptions
)
2191 comphelper::ProfileZone
aZone("lo_documentLoadWithOptions");
2193 SolarMutexGuard aGuard
;
2195 static int nDocumentIdCounter
= 0;
2197 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
2198 pLib
->maLastExceptionMsg
.clear();
2200 const OUString
aURL(getAbsoluteURL(pURL
));
2203 pLib
->maLastExceptionMsg
= "Filename to load was not provided.";
2204 SAL_INFO("lok", "URL for load is empty");
2208 pLib
->maLastExceptionMsg
.clear();
2212 pLib
->maLastExceptionMsg
= "ComponentContext is not available";
2213 SAL_INFO("lok", "ComponentContext is not available");
2217 uno::Reference
<frame::XDesktop2
> xComponentLoader
= frame::Desktop::create(xContext
);
2219 if (!xComponentLoader
.is())
2221 pLib
->maLastExceptionMsg
= "ComponentLoader is not available";
2222 SAL_INFO("lok", "ComponentLoader is not available");
2228 // 'Language=...' is an option that LOK consumes by itself, and does
2229 // not pass it as a parameter to the filter
2230 OUString aOptions
= getUString(pOptions
);
2231 const OUString aLanguage
= extractParameter(aOptions
, "Language");
2232 bool isValidLangTag
= LanguageTag::isValidBcp47(aLanguage
, nullptr);
2234 if (!aLanguage
.isEmpty() && isValidLangTag
)
2236 SfxLokHelper::setDefaultLanguage(aLanguage
);
2237 // Set the LOK language tag, used for dialog tunneling.
2238 comphelper::LibreOfficeKit::setLanguageTag(LanguageTag(aLanguage
));
2239 comphelper::LibreOfficeKit::setLocale(LanguageTag(aLanguage
));
2241 SAL_INFO("lok", "Set document language to " << aLanguage
);
2242 // use with care - it sets it for the entire core, not just the
2244 setLanguageAndLocale(aLanguage
);
2245 // Need to reset the static initialized values
2246 SvNumberFormatter::resetTheCurrencyTable();
2249 const OUString aDeviceFormFactor
= extractParameter(aOptions
, "DeviceFormFactor");
2250 SfxLokHelper::setDeviceFormFactor(aDeviceFormFactor
);
2252 uno::Sequence
<css::beans::PropertyValue
> aFilterOptions(2);
2253 aFilterOptions
[0] = css::beans::PropertyValue( "FilterOptions",
2255 uno::makeAny(aOptions
),
2256 beans::PropertyState_DIRECT_VALUE
);
2258 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
2259 new LOKInteractionHandler("load", pLib
));
2260 auto const pair(pLib
->mInteractionMap
.insert(std::make_pair(aURL
.toUtf8(), pInteraction
)));
2261 comphelper::ScopeGuard
const g([&] () {
2264 pLib
->mInteractionMap
.erase(aURL
.toUtf8());
2267 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
2268 aFilterOptions
[1].Name
= "InteractionHandler";
2269 aFilterOptions
[1].Value
<<= xInteraction
;
2272 sal_Int16 nMacroExecMode = document::MacroExecMode::USE_CONFIG;
2273 aFilterOptions[2].Name = "MacroExecutionMode";
2274 aFilterOptions[2].Value <<= nMacroExecMode;
2276 sal_Int16 nUpdateDoc = document::UpdateDocMode::ACCORDING_TO_CONFIG;
2277 aFilterOptions[3].Name = "UpdateDocMode";
2278 aFilterOptions[3].Value <<= nUpdateDoc;
2281 const int nThisDocumentId
= nDocumentIdCounter
++;
2282 SfxViewShell::SetCurrentDocId(ViewShellDocId(nThisDocumentId
));
2283 uno::Reference
<lang::XComponent
> xComponent
= xComponentLoader
->loadComponentFromURL(
2287 assert(!xComponent
.is() || pair
.second
); // concurrent loading of same URL ought to fail
2289 if (!xComponent
.is())
2291 pLib
->maLastExceptionMsg
= "loadComponentFromURL returned an empty reference";
2292 SAL_INFO("lok", "Document can't be loaded - " << pLib
->maLastExceptionMsg
);
2296 LibLODocument_Impl
* pDocument
= new LibLODocument_Impl(xComponent
, nThisDocumentId
);
2298 // After loading the document, its initial view is the "current" view.
2299 if (pLib
->mpCallback
)
2301 int nState
= doc_getSignatureState(pDocument
);
2302 pLib
->mpCallback(LOK_CALLBACK_SIGNATURE_STATUS
, OString::number(nState
).getStr(), pLib
->mpCallbackData
);
2306 catch (const uno::Exception
& exception
)
2308 pLib
->maLastExceptionMsg
= exception
.Message
;
2309 TOOLS_INFO_EXCEPTION("lok", "Document can't be loaded");
2315 static int lo_runMacro(LibreOfficeKit
* pThis
, const char *pURL
)
2317 comphelper::ProfileZone
aZone("lo_runMacro");
2319 SolarMutexGuard aGuard
;
2321 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
2322 pLib
->maLastExceptionMsg
.clear();
2324 OUString
sURL( pURL
, strlen(pURL
), RTL_TEXTENCODING_UTF8
);
2327 pLib
->maLastExceptionMsg
= "Macro to run was not provided.";
2328 SAL_INFO("lok", "Macro URL is empty");
2332 if (!sURL
.startsWith("macro://"))
2334 pLib
->maLastExceptionMsg
= "This doesn't look like macro URL";
2335 SAL_INFO("lok", "Macro URL is invalid");
2339 pLib
->maLastExceptionMsg
.clear();
2343 pLib
->maLastExceptionMsg
= "ComponentContext is not available";
2344 SAL_INFO("lok", "ComponentContext is not available");
2349 aURL
.Complete
= sURL
;
2351 uno::Reference
< util::XURLTransformer
> xParser( util::URLTransformer::create( xContext
) );
2354 xParser
->parseStrict( aURL
);
2356 uno::Reference
<frame::XDesktop2
> xComponentLoader
= frame::Desktop::create(xContext
);
2358 if (!xComponentLoader
.is())
2360 pLib
->maLastExceptionMsg
= "ComponentLoader is not available";
2361 SAL_INFO("lok", "ComponentLoader is not available");
2365 xFactory
= xContext
->getServiceManager();
2369 uno::Reference
<frame::XDispatchProvider
> xDP
;
2370 xSFactory
.set(xFactory
, uno::UNO_QUERY_THROW
);
2371 xDP
.set( xSFactory
->createInstance("com.sun.star.comp.sfx2.SfxMacroLoader"), uno::UNO_QUERY
);
2372 uno::Reference
<frame::XDispatch
> xD
= xDP
->queryDispatch( aURL
, OUString(), 0);
2376 pLib
->maLastExceptionMsg
= "Macro loader is not available";
2377 SAL_INFO("lok", "Macro loader is not available");
2381 uno::Reference
< frame::XSynchronousDispatch
> xSyncDisp( xD
, uno::UNO_QUERY_THROW
);
2382 uno::Sequence
<css::beans::PropertyValue
> aEmpty
;
2383 css::beans::PropertyValue aErr
;
2384 uno::Any aRet
= xSyncDisp
->dispatchWithReturnValue( aURL
, aEmpty
);
2387 if (aErr
.Name
== "ErrorCode")
2389 sal_uInt32 nErrCode
= 0; // ERRCODE_NONE
2390 aErr
.Value
>>= nErrCode
;
2392 pLib
->maLastExceptionMsg
= "An error occurred running macro (error code: " + OUString::number( nErrCode
) + ")";
2393 SAL_INFO("lok", "Macro execution terminated with error code " << nErrCode
);
2404 static bool lo_signDocument(LibreOfficeKit
* /*pThis*/,
2406 const unsigned char* pCertificateBinary
,
2407 const int nCertificateBinarySize
,
2408 const unsigned char* pPrivateKeyBinary
,
2409 const int nPrivateKeyBinarySize
)
2411 comphelper::ProfileZone
aZone("lo_signDocument");
2413 OUString
aURL(getAbsoluteURL(pURL
));
2420 uno::Sequence
<sal_Int8
> aCertificateSequence
;
2422 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
2423 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
2424 if (!aCertificateBase64String
.empty())
2426 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
2427 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
2431 aCertificateSequence
.realloc(nCertificateBinarySize
);
2432 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
2435 uno::Sequence
<sal_Int8
> aPrivateKeySequence
;
2436 std::string
aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary
), nPrivateKeyBinarySize
);
2437 std::string aPrivateKeyBase64String
= extractPrivateKey(aPrivateKeyString
);
2438 if (!aPrivateKeyBase64String
.empty())
2440 OUString aBase64OUString
= OUString::createFromAscii(aPrivateKeyBase64String
.c_str());
2441 comphelper::Base64::decode(aPrivateKeySequence
, aBase64OUString
);
2445 aPrivateKeySequence
.realloc(nPrivateKeyBinarySize
);
2446 std::copy(pPrivateKeyBinary
, pPrivateKeyBinary
+ nPrivateKeyBinarySize
, aPrivateKeySequence
.begin());
2449 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
2450 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
2451 if (!xSecurityContext
.is())
2454 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
2455 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
2457 if (!xCertificateCreator
.is())
2460 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->createDERCertificateWithPrivateKey(aCertificateSequence
, aPrivateKeySequence
);
2462 if (!xCertificate
.is())
2465 sfx2::DocumentSigner
aDocumentSigner(aURL
);
2466 if (!aDocumentSigner
.signDocument(xCertificate
))
2472 static void lo_registerCallback (LibreOfficeKit
* pThis
,
2473 LibreOfficeKitCallback pCallback
,
2476 SolarMutexGuard aGuard
;
2478 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
2479 pLib
->maLastExceptionMsg
.clear();
2481 pLib
->mpCallback
= pCallback
;
2482 pLib
->mpCallbackData
= pData
;
2485 static int doc_saveAs(LibreOfficeKitDocument
* pThis
, const char* sUrl
, const char* pFormat
, const char* pFilterOptions
)
2487 comphelper::ProfileZone
aZone("doc_saveAs");
2489 SolarMutexGuard aGuard
;
2490 SetLastExceptionMsg();
2492 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2494 OUString sFormat
= getUString(pFormat
);
2495 OUString
aURL(getAbsoluteURL(sUrl
));
2497 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
2501 SetLastExceptionMsg("Filename to save to was not provided.");
2502 SAL_INFO("lok", "URL for save is empty");
2508 const ExtensionMap
* pMap
;
2510 switch (doc_getDocumentType(pThis
))
2512 case LOK_DOCTYPE_SPREADSHEET
:
2513 pMap
= aCalcExtensionMap
;
2515 case LOK_DOCTYPE_PRESENTATION
:
2516 pMap
= aImpressExtensionMap
;
2518 case LOK_DOCTYPE_DRAWING
:
2519 pMap
= aDrawExtensionMap
;
2521 case LOK_DOCTYPE_TEXT
:
2522 pMap
= aWriterExtensionMap
;
2524 case LOK_DOCTYPE_OTHER
:
2526 SAL_INFO("lok", "Can't save document - unsupported document type.");
2530 if (pFormat
== nullptr)
2532 // sniff from the extension
2533 sal_Int32 idx
= aURL
.lastIndexOf(".");
2536 sFormat
= aURL
.copy( idx
+ 1 );
2540 SetLastExceptionMsg("input filename without a suffix");
2545 OUString aFilterName
;
2546 for (sal_Int32 i
= 0; pMap
[i
].extn
; ++i
)
2548 if (sFormat
.equalsIgnoreAsciiCaseAscii(pMap
[i
].extn
))
2550 aFilterName
= getUString(pMap
[i
].filterName
);
2554 if (aFilterName
.isEmpty())
2556 SetLastExceptionMsg("no output filter found for provided suffix");
2560 OUString aFilterOptions
= getUString(pFilterOptions
);
2562 // Check if watermark for pdf is passed by filteroptions...
2563 // It is not a real filter option so it must be filtered out.
2564 OUString watermarkText
, sFullSheetPreview
;
2566 if ((aIndex
= aFilterOptions
.indexOf(",Watermark=")) >= 0)
2568 int bIndex
= aFilterOptions
.indexOf("WATERMARKEND");
2569 watermarkText
= aFilterOptions
.subView(aIndex
+11, bIndex
-(aIndex
+11));
2570 aFilterOptions
= OUString::Concat(aFilterOptions
.subView(0, aIndex
)) + aFilterOptions
.subView(bIndex
+12);
2573 if ((aIndex
= aFilterOptions
.indexOf(",FullSheetPreview=")) >= 0)
2575 int bIndex
= aFilterOptions
.indexOf("FULLSHEETPREVEND");
2576 sFullSheetPreview
= aFilterOptions
.subView(aIndex
+18, bIndex
-(aIndex
+18));
2577 aFilterOptions
= OUString::Concat(aFilterOptions
.subView(0, aIndex
)) + aFilterOptions
.subView(bIndex
+16);
2580 bool bFullSheetPreview
= sFullSheetPreview
== "true";
2582 // 'TakeOwnership' == this is a 'real' SaveAs (that is, the document
2583 // gets a new name). When this is not provided, the meaning of
2584 // saveAs() is more like save-a-copy, which allows saving to any
2585 // random format like PDF or PNG.
2586 // It is not a real filter option, so we have to filter it out.
2587 const uno::Sequence
<OUString
> aOptionSeq
= comphelper::string::convertCommaSeparated(aFilterOptions
);
2588 std::vector
<OUString
> aFilteredOptionVec
;
2589 bool bTakeOwnership
= false;
2590 MediaDescriptor aSaveMediaDescriptor
;
2591 for (const auto& rOption
: aOptionSeq
)
2593 if (rOption
== "TakeOwnership")
2594 bTakeOwnership
= true;
2595 else if (rOption
== "NoFileSync")
2596 aSaveMediaDescriptor
["NoFileSync"] <<= true;
2598 aFilteredOptionVec
.push_back(rOption
);
2601 aSaveMediaDescriptor
["Overwrite"] <<= true;
2602 aSaveMediaDescriptor
["FilterName"] <<= aFilterName
;
2604 auto aFilteredOptionSeq
= comphelper::containerToSequence
<OUString
>(aFilteredOptionVec
);
2605 aFilterOptions
= comphelper::string::convertCommaSeparated(aFilteredOptionSeq
);
2606 aSaveMediaDescriptor
[MediaDescriptor::PROP_FILTEROPTIONS()] <<= aFilterOptions
;
2608 comphelper::SequenceAsHashMap aFilterDataMap
;
2610 setFormatSpecificFilterData(sFormat
, aFilterDataMap
);
2612 if (!watermarkText
.isEmpty())
2613 aFilterDataMap
["TiledWatermark"] <<= watermarkText
;
2615 if (bFullSheetPreview
)
2616 aFilterDataMap
["SinglePageSheets"] <<= true;
2618 if (!aFilterDataMap
.empty())
2620 aSaveMediaDescriptor
["FilterData"] <<= aFilterDataMap
.getAsConstPropertyValueList();
2623 // add interaction handler too
2626 // gImpl does not have to exist when running from a unit test
2627 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
2628 new LOKInteractionHandler("saveas", gImpl
, pDocument
));
2629 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
2631 aSaveMediaDescriptor
[MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= xInteraction
;
2636 xStorable
->storeAsURL(aURL
, aSaveMediaDescriptor
.getAsConstPropertyValueList());
2638 xStorable
->storeToURL(aURL
, aSaveMediaDescriptor
.getAsConstPropertyValueList());
2642 catch (const uno::Exception
& exception
)
2644 SetLastExceptionMsg("exception: " + exception
.Message
);
2650 * Initialize UNO commands, in the sense that from now on, the LOK client gets updates for status
2651 * changes of these commands. This is necessary, because (unlike in the desktop case) there are no
2652 * toolbars hosting widgets these UNO commands, so no such status updates would be sent to the
2653 * headless LOK clients out of the box.
2655 static void doc_iniUnoCommands ()
2657 SolarMutexGuard aGuard
;
2658 SetLastExceptionMsg();
2660 OUString sUnoCommands
[] =
2662 OUString(".uno:AlignLeft"),
2663 OUString(".uno:AlignHorizontalCenter"),
2664 OUString(".uno:AlignRight"),
2665 OUString(".uno:BackColor"),
2666 OUString(".uno:BackgroundColor"),
2667 OUString(".uno:TableCellBackgroundColor"),
2668 OUString(".uno:Bold"),
2669 OUString(".uno:CenterPara"),
2670 OUString(".uno:CharBackColor"),
2671 OUString(".uno:CharBackgroundExt"),
2672 OUString(".uno:CharFontName"),
2673 OUString(".uno:Color"),
2674 OUString(".uno:ControlCodes"),
2675 OUString(".uno:DecrementIndent"),
2676 OUString(".uno:DefaultBullet"),
2677 OUString(".uno:DefaultNumbering"),
2678 OUString(".uno:FontColor"),
2679 OUString(".uno:FontHeight"),
2680 OUString(".uno:IncrementIndent"),
2681 OUString(".uno:Italic"),
2682 OUString(".uno:JustifyPara"),
2683 OUString(".uno:OutlineFont"),
2684 OUString(".uno:LeftPara"),
2685 OUString(".uno:LanguageStatus"),
2686 OUString(".uno:RightPara"),
2687 OUString(".uno:Shadowed"),
2688 OUString(".uno:SubScript"),
2689 OUString(".uno:SuperScript"),
2690 OUString(".uno:Strikeout"),
2691 OUString(".uno:StyleApply"),
2692 OUString(".uno:Underline"),
2693 OUString(".uno:ModifiedStatus"),
2694 OUString(".uno:Undo"),
2695 OUString(".uno:Redo"),
2696 OUString(".uno:InsertPage"),
2697 OUString(".uno:DeletePage"),
2698 OUString(".uno:DuplicatePage"),
2699 OUString(".uno:Cut"),
2700 OUString(".uno:Copy"),
2701 OUString(".uno:Paste"),
2702 OUString(".uno:SelectAll"),
2703 OUString(".uno:InsertAnnotation"),
2704 OUString(".uno:DeleteAnnotation"),
2705 OUString(".uno:ReplyComment"),
2706 OUString(".uno:ResolveComment"),
2707 OUString(".uno:ResolveCommentThread"),
2708 OUString(".uno:InsertRowsBefore"),
2709 OUString(".uno:InsertRowsAfter"),
2710 OUString(".uno:InsertColumnsBefore"),
2711 OUString(".uno:InsertColumnsAfter"),
2712 OUString(".uno:MergeCells"),
2713 OUString(".uno:DeleteRows"),
2714 OUString(".uno:DeleteColumns"),
2715 OUString(".uno:DeleteTable"),
2716 OUString(".uno:SelectTable"),
2717 OUString(".uno:EntireRow"),
2718 OUString(".uno:EntireColumn"),
2719 OUString(".uno:EntireCell"),
2720 OUString(".uno:AssignLayout"),
2721 OUString(".uno:StatusDocPos"),
2722 OUString(".uno:RowColSelCount"),
2723 OUString(".uno:StatusPageStyle"),
2724 OUString(".uno:InsertMode"),
2725 OUString(".uno:SpellOnline"),
2726 OUString(".uno:StatusSelectionMode"),
2727 OUString(".uno:StateTableCell"),
2728 OUString(".uno:StatusBarFunc"),
2729 OUString(".uno:StatePageNumber"),
2730 OUString(".uno:StateWordCount"),
2731 OUString(".uno:SelectionMode"),
2732 OUString(".uno:PageStatus"),
2733 OUString(".uno:LayoutStatus"),
2734 OUString(".uno:Context"),
2735 OUString(".uno:WrapText"),
2736 OUString(".uno:ToggleMergeCells"),
2737 OUString(".uno:NumberFormatCurrency"),
2738 OUString(".uno:NumberFormatPercent"),
2739 OUString(".uno:NumberFormatDecimal"),
2740 OUString(".uno:NumberFormatDate"),
2741 OUString(".uno:FrameLineColor"),
2742 OUString(".uno:SortAscending"),
2743 OUString(".uno:SortDescending"),
2744 OUString(".uno:TrackChanges"),
2745 OUString(".uno:ShowTrackedChanges"),
2746 OUString(".uno:NextTrackedChange"),
2747 OUString(".uno:PreviousTrackedChange"),
2748 OUString(".uno:AcceptAllTrackedChanges"),
2749 OUString(".uno:RejectAllTrackedChanges"),
2750 OUString(".uno:TableDialog"),
2751 OUString(".uno:FormatCellDialog"),
2752 OUString(".uno:FontDialog"),
2753 OUString(".uno:ParagraphDialog"),
2754 OUString(".uno:OutlineBullet"),
2755 OUString(".uno:InsertIndexesEntry"),
2756 OUString(".uno:DocumentRepair"),
2757 OUString(".uno:TransformDialog"),
2758 OUString(".uno:InsertPageHeader"),
2759 OUString(".uno:InsertPageFooter"),
2760 OUString(".uno:OnlineAutoFormat"),
2761 OUString(".uno:InsertObjectChart"),
2762 OUString(".uno:InsertSection"),
2763 OUString(".uno:InsertAnnotation"),
2764 OUString(".uno:InsertPagebreak"),
2765 OUString(".uno:InsertColumnBreak"),
2766 OUString(".uno:HyperlinkDialog"),
2767 OUString(".uno:InsertSymbol"),
2768 OUString(".uno:EditRegion"),
2769 OUString(".uno:ThesaurusDialog"),
2770 OUString(".uno:FormatArea"),
2771 OUString(".uno:FormatLine"),
2772 OUString(".uno:FormatColumns"),
2773 OUString(".uno:Watermark"),
2774 OUString(".uno:ResetAttributes"),
2775 OUString(".uno:Orientation"),
2776 OUString(".uno:ObjectAlignLeft"),
2777 OUString(".uno:ObjectAlignRight"),
2778 OUString(".uno:AlignCenter"),
2779 OUString(".uno:TransformPosX"),
2780 OUString(".uno:TransformPosY"),
2781 OUString(".uno:TransformWidth"),
2782 OUString(".uno:TransformHeight"),
2783 OUString(".uno:ObjectBackOne"),
2784 OUString(".uno:SendToBack"),
2785 OUString(".uno:ObjectForwardOne"),
2786 OUString(".uno:BringToFront"),
2787 OUString(".uno:WrapRight"),
2788 OUString(".uno:WrapThrough"),
2789 OUString(".uno:WrapLeft"),
2790 OUString(".uno:WrapIdeal"),
2791 OUString(".uno:WrapOn"),
2792 OUString(".uno:WrapOff"),
2793 OUString(".uno:UpdateCurIndex"),
2794 OUString(".uno:InsertCaptionDialog"),
2795 OUString(".uno:FormatGroup"),
2796 OUString(".uno:SplitTable"),
2797 OUString(".uno:MergeCells"),
2798 OUString(".uno:DeleteNote"),
2799 OUString(".uno:AcceptChanges"),
2800 OUString(".uno:FormatPaintbrush"),
2801 OUString(".uno:SetDefault"),
2802 OUString(".uno:ParaLeftToRight"),
2803 OUString(".uno:ParaRightToLeft"),
2804 OUString(".uno:ParaspaceIncrease"),
2805 OUString(".uno:ParaspaceDecrease"),
2806 OUString(".uno:AcceptTrackedChange"),
2807 OUString(".uno:RejectTrackedChange"),
2808 OUString(".uno:ShowResolvedAnnotations"),
2809 OUString(".uno:InsertBreak"),
2810 OUString(".uno:InsertEndnote"),
2811 OUString(".uno:InsertFootnote"),
2812 OUString(".uno:InsertReferenceField"),
2813 OUString(".uno:InsertBookmark"),
2814 OUString(".uno:InsertAuthoritiesEntry"),
2815 OUString(".uno:InsertMultiIndex"),
2816 OUString(".uno:InsertField"),
2817 OUString(".uno:InsertPageNumberField"),
2818 OUString(".uno:InsertPageCountField"),
2819 OUString(".uno:InsertDateField"),
2820 OUString(".uno:InsertTitleField"),
2821 OUString(".uno:InsertFieldCtrl"),
2822 OUString(".uno:CharmapControl"),
2823 OUString(".uno:EnterGroup"),
2824 OUString(".uno:LeaveGroup"),
2825 OUString(".uno:AlignUp"),
2826 OUString(".uno:AlignMiddle"),
2827 OUString(".uno:AlignDown"),
2828 OUString(".uno:TraceChangeMode"),
2829 OUString(".uno:Combine"),
2830 OUString(".uno:Merge"),
2831 OUString(".uno:Dismantle"),
2832 OUString(".uno:Substract"),
2833 OUString(".uno:DistributeSelection"),
2834 OUString(".uno:Intersect"),
2835 OUString(".uno:BorderInner"),
2836 OUString(".uno:BorderOuter"),
2837 OUString(".uno:FreezePanes"),
2838 OUString(".uno:FreezePanesColumn"),
2839 OUString(".uno:FreezePanesRow"),
2840 OUString(".uno:Sidebar")
2843 util::URL aCommandURL
;
2844 SfxViewShell
* pViewShell
= SfxViewShell::Current();
2845 SfxViewFrame
* pViewFrame
= pViewShell
? pViewShell
->GetViewFrame(): nullptr;
2847 // check if Frame-Controller were created.
2850 SAL_WARN("lok", "iniUnoCommands: No Frame-Controller created.");
2855 xContext
= comphelper::getProcessComponentContext();
2858 SAL_WARN("lok", "iniUnoCommands: Component context is not available");
2862 SfxSlotPool
& rSlotPool
= SfxSlotPool::GetSlotPool(pViewFrame
);
2863 uno::Reference
<util::XURLTransformer
> xParser(util::URLTransformer::create(xContext
));
2865 for (const auto & sUnoCommand
: sUnoCommands
)
2867 aCommandURL
.Complete
= sUnoCommand
;
2868 xParser
->parseStrict(aCommandURL
);
2870 // when null, this command is not supported by the given component
2871 // (like eg. Calc does not have ".uno:DefaultBullet" etc.)
2872 if (const SfxSlot
* pSlot
= rSlotPool
.GetUnoSlot(aCommandURL
.Path
))
2874 // Initialize slot to dispatch .uno: Command.
2875 pViewFrame
->GetBindings().GetDispatch(pSlot
, aCommandURL
, false);
2880 static int doc_getDocumentType (LibreOfficeKitDocument
* pThis
)
2882 comphelper::ProfileZone
aZone("doc_getDocumentType");
2884 SolarMutexGuard aGuard
;
2885 SetLastExceptionMsg();
2887 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
2891 uno::Reference
<lang::XServiceInfo
> xDocument(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
2893 if (xDocument
->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
2895 return LOK_DOCTYPE_SPREADSHEET
;
2897 else if (xDocument
->supportsService("com.sun.star.presentation.PresentationDocument"))
2899 return LOK_DOCTYPE_PRESENTATION
;
2901 else if (xDocument
->supportsService("com.sun.star.drawing.DrawingDocument"))
2903 return LOK_DOCTYPE_DRAWING
;
2905 else if (xDocument
->supportsService("com.sun.star.text.TextDocument") || xDocument
->supportsService("com.sun.star.text.WebDocument"))
2907 return LOK_DOCTYPE_TEXT
;
2911 SetLastExceptionMsg("unknown document type");
2914 catch (const uno::Exception
& exception
)
2916 SetLastExceptionMsg("exception: " + exception
.Message
);
2918 return LOK_DOCTYPE_OTHER
;
2921 static int doc_getParts (LibreOfficeKitDocument
* pThis
)
2923 comphelper::ProfileZone
aZone("doc_getParts");
2925 SolarMutexGuard aGuard
;
2927 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2930 SetLastExceptionMsg("Document doesn't support tiled rendering");
2934 return pDoc
->getParts();
2937 static int doc_getPart (LibreOfficeKitDocument
* pThis
)
2939 comphelper::ProfileZone
aZone("doc_getPart");
2941 SolarMutexGuard aGuard
;
2942 SetLastExceptionMsg();
2944 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2947 SetLastExceptionMsg("Document doesn't support tiled rendering");
2951 return pDoc
->getPart();
2954 static void doc_setPart(LibreOfficeKitDocument
* pThis
, int nPart
)
2956 comphelper::ProfileZone
aZone("doc_setPart");
2958 SolarMutexGuard aGuard
;
2959 SetLastExceptionMsg();
2961 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2964 SetLastExceptionMsg("Document doesn't support tiled rendering");
2968 pDoc
->setPart( nPart
);
2971 static char* doc_getPartInfo(LibreOfficeKitDocument
* pThis
, int nPart
)
2973 comphelper::ProfileZone
aZone("doc_getPartInfo");
2975 SolarMutexGuard aGuard
;
2976 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2979 SetLastExceptionMsg("Document doesn't support tiled rendering");
2983 return convertOUString(pDoc
->getPartInfo(nPart
));
2986 static void doc_selectPart(LibreOfficeKitDocument
* pThis
, int nPart
, int nSelect
)
2988 SolarMutexGuard aGuard
;
2990 gImpl
->maLastExceptionMsg
.clear();
2992 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
2995 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
2999 pDoc
->selectPart( nPart
, nSelect
);
3002 static void doc_moveSelectedParts(LibreOfficeKitDocument
* pThis
, int nPosition
, bool bDuplicate
)
3004 SolarMutexGuard aGuard
;
3006 gImpl
->maLastExceptionMsg
.clear();
3008 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3011 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3015 pDoc
->moveSelectedParts(nPosition
, bDuplicate
);
3018 static char* doc_getPartPageRectangles(LibreOfficeKitDocument
* pThis
)
3020 comphelper::ProfileZone
aZone("doc_getPartPageRectangles");
3022 SolarMutexGuard aGuard
;
3023 SetLastExceptionMsg();
3025 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3028 SetLastExceptionMsg("Document doesn't support tiled rendering");
3032 return convertOUString(pDoc
->getPartPageRectangles());
3035 static char* doc_getPartName(LibreOfficeKitDocument
* pThis
, int nPart
)
3037 comphelper::ProfileZone
aZone("doc_getPartName");
3039 SolarMutexGuard aGuard
;
3040 SetLastExceptionMsg();
3042 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3045 SetLastExceptionMsg("Document doesn't support tiled rendering");
3049 return convertOUString(pDoc
->getPartName(nPart
));
3052 static char* doc_getPartHash(LibreOfficeKitDocument
* pThis
, int nPart
)
3054 comphelper::ProfileZone
aZone("doc_getPartHash");
3056 SolarMutexGuard aGuard
;
3057 SetLastExceptionMsg();
3059 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3062 SetLastExceptionMsg("Document doesn't support tiled rendering");
3066 return convertOUString(pDoc
->getPartHash(nPart
));
3069 static void doc_setPartMode(LibreOfficeKitDocument
* pThis
,
3072 comphelper::ProfileZone
aZone("doc_setPartMode");
3074 SolarMutexGuard aGuard
;
3075 SetLastExceptionMsg();
3077 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3080 SetLastExceptionMsg("Document doesn't support tiled rendering");
3085 int nCurrentPart
= pDoc
->getPart();
3087 pDoc
->setPartMode(nPartMode
);
3089 // We need to make sure the internal state is updated, just changing the mode
3090 // might not update the relevant shells (i.e. impress will keep rendering the
3091 // previous mode unless we do this).
3092 // TODO: we might want to do this within the relevant components rather than
3093 // here, but that's also dependent on how we implement embedded object
3094 // rendering I guess?
3095 // TODO: we could be clever and e.g. set to 0 when we change to/from
3096 // embedded object mode, and not when changing between slide/notes/combined
3098 if ( nCurrentPart
< pDoc
->getParts() )
3100 pDoc
->setPart( nCurrentPart
);
3108 static void doc_paintTile(LibreOfficeKitDocument
* pThis
,
3109 unsigned char* pBuffer
,
3110 const int nCanvasWidth
, const int nCanvasHeight
,
3111 const int nTilePosX
, const int nTilePosY
,
3112 const int nTileWidth
, const int nTileHeight
)
3114 comphelper::ProfileZone
aZone("doc_paintTile");
3116 SolarMutexGuard aGuard
;
3117 SetLastExceptionMsg();
3119 SAL_INFO( "lok.tiledrendering", "paintTile: painting [" << nTileWidth
<< "x" << nTileHeight
<<
3120 "]@(" << nTilePosX
<< ", " << nTilePosY
<< ") to [" <<
3121 nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
3123 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3126 SetLastExceptionMsg("Document doesn't support tiled rendering");
3130 #if defined(UNX) && !defined(MACOSX) && !defined(ENABLE_HEADLESS)
3132 // Painting of zoomed or HiDPI spreadsheets is special, we actually draw everything at 100%,
3133 // and only set cairo's (or CoreGraphic's, in the iOS case) scale factor accordingly, so that
3134 // everything is painted bigger or smaller. This is different to what Calc's internal scaling
3135 // would do - because that one is trying to fit the lines between cells to integer multiples of
3137 comphelper::ScopeGuard
dpiScaleGuard([]() { comphelper::LibreOfficeKit::setDPIScale(1.0); });
3140 double fDPIScaleX
= 1.0;
3141 paintTileIOS(pThis
, pBuffer
, nCanvasWidth
, nCanvasHeight
, fDPIScaleX
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
3143 ScopedVclPtrInstance
< VirtualDevice
> pDevice(DeviceFormat::DEFAULT
);
3145 #if !defined(ANDROID) || HAVE_FEATURE_ANDROID_LOK
3146 // Don't set the transparent background in the 'old' (JNI-based) Android
3147 // app - no idea why it needs avoiding this.
3148 // Set background to transparent by default.
3149 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
3152 pDevice
->SetOutputSizePixelScaleOffsetAndBuffer(
3153 Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(),
3156 pDoc
->paintTile(*pDevice
, nCanvasWidth
, nCanvasHeight
,
3157 nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
3159 static bool bDebug
= getenv("LOK_DEBUG_TILES") != nullptr;
3162 // Draw a small red rectangle in the top left corner so that it's easy to see where a new tile begins.
3163 tools::Rectangle
aRect(0, 0, 5, 5);
3164 aRect
= pDevice
->PixelToLogic(aRect
);
3165 pDevice
->Push(PushFlags::FILLCOLOR
| PushFlags::LINECOLOR
);
3166 pDevice
->SetFillColor(COL_LIGHTRED
);
3167 pDevice
->SetLineColor();
3168 pDevice
->DrawRect(aRect
);
3180 // This function is separate only to be used by LibreOfficeLight. If that app can be retired, this
3181 // function's code can be inlined.
3182 static void doc_paintTileToCGContext(LibreOfficeKitDocument
* pThis
,
3184 const int nCanvasWidth
, const int nCanvasHeight
,
3185 const int nTilePosX
, const int nTilePosY
,
3186 const int nTileWidth
, const int nTileHeight
)
3188 SolarMutexGuard aGuard
;
3189 SetLastExceptionMsg();
3191 SAL_INFO( "lok.tiledrendering", "paintTileToCGContext: painting [" << nTileWidth
<< "x" << nTileHeight
<<
3192 "]@(" << nTilePosX
<< ", " << nTilePosY
<< ") to [" <<
3193 nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
3195 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3198 SetLastExceptionMsg("Document doesn't support tiled rendering");
3202 Size
aCanvasSize(nCanvasWidth
, nCanvasHeight
);
3203 paintTileToCGContext(pDoc
, rCGContext
, aCanvasSize
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
3208 static void doc_paintPartTile(LibreOfficeKitDocument
* pThis
,
3209 unsigned char* pBuffer
,
3211 const int nCanvasWidth
, const int nCanvasHeight
,
3212 const int nTilePosX
, const int nTilePosY
,
3213 const int nTileWidth
, const int nTileHeight
)
3215 comphelper::ProfileZone
aZone("doc_paintPartTile");
3217 SolarMutexGuard aGuard
;
3218 SetLastExceptionMsg();
3220 SAL_INFO( "lok.tiledrendering", "paintPartTile: painting @ " << nPart
<< " ["
3221 << nTileWidth
<< "x" << nTileHeight
<< "]@("
3222 << nTilePosX
<< ", " << nTilePosY
<< ") to ["
3223 << nCanvasWidth
<< "x" << nCanvasHeight
<< "]px" );
3225 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3226 int nOrigViewId
= doc_getView(pThis
);
3228 if (nOrigViewId
< 0)
3230 // tile painting always needs a SfxViewShell::Current(), but actually
3231 // it does not really matter which one - all of them should paint the
3232 // same thing. It's important to get a view for the correct document,
3234 // doc_getViewsCount() returns the count of views for the document in the current view.
3235 int viewCount
= doc_getViewsCount(pThis
);
3239 std::vector
<int> viewIds(viewCount
);
3240 doc_getViewIds(pThis
, viewIds
.data(), viewCount
);
3242 nOrigViewId
= viewIds
[0];
3243 doc_setView(pThis
, nOrigViewId
);
3246 // Disable callbacks while we are painting.
3247 if (nOrigViewId
>= 0)
3249 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nOrigViewId
);
3250 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
3251 handlerIt
->second
->disableCallbacks();
3256 // Text documents have a single coordinate system; don't change part.
3258 const bool isText
= (doc_getDocumentType(pThis
) == LOK_DOCTYPE_TEXT
);
3259 int nViewId
= nOrigViewId
;
3262 // Check if just switching to another view is enough, that has
3263 // less side-effects.
3264 if (nPart
!= doc_getPart(pThis
))
3266 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
3269 if (pViewShell
->getPart() == nPart
)
3271 nViewId
= static_cast<sal_Int32
>(pViewShell
->GetViewShellId());
3272 doc_setView(pThis
, nViewId
);
3275 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
3279 nOrigPart
= doc_getPart(pThis
);
3280 if (nPart
!= nOrigPart
)
3282 doc_setPart(pThis
, nPart
);
3286 doc_paintTile(pThis
, pBuffer
, nCanvasWidth
, nCanvasHeight
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
3288 if (!isText
&& nPart
!= nOrigPart
)
3290 doc_setPart(pThis
, nOrigPart
);
3292 if (!isText
&& nViewId
!= nOrigViewId
)
3294 doc_setView(pThis
, nOrigViewId
);
3297 catch (const std::exception
&)
3299 // Nothing to do but restore the PartTilePainting flag.
3302 if (nOrigViewId
>= 0)
3304 const auto handlerIt
= pDocument
->mpCallbackFlushHandlers
.find(nOrigViewId
);
3305 if (handlerIt
!= pDocument
->mpCallbackFlushHandlers
.end())
3306 handlerIt
->second
->enableCallbacks();
3310 static int doc_getTileMode(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
3312 SetLastExceptionMsg();
3313 return LOK_TILEMODE_BGRA
;
3316 static void doc_getDocumentSize(LibreOfficeKitDocument
* pThis
,
3320 comphelper::ProfileZone
aZone("doc_getDocumentSize");
3322 SolarMutexGuard aGuard
;
3323 SetLastExceptionMsg();
3325 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3328 Size aDocumentSize
= pDoc
->getDocumentSize();
3329 *pWidth
= aDocumentSize
.Width();
3330 *pHeight
= aDocumentSize
.Height();
3334 SetLastExceptionMsg("Document doesn't support tiled rendering");
3338 static void doc_initializeForRendering(LibreOfficeKitDocument
* pThis
,
3339 const char* pArguments
)
3341 comphelper::ProfileZone
aZone("doc_initializeForRendering");
3343 SolarMutexGuard aGuard
;
3344 SetLastExceptionMsg();
3346 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3349 doc_iniUnoCommands();
3350 pDoc
->initializeForTiledRendering(
3351 comphelper::containerToSequence(jsonToPropertyValuesVector(pArguments
)));
3355 static void doc_registerCallback(LibreOfficeKitDocument
* pThis
,
3356 LibreOfficeKitCallback pCallback
,
3359 SolarMutexGuard aGuard
;
3360 SetLastExceptionMsg();
3362 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3364 const int nView
= SfxLokHelper::getView();
3368 const size_t nId
= nView
;
3369 if (pCallback
!= nullptr)
3371 for (auto& pair
: pDocument
->mpCallbackFlushHandlers
)
3373 if (pair
.first
== nId
)
3376 pair
.second
->addViewStates(nView
);
3381 for (auto& pair
: pDocument
->mpCallbackFlushHandlers
)
3383 if (pair
.first
== nId
)
3386 pair
.second
->removeViewStates(nView
);
3390 pDocument
->mpCallbackFlushHandlers
[nView
] = std::make_shared
<CallbackFlushHandler
>(pThis
, pCallback
, pData
);
3392 if (pCallback
!= nullptr)
3394 for (const auto& pair
: pDocument
->mpCallbackFlushHandlers
)
3396 if (pair
.first
== nId
)
3399 pDocument
->mpCallbackFlushHandlers
[nView
]->addViewStates(pair
.first
);
3402 if (SfxViewShell
* pViewShell
= SfxViewShell::Current())
3404 pViewShell
->registerLibreOfficeKitViewCallback(
3405 CallbackFlushHandler::callback
, pDocument
->mpCallbackFlushHandlers
[nView
].get());
3410 if (SfxViewShell
* pViewShell
= SfxViewShell::Current())
3412 pViewShell
->registerLibreOfficeKitViewCallback(nullptr, nullptr);
3417 /// Returns the JSON representation of all the comments in the document
3418 static char* getPostIts(LibreOfficeKitDocument
* pThis
)
3420 SetLastExceptionMsg();
3421 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3424 SetLastExceptionMsg("Document doesn't support tiled rendering");
3427 tools::JsonWriter aJsonWriter
;
3428 pDoc
->getPostIts(aJsonWriter
);
3429 return aJsonWriter
.extractData();
3432 /// Returns the JSON representation of the positions of all the comments in the document
3433 static char* getPostItsPos(LibreOfficeKitDocument
* pThis
)
3435 SetLastExceptionMsg();
3436 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3439 SetLastExceptionMsg("Document doesn't support tiled rendering");
3442 tools::JsonWriter aJsonWriter
;
3443 pDoc
->getPostItsPos(aJsonWriter
);
3444 return aJsonWriter
.extractData();
3447 static char* getRulerState(LibreOfficeKitDocument
* pThis
)
3449 SetLastExceptionMsg();
3450 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3453 SetLastExceptionMsg("Document doesn't support tiled rendering");
3456 tools::JsonWriter aJsonWriter
;
3457 pDoc
->getRulerState(aJsonWriter
);
3458 return aJsonWriter
.extractData();
3461 static void doc_postKeyEvent(LibreOfficeKitDocument
* pThis
, int nType
, int nCharCode
, int nKeyCode
)
3463 comphelper::ProfileZone
aZone("doc_postKeyEvent");
3465 SolarMutexGuard aGuard
;
3466 SetLastExceptionMsg();
3468 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3471 SetLastExceptionMsg("Document doesn't support tiled rendering");
3477 pDoc
->postKeyEvent(nType
, nCharCode
, nKeyCode
);
3479 catch (const uno::Exception
& exception
)
3481 SetLastExceptionMsg(exception
.Message
);
3482 SAL_INFO("lok", "Failed to postKeyEvent " << exception
.Message
);
3486 static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument
* pThis
, unsigned nWindowId
, int nType
, const char* pText
)
3488 comphelper::ProfileZone
aZone("doc_postWindowExtTextInputEvent");
3490 SolarMutexGuard aGuard
;
3491 VclPtr
<vcl::Window
> pWindow
;
3494 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3497 SetLastExceptionMsg("Document doesn't support tiled rendering");
3500 pWindow
= pDoc
->getDocWindow();
3504 pWindow
= vcl::Window::FindLOKWindow(nWindowId
);
3509 SetLastExceptionMsg("No window found for window id: " + OUString::number(nWindowId
));
3513 SfxLokHelper::postExtTextEventAsync(pWindow
, nType
, OUString::fromUtf8(OString(pText
, strlen(pText
))));
3516 static void doc_removeTextContext(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
, int nCharBefore
, int nCharAfter
)
3518 SolarMutexGuard aGuard
;
3519 VclPtr
<vcl::Window
> pWindow
;
3520 if (nLOKWindowId
== 0)
3522 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
3525 gImpl
->maLastExceptionMsg
= "Document doesn't support tiled rendering";
3528 pWindow
= pDoc
->getDocWindow();
3532 pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3537 gImpl
->maLastExceptionMsg
= "No window found for window id: " + OUString::number(nLOKWindowId
);
3541 // Annoyingly - backspace and delete are handled in the apps via an accelerator
3542 // which are PostMessage'd by SfxViewShell::ExecKey_Impl so to stay in the same
3543 // order we do this synchronously here, unless we're in a dialog.
3544 if (nCharBefore
> 0)
3547 if (nLOKWindowId
== 0)
3549 KeyEvent
aEvt(8, 1283);
3550 for (int i
= 0; i
< nCharBefore
; ++i
)
3551 pWindow
->KeyInput(aEvt
);
3554 SfxLokHelper::postKeyEventAsync(pWindow
, LOK_KEYEVENT_KEYINPUT
, 8, 1283, nCharBefore
- 1);
3560 if (nLOKWindowId
== 0)
3562 KeyEvent
aEvt(46, 1286);
3563 for (int i
= 0; i
< nCharAfter
; ++i
)
3564 pWindow
->KeyInput(aEvt
);
3567 SfxLokHelper::postKeyEventAsync(pWindow
, LOK_KEYEVENT_KEYINPUT
, 46, 1286, nCharAfter
- 1);
3571 static void doc_postWindowKeyEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nType
, int nCharCode
, int nKeyCode
)
3573 comphelper::ProfileZone
aZone("doc_postWindowKeyEvent");
3575 SolarMutexGuard aGuard
;
3576 SetLastExceptionMsg();
3578 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
3581 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3585 KeyEvent
aEvent(nCharCode
, nKeyCode
, 0);
3589 case LOK_KEYEVENT_KEYINPUT
:
3590 Application::PostKeyEvent(VclEventId::WindowKeyInput
, pWindow
, &aEvent
);
3592 case LOK_KEYEVENT_KEYUP
:
3593 Application::PostKeyEvent(VclEventId::WindowKeyUp
, pWindow
, &aEvent
);
3601 static size_t doc_renderShapeSelection(LibreOfficeKitDocument
* pThis
, char** pOutput
)
3603 comphelper::ProfileZone
aZone("doc_renderShapeSelection");
3605 SolarMutexGuard aGuard
;
3606 SetLastExceptionMsg();
3608 LokChartHelper
aChartHelper(SfxViewShell::Current());
3610 if (aChartHelper
.GetWindow())
3615 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3617 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
3619 SvMemoryStream aOutStream
;
3620 uno::Reference
<io::XOutputStream
> xOut
= new utl::OOutputStreamWrapper(aOutStream
);
3622 utl::MediaDescriptor aMediaDescriptor
;
3623 switch (doc_getDocumentType(pThis
))
3625 case LOK_DOCTYPE_PRESENTATION
:
3626 aMediaDescriptor
["FilterName"] <<= OUString("impress_svg_Export");
3628 case LOK_DOCTYPE_TEXT
:
3629 aMediaDescriptor
["FilterName"] <<= OUString("writer_svg_Export");
3631 case LOK_DOCTYPE_SPREADSHEET
:
3632 aMediaDescriptor
["FilterName"] <<= OUString("calc_svg_Export");
3635 SAL_WARN("lok", "Failed to render shape selection: Document type is not supported");
3637 aMediaDescriptor
["SelectionOnly"] <<= true;
3638 aMediaDescriptor
["OutputStream"] <<= xOut
;
3640 xStorable
->storeToURL("private:stream", aMediaDescriptor
.getAsConstPropertyValueList());
3644 const size_t nOutputSize
= aOutStream
.GetEndOfData();
3645 *pOutput
= static_cast<char*>(malloc(nOutputSize
));
3648 std::memcpy(*pOutput
, aOutStream
.GetData(), nOutputSize
);
3653 catch (const uno::Exception
& exception
)
3655 css::uno::Any
exAny( cppu::getCaughtException() );
3656 SetLastExceptionMsg(exception
.Message
);
3657 SAL_WARN("lok", "Failed to render shape selection: " << exceptionToString(exAny
));
3665 /** Class to react on finishing of a dispatched command.
3667 This will call a LOK_COMMAND_FINISHED callback when postUnoCommand was
3668 called with the parameter requesting the notification.
3670 @see LibreOfficeKitCallbackType::LOK_CALLBACK_UNO_COMMAND_RESULT.
3672 class DispatchResultListener
: public cppu::WeakImplHelper
<css::frame::XDispatchResultListener
>
3674 OString maCommand
; ///< Command for which this is the result.
3675 std::shared_ptr
<CallbackFlushHandler
> mpCallback
; ///< Callback to call.
3678 DispatchResultListener(const char* pCommand
, std::shared_ptr
<CallbackFlushHandler
> const & pCallback
)
3679 : maCommand(pCommand
)
3680 , mpCallback(pCallback
)
3685 virtual void SAL_CALL
dispatchFinished(const css::frame::DispatchResultEvent
& rEvent
) override
3687 boost::property_tree::ptree aTree
;
3688 aTree
.put("commandName", maCommand
.getStr());
3690 if (rEvent
.State
!= frame::DispatchResultState::DONTKNOW
)
3692 bool bSuccess
= (rEvent
.State
== frame::DispatchResultState::SUCCESS
);
3693 aTree
.put("success", bSuccess
);
3696 aTree
.add_child("result", unoAnyToPropertyTree(rEvent
.Result
));
3698 std::stringstream aStream
;
3699 boost::property_tree::write_json(aStream
, aTree
);
3700 OString aPayload
= aStream
.str().c_str();
3701 mpCallback
->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aPayload
.getStr());
3704 virtual void SAL_CALL
disposing(const css::lang::EventObject
&) override
{}
3707 } // anonymous namespace
3709 static void doc_sendDialogEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned long long int nWindowId
, const char* pArguments
)
3711 SolarMutexGuard aGuard
;
3713 StringMap
aMap(jsonToStringMap(pArguments
));
3714 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nWindowId
);
3716 if (!pWindow
&& nWindowId
>= 1000000000 /* why unsigned? */)
3717 pWindow
= getSidebarWindow();
3719 if (aMap
.find("id") == aMap
.end())
3722 static constexpr OUStringLiteral
sClickAction(u
"CLICK");
3723 static constexpr OUStringLiteral
sSelectAction(u
"SELECT");
3724 static constexpr OUStringLiteral
sClearAction(u
"CLEAR");
3725 static constexpr OUStringLiteral
sTypeAction(u
"TYPE");
3726 static constexpr OUStringLiteral
sUpAction(u
"UP");
3727 static constexpr OUStringLiteral
sDownAction(u
"DOWN");
3728 static constexpr OUStringLiteral
sValue(u
"VALUE");
3730 bool bIsWeldedDialog
= false;
3734 OString sControlId
= OUStringToOString(aMap
["id"], RTL_TEXTENCODING_ASCII_US
);
3736 bIsWeldedDialog
= jsdialog::ExecuteAction(nWindowId
, sControlId
, aMap
);
3737 if (!bIsWeldedDialog
)
3738 bIsWeldedDialog
= jsdialog::ExecuteAction(reinterpret_cast<sal_uInt64
>(SfxViewShell::Current()),
3743 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
3747 if (!bIsWeldedDialog
)
3749 WindowUIObject
aUIObject(pWindow
);
3750 std::unique_ptr
<UIObject
> pUIWindow(aUIObject
.get_visible_child(aMap
["id"]));
3752 OUString
sAction((aMap
.find("cmd") != aMap
.end())? aMap
["cmd"]: "");
3754 if (sAction
== "selected")
3756 aMap
["POS"] = aMap
["data"];
3757 aMap
["TEXT"] = aMap
["data"];
3759 pUIWindow
->execute(sSelectAction
, aMap
);
3761 else if (sAction
== "plus")
3763 pUIWindow
->execute(sUpAction
, aMap
);
3765 else if (sAction
== "minus")
3767 pUIWindow
->execute(sDownAction
, aMap
);
3769 else if (sAction
== "set")
3771 aMap
["TEXT"] = aMap
["data"];
3773 pUIWindow
->execute(sClearAction
, aMap
);
3774 pUIWindow
->execute(sTypeAction
, aMap
);
3776 else if (sAction
== "value")
3778 aMap
["VALUE"] = aMap
["data"];
3779 pUIWindow
->execute(sValue
, aMap
);
3782 pUIWindow
->execute(sClickAction
, aMap
);
3788 if (!bIsWeldedDialog
)
3792 static void doc_postUnoCommand(LibreOfficeKitDocument
* pThis
, const char* pCommand
, const char* pArguments
, bool bNotifyWhenFinished
)
3794 comphelper::ProfileZone
aZone("doc_postUnoCommand");
3796 SolarMutexGuard aGuard
;
3797 SetLastExceptionMsg();
3799 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
3800 OUString
aCommand(pCommand
, strlen(pCommand
), RTL_TEXTENCODING_UTF8
);
3801 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
3803 std::vector
<beans::PropertyValue
> aPropertyValuesVector(jsonToPropertyValuesVector(pArguments
));
3805 if (!vcl::lok::isUnipoll())
3807 beans::PropertyValue aSynchronMode
;
3808 aSynchronMode
.Name
= "SynchronMode";
3809 aSynchronMode
.Value
<<= false;
3810 aPropertyValuesVector
.push_back(aSynchronMode
);
3813 int nView
= SfxLokHelper::getView();
3817 if (gImpl
&& aCommand
== ".uno:ToggleOrientation")
3819 ExecuteOrientationChange();
3823 // handle potential interaction
3824 if (gImpl
&& aCommand
== ".uno:Save")
3826 // Check if saving a PDF file
3827 OUString aMimeType
= lcl_getCurrentDocumentMimeType(pDocument
);
3828 if (aMimeType
== "application/pdf")
3830 // If we have a PDF file (for saving annotations for example), we need
3831 // to run save-as to the same file as the opened document. Plain save
3832 // doesn't work as the PDF is not a "native" format.
3833 uno::Reference
<frame::XStorable
> xStorable(pDocument
->mxComponent
, uno::UNO_QUERY_THROW
);
3834 OUString aURL
= xStorable
->getLocation();
3835 OString aURLUtf8
= OUStringToOString(aURL
, RTL_TEXTENCODING_UTF8
);
3836 bool bResult
= doc_saveAs(pThis
, aURLUtf8
.getStr(), "pdf", nullptr);
3838 // Send the result of save
3839 boost::property_tree::ptree aTree
;
3840 aTree
.put("commandName", pCommand
);
3841 aTree
.put("success", bResult
);
3842 std::stringstream aStream
;
3843 boost::property_tree::write_json(aStream
, aTree
);
3844 OString aPayload
= aStream
.str().c_str();
3845 pDocument
->mpCallbackFlushHandlers
[nView
]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aPayload
.getStr());
3850 rtl::Reference
<LOKInteractionHandler
> const pInteraction(
3851 new LOKInteractionHandler("save", gImpl
, pDocument
));
3852 uno::Reference
<task::XInteractionHandler2
> const xInteraction(pInteraction
.get());
3854 beans::PropertyValue aValue
;
3855 aValue
.Name
= "InteractionHandler";
3856 aValue
.Value
<<= xInteraction
;
3857 aPropertyValuesVector
.push_back(aValue
);
3859 bool bDontSaveIfUnmodified
= false;
3860 aPropertyValuesVector
.erase(std::remove_if(aPropertyValuesVector
.begin(),
3861 aPropertyValuesVector
.end(),
3862 [&bDontSaveIfUnmodified
](const beans::PropertyValue
& aItem
){
3863 if (aItem
.Name
== "DontSaveIfUnmodified")
3865 bDontSaveIfUnmodified
= aItem
.Value
.get
<bool>();
3869 }), aPropertyValuesVector
.end());
3871 // skip saving and tell the result via UNO_COMMAND_RESULT
3872 if (bDontSaveIfUnmodified
&& !pDocSh
->IsModified())
3874 boost::property_tree::ptree aTree
;
3875 aTree
.put("commandName", pCommand
);
3876 aTree
.put("success", false);
3878 // Add the reason for not saving
3879 const uno::Any aResultValue
= uno::makeAny(OUString("unmodified"));
3880 aTree
.add_child("result", unoAnyToPropertyTree(aResultValue
));
3882 std::stringstream aStream
;
3883 boost::property_tree::write_json(aStream
, aTree
);
3884 OString aPayload
= aStream
.str().c_str();
3885 pDocument
->mpCallbackFlushHandlers
[nView
]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT
, aPayload
.getStr());
3889 else if (gImpl
&& aCommand
== ".uno:TransformDialog")
3891 bool bNeedConversion
= false;
3892 SfxViewShell
* pViewShell
= SfxViewShell::Current();
3893 LokChartHelper
aChartHelper(pViewShell
);
3895 if (aChartHelper
.GetWindow() )
3897 bNeedConversion
= true;
3899 else if (const SdrView
* pView
= pViewShell
->GetDrawView())
3901 if (OutputDevice
* pOutputDevice
= pView
->GetFirstOutputDevice())
3903 bNeedConversion
= (pOutputDevice
->GetMapMode().GetMapUnit() == MapUnit::Map100thMM
);
3907 if (bNeedConversion
)
3910 for (beans::PropertyValue
& rPropValue
: aPropertyValuesVector
)
3912 if (rPropValue
.Name
== "TransformPosX"
3913 || rPropValue
.Name
== "TransformPosY"
3914 || rPropValue
.Name
== "TransformWidth"
3915 || rPropValue
.Name
== "TransformHeight"
3916 || rPropValue
.Name
== "TransformRotationX"
3917 || rPropValue
.Name
== "TransformRotationY")
3919 rPropValue
.Value
>>= value
;
3920 value
= OutputDevice::LogicToLogic(value
, MapUnit::MapTwip
, MapUnit::Map100thMM
);
3921 rPropValue
.Value
<<= value
;
3926 if (aChartHelper
.GetWindow() && aPropertyValuesVector
.size() > 0)
3928 if (aPropertyValuesVector
[0].Name
!= "Action")
3930 tools::Rectangle aChartBB
= aChartHelper
.GetChartBoundingBox();
3931 int nLeft
= OutputDevice::LogicToLogic(aChartBB
.Left(), MapUnit::MapTwip
, MapUnit::Map100thMM
);
3932 int nTop
= OutputDevice::LogicToLogic(aChartBB
.Top(), MapUnit::MapTwip
, MapUnit::Map100thMM
);
3934 for (beans::PropertyValue
& rPropValue
: aPropertyValuesVector
)
3936 if (rPropValue
.Name
== "TransformPosX" || rPropValue
.Name
== "TransformRotationX")
3938 auto const value
= *o3tl::doAccess
<sal_Int32
>(rPropValue
.Value
);
3939 rPropValue
.Value
<<= value
- nLeft
;
3941 else if (rPropValue
.Name
== "TransformPosY" || rPropValue
.Name
== "TransformRotationY")
3943 auto const value
= *o3tl::doAccess
<sal_Int32
>(rPropValue
.Value
);
3944 rPropValue
.Value
<<= value
- nTop
;
3948 util::URL aCommandURL
;
3949 aCommandURL
.Path
= "LOKTransform";
3950 css::uno::Reference
<css::frame::XDispatch
>& aChartDispatcher
= aChartHelper
.GetXDispatcher();
3951 aChartDispatcher
->dispatch(aCommandURL
, comphelper::containerToSequence(aPropertyValuesVector
));
3955 else if (gImpl
&& aCommand
== ".uno:LOKSidebarWriterPage")
3957 setupSidebar("WriterPageDeck");
3960 else if (gImpl
&& aCommand
== ".uno:SidebarShow")
3965 else if (gImpl
&& aCommand
== ".uno:SidebarHide")
3971 bool bResult
= false;
3972 LokChartHelper
aChartHelper(SfxViewShell::Current());
3974 if (aChartHelper
.GetWindow() && aCommand
!= ".uno:Save" )
3976 util::URL aCommandURL
;
3977 aCommandURL
.Path
= aCommand
.copy(5);
3978 css::uno::Reference
<css::frame::XDispatch
>& aChartDispatcher
= aChartHelper
.GetXDispatcher();
3979 aChartDispatcher
->dispatch(aCommandURL
, comphelper::containerToSequence(aPropertyValuesVector
));
3982 else if (bNotifyWhenFinished
&& pDocument
->mpCallbackFlushHandlers
.count(nView
))
3984 bResult
= comphelper::dispatchCommand(aCommand
, comphelper::containerToSequence(aPropertyValuesVector
),
3985 new DispatchResultListener(pCommand
, pDocument
->mpCallbackFlushHandlers
[nView
]));
3988 bResult
= comphelper::dispatchCommand(aCommand
, comphelper::containerToSequence(aPropertyValuesVector
));
3992 SetLastExceptionMsg("Failed to dispatch " + aCommand
);
3996 static void doc_postMouseEvent(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
, int nCount
, int nButtons
, int nModifier
)
3998 comphelper::ProfileZone
aZone("doc_postMouseEvent");
4000 SolarMutexGuard aGuard
;
4001 SetLastExceptionMsg();
4003 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4006 SetLastExceptionMsg("Document doesn't support tiled rendering");
4011 pDoc
->postMouseEvent(nType
, nX
, nY
, nCount
, nButtons
, nModifier
);
4013 catch (const uno::Exception
& exception
)
4015 SetLastExceptionMsg(exception
.Message
);
4016 SAL_INFO("lok", "Failed to postMouseEvent " << exception
.Message
);
4020 static void doc_postWindowMouseEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nType
, int nX
, int nY
, int nCount
, int nButtons
, int nModifier
)
4022 comphelper::ProfileZone
aZone("doc_postWindowMouseEvent");
4024 SolarMutexGuard aGuard
;
4025 SetLastExceptionMsg();
4027 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
4030 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
4034 const Point
aPos(nX
, nY
);
4036 MouseEvent
aEvent(aPos
, nCount
, MouseEventModifiers::SIMPLECLICK
, nButtons
, nModifier
);
4038 vcl::EnableDialogInput(pWindow
);
4042 case LOK_MOUSEEVENT_MOUSEBUTTONDOWN
:
4043 Application::PostMouseEvent(VclEventId::WindowMouseButtonDown
, pWindow
, &aEvent
);
4045 case LOK_MOUSEEVENT_MOUSEBUTTONUP
:
4046 Application::PostMouseEvent(VclEventId::WindowMouseButtonUp
, pWindow
, &aEvent
);
4048 case LOK_MOUSEEVENT_MOUSEMOVE
:
4049 Application::PostMouseEvent(VclEventId::WindowMouseMove
, pWindow
, &aEvent
);
4057 static void doc_postWindowGestureEvent(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, const char* pType
, int nX
, int nY
, int nOffset
)
4059 comphelper::ProfileZone
aZone("doc_postWindowGestureEvent");
4061 SolarMutexGuard aGuard
;
4062 SetLastExceptionMsg();
4064 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
4067 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
4071 OString
aType(pType
);
4072 GestureEventType eEventType
= GestureEventType::PanningUpdate
;
4074 if (aType
== "panBegin")
4075 eEventType
= GestureEventType::PanningBegin
;
4076 else if (aType
== "panEnd")
4077 eEventType
= GestureEventType::PanningEnd
;
4079 GestureEvent aEvent
{
4084 PanningOrientation::Vertical
,
4087 vcl::EnableDialogInput(pWindow
);
4089 Application::PostGestureEvent(VclEventId::WindowGestureEvent
, pWindow
, &aEvent
);
4092 static void doc_setTextSelection(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
)
4094 comphelper::ProfileZone
aZone("doc_setTextSelection");
4096 SolarMutexGuard aGuard
;
4097 SetLastExceptionMsg();
4099 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4102 SetLastExceptionMsg("Document doesn't support tiled rendering");
4106 pDoc
->setTextSelection(nType
, nX
, nY
);
4109 static void doc_setWindowTextSelection(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, bool swap
, int nX
, int nY
)
4111 comphelper::ProfileZone
aZone("doc_setWindowTextSelection");
4113 SolarMutexGuard aGuard
;
4114 SetLastExceptionMsg();
4116 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
4119 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
4124 Size
aOffset(pWindow
->GetOutOffXPixel(), pWindow
->GetOutOffYPixel());
4125 Point
aCursorPos(nX
, nY
);
4126 aCursorPos
.Move(aOffset
);
4127 sal_uInt16 nModifier
= swap
? KEY_MOD1
+ KEY_MOD2
: KEY_SHIFT
;
4129 MouseEvent
aCursorEvent(aCursorPos
, 1, MouseEventModifiers::SIMPLECLICK
, 0, nModifier
);
4130 Application::PostMouseEvent(VclEventId::WindowMouseButtonDown
, pWindow
, &aCursorEvent
);
4131 Application::PostMouseEvent(VclEventId::WindowMouseButtonUp
, pWindow
, &aCursorEvent
);
4134 static bool getFromTransferrable(
4135 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
4136 const OString
&aInMimeType
, OString
&aRet
);
4138 static bool encodeImageAsHTML(
4139 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
4140 const OString
&aMimeType
, OString
&aRet
)
4142 if (!getFromTransferrable(xTransferable
, aMimeType
, aRet
))
4145 // Encode in base64.
4146 auto aSeq
= Sequence
<sal_Int8
>(reinterpret_cast<const sal_Int8
*>(aRet
.getStr()),
4148 OUStringBuffer aBase64Data
;
4149 comphelper::Base64::encode(aBase64Data
, aSeq
);
4152 aRet
= "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
4154 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
4155 "name=\"generator\" content=\""
4156 + getGenerator().toUtf8()
4158 "</head><body><img src=\"data:" + aMimeType
+ ";base64,"
4159 + aBase64Data
.makeStringAndClear().toUtf8() + "\"/></body></html>";
4164 static bool encodeTextAsHTML(
4165 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
4166 const OString
&aMimeType
, OString
&aRet
)
4168 if (!getFromTransferrable(xTransferable
, aMimeType
, aRet
))
4171 // Embed in HTML - FIXME: needs some escaping.
4172 aRet
= "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
4174 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
4175 "name=\"generator\" content=\""
4176 + getGenerator().toUtf8()
4177 + "\"/></head><body><pre>" + aRet
+ "</pre></body></html>";
4182 static bool getFromTransferrable(
4183 const css::uno::Reference
<css::datatransfer::XTransferable
> &xTransferable
,
4184 const OString
&aInMimeType
, OString
&aRet
)
4186 OString
aMimeType(aInMimeType
);
4188 // Take care of UTF-8 text here.
4189 bool bConvert
= false;
4190 sal_Int32 nIndex
= 0;
4191 if (aMimeType
.getToken(0, ';', nIndex
) == "text/plain")
4193 if (aMimeType
.getToken(0, ';', nIndex
) == "charset=utf-8")
4195 aMimeType
= "text/plain;charset=utf-16";
4200 datatransfer::DataFlavor aFlavor
;
4201 aFlavor
.MimeType
= OUString::fromUtf8(aMimeType
.getStr());
4202 if (aMimeType
== "text/plain;charset=utf-16")
4203 aFlavor
.DataType
= cppu::UnoType
<OUString
>::get();
4205 aFlavor
.DataType
= cppu::UnoType
< uno::Sequence
<sal_Int8
> >::get();
4207 if (!xTransferable
->isDataFlavorSupported(aFlavor
))
4209 // Try harder for HTML it is our copy/paste meta-file format
4210 if (aInMimeType
== "text/html")
4212 // Desperate measures - convert text to HTML instead.
4213 if (encodeTextAsHTML(xTransferable
, "text/plain;charset=utf-8", aRet
))
4215 // If html is not supported, might be a graphic-selection,
4216 if (encodeImageAsHTML(xTransferable
, "image/png", aRet
))
4220 SetLastExceptionMsg("Flavor " + aFlavor
.MimeType
+ " is not supported");
4227 aAny
= xTransferable
->getTransferData(aFlavor
);
4229 catch (const css::datatransfer::UnsupportedFlavorException
& e
)
4231 SetLastExceptionMsg("Unsupported flavor " + aFlavor
.MimeType
+ " exception " + e
.Message
);
4234 catch (const css::uno::Exception
& e
)
4236 SetLastExceptionMsg("Exception getting " + aFlavor
.MimeType
+ " exception " + e
.Message
);
4240 if (aFlavor
.DataType
== cppu::UnoType
<OUString
>::get())
4245 aRet
= OUStringToOString(aString
, RTL_TEXTENCODING_UTF8
);
4247 aRet
= OString(reinterpret_cast<const char *>(aString
.getStr()), aString
.getLength() * sizeof(sal_Unicode
));
4251 uno::Sequence
<sal_Int8
> aSequence
;
4253 aRet
= OString(reinterpret_cast<char*>(aSequence
.getArray()), aSequence
.getLength());
4259 static char* doc_getTextSelection(LibreOfficeKitDocument
* pThis
, const char* pMimeType
, char** pUsedMimeType
)
4261 comphelper::ProfileZone
aZone("doc_getTextSelection");
4263 SolarMutexGuard aGuard
;
4264 SetLastExceptionMsg();
4266 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4269 SetLastExceptionMsg("Document doesn't support tiled rendering");
4273 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
= pDoc
->getSelection();
4276 SetLastExceptionMsg("No selection available");
4280 const char *pType
= pMimeType
;
4281 if (!pType
|| pType
[0] == '\0')
4282 pType
= "text/plain;charset=utf-8";
4285 bool bSuccess
= getFromTransferrable(xTransferable
, OString(pType
), aRet
);
4289 if (pUsedMimeType
) // legacy
4292 *pUsedMimeType
= strdup(pMimeType
);
4294 *pUsedMimeType
= nullptr;
4297 return convertOString(aRet
);
4300 static int doc_getSelectionType(LibreOfficeKitDocument
* pThis
)
4302 comphelper::ProfileZone
aZone("doc_getSelectionType");
4304 SolarMutexGuard aGuard
;
4305 SetLastExceptionMsg();
4307 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4310 SetLastExceptionMsg("Document doesn't support tiled rendering");
4311 return LOK_SELTYPE_NONE
;
4314 css::uno::Reference
<css::datatransfer::XTransferable2
> xTransferable(pDoc
->getSelection(), css::uno::UNO_QUERY
);
4317 SetLastExceptionMsg("No selection available");
4318 return LOK_SELTYPE_NONE
;
4321 if (xTransferable
->isComplex())
4322 return LOK_SELTYPE_COMPLEX
;
4325 bool bSuccess
= getFromTransferrable(xTransferable
, "text/plain;charset=utf-8", aRet
);
4327 return LOK_SELTYPE_NONE
;
4329 if (aRet
.getLength() > 10000)
4330 return LOK_SELTYPE_COMPLEX
;
4332 return aRet
.getLength() ? LOK_SELTYPE_TEXT
: LOK_SELTYPE_NONE
;
4335 static int doc_getClipboard(LibreOfficeKitDocument
* pThis
,
4336 const char **pMimeTypes
,
4338 char ***pOutMimeTypes
,
4340 char ***pOutStreams
)
4342 comphelper::ProfileZone
aZone("doc_getClipboard");
4344 SolarMutexGuard aGuard
;
4345 SetLastExceptionMsg();
4348 assert (pOutMimeTypes
);
4350 assert (pOutStreams
);
4353 *pOutMimeTypes
= nullptr;
4354 *pOutSizes
= nullptr;
4355 *pOutStreams
= nullptr;
4357 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4360 SetLastExceptionMsg("Document doesn't support tiled rendering");
4364 rtl::Reference
<LOKClipboard
> xClip(LOKClipboardFactory::getClipboardForCurView());
4366 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable
= xClip
->getContents();
4367 SAL_INFO("lok", "Got from clip: " << xClip
.get() << " transferrable: " << xTransferable
);
4370 SetLastExceptionMsg("No clipboard content available");
4374 std::vector
<OString
> aMimeTypes
;
4375 if (!pMimeTypes
) // everything
4377 const uno::Sequence
< css::datatransfer::DataFlavor
> flavors
= xTransferable
->getTransferDataFlavors();
4378 if (!flavors
.getLength())
4380 SetLastExceptionMsg("Flavourless selection");
4383 for (const auto &it
: flavors
)
4384 aMimeTypes
.push_back(OUStringToOString(it
.MimeType
, RTL_TEXTENCODING_UTF8
));
4388 for (size_t i
= 0; pMimeTypes
[i
]; ++i
)
4389 aMimeTypes
.push_back(OString(pMimeTypes
[i
]));
4392 *pOutCount
= aMimeTypes
.size();
4393 *pOutSizes
= static_cast<size_t *>(malloc(*pOutCount
* sizeof(size_t)));
4394 *pOutMimeTypes
= static_cast<char **>(malloc(*pOutCount
* sizeof(char *)));
4395 *pOutStreams
= static_cast<char **>(malloc(*pOutCount
* sizeof(char *)));
4396 for (size_t i
= 0; i
< aMimeTypes
.size(); ++i
)
4398 if (aMimeTypes
[i
] == "text/plain;charset=utf-16")
4399 (*pOutMimeTypes
)[i
] = strdup("text/plain;charset=utf-8");
4401 (*pOutMimeTypes
)[i
] = strdup(aMimeTypes
[i
].getStr());
4404 bool bSuccess
= getFromTransferrable(xTransferable
, (*pOutMimeTypes
)[i
], aRet
);
4405 if (!bSuccess
|| aRet
.getLength() < 1)
4407 (*pOutSizes
)[i
] = 0;
4408 (*pOutStreams
)[i
] = nullptr;
4412 (*pOutSizes
)[i
] = aRet
.getLength();
4413 (*pOutStreams
)[i
] = convertOString(aRet
);
4420 static int doc_setClipboard(LibreOfficeKitDocument
* pThis
,
4421 const size_t nInCount
,
4422 const char **pInMimeTypes
,
4423 const size_t *pInSizes
,
4424 const char **pInStreams
)
4429 (void) pInMimeTypes
;
4433 comphelper::ProfileZone
aZone("doc_setClipboard");
4435 SolarMutexGuard aGuard
;
4436 SetLastExceptionMsg();
4438 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4441 SetLastExceptionMsg("Document doesn't support tiled rendering");
4445 uno::Reference
<datatransfer::XTransferable
> xTransferable(new LOKTransferable(nInCount
, pInMimeTypes
, pInSizes
, pInStreams
));
4447 auto xClip
= forceSetClipboardForCurrentView(pThis
);
4448 xClip
->setContents(xTransferable
, uno::Reference
<datatransfer::clipboard::XClipboardOwner
>());
4450 SAL_INFO("lok", "Set clip: " << xClip
.get() << " to: " << xTransferable
);
4452 if (!pDoc
->isMimeTypeSupported())
4454 SetLastExceptionMsg("Document doesn't support this mime type");
4461 static bool doc_paste(LibreOfficeKitDocument
* pThis
, const char* pMimeType
, const char* pData
, size_t nSize
)
4463 comphelper::ProfileZone
aZone("doc_paste");
4465 SolarMutexGuard aGuard
;
4467 const char *pInMimeTypes
[1];
4468 const char *pInStreams
[1];
4470 pInMimeTypes
[0] = pMimeType
;
4471 pInSizes
[0] = nSize
;
4472 pInStreams
[0] = pData
;
4474 if (!doc_setClipboard(pThis
, 1, pInMimeTypes
, pInSizes
, pInStreams
))
4477 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
4479 {"AnchorType", uno::makeAny(static_cast<sal_uInt16
>(text::TextContentAnchorType_AS_CHARACTER
))},
4480 {"IgnoreComments", uno::makeAny(true)},
4482 if (!comphelper::dispatchCommand(".uno:Paste", aPropertyValues
))
4484 SetLastExceptionMsg("Failed to dispatch the .uno: command");
4491 static void doc_setGraphicSelection(LibreOfficeKitDocument
* pThis
, int nType
, int nX
, int nY
)
4493 comphelper::ProfileZone
aZone("doc_setGraphicSelection");
4495 SolarMutexGuard aGuard
;
4496 SetLastExceptionMsg();
4498 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4501 SetLastExceptionMsg("Document doesn't support tiled rendering");
4505 pDoc
->setGraphicSelection(nType
, nX
, nY
);
4508 static void doc_resetSelection(LibreOfficeKitDocument
* pThis
)
4510 comphelper::ProfileZone
aZone("doc_resetSelection");
4512 SolarMutexGuard aGuard
;
4513 SetLastExceptionMsg();
4515 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4518 SetLastExceptionMsg("Document doesn't support tiled rendering");
4522 pDoc
->resetSelection();
4525 static char* getLanguages(const char* pCommand
)
4527 css::uno::Sequence
< css::lang::Locale
> aLocales
;
4531 css::uno::Reference
<css::linguistic2::XLinguServiceManager2
> xLangSrv
= css::linguistic2::LinguServiceManager::create(xContext
);
4534 css::uno::Reference
<css::linguistic2::XSpellChecker
> xSpell
= xLangSrv
->getSpellChecker();
4536 aLocales
= xSpell
->getLocales();
4540 boost::property_tree::ptree aTree
;
4541 aTree
.put("commandName", pCommand
);
4542 boost::property_tree::ptree aValues
;
4543 boost::property_tree::ptree aChild
;
4545 for ( css::lang::Locale
const & locale
: std::as_const(aLocales
) )
4547 const LanguageTag
aLanguageTag( locale
);
4548 sLanguage
= SvtLanguageTable::GetLanguageString(aLanguageTag
.getLanguageType());
4549 if (sLanguage
.startsWith("{") && sLanguage
.endsWith("}"))
4552 sLanguage
+= ";" + aLanguageTag
.getBcp47(false);
4553 aChild
.put("", sLanguage
.toUtf8());
4554 aValues
.push_back(std::make_pair("", aChild
));
4556 aTree
.add_child("commandValues", aValues
);
4557 std::stringstream aStream
;
4558 boost::property_tree::write_json(aStream
, aTree
);
4559 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4560 assert(pJson
); // Don't handle OOM conditions
4561 strcpy(pJson
, aStream
.str().c_str());
4562 pJson
[aStream
.str().size()] = '\0';
4566 static char* getFonts (const char* pCommand
)
4568 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
4569 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
4570 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
4571 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
4573 boost::property_tree::ptree aTree
;
4574 aTree
.put("commandName", pCommand
);
4575 boost::property_tree::ptree aValues
;
4578 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
4579 for (sal_uInt16 i
= 0; i
< nFontCount
; ++i
)
4581 boost::property_tree::ptree aChildren
;
4582 const FontMetric
& rFontMetric
= pList
->GetFontName(i
);
4583 const int* pAry
= pList
->GetSizeAry(rFontMetric
);
4584 sal_uInt16 nSizeCount
= 0;
4585 while (pAry
[nSizeCount
])
4587 boost::property_tree::ptree aChild
;
4588 aChild
.put("", static_cast<float>(pAry
[nSizeCount
]) / 10);
4589 aChildren
.push_back(std::make_pair("", aChild
));
4592 aValues
.add_child(rFontMetric
.GetFamilyName().toUtf8().getStr(), aChildren
);
4595 aTree
.add_child("commandValues", aValues
);
4596 std::stringstream aStream
;
4597 boost::property_tree::write_json(aStream
, aTree
);
4598 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4599 assert(pJson
); // Don't handle OOM conditions
4600 strcpy(pJson
, aStream
.str().c_str());
4601 pJson
[aStream
.str().size()] = '\0';
4605 static char* getFontSubset (const OString
& aFontName
)
4607 OUString
aFoundFont(::rtl::Uri::decode(OStringToOUString(aFontName
, RTL_TEXTENCODING_UTF8
), rtl_UriDecodeStrict
, RTL_TEXTENCODING_UTF8
));
4608 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
4609 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
4610 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
4611 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
4613 boost::property_tree::ptree aTree
;
4614 aTree
.put("commandName", ".uno:FontSubset");
4615 boost::property_tree::ptree aValues
;
4617 if ( pList
&& !aFoundFont
.isEmpty() )
4619 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
4620 sal_uInt16 nItFont
= 0;
4621 for (; nItFont
< nFontCount
; ++nItFont
)
4623 if (aFoundFont
== pList
->GetFontName(nItFont
).GetFamilyName())
4629 if ( nItFont
< nFontCount
)
4631 FontCharMapRef
xFontCharMap (new FontCharMap());
4632 auto aDevice(VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
));
4633 const vcl::Font
& aFont(pList
->GetFontName(nItFont
));
4635 aDevice
->SetFont(aFont
);
4636 aDevice
->GetFontCharMap(xFontCharMap
);
4637 SubsetMap
aSubMap(xFontCharMap
);
4639 for (auto const& subset
: aSubMap
.GetSubsetMap())
4641 boost::property_tree::ptree aChild
;
4642 aChild
.put("", static_cast<int>(ublock_getCode(subset
.GetRangeMin())));
4643 aValues
.push_back(std::make_pair("", aChild
));
4648 aTree
.add_child("commandValues", aValues
);
4649 std::stringstream aStream
;
4650 boost::property_tree::write_json(aStream
, aTree
);
4651 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4652 assert(pJson
); // Don't handle OOM conditions
4653 strcpy(pJson
, aStream
.str().c_str());
4654 pJson
[aStream
.str().size()] = '\0';
4658 static char* getStyles(LibreOfficeKitDocument
* pThis
, const char* pCommand
)
4660 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4662 boost::property_tree::ptree aTree
;
4663 aTree
.put("commandName", pCommand
);
4664 uno::Reference
<css::style::XStyleFamiliesSupplier
> xStyleFamiliesSupplier(pDocument
->mxComponent
, uno::UNO_QUERY
);
4665 const uno::Reference
<container::XNameAccess
> xStyleFamilies
= xStyleFamiliesSupplier
->getStyleFamilies();
4666 const uno::Sequence
<OUString
> aStyleFamilies
= xStyleFamilies
->getElementNames();
4668 static const std::vector
<OUString
> aWriterStyles
=
4679 // We need to keep a list of the default style names
4680 // in order to filter these out later when processing
4681 // the full list of styles.
4682 std::set
<OUString
> aDefaultStyleNames
;
4684 boost::property_tree::ptree aValues
;
4685 for (OUString
const & sStyleFam
: aStyleFamilies
)
4687 boost::property_tree::ptree aChildren
;
4688 uno::Reference
<container::XNameAccess
> xStyleFamily(xStyleFamilies
->getByName(sStyleFam
), uno::UNO_QUERY
);
4690 // Writer provides a huge number of styles, we have a list of 7 "default" styles which
4691 // should be shown in the normal dropdown, which we should add to the start of the list
4692 // to simplify their selection.
4693 if (sStyleFam
== "ParagraphStyles"
4694 && doc_getDocumentType(pThis
) == LOK_DOCTYPE_TEXT
)
4696 for (const OUString
& rStyle
: aWriterStyles
)
4698 aDefaultStyleNames
.insert( rStyle
);
4700 boost::property_tree::ptree aChild
;
4701 aChild
.put("", rStyle
.toUtf8());
4702 aChildren
.push_back(std::make_pair("", aChild
));
4706 const uno::Sequence
<OUString
> aStyles
= xStyleFamily
->getElementNames();
4707 for (const OUString
& rStyle
: aStyles
)
4709 // Filter out the default styles - they are already at the top
4711 if (aDefaultStyleNames
.find(rStyle
) == aDefaultStyleNames
.end() ||
4712 (sStyleFam
!= "ParagraphStyles" || doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
) )
4714 boost::property_tree::ptree aChild
;
4715 aChild
.put("", rStyle
.toUtf8());
4716 aChildren
.push_back(std::make_pair("", aChild
));
4719 aValues
.add_child(sStyleFam
.toUtf8().getStr(), aChildren
);
4722 // Header & Footer Styles
4724 boost::property_tree::ptree aChild
;
4725 boost::property_tree::ptree aChildren
;
4726 const OUString
sPageStyles("PageStyles");
4727 uno::Reference
<beans::XPropertySet
> xProperty
;
4728 uno::Reference
<container::XNameContainer
> xContainer
;
4730 if (xStyleFamilies
->hasByName(sPageStyles
) && (xStyleFamilies
->getByName(sPageStyles
) >>= xContainer
))
4732 const uno::Sequence
<OUString
> aSeqNames
= xContainer
->getElementNames();
4733 for (OUString
const & sName
: aSeqNames
)
4736 xProperty
.set(xContainer
->getByName(sName
), uno::UNO_QUERY
);
4737 if (xProperty
.is() && (xProperty
->getPropertyValue("IsPhysical") >>= bIsPhysical
) && bIsPhysical
)
4739 OUString displayName
;
4740 xProperty
->getPropertyValue("DisplayName") >>= displayName
;
4741 aChild
.put("", displayName
.toUtf8());
4742 aChildren
.push_back(std::make_pair("", aChild
));
4745 aValues
.add_child("HeaderFooter", aChildren
);
4750 boost::property_tree::ptree aCommandList
;
4753 boost::property_tree::ptree aChild
;
4755 OUString sClearFormat
= SvxResId(RID_SVXSTR_CLEARFORM
);
4757 boost::property_tree::ptree aName
;
4758 aName
.put("", sClearFormat
.toUtf8());
4759 aChild
.push_back(std::make_pair("text", aName
));
4761 boost::property_tree::ptree aCommand
;
4762 aCommand
.put("", ".uno:ResetAttributes");
4763 aChild
.push_back(std::make_pair("id", aCommand
));
4765 aCommandList
.push_back(std::make_pair("", aChild
));
4768 aValues
.add_child("Commands", aCommandList
);
4771 aTree
.add_child("commandValues", aValues
);
4772 std::stringstream aStream
;
4773 boost::property_tree::write_json(aStream
, aTree
);
4774 char* pJson
= static_cast<char*>(malloc(aStream
.str().size() + 1));
4775 assert(pJson
); // Don't handle OOM conditions
4776 strcpy(pJson
, aStream
.str().c_str());
4777 pJson
[aStream
.str().size()] = '\0';
4783 enum class UndoOrRedo
4791 /// Returns the JSON representation of either an undo or a redo stack.
4792 static char* getUndoOrRedo(LibreOfficeKitDocument
* pThis
, UndoOrRedo eCommand
)
4794 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4796 auto pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
4800 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
4804 SfxUndoManager
* pUndoManager
= pObjectShell
->GetUndoManager();
4809 if (eCommand
== UndoOrRedo::UNDO
)
4810 aString
= pUndoManager
->GetUndoActionsInfo();
4812 aString
= pUndoManager
->GetRedoActionsInfo();
4813 char* pJson
= strdup(aString
.toUtf8().getStr());
4817 /// Returns the JSON representation of the redline stack.
4818 static char* getTrackedChanges(LibreOfficeKitDocument
* pThis
)
4820 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
4822 uno::Reference
<document::XRedlinesSupplier
> xRedlinesSupplier(pDocument
->mxComponent
, uno::UNO_QUERY
);
4823 tools::JsonWriter aJson
;
4824 // We want positions of the track changes also which is not possible from
4825 // UNO. Enable positioning information for text documents only for now, so
4826 // construct the tracked changes JSON from inside the sw/, not here using UNO
4827 if (doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
&& xRedlinesSupplier
.is())
4829 auto redlinesNode
= aJson
.startNode("redlines");
4830 uno::Reference
<container::XEnumeration
> xRedlines
= xRedlinesSupplier
->getRedlines()->createEnumeration();
4831 for (size_t nIndex
= 0; xRedlines
->hasMoreElements(); ++nIndex
)
4833 uno::Reference
<beans::XPropertySet
> xRedline(xRedlines
->nextElement(), uno::UNO_QUERY
);
4834 auto redlineNode
= aJson
.startNode("");
4835 aJson
.put("index", static_cast<sal_Int32
>(nIndex
));
4838 xRedline
->getPropertyValue("RedlineAuthor") >>= sAuthor
;
4839 aJson
.put("author", sAuthor
);
4842 xRedline
->getPropertyValue("RedlineType") >>= sType
;
4843 aJson
.put("type", sType
);
4846 xRedline
->getPropertyValue("RedlineComment") >>= sComment
;
4847 aJson
.put("comment", sComment
);
4849 OUString sDescription
;
4850 xRedline
->getPropertyValue("RedlineDescription") >>= sDescription
;
4851 aJson
.put("description", sDescription
);
4853 util::DateTime aDateTime
;
4854 xRedline
->getPropertyValue("RedlineDateTime") >>= aDateTime
;
4855 OUString sDateTime
= utl::toISO8601(aDateTime
);
4856 aJson
.put("dateTime", sDateTime
);
4861 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4864 SetLastExceptionMsg("Document doesn't support tiled rendering");
4867 pDoc
->getTrackedChanges(aJson
);
4870 return aJson
.extractData();
4874 /// Returns the JSON representation of the redline author table.
4875 static char* getTrackedChangeAuthors(LibreOfficeKitDocument
* pThis
)
4877 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4880 SetLastExceptionMsg("Document doesn't support tiled rendering");
4883 tools::JsonWriter aJsonWriter
;
4884 pDoc
->getTrackedChangeAuthors(aJsonWriter
);
4885 return aJsonWriter
.extractData();
4888 static char* doc_getCommandValues(LibreOfficeKitDocument
* pThis
, const char* pCommand
)
4890 comphelper::ProfileZone
aZone("doc_getCommandValues");
4892 SolarMutexGuard aGuard
;
4893 SetLastExceptionMsg();
4895 OString
aCommand(pCommand
);
4896 static constexpr OStringLiteral
aViewRowColumnHeaders(".uno:ViewRowColumnHeaders");
4897 static constexpr OStringLiteral
aSheetGeometryData(".uno:SheetGeometryData");
4898 static constexpr OStringLiteral
aCellCursor(".uno:CellCursor");
4899 static constexpr OStringLiteral
aFontSubset(".uno:FontSubset&name=");
4901 if (!strcmp(pCommand
, ".uno:LanguageStatus"))
4903 return getLanguages(pCommand
);
4905 else if (!strcmp(pCommand
, ".uno:CharFontName"))
4907 return getFonts(pCommand
);
4909 else if (!strcmp(pCommand
, ".uno:StyleApply"))
4911 return getStyles(pThis
, pCommand
);
4913 else if (aCommand
== ".uno:Undo")
4915 return getUndoOrRedo(pThis
, UndoOrRedo::UNDO
);
4917 else if (aCommand
== ".uno:Redo")
4919 return getUndoOrRedo(pThis
, UndoOrRedo::REDO
);
4921 else if (aCommand
== ".uno:AcceptTrackedChanges")
4923 return getTrackedChanges(pThis
);
4925 else if (aCommand
== ".uno:TrackedChangeAuthors")
4927 return getTrackedChangeAuthors(pThis
);
4929 else if (aCommand
== ".uno:ViewAnnotations")
4931 return getPostIts(pThis
);
4933 else if (aCommand
== ".uno:ViewAnnotationsPosition")
4935 return getPostItsPos(pThis
);
4937 else if (aCommand
== ".uno:RulerState")
4939 return getRulerState(pThis
);
4941 else if (aCommand
.startsWith(aViewRowColumnHeaders
))
4943 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4946 SetLastExceptionMsg("Document doesn't support tiled rendering");
4950 tools::Rectangle aRectangle
;
4951 if (aCommand
.getLength() > aViewRowColumnHeaders
.getLength())
4953 // Command has parameters.
4958 OString aArguments
= aCommand
.copy(aViewRowColumnHeaders
.getLength() + 1);
4959 sal_Int32 nParamIndex
= 0;
4962 OString aParamToken
= aArguments
.getToken(0, '&', nParamIndex
);
4963 sal_Int32 nIndex
= 0;
4968 OString aToken
= aParamToken
.getToken(0, '=', nIndex
);
4969 if (!aKey
.getLength())
4974 while (nIndex
>= 0);
4976 nX
= aValue
.toInt32();
4977 else if (aKey
== "y")
4978 nY
= aValue
.toInt32();
4979 else if (aKey
== "width")
4980 nWidth
= aValue
.toInt32();
4981 else if (aKey
== "height")
4982 nHeight
= aValue
.toInt32();
4984 while (nParamIndex
>= 0);
4986 aRectangle
= tools::Rectangle(nX
, nY
, nX
+ nWidth
, nY
+ nHeight
);
4989 tools::JsonWriter aJsonWriter
;
4990 pDoc
->getRowColumnHeaders(aRectangle
, aJsonWriter
);
4991 return aJsonWriter
.extractData();
4993 else if (aCommand
.startsWith(aSheetGeometryData
))
4995 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
4998 SetLastExceptionMsg("Document doesn't support tiled rendering");
5002 bool bColumns
= true;
5005 bool bHidden
= true;
5006 bool bFiltered
= true;
5007 bool bGroups
= true;
5008 if (aCommand
.getLength() > aSheetGeometryData
.getLength())
5010 bColumns
= bRows
= bSizes
= bHidden
= bFiltered
= bGroups
= false;
5012 OString aArguments
= aCommand
.copy(aSheetGeometryData
.getLength() + 1);
5013 sal_Int32 nParamIndex
= 0;
5016 OString aParamToken
= aArguments
.getToken(0, '&', nParamIndex
);
5017 sal_Int32 nIndex
= 0;
5022 OString aToken
= aParamToken
.getToken(0, '=', nIndex
);
5023 if (!aKey
.getLength())
5028 } while (nIndex
>= 0);
5030 bool bEnableFlag
= aValue
.isEmpty() ||
5031 aValue
.equalsIgnoreAsciiCase("true") || aValue
.toInt32() > 0;
5035 if (aKey
== "columns")
5037 else if (aKey
== "rows")
5039 else if (aKey
== "sizes")
5041 else if (aKey
== "hidden")
5043 else if (aKey
== "filtered")
5045 else if (aKey
== "groups")
5048 } while (nParamIndex
>= 0);
5051 OString aGeomDataStr
5052 = pDoc
->getSheetGeometryData(bColumns
, bRows
, bSizes
, bHidden
, bFiltered
, bGroups
);
5054 if (aGeomDataStr
.isEmpty())
5057 return convertOString(aGeomDataStr
);
5059 else if (aCommand
.startsWith(aCellCursor
))
5061 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5064 SetLastExceptionMsg("Document doesn't support tiled rendering");
5067 // Ignore command's deprecated parameters.
5068 tools::JsonWriter aJsonWriter
;
5069 pDoc
->getCellCursor(aJsonWriter
);
5070 return aJsonWriter
.extractData();
5072 else if (aCommand
.startsWith(aFontSubset
))
5074 return getFontSubset(OString(pCommand
+ aFontSubset
.getLength()));
5078 SetLastExceptionMsg("Unknown command, no values returned");
5083 static void doc_setClientZoom(LibreOfficeKitDocument
* pThis
, int nTilePixelWidth
, int nTilePixelHeight
,
5084 int nTileTwipWidth
, int nTileTwipHeight
)
5086 comphelper::ProfileZone
aZone("doc_setClientZoom");
5088 SolarMutexGuard aGuard
;
5089 SetLastExceptionMsg();
5091 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5094 SetLastExceptionMsg("Document doesn't support tiled rendering");
5098 pDoc
->setClientZoom(nTilePixelWidth
, nTilePixelHeight
, nTileTwipWidth
, nTileTwipHeight
);
5101 static void doc_setClientVisibleArea(LibreOfficeKitDocument
* pThis
, int nX
, int nY
, int nWidth
, int nHeight
)
5103 comphelper::ProfileZone
aZone("doc_setClientVisibleArea");
5105 SolarMutexGuard aGuard
;
5106 SetLastExceptionMsg();
5108 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5111 SetLastExceptionMsg("Document doesn't support tiled rendering");
5115 tools::Rectangle
aRectangle(Point(nX
, nY
), Size(nWidth
, nHeight
));
5116 pDoc
->setClientVisibleArea(aRectangle
);
5119 static void doc_setOutlineState(LibreOfficeKitDocument
* pThis
, bool bColumn
, int nLevel
, int nIndex
, bool bHidden
)
5121 comphelper::ProfileZone
aZone("doc_setOutlineState");
5123 SolarMutexGuard aGuard
;
5124 SetLastExceptionMsg();
5126 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5129 SetLastExceptionMsg("Document doesn't support tiled rendering");
5133 pDoc
->setOutlineState(bColumn
, nLevel
, nIndex
, bHidden
);
5136 static int doc_createViewWithOptions(LibreOfficeKitDocument
* pThis
,
5137 const char* pOptions
)
5139 comphelper::ProfileZone
aZone("doc_createView");
5141 SolarMutexGuard aGuard
;
5142 SetLastExceptionMsg();
5144 OUString aOptions
= getUString(pOptions
);
5145 const OUString aLanguage
= extractParameter(aOptions
, "Language");
5147 if (!aLanguage
.isEmpty())
5149 // Set the LOK language tag, used for dialog tunneling.
5150 comphelper::LibreOfficeKit::setLanguageTag(LanguageTag(aLanguage
));
5151 comphelper::LibreOfficeKit::setLocale(LanguageTag(aLanguage
));
5154 const OUString aDeviceFormFactor
= extractParameter(aOptions
, "DeviceFormFactor");
5155 SfxLokHelper::setDeviceFormFactor(aDeviceFormFactor
);
5157 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5158 const int nId
= SfxLokHelper::createView(pDocument
->mnDocumentId
);
5163 forceSetClipboardForCurrentView(pThis
);
5169 static int doc_createView(LibreOfficeKitDocument
* pThis
)
5171 return doc_createViewWithOptions(pThis
, nullptr); // No options.
5174 static void doc_destroyView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
)
5176 comphelper::ProfileZone
aZone("doc_destroyView");
5178 SolarMutexGuard aGuard
;
5179 SetLastExceptionMsg();
5181 LOKClipboardFactory::releaseClipboardForView(nId
);
5183 SfxLokHelper::destroyView(nId
);
5186 static void doc_setView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
)
5188 comphelper::ProfileZone
aZone("doc_setView");
5190 SolarMutexGuard aGuard
;
5191 SetLastExceptionMsg();
5193 SfxLokHelper::setView(nId
);
5196 static int doc_getView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/)
5198 comphelper::ProfileZone
aZone("doc_getView");
5200 SolarMutexGuard aGuard
;
5201 SetLastExceptionMsg();
5203 return SfxLokHelper::getView();
5206 static int doc_getViewsCount(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* pThis
)
5208 comphelper::ProfileZone
aZone("doc_getViewsCount");
5210 SolarMutexGuard aGuard
;
5211 SetLastExceptionMsg();
5213 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5214 return SfxLokHelper::getViewsCount(pDocument
->mnDocumentId
);
5217 static bool doc_getViewIds(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* pThis
, int* pArray
, size_t nSize
)
5219 comphelper::ProfileZone
aZone("doc_getViewsIds");
5221 SolarMutexGuard aGuard
;
5222 SetLastExceptionMsg();
5224 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5225 return SfxLokHelper::getViewIds(pDocument
->mnDocumentId
, pArray
, nSize
);
5228 static void doc_setViewLanguage(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/, int nId
, const char* language
)
5230 comphelper::ProfileZone
aZone("doc_setViewLanguage");
5232 SolarMutexGuard aGuard
;
5233 SetLastExceptionMsg();
5235 OUString sLanguage
= OStringToOUString(language
, RTL_TEXTENCODING_UTF8
);
5236 SfxLokHelper::setViewLanguage(nId
, sLanguage
);
5237 SfxLokHelper::setViewLocale(nId
, sLanguage
);
5242 unsigned char* doc_renderFont(LibreOfficeKitDocument
* pThis
,
5243 const char* pFontName
,
5248 return doc_renderFontOrientation(pThis
, pFontName
, pChar
, pFontWidth
, pFontHeight
, 0);
5251 unsigned char* doc_renderFontOrientation(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
* /*pThis*/,
5252 const char* pFontName
,
5258 comphelper::ProfileZone
aZone("doc_renderFont");
5260 SolarMutexGuard aGuard
;
5261 SetLastExceptionMsg();
5263 OString
aSearchedFontName(pFontName
);
5264 OUString
aText(OStringToOUString(pChar
, RTL_TEXTENCODING_UTF8
));
5265 SfxObjectShell
* pDocSh
= SfxObjectShell::Current();
5266 const SvxFontListItem
* pFonts
= static_cast<const SvxFontListItem
*>(
5267 pDocSh
->GetItem(SID_ATTR_CHAR_FONTLIST
));
5268 const FontList
* pList
= pFonts
? pFonts
->GetFontList() : nullptr;
5270 const int nDefaultFontSize
= 25;
5274 sal_uInt16 nFontCount
= pList
->GetFontNameCount();
5275 for (sal_uInt16 i
= 0; i
< nFontCount
; ++i
)
5277 const FontMetric
& rFontMetric
= pList
->GetFontName(i
);
5278 const OUString
& aFontName
= rFontMetric
.GetFamilyName();
5279 if (aSearchedFontName
!= aFontName
.toUtf8())
5282 if (aText
.isEmpty())
5283 aText
= rFontMetric
.GetFamilyName();
5285 auto aDevice(VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
));
5286 ::tools::Rectangle aRect
;
5287 vcl::Font
aFont(rFontMetric
);
5288 aFont
.SetFontSize(Size(0, nDefaultFontSize
));
5289 aFont
.SetOrientation(Degree10(pOrientation
));
5290 aDevice
->SetFont(aFont
);
5291 aDevice
->GetTextBoundRect(aRect
, aText
);
5292 if (aRect
.IsEmpty())
5295 int nFontWidth
= aRect
.BottomRight().X() + 1;
5296 int nFontHeight
= aRect
.BottomRight().Y() + 1;
5298 if (nFontWidth
<= 0 || nFontHeight
<= 0)
5301 if (*pFontWidth
> 0 && *pFontHeight
> 0)
5303 double fScaleX
= *pFontWidth
/ static_cast<double>(nFontWidth
) / 1.5;
5304 double fScaleY
= *pFontHeight
/ static_cast<double>(nFontHeight
) / 1.5;
5306 double fScale
= std::min(fScaleX
, fScaleY
);
5310 int nFontSize
= fScale
* nDefaultFontSize
;
5311 aFont
.SetFontSize(Size(0, nFontSize
));
5312 aDevice
->SetFont(aFont
);
5315 aRect
= tools::Rectangle(0, 0, *pFontWidth
, *pFontHeight
);
5317 nFontWidth
= *pFontWidth
;
5318 nFontHeight
= *pFontHeight
;
5322 unsigned char* pBuffer
= static_cast<unsigned char*>(malloc(4 * nFontWidth
* nFontHeight
));
5326 memset(pBuffer
, 0, nFontWidth
* nFontHeight
* 4);
5327 aDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
5328 aDevice
->SetOutputSizePixelScaleOffsetAndBuffer(
5329 Size(nFontWidth
, nFontHeight
), Fraction(1.0), Point(),
5332 if (*pFontWidth
> 0 && *pFontHeight
> 0)
5334 DrawTextFlags
const nStyle
=
5335 DrawTextFlags::Center
5336 | DrawTextFlags::VCenter
5337 | DrawTextFlags::MultiLine
5338 | DrawTextFlags::WordBreak
;// | DrawTextFlags::WordBreakHyphenation ;
5340 aDevice
->DrawText(aRect
, aText
, nStyle
);
5344 *pFontWidth
= nFontWidth
;
5345 *pFontHeight
= nFontHeight
;
5347 aDevice
->DrawText(Point(0,0), aText
);
5358 static void doc_paintWindow(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
5359 unsigned char* pBuffer
,
5360 const int nX
, const int nY
,
5361 const int nWidth
, const int nHeight
)
5363 doc_paintWindowDPI(pThis
, nLOKWindowId
, pBuffer
, nX
, nY
, nWidth
, nHeight
, 1.0);
5366 static void doc_paintWindowDPI(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
5367 unsigned char* pBuffer
,
5368 const int nX
, const int nY
,
5369 const int nWidth
, const int nHeight
,
5370 const double fDPIScale
)
5372 doc_paintWindowForView(pThis
, nLOKWindowId
, pBuffer
, nX
, nY
, nWidth
, nHeight
, fDPIScale
, -1);
5375 static void doc_paintWindowForView(LibreOfficeKitDocument
* pThis
, unsigned nLOKWindowId
,
5376 unsigned char* pBuffer
, const int nX
, const int nY
,
5377 const int nWidth
, const int nHeight
,
5378 const double fDPIScale
, int viewId
)
5380 comphelper::ProfileZone
aZone("doc_paintWindowDPI");
5382 SolarMutexGuard aGuard
;
5383 SetLastExceptionMsg();
5385 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
5388 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
5392 // Used to avoid work in setView if set.
5393 comphelper::LibreOfficeKit::setDialogPainting(true);
5396 doc_setView(pThis
, viewId
);
5398 // Setup cairo (or CoreGraphics, in the iOS case) to draw with the changed DPI scale (and return
5399 // back to 1.0 when the painting finishes)
5400 comphelper::ScopeGuard
dpiScaleGuard([]() { comphelper::LibreOfficeKit::setDPIScale(1.0); });
5401 comphelper::LibreOfficeKit::setDPIScale(fDPIScale
);
5405 CGContextRef cgc
= CGBitmapContextCreate(pBuffer
, nWidth
, nHeight
, 8, nWidth
*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst
| kCGImageByteOrder32Little
);
5407 CGContextTranslateCTM(cgc
, 0, nHeight
);
5408 CGContextScaleCTM(cgc
, fDPIScale
, -fDPIScale
);
5410 SystemGraphicsData aData
;
5411 aData
.rCGContext
= cgc
;
5413 ScopedVclPtrInstance
<VirtualDevice
> pDevice(aData
, Size(1, 1), DeviceFormat::DEFAULT
);
5414 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
5416 pDevice
->SetOutputSizePixel(Size(nWidth
, nHeight
));
5418 MapMode
aMapMode(pDevice
->GetMapMode());
5419 aMapMode
.SetOrigin(Point(-(nX
/ fDPIScale
), -(nY
/ fDPIScale
)));
5420 pDevice
->SetMapMode(aMapMode
);
5422 pWindow
->PaintToDevice(pDevice
.get(), Point(0, 0));
5424 CGContextRelease(cgc
);
5428 ScopedVclPtrInstance
<VirtualDevice
> pDevice(DeviceFormat::DEFAULT
);
5429 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
5431 pDevice
->SetOutputSizePixelScaleOffsetAndBuffer(Size(nWidth
, nHeight
), Fraction(1.0), Point(), pBuffer
);
5433 MapMode
aMapMode(pDevice
->GetMapMode());
5434 aMapMode
.SetOrigin(Point(-(nX
/ fDPIScale
), -(nY
/ fDPIScale
)));
5435 pDevice
->SetMapMode(aMapMode
);
5437 pWindow
->PaintToDevice(pDevice
.get(), Point(0, 0));
5440 comphelper::LibreOfficeKit::setDialogPainting(false);
5443 static void doc_postWindow(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
, int nAction
, const char* pData
)
5445 comphelper::ProfileZone
aZone("doc_postWindow");
5447 SolarMutexGuard aGuard
;
5448 SetLastExceptionMsg();
5450 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
5453 SetLastExceptionMsg("Document doesn't support dialog rendering, or window not found.");
5457 if (nAction
== LOK_WINDOW_CLOSE
)
5459 bool bWasDialog
= vcl::CloseDialog(pWindow
);
5462 if (FloatingWindow
* pFloatWin
= dynamic_cast<FloatingWindow
*>(pWindow
.get()))
5463 pFloatWin
->EndPopupMode(FloatWinPopupEndFlags::Cancel
| FloatWinPopupEndFlags::CloseAll
);
5466 else if (nAction
== LOK_WINDOW_PASTE
)
5469 css::uno::Sequence
<sal_Int8
> aData
;
5470 std::vector
<beans::PropertyValue
> aArgs(jsonToPropertyValuesVector(pData
));
5472 aArgs
.size() == 2 &&
5473 aArgs
[0].Name
== "MimeType" && (aArgs
[0].Value
>>= aMimeType
) &&
5474 aArgs
[1].Name
== "Data" && (aArgs
[1].Value
>>= aData
);
5477 if (!aMimeType
.isEmpty() && aData
.hasElements())
5479 uno::Reference
<datatransfer::XTransferable
> xTransferable(new LOKTransferable(aMimeType
, aData
));
5480 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard(new LOKClipboard
);
5481 xClipboard
->setContents(xTransferable
, uno::Reference
<datatransfer::clipboard::XClipboardOwner
>());
5482 pWindow
->SetClipboard(xClipboard
);
5484 KeyEvent
aEvent(0, KEY_PASTE
, 0);
5485 Application::PostKeyEvent(VclEventId::WindowKeyInput
, pWindow
, &aEvent
);
5488 SetLastExceptionMsg("Window command 'paste': wrong parameters.");
5492 // CERTIFICATE AND DOCUMENT SIGNING
5493 static bool doc_insertCertificate(LibreOfficeKitDocument
* pThis
,
5494 const unsigned char* pCertificateBinary
, const int nCertificateBinarySize
,
5495 const unsigned char* pPrivateKeyBinary
, const int nPrivateKeySize
)
5497 comphelper::ProfileZone
aZone("doc_insertCertificate");
5502 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5504 if (!pDocument
->mxComponent
.is())
5507 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
5511 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
5516 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
5517 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
5518 if (!xSecurityContext
.is())
5521 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
5522 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
5524 if (!xCertificateCreator
.is())
5527 uno::Sequence
<sal_Int8
> aCertificateSequence
;
5529 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
5530 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
5531 if (!aCertificateBase64String
.empty())
5533 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
5534 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
5538 aCertificateSequence
.realloc(nCertificateBinarySize
);
5539 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
5542 uno::Sequence
<sal_Int8
> aPrivateKeySequence
;
5543 std::string
aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary
), nPrivateKeySize
);
5544 std::string aPrivateKeyBase64String
= extractPrivateKey(aPrivateKeyString
);
5545 if (!aPrivateKeyBase64String
.empty())
5547 OUString aBase64OUString
= OUString::createFromAscii(aPrivateKeyBase64String
.c_str());
5548 comphelper::Base64::decode(aPrivateKeySequence
, aBase64OUString
);
5552 aPrivateKeySequence
.realloc(nPrivateKeySize
);
5553 std::copy(pPrivateKeyBinary
, pPrivateKeyBinary
+ nPrivateKeySize
, aPrivateKeySequence
.begin());
5556 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->createDERCertificateWithPrivateKey(aCertificateSequence
, aPrivateKeySequence
);
5558 if (!xCertificate
.is())
5561 SolarMutexGuard aGuard
;
5563 return pObjectShell
->SignDocumentContentUsingCertificate(xCertificate
);
5566 static bool doc_addCertificate(LibreOfficeKitDocument
* pThis
,
5567 const unsigned char* pCertificateBinary
, const int nCertificateBinarySize
)
5569 comphelper::ProfileZone
aZone("doc_addCertificate");
5574 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5576 if (!pDocument
->mxComponent
.is())
5579 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
5583 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
5588 uno::Reference
<xml::crypto::XSEInitializer
> xSEInitializer
= xml::crypto::SEInitializer::create(xContext
);
5589 uno::Reference
<xml::crypto::XXMLSecurityContext
> xSecurityContext
= xSEInitializer
->createSecurityContext(OUString());
5590 if (!xSecurityContext
.is())
5593 uno::Reference
<xml::crypto::XSecurityEnvironment
> xSecurityEnvironment
= xSecurityContext
->getSecurityEnvironment();
5594 uno::Reference
<xml::crypto::XCertificateCreator
> xCertificateCreator(xSecurityEnvironment
, uno::UNO_QUERY
);
5596 if (!xCertificateCreator
.is())
5599 uno::Sequence
<sal_Int8
> aCertificateSequence
;
5601 std::string
aCertificateString(reinterpret_cast<const char*>(pCertificateBinary
), nCertificateBinarySize
);
5602 std::string aCertificateBase64String
= extractCertificate(aCertificateString
);
5603 if (!aCertificateBase64String
.empty())
5605 OUString aBase64OUString
= OUString::createFromAscii(aCertificateBase64String
.c_str());
5606 comphelper::Base64::decode(aCertificateSequence
, aBase64OUString
);
5610 aCertificateSequence
.realloc(nCertificateBinarySize
);
5611 std::copy(pCertificateBinary
, pCertificateBinary
+ nCertificateBinarySize
, aCertificateSequence
.begin());
5614 uno::Reference
<security::XCertificate
> xCertificate
= xCertificateCreator
->addDERCertificateToTheDatabase(aCertificateSequence
, "TCu,Cu,Tu");
5616 if (!xCertificate
.is())
5619 SAL_INFO("lok", "Certificate Added = IssuerName: " << xCertificate
->getIssuerName() << " SubjectName: " << xCertificate
->getSubjectName());
5624 static int doc_getSignatureState(LibreOfficeKitDocument
* pThis
)
5626 comphelper::ProfileZone
aZone("doc_getSignatureState");
5628 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
5630 if (!pDocument
->mxComponent
.is())
5631 return int(SignatureState::UNKNOWN
);
5633 SfxBaseModel
* pBaseModel
= dynamic_cast<SfxBaseModel
*>(pDocument
->mxComponent
.get());
5635 return int(SignatureState::UNKNOWN
);
5637 SfxObjectShell
* pObjectShell
= pBaseModel
->GetObjectShell();
5639 return int(SignatureState::UNKNOWN
);
5641 SolarMutexGuard aGuard
;
5643 pObjectShell
->RecheckSignature(false);
5645 return int(pObjectShell
->GetDocumentSignatureState());
5648 static void doc_resizeWindow(LibreOfficeKitDocument
* /*pThis*/, unsigned nLOKWindowId
,
5649 const int nWidth
, const int nHeight
)
5651 SolarMutexGuard aGuard
;
5653 gImpl
->maLastExceptionMsg
.clear();
5655 VclPtr
<Window
> pWindow
= vcl::Window::FindLOKWindow(nLOKWindowId
);
5658 gImpl
->maLastExceptionMsg
= "Document doesn't support dialog resizing, or window not found.";
5662 pWindow
->SetSizePixel(Size(nWidth
, nHeight
));
5665 static void doc_completeFunction(LibreOfficeKitDocument
* pThis
, const char* pFunctionName
)
5667 SolarMutexGuard aGuard
;
5668 SetLastExceptionMsg();
5670 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5673 SetLastExceptionMsg("Document doesn't support tiled rendering");
5677 pDoc
->completeFunction(OUString::fromUtf8(pFunctionName
));
5681 static void doc_sendFormFieldEvent(LibreOfficeKitDocument
* pThis
, const char* pArguments
)
5683 SolarMutexGuard aGuard
;
5685 // Supported in Writer only
5686 if (doc_getDocumentType(pThis
) != LOK_DOCTYPE_TEXT
)
5689 StringMap
aMap(jsonToStringMap(pArguments
));
5690 ITiledRenderable
* pDoc
= getTiledRenderable(pThis
);
5693 SetLastExceptionMsg("Document doesn't support tiled rendering!");
5698 if (aMap
.find("type") == aMap
.end() || aMap
.find("cmd") == aMap
.end())
5700 SetLastExceptionMsg("Wrong arguments for sendFormFieldEvent!");
5704 pDoc
->executeFromFieldEvent(aMap
);
5707 static char* lo_getError (LibreOfficeKit
*pThis
)
5709 comphelper::ProfileZone
aZone("lo_getError");
5711 SolarMutexGuard aGuard
;
5713 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5714 return convertOUString(pLib
->maLastExceptionMsg
);
5717 static void lo_freeError(char* pFree
)
5722 static char* lo_getFilterTypes(LibreOfficeKit
* pThis
)
5724 SolarMutexGuard aGuard
;
5725 SetLastExceptionMsg();
5727 LibLibreOffice_Impl
* pImpl
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5729 if (!xSFactory
.is())
5730 xSFactory
= comphelper::getProcessServiceFactory();
5732 if (!xSFactory
.is())
5734 pImpl
->maLastExceptionMsg
= "Service factory is not available";
5738 uno::Reference
<container::XNameAccess
> xTypeDetection(xSFactory
->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY
);
5739 const uno::Sequence
<OUString
> aTypes
= xTypeDetection
->getElementNames();
5740 boost::property_tree::ptree aTree
;
5741 for (const OUString
& rType
: aTypes
)
5743 uno::Sequence
<beans::PropertyValue
> aValues
;
5744 if (xTypeDetection
->getByName(rType
) >>= aValues
)
5746 auto it
= std::find_if(aValues
.begin(), aValues
.end(), [](const beans::PropertyValue
& rValue
) { return rValue
.Name
== "MediaType"; });
5748 if (it
!= aValues
.end() && (it
->Value
>>= aValue
) && !aValue
.isEmpty())
5750 boost::property_tree::ptree aChild
;
5751 aChild
.put("MediaType", aValue
.toUtf8());
5752 aTree
.add_child(rType
.toUtf8().getStr(), aChild
);
5756 std::stringstream aStream
;
5757 boost::property_tree::write_json(aStream
, aTree
);
5758 return strdup(aStream
.str().c_str());
5761 static void lo_setOptionalFeatures(LibreOfficeKit
* pThis
, unsigned long long const features
)
5763 comphelper::ProfileZone
aZone("lo_setOptionalFeatures");
5765 SolarMutexGuard aGuard
;
5766 SetLastExceptionMsg();
5768 LibLibreOffice_Impl
*const pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5769 pLib
->mOptionalFeatures
= features
;
5770 if (features
& LOK_FEATURE_PART_IN_INVALIDATION_CALLBACK
)
5771 comphelper::LibreOfficeKit::setPartInInvalidation(true);
5772 if (features
& LOK_FEATURE_NO_TILED_ANNOTATIONS
)
5773 comphelper::LibreOfficeKit::setTiledAnnotations(false);
5774 if (features
& LOK_FEATURE_RANGE_HEADERS
)
5775 comphelper::LibreOfficeKit::setRangeHeaders(true);
5776 if (features
& LOK_FEATURE_VIEWID_IN_VISCURSOR_INVALIDATION_CALLBACK
)
5777 comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
5780 static void lo_setDocumentPassword(LibreOfficeKit
* pThis
,
5781 const char* pURL
, const char* pPassword
)
5783 comphelper::ProfileZone
aZone("lo_setDocumentPassword");
5785 SolarMutexGuard aGuard
;
5786 SetLastExceptionMsg();
5790 LibLibreOffice_Impl
*const pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
5791 assert(pLib
->mInteractionMap
.find(OString(pURL
)) != pLib
->mInteractionMap
.end());
5792 pLib
->mInteractionMap
.find(OString(pURL
))->second
->SetPassword(pPassword
);
5795 static char* lo_getVersionInfo(SAL_UNUSED_PARAMETER LibreOfficeKit
* /*pThis*/)
5797 SetLastExceptionMsg();
5798 return convertOUString(ReplaceStringHookProc(
5800 "\"ProductName\": \"%PRODUCTNAME\", "
5801 "\"ProductVersion\": \"%PRODUCTVERSION\", "
5802 "\"ProductExtension\": \"%PRODUCTEXTENSION\", "
5803 "\"BuildId\": \"%BUILDID\" "
5807 static void aBasicErrorFunc(const OUString
& rError
, const OUString
& rAction
)
5809 OString aBuffer
= "Unexpected dialog: " +
5810 OUStringToOString(rAction
, RTL_TEXTENCODING_ASCII_US
) +
5812 OUStringToOString(rError
, RTL_TEXTENCODING_ASCII_US
);
5814 fprintf(stderr
, "Unexpected basic error dialog '%s'\n", aBuffer
.getStr());
5817 static bool initialize_uno(const OUString
& aAppProgramURL
)
5820 // For iOS we already hardcode the inifile as "rc" in the .app directory.
5821 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/" SAL_CONFIGFILE("fundamental"));
5822 xContext
= cppu::defaultBootstrap_InitialComponentContext(aAppProgramURL
+ "/rc");
5823 #elif defined MACOSX
5824 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/../Resources/" SAL_CONFIGFILE("soffice"));
5825 xContext
= cppu::defaultBootstrap_InitialComponentContext();
5827 rtl::Bootstrap::setIniFilename(aAppProgramURL
+ "/" SAL_CONFIGFILE("soffice"));
5828 xContext
= cppu::defaultBootstrap_InitialComponentContext();
5833 SetLastExceptionMsg("XComponentContext could not be created");
5834 SAL_INFO("lok", "XComponentContext could not be created");
5838 xFactory
= xContext
->getServiceManager();
5841 SetLastExceptionMsg("XMultiComponentFactory could not be created");
5842 SAL_INFO("lok", "XMultiComponentFactory could not be created");
5846 xSFactory
.set(xFactory
, uno::UNO_QUERY_THROW
);
5847 comphelper::setProcessServiceFactory(xSFactory
);
5849 SAL_INFO("lok", "Uno initialized - " << xContext
.is());
5851 // set UserInstallation to user profile dir in test/user-template
5852 // rtl::Bootstrap aDefaultVars;
5853 // aDefaultVars.set(OUString("UserInstallation"), aAppProgramURL + "../registry" );
5854 // configmgr setup ?
5859 // pre-unipoll version.
5860 static void lo_startmain(void*)
5862 osl_setThreadName("lo_startmain");
5864 if (comphelper::SolarMutex::get())
5865 Application::GetSolarMutex().tryToAcquire();
5867 Application::UpdateMainThread();
5871 Application::ReleaseSolarMutex();
5875 static void lo_runLoop(LibreOfficeKit
* /*pThis*/,
5876 LibreOfficeKitPollCallback pPollCallback
,
5877 LibreOfficeKitWakeCallback pWakeCallback
,
5880 #if defined(IOS) || defined(ANDROID)
5881 Application::GetSolarMutex().acquire();
5885 SolarMutexGuard aGuard
;
5887 vcl::lok::registerPollCallbacks(pPollCallback
, pWakeCallback
, pData
);
5888 Application::UpdateMainThread();
5891 #if defined(IOS) || defined(ANDROID)
5892 vcl::lok::unregisterPollCallbacks();
5893 Application::ReleaseSolarMutex();
5897 static bool bInitialized
= false;
5899 static void lo_status_indicator_callback(void *data
, comphelper::LibreOfficeKit::statusIndicatorCallbackType type
, int percent
)
5901 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(data
);
5903 if (!pLib
->mpCallback
)
5908 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Start
:
5909 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START
, nullptr, pLib
->mpCallbackData
);
5911 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::SetValue
:
5912 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
,
5913 OUString(OUString::number(percent
)).toUtf8().getStr(), pLib
->mpCallbackData
);
5915 case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Finish
:
5916 pLib
->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_FINISH
, nullptr, pLib
->mpCallbackData
);
5921 /// Used only by LibreOfficeKit when used by Online to pre-initialize
5922 static void preloadData()
5924 comphelper::ProfileZone
aZone("preload data");
5926 // Create user profile in the temp directory for loading the dictionaries
5928 rtl::Bootstrap::get("UserInstallation", sUserPath
);
5929 utl::TempFile
aTempDir(nullptr, true);
5930 aTempDir
.EnableKillingFile();
5931 rtl::Bootstrap::set("UserInstallation", aTempDir
.GetURL());
5933 // Register the bundled extensions
5934 desktop::Desktop::SynchronizeExtensionRepositories(true);
5935 bool bAbort
= desktop::Desktop::CheckExtensionDependencies();
5937 std::cerr
<< "CheckExtensionDependencies failed" << std::endl
;
5939 // preload all available dictionaries
5940 css::uno::Reference
<css::linguistic2::XLinguServiceManager
> xLngSvcMgr
=
5941 css::linguistic2::LinguServiceManager::create(comphelper::getProcessComponentContext());
5942 css::uno::Reference
<linguistic2::XSpellChecker
> xSpellChecker(xLngSvcMgr
->getSpellChecker());
5944 std::cerr
<< "Preloading dictionaries: ";
5945 css::uno::Reference
<linguistic2::XSupportedLocales
> xSpellLocales(xSpellChecker
, css::uno::UNO_QUERY_THROW
);
5946 uno::Sequence
< css::lang::Locale
> aLocales
= xSpellLocales
->getLocales();
5947 for (auto &it
: aLocales
)
5949 std::cerr
<< it
.Language
<< "_" << it
.Country
<< " ";
5950 css::beans::PropertyValues aNone
;
5951 xSpellChecker
->isValid("forcefed", it
, aNone
);
5955 // Hack to load and cache the module liblocaledata_others.so which is not loaded normally
5956 // (when loading dictionaries of just non-Asian locales). Creating a XCalendar4 of one Asian locale
5957 // will cheaply load this missing "others" locale library. Appending an Asian locale in
5958 // LOK_ALLOWLIST_LANGUAGES env-var also works but at the cost of loading that dictionary.
5959 css::uno::Reference
< css::i18n::XCalendar4
> xCal
= css::i18n::LocaleCalendar2::create(comphelper::getProcessComponentContext());
5960 css::lang::Locale aAsianLocale
= {"hi", "IN", ""};
5961 xCal
->loadDefaultCalendar(aAsianLocale
);
5963 // preload all available thesauri
5964 css::uno::Reference
<linguistic2::XThesaurus
> xThesaurus(xLngSvcMgr
->getThesaurus());
5965 css::uno::Reference
<linguistic2::XSupportedLocales
> xThesLocales(xSpellChecker
, css::uno::UNO_QUERY_THROW
);
5966 aLocales
= xThesLocales
->getLocales();
5967 std::cerr
<< "Preloading thesauri: ";
5968 for (auto &it
: aLocales
)
5970 std::cerr
<< it
.Language
<< "_" << it
.Country
<< " ";
5971 css::beans::PropertyValues aNone
;
5972 xThesaurus
->queryMeanings("forcefed", it
, aNone
);
5976 css::uno::Reference
< css::ui::XAcceleratorConfiguration
> xGlobalCfg
= css::ui::GlobalAcceleratorConfiguration::create(
5977 comphelper::getProcessComponentContext());
5978 xGlobalCfg
->getAllKeyEvents();
5980 std::cerr
<< "Preload icons\n";
5981 ImageTree
&images
= ImageTree::get();
5982 images
.getImageUrl("forcefed.png", "style", "FO_oo");
5984 std::cerr
<< "Preload languages\n";
5986 // force load language singleton
5987 SvtLanguageTable::HasLanguageType(LANGUAGE_SYSTEM
);
5988 (void)LanguageTag::isValidBcp47("foo", nullptr);
5990 std::cerr
<< "Preload fonts\n";
5992 // Initialize fonts.
5993 css::uno::Reference
<css::linguistic2::XLinguServiceManager2
> xLangSrv
= css::linguistic2::LinguServiceManager::create(xContext
);
5996 css::uno::Reference
<css::linguistic2::XSpellChecker
> xSpell
= xLangSrv
->getSpellChecker();
5998 aLocales
= xSpell
->getLocales();
6001 for (const auto& aLocale
: std::as_const(aLocales
))
6003 //TODO: Add more types and cache more aggressively. For now this initializes the fontcache.
6004 using namespace ::com::sun::star::i18n::ScriptType
;
6006 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), LATIN
);
6007 OutputDevice::GetDefaultFont(DefaultFontType::LATIN_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
6008 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), ASIAN
);
6009 OutputDevice::GetDefaultFont(DefaultFontType::CJK_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
6010 nLang
= MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType(aLocale
, false), COMPLEX
);
6011 OutputDevice::GetDefaultFont(DefaultFontType::CTL_SPREADSHEET
, nLang
, GetDefaultFontFlags::OnlyOne
);
6014 // Set user profile's path back to the original one
6015 rtl::Bootstrap::set("UserInstallation", sUserPath
);
6020 class ProfileZoneDumper
: public AutoTimer
6022 static const int dumpTimeoutMS
= 5000;
6024 ProfileZoneDumper() : AutoTimer( "zone dumper" )
6026 SetTimeout(dumpTimeoutMS
);
6029 virtual void Invoke() override
6031 const css::uno::Sequence
<OUString
> aEvents
=
6032 comphelper::ProfileRecording::getRecordingAndClear();
6033 OStringBuffer aOutput
;
6034 for (const auto &s
: aEvents
)
6036 aOutput
.append(OUStringToOString(s
, RTL_TEXTENCODING_UTF8
));
6037 aOutput
.append("\n");
6039 OString aChunk
= aOutput
.makeStringAndClear();
6040 if (gImpl
&& gImpl
->mpCallback
)
6041 gImpl
->mpCallback(LOK_CALLBACK_PROFILE_FRAME
, aChunk
.getStr(), gImpl
->mpCallbackData
);
6045 static void activateNotebookbar(const OUString
& rApp
)
6047 OUString aPath
= "org.openoffice.Office.UI.ToolbarMode/Applications/" + rApp
;
6049 const utl::OConfigurationTreeRoot
aAppNode(xContext
, aPath
, true);
6051 if (aAppNode
.isValid())
6053 aAppNode
.setNodeValue("Active", makeAny(OUString("notebookbar.ui")));
6060 static int lo_initialize(LibreOfficeKit
* pThis
, const char* pAppPath
, const char* pUserProfileUrl
)
6063 PRE_INIT
, // setup shared data in master process
6064 SECOND_INIT
, // complete init. after fork
6065 FULL_INIT
// do a standard complete init.
6068 // Did we do a pre-initialize
6069 static bool bPreInited
= false;
6070 static bool bUnipoll
= false;
6071 static bool bProfileZones
= false;
6072 static bool bNotebookbar
= false;
6074 { // cf. string lifetime for preinit
6075 std::vector
<OUString
> aOpts
;
6077 // ':' delimited options - avoiding ABI change for new parameters
6078 const char *pOptions
= getenv("SAL_LOK_OPTIONS");
6080 aOpts
= comphelper::string::split(OUString(pOptions
, strlen(pOptions
), RTL_TEXTENCODING_UTF8
), ':');
6081 for (const auto &it
: aOpts
)
6083 if (it
== "unipoll")
6085 else if (it
== "profile_events")
6086 bProfileZones
= true;
6087 else if (it
== "sc_no_grid_bg")
6088 comphelper::LibreOfficeKit::setCompatFlag(
6089 comphelper::LibreOfficeKit::Compat::scNoGridBackground
);
6090 else if (it
== "sc_print_twips_msgs")
6091 comphelper::LibreOfficeKit::setCompatFlag(
6092 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
6093 else if (it
== "notebookbar")
6094 bNotebookbar
= true;
6098 // What stage are we at ?
6099 if (pThis
== nullptr)
6101 else if (bPreInited
)
6102 eStage
= SECOND_INIT
;
6106 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
6111 // Turn profile zones on early
6112 if (bProfileZones
&& eStage
== SECOND_INIT
)
6114 comphelper::ProfileRecording::startRecording(true);
6115 new ProfileZoneDumper();
6118 comphelper::ProfileZone
aZone("lok-init");
6120 if (eStage
== PRE_INIT
)
6121 rtl_alloc_preInit(true);
6122 else if (eStage
== SECOND_INIT
)
6123 rtl_alloc_preInit(false);
6125 if (eStage
!= SECOND_INIT
)
6126 comphelper::LibreOfficeKit::setActive();
6128 if (eStage
!= PRE_INIT
)
6129 comphelper::LibreOfficeKit::setStatusIndicatorCallback(lo_status_indicator_callback
, pLib
);
6131 if (pUserProfileUrl
&& eStage
!= PRE_INIT
)
6134 pUserProfileUrl
, strlen(pUserProfileUrl
), RTL_TEXTENCODING_UTF8
);
6136 if (url
.startsWithIgnoreAsciiCase("vnd.sun.star.pathname:", &path
))
6139 osl::FileBase::RC e
= osl::FileBase::getFileURLFromSystemPath(
6141 if (e
== osl::FileBase::E_None
)
6144 SAL_WARN("lok", "resolving <" << url
<< "> failed with " << +e
);
6146 rtl::Bootstrap::set("UserInstallation", url
);
6147 if (eStage
== SECOND_INIT
)
6148 utl::Bootstrap::reloadData();
6154 aAppPath
= OUString(pAppPath
, strlen(pAppPath
), RTL_TEXTENCODING_UTF8
);
6159 aAppPath
= OUString::fromUtf8(lo_get_app_data_dir()) + "/program";
6161 // Fun conversion dance back and forth between URLs and system paths...
6163 ::osl::Module::getUrlFromAddress( reinterpret_cast< oslGenericFunction
>(lo_initialize
),
6165 osl::FileBase::getSystemPathFromFileURL( aAppURL
, aAppPath
);
6169 // The above gives something like
6170 // "/private/var/containers/Bundle/Application/953AA851-CC15-4C60-A2CB-C2C6F24E6F71/Foo.app/Foo",
6171 // and we want to drop the final component (the binary name).
6172 sal_Int32 lastSlash
= aAppPath
.lastIndexOf('/');
6173 assert(lastSlash
> 0);
6174 aAppPath
= aAppPath
.copy(0, lastSlash
);
6179 if (osl::FileBase::getFileURLFromSystemPath(aAppPath
, aAppURL
) != osl::FileBase::E_None
)
6183 // A LibreOffice-using iOS app should have the ICU data file in the app bundle. Initialize ICU
6185 NSString
*bundlePath
= [[NSBundle mainBundle
] bundlePath
];
6187 int fd
= open([[bundlePath stringByAppendingPathComponent
:@
"ICU.dat"] UTF8String
], O_RDONLY
);
6189 NSLog(@
"Could not open ICU data file %s", [[bundlePath stringByAppendingPathComponent
:@
"ICU.dat"] UTF8String
]);
6193 if (fstat(fd
, &st
) == -1)
6194 NSLog(@
"fstat on ICU data file failed: %s", strerror(errno
));
6197 void *icudata
= mmap(0, (size_t) st
.st_size
, PROT_READ
, MAP_FILE
|MAP_PRIVATE
, fd
, 0);
6198 if (icudata
== MAP_FAILED
)
6199 NSLog(@
"mmap failed: %s", strerror(errno
));
6202 UErrorCode icuStatus
= U_ZERO_ERROR
;
6203 udata_setCommonData(icudata
, &icuStatus
);
6204 if (U_FAILURE(icuStatus
))
6205 NSLog(@
"udata_setCommonData failed");
6208 // Quick test that ICU works...
6209 UConverter
*cnv
= ucnv_open("iso-8859-3", &icuStatus
);
6210 if (U_SUCCESS(icuStatus
))
6213 NSLog(@
"ucnv_open() failed: %s", u_errorName(icuStatus
));
6223 if (eStage
!= SECOND_INIT
)
6225 SAL_INFO("lok", "Attempting to initialize UNO");
6227 if (!initialize_uno(aAppURL
))
6230 // Force headless -- this is only for bitmap rendering.
6231 rtl::Bootstrap::set("SAL_USE_VCLPLUGIN", "svp");
6233 // We specifically need to make sure we have the "headless"
6234 // command arg set (various code specifically checks via
6235 // CommandLineArgs):
6236 desktop::Desktop::GetCommandLineArgs().setHeadless();
6239 if (InitVCL() && [NSThread isMainThread
])
6241 static bool bFirstTime
= true;
6244 Application::GetSolarMutex().release();
6248 SfxApplication::GetOrCreate();
6251 #if HAVE_FEATURE_ANDROID_LOK
6252 // Register the bundled extensions - so that the dictionaries work
6253 desktop::Desktop::SynchronizeExtensionRepositories(false);
6254 bool bFailed
= desktop::Desktop::CheckExtensionDependencies();
6256 SAL_INFO("lok", "CheckExtensionDependencies failed");
6259 if (eStage
== PRE_INIT
)
6262 comphelper::ProfileZone
aInit("Init vcl");
6263 std::cerr
<< "Init vcl\n";
6267 // pre-load all graphic libraries.
6268 GraphicFilter::GetGraphicFilter().preload();
6270 // pre-load all component libraries.
6272 throw css::uno::DeploymentException("preInit: XComponentContext is not created");
6274 css::uno::Reference
< css::uno::XInterface
> xService
;
6275 xContext
->getValueByName("/singletons/com.sun.star.lang.theServiceManager") >>= xService
;
6277 throw css::uno::DeploymentException("preInit: XMultiComponentFactory is not created");
6279 css::uno::Reference
<css::lang::XInitialization
> aService(
6280 xService
, css::uno::UNO_QUERY_THROW
);
6283 // In order to load implementations and invoke
6284 // component factory it is required:
6285 // 1) defaultBootstrap_InitialComponentContext()
6286 // 2) comphelper::setProcessServiceFactory(xSFactory);
6289 comphelper::ProfileZone
aInit("preload");
6290 aService
->initialize({css::uno::makeAny
<OUString
>("preload")});
6292 { // Force load some modules
6293 comphelper::ProfileZone
aInit("preload modules");
6294 VclBuilder::preload();
6295 VclAbstractDialogFactory::Create();
6300 // Release Solar Mutex, lo_startmain thread should acquire it.
6301 Application::ReleaseSolarMutex();
6304 setLanguageAndLocale("en-US");
6307 if (eStage
!= PRE_INIT
)
6309 SAL_INFO("lok", "Re-initialize temp paths");
6310 SvtPathOptions aOptions
;
6312 osl::FileBase::getTempDirURL(aNewTemp
);
6313 aOptions
.SetTempPath(aNewTemp
);
6314 desktop::Desktop::CreateTemporaryDirectory();
6316 // The RequestHandler is specifically set to be ready when all the other
6317 // init in Desktop::Main (run from soffice_main) is done. We can enable
6318 // the RequestHandler here (without starting any IPC thread;
6319 // shortcutting the invocation in Desktop::Main that would start the IPC
6320 // thread), and can then use it to wait until we're definitely ready to
6323 SAL_INFO("lok", "Enabling RequestHandler");
6324 RequestHandler::Enable(false);
6325 SAL_INFO("lok", "Starting soffice_main");
6326 RequestHandler::SetReady(false);
6329 // Start the main thread only in non-unipoll mode (i.e. multithreaded).
6330 pLib
->maThread
= osl_createThread(lo_startmain
, nullptr);
6331 SAL_INFO("lok", "Waiting for RequestHandler");
6332 RequestHandler::WaitForReady();
6333 SAL_INFO("lok", "RequestHandler ready -- continuing");
6339 if (eStage
!= SECOND_INIT
)
6340 ErrorRegistry::RegisterDisplay(aBasicErrorFunc
);
6342 SAL_INFO("lok", "LOK Initialized");
6343 if (eStage
== PRE_INIT
)
6346 bInitialized
= true;
6348 catch (css::uno::Exception
& exception
)
6350 fprintf(stderr
, "Bootstrapping exception '%s'\n",
6351 OUStringToOString(exception
.Message
, RTL_TEXTENCODING_UTF8
).getStr());
6354 if (eStage
== PRE_INIT
)
6356 comphelper::ThreadPool::getSharedOptimalPool().shutdown();
6359 // Turn off quick editing on IOS and ANDROID
6360 #if defined IOS || defined ANDROID
6361 if (officecfg::Office::Impress::Misc::TextObject::QuickEditing::get())
6363 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
6364 officecfg::Office::Impress::Misc::TextObject::QuickEditing::set(false, batch
);
6371 activateNotebookbar("Writer");
6372 activateNotebookbar("Calc");
6373 activateNotebookbar("Impress");
6376 return bInitialized
;
6380 LibreOfficeKit
*libreofficekit_hook_2(const char* install_path
, const char* user_profile_url
)
6384 SAL_INFO("lok", "Create libreoffice object");
6386 gImpl
= new LibLibreOffice_Impl();
6387 if (!lo_initialize(gImpl
, install_path
, user_profile_url
))
6392 return static_cast<LibreOfficeKit
*>(gImpl
);
6396 LibreOfficeKit
*libreofficekit_hook(const char* install_path
)
6398 return libreofficekit_hook_2(install_path
, nullptr);
6402 int lok_preinit(const char* install_path
, const char* user_profile_url
)
6404 return lo_initialize(nullptr, install_path
, user_profile_url
);
6407 static void lo_destroy(LibreOfficeKit
* pThis
)
6409 SolarMutexClearableGuard aGuard
;
6411 LibLibreOffice_Impl
* pLib
= static_cast<LibLibreOffice_Impl
*>(pThis
);
6414 SAL_INFO("lok", "LO Destroy");
6416 comphelper::LibreOfficeKit::setStatusIndicatorCallback(nullptr, nullptr);
6417 uno::Reference
<frame::XDesktop2
> xDesktop
= frame::Desktop::create ( ::comphelper::getProcessComponentContext() );
6418 // FIXME: the terminate() call here is a no-op because it detects
6419 // that LibreOfficeKit::isActive() and then returns early!
6420 bool bSuccess
= xDesktop
.is() && xDesktop
->terminate();
6424 bSuccess
= GetpApp() && GetpApp()->QueryExit();
6429 Application::Quit();
6434 osl_joinWithThread(pLib
->maThread
);
6435 osl_destroyThread(pLib
->maThread
);
6438 bInitialized
= false;
6439 SAL_INFO("lok", "LO Destroy Done");
6444 // Used by the unmaintained LibreOfficeLight app. Once that has been retired, get rid of this, too.
6446 __attribute__((visibility("default")))
6447 void temporaryHackToInvokeCallbackHandlers(LibreOfficeKitDocument
* pThis
)
6449 SolarMutexGuard aGuard
;
6450 LibLODocument_Impl
* pDocument
= static_cast<LibLODocument_Impl
*>(pThis
);
6452 int nOrigViewId
= doc_getView(pThis
);
6454 if (nOrigViewId
>= 0 && pDocument
->mpCallbackFlushHandlers
[nOrigViewId
])
6456 pDocument
->mpCallbackFlushHandlers
[nOrigViewId
]->Invoke();
6464 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */