summaryrefslogtreecommitdiff
path: root/desktop/source/lib/init.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/source/lib/init.cxx')
-rw-r--r--desktop/source/lib/init.cxx522
1 files changed, 330 insertions, 192 deletions
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 8428dc2343d4..f1becd67d215 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -183,6 +183,7 @@
#include "lokinteractionhandler.hxx"
#include "lokclipboard.hxx"
+#include <officecfg/Office/Common.hxx>
#include <officecfg/Office/Impress.hxx>
using namespace css;
@@ -217,8 +218,14 @@ public:
SetTimeout(dumpTimeoutMS);
Start();
}
+
virtual void Invoke() override
{
+ flushRecordings();
+ }
+
+ static void flushRecordings()
+ {
const css::uno::Sequence<OUString> aEvents =
comphelper::TraceEvent::getRecordingAndClear();
OStringBuffer aOutput;
@@ -1077,6 +1084,10 @@ static void doc_postKeyEvent(LibreOfficeKitDocument* pThis,
int nType,
int nCharCode,
int nKeyCode);
+static void doc_setBlockedCommandList(LibreOfficeKitDocument* pThis,
+ int nViewId,
+ const char* bolckedCommandList);
+
static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument* pThis,
unsigned nWindowId,
int nType,
@@ -1251,6 +1262,26 @@ rtl::Reference<LOKClipboard> forceSetClipboardForCurrentView(LibreOfficeKitDocum
#endif
+const vcl::Font* FindFont(const OUString& rFontName)
+{
+ SfxObjectShell* pDocSh = SfxObjectShell::Current();
+ const SvxFontListItem* pFonts
+ = static_cast<const SvxFontListItem*>(pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
+ const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr;
+ if (pList && !rFontName.isEmpty())
+ if (sal_Handle hMetric = pList->GetFirstFontMetric(rFontName))
+ return &FontList::GetFontMetric(hMetric);
+ return nullptr;
+}
+
+vcl::Font FindFont_FallbackToDefault(const OUString& rFontName)
+{
+ if (auto pFound = FindFont(rFontName))
+ return *pFound;
+
+ return OutputDevice::GetDefaultFont(DefaultFontType::SANS_UNICODE, LANGUAGE_NONE,
+ GetDefaultFontFlags::NONE);
+}
} // anonymous namespace
LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XComponent> &xComponent, int nDocumentId)
@@ -1340,6 +1371,8 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone
m_pDocumentClass->sendFormFieldEvent = doc_sendFormFieldEvent;
+ m_pDocumentClass->setBlockedCommandList = doc_setBlockedCommandList;
+
gDocumentClass = m_pDocumentClass;
}
pClass = m_pDocumentClass.get();
@@ -1372,13 +1405,29 @@ static OUString getGenerator()
extern "C" {
+CallbackFlushHandler::TimeoutIdle::TimeoutIdle( CallbackFlushHandler* handler )
+ : Timer( "lokit timer callback" )
+ , mHandler( handler )
+{
+ // A second timer with higher priority, it'll ensure we flush in reasonable time if we get too busy
+ // to get POST_PAINT priority processing. Otherwise it could take a long time to flush.
+ SetPriority(TaskPriority::DEFAULT);
+ SetTimeout( 100 ); // 100 ms
+}
+
+void CallbackFlushHandler::TimeoutIdle::Invoke()
+{
+ mHandler->Invoke();
+}
+
CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, LibreOfficeKitCallback pCallback, void* pData)
- : Idle( "lokit timer callback" ),
+ : Idle( "lokit idle callback" ),
m_pDocument(pDocument),
m_pCallback(pCallback),
m_pData(pData),
m_nDisableCallbacks(0),
- m_bEventLatch(false)
+ m_bEventLatch(false),
+ m_TimeoutIdle( this )
{
SetPriority(TaskPriority::POST_PAINT);
@@ -1394,6 +1443,7 @@ CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, Li
m_states.emplace(LOK_CALLBACK_CELL_ADDRESS, "NIL");
m_states.emplace(LOK_CALLBACK_CURSOR_VISIBLE, "NIL");
m_states.emplace(LOK_CALLBACK_SET_PART, "NIL");
+ m_states.emplace(LOK_CALLBACK_TABLE_SELECTED, "NIL");
Start();
}
@@ -1412,22 +1462,33 @@ void CallbackFlushHandler::callback(const int type, const char* payload, void* d
}
}
+CallbackFlushHandler::queue_type2::reverse_iterator CallbackFlushHandler::toQueue2(CallbackFlushHandler::queue_type1::reverse_iterator pos)
+{
+ int delta = std::distance(m_queue1.rbegin(), pos);
+ return m_queue2.rbegin() + delta;
+}
+
void CallbackFlushHandler::queue(const int type, const char* data)
{
comphelper::ProfileZone aZone("CallbackFlushHander::queue");
- CallbackData aCallbackData(type, (data ? data : "(nil)"));
+ CallbackData aCallbackData(data ? data : "(nil)");
const std::string& payload = aCallbackData.PayloadString;
- SAL_INFO("lok", "Queue: [" << type << "]: [" << payload << "] on " << m_queue.size() << " entries.");
+ SAL_INFO("lok", "Queue: [" << type << "]: [" << payload << "] on " << m_queue1.size() << " entries.");
bool bIsChartActive = false;
+ bool bIsComment = false;
if (type == LOK_CALLBACK_GRAPHIC_SELECTION)
{
LokChartHelper aChartHelper(SfxViewShell::Current());
bIsChartActive = aChartHelper.GetWindow() != nullptr;
}
+ else if (type == LOK_CALLBACK_COMMENT)
+ {
+ bIsComment = true;
+ }
- if (callbacksDisabled() && !bIsChartActive)
+ if (callbacksDisabled() && !bIsChartActive && !bIsComment)
{
// We drop notifications when this is set, except for important ones.
// When we issue a complex command (such as .uno:InsertAnnotation)
@@ -1496,11 +1557,13 @@ void CallbackFlushHandler::queue(const int type, const char* data)
case LOK_CALLBACK_WINDOW:
case LOK_CALLBACK_CALC_FUNCTION_LIST:
case LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY:
+ case LOK_CALLBACK_REFERENCE_MARKS:
+ case LOK_CALLBACK_CELL_AUTO_FILL_AREA:
{
- const auto& pos = std::find_if(m_queue.rbegin(), m_queue.rend(),
- [type] (const queue_type::value_type& elem) { return (elem.Type == type); });
-
- if (pos != m_queue.rend() && pos->PayloadString == payload)
+ const auto& pos = std::find_if(m_queue1.rbegin(), m_queue1.rend(),
+ [type] (int elemType) { return (elemType == type); });
+ auto pos2 = toQueue2(pos);
+ if (pos != m_queue1.rend() && pos2->PayloadString == payload)
{
SAL_INFO("lok", "Skipping queue duplicate [" << type << + "]: [" << payload << "].");
return;
@@ -1511,15 +1574,17 @@ void CallbackFlushHandler::queue(const int type, const char* data)
if (type == LOK_CALLBACK_TEXT_SELECTION && payload.empty())
{
- const auto& posStart = std::find_if(m_queue.rbegin(), m_queue.rend(),
- [] (const queue_type::value_type& elem) { return (elem.Type == LOK_CALLBACK_TEXT_SELECTION_START); });
- if (posStart != m_queue.rend())
- posStart->PayloadString.clear();
+ const auto& posStart = std::find_if(m_queue1.rbegin(), m_queue1.rend(),
+ [] (int elemType) { return (elemType == LOK_CALLBACK_TEXT_SELECTION_START); });
+ auto posStart2 = toQueue2(posStart);
+ if (posStart != m_queue1.rend())
+ posStart2->PayloadString.clear();
- const auto& posEnd = std::find_if(m_queue.rbegin(), m_queue.rend(),
- [] (const queue_type::value_type& elem) { return (elem.Type == LOK_CALLBACK_TEXT_SELECTION_END); });
- if (posEnd != m_queue.rend())
- posEnd->PayloadString.clear();
+ const auto& posEnd = std::find_if(m_queue1.rbegin(), m_queue1.rend(),
+ [] (int elemType) { return (elemType == LOK_CALLBACK_TEXT_SELECTION_END); });
+ auto posEnd2 = toQueue2(posEnd);
+ if (posEnd != m_queue1.rend())
+ posEnd2->PayloadString.clear();
}
// When payload is empty discards any previous state.
@@ -1534,7 +1599,7 @@ void CallbackFlushHandler::queue(const int type, const char* data)
case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
case LOK_CALLBACK_INVALIDATE_TILES:
if (removeAll(
- [type](const queue_type::value_type& elem) { return (elem.Type == type); }))
+ [type](int elemType, const CallbackData&) { return (elemType == type); }))
SAL_INFO("lok", "Removed dups of [" << type << "]: [" << payload << "].");
break;
}
@@ -1558,7 +1623,7 @@ void CallbackFlushHandler::queue(const int type, const char* data)
case LOK_CALLBACK_RULER_UPDATE:
{
if (removeAll(
- [type](const queue_type::value_type& elem) { return (elem.Type == type); }))
+ [type](int elemType, const CallbackData&) { return (elemType == type); }))
SAL_INFO("lok", "Removed dups of [" << type << "]: [" << payload << "].");
}
break;
@@ -1582,15 +1647,15 @@ void CallbackFlushHandler::queue(const int type, const char* data)
payload.find("\"hyperlink\": {}") == std::string::npos;
const int nViewId = lcl_getViewId(payload);
removeAll(
- [type, nViewId, hyperLinkException] (const queue_type::value_type& elem) {
- return (elem.Type == type && nViewId == lcl_getViewId(elem) && !hyperLinkException);
+ [type, nViewId, hyperLinkException] (int elemType, const CallbackData& elemData) {
+ return (elemType == type && nViewId == lcl_getViewId(elemData) && !hyperLinkException);
}
);
}
break;
case LOK_CALLBACK_INVALIDATE_TILES:
- if (processInvalidateTilesEvent(aCallbackData))
+ if (processInvalidateTilesEvent(type, aCallbackData))
return;
break;
@@ -1608,8 +1673,8 @@ void CallbackFlushHandler::queue(const int type, const char* data)
if (name != ".uno:ModifiedStatus=")
{
removeAll(
- [type, &name] (const queue_type::value_type& elem) {
- return (elem.Type == type) && (elem.PayloadString.compare(0, name.size(), name) == 0);
+ [type, &name] (int elemType, const CallbackData& elemData) {
+ return (elemType == type) && (elemData.PayloadString.compare(0, name.size(), name) == 0);
}
);
}
@@ -1618,7 +1683,7 @@ void CallbackFlushHandler::queue(const int type, const char* data)
break;
case LOK_CALLBACK_WINDOW:
- if (processWindowEvent(aCallbackData))
+ if (processWindowEvent(type, aCallbackData))
return;
break;
@@ -1626,8 +1691,8 @@ void CallbackFlushHandler::queue(const int type, const char* data)
{
// remove only selection ranges and 'EMPTY' messages
// always send 'INPLACE' and 'INPLACE EXIT' messages
- removeAll([type, payload] (const queue_type::value_type& elem)
- { return (elem.Type == type && elem.PayloadString[0] != 'I'); });
+ removeAll([type, payload] (int elemType, const CallbackData& elemData)
+ { return (elemType == type && elemData.PayloadString[0] != 'I'); });
}
break;
}
@@ -1635,23 +1700,26 @@ void CallbackFlushHandler::queue(const int type, const char* data)
// Validate that the cached data and the payload string are identical.
assert(aCallbackData.validate() && "Cached callback payload object and string mismatch!");
- m_queue.emplace_back(aCallbackData);
- SAL_INFO("lok", "Queued #" << (m_queue.size() - 1) <<
- " [" << type << "]: [" << payload << "] to have " << m_queue.size() << " entries.");
+ m_queue1.emplace_back(type);
+ m_queue2.emplace_back(aCallbackData);
+ SAL_INFO("lok", "Queued #" << (m_queue1.size() - 1) <<
+ " [" << type << "]: [" << payload << "] to have " << m_queue1.size() << " entries.");
#ifdef DBG_UTIL
{
// Dump the queue state and validate cached data.
int i = 1;
std::ostringstream oss;
- if (m_queue.empty())
+ if (m_queue1.empty())
oss << "Empty";
else
- oss << m_queue.size() << " items\n";
- for (const CallbackData& c : m_queue)
- oss << i++ << ": [" << c.Type << "] [" << c.PayloadString << "].\n";
+ oss << m_queue1.size() << " items\n";
+ auto it1 = m_queue1.begin();
+ auto it2 = m_queue2.begin();
+ for (; it1 != m_queue1.end(); ++it1, ++it2)
+ oss << i++ << ": [" << *it1 << "] [" << it2->PayloadString << "].\n";
SAL_INFO("lok", "Current Queue: " << oss.str());
- for (const CallbackData& c : m_queue)
+ for (const CallbackData& c : m_queue2)
assert(c.validate());
}
#endif
@@ -1661,12 +1729,13 @@ void CallbackFlushHandler::queue(const int type, const char* data)
{
Start();
}
+ if (!m_TimeoutIdle.IsActive())
+ m_TimeoutIdle.Start();
}
-bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData& aCallbackData)
+bool CallbackFlushHandler::processInvalidateTilesEvent(int type, CallbackData& aCallbackData)
{
const std::string& payload = aCallbackData.PayloadString;
- const int type = aCallbackData.Type;
RectangleAndPart& rcNew = aCallbackData.setRectangleAndPart(payload);
if (rcNew.isEmpty())
@@ -1678,12 +1747,13 @@ bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData& aCallbackDa
// If we have to invalidate all tiles, we can skip any new tile invalidation.
// Find the last INVALIDATE_TILES entry, if any to see if it's invalidate-all.
const auto& pos
- = std::find_if(m_queue.rbegin(), m_queue.rend(), [](const queue_type::value_type& elem) {
- return (elem.Type == LOK_CALLBACK_INVALIDATE_TILES);
+ = std::find_if(m_queue1.rbegin(), m_queue1.rend(), [](int elemType) {
+ return (elemType == LOK_CALLBACK_INVALIDATE_TILES);
});
- if (pos != m_queue.rend())
+ if (pos != m_queue1.rend())
{
- const RectangleAndPart& rcOld = pos->getRectangleAndPart();
+ auto pos2 = toQueue2(pos);
+ const RectangleAndPart& rcOld = pos2->getRectangleAndPart();
if (rcOld.isInfinite() && (rcOld.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart))
{
SAL_INFO("lok", "Skipping queue [" << type << "]: [" << payload
@@ -1707,11 +1777,11 @@ bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData& aCallbackDa
{
SAL_INFO("lok", "Have Empty [" << type << "]: [" << payload
<< "] so removing all with part " << rcNew.m_nPart << ".");
- removeAll([&rcNew](const queue_type::value_type& elem) {
- if (elem.Type == LOK_CALLBACK_INVALIDATE_TILES)
+ removeAll([&rcNew](int elemType, const CallbackData& elemData) {
+ if (elemType == LOK_CALLBACK_INVALIDATE_TILES)
{
// Remove exiting if new is all-encompassing, or if of the same part.
- const RectangleAndPart rcOld = RectangleAndPart::Create(elem.PayloadString);
+ const RectangleAndPart rcOld = RectangleAndPart::Create(elemData.PayloadString);
return (rcNew.m_nPart == -1 || rcOld.m_nPart == rcNew.m_nPart);
}
@@ -1724,10 +1794,10 @@ bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData& aCallbackDa
const auto rcOrig = rcNew;
SAL_INFO("lok", "Have [" << type << "]: [" << payload << "] so merging overlapping.");
- removeAll([&rcNew](const queue_type::value_type& elem) {
- if (elem.Type == LOK_CALLBACK_INVALIDATE_TILES)
+ removeAll([&rcNew](int elemType, const CallbackData& elemData) {
+ if (elemType == LOK_CALLBACK_INVALIDATE_TILES)
{
- const RectangleAndPart& rcOld = elem.getRectangleAndPart();
+ const RectangleAndPart& rcOld = elemData.getRectangleAndPart();
if (rcNew.m_nPart != -1 && rcOld.m_nPart != -1 && rcOld.m_nPart != rcNew.m_nPart)
{
SAL_INFO("lok", "Nothing to merge between new: "
@@ -1796,10 +1866,9 @@ bool CallbackFlushHandler::processInvalidateTilesEvent(CallbackData& aCallbackDa
return false;
}
-bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData)
+bool CallbackFlushHandler::processWindowEvent(int type, CallbackData& aCallbackData)
{
const std::string& payload = aCallbackData.PayloadString;
- const int type = aCallbackData.Type;
boost::property_tree::ptree& aTree = aCallbackData.setJson(payload);
const unsigned nLOKWindowId = aTree.get<unsigned>("id", 0);
@@ -1811,10 +1880,10 @@ bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData)
// remove all previous window part invalidations
if (aRectStr.empty())
{
- removeAll([&nLOKWindowId](const queue_type::value_type& elem) {
- if (elem.Type == LOK_CALLBACK_WINDOW)
+ removeAll([&nLOKWindowId](int elemType, const CallbackData& elemData) {
+ if (elemType == LOK_CALLBACK_WINDOW)
{
- const boost::property_tree::ptree& aOldTree = elem.getJson();
+ const boost::property_tree::ptree& aOldTree = elemData.getJson();
if (nLOKWindowId == aOldTree.get<unsigned>("id", 0)
&& aOldTree.get<std::string>("action", "") == "invalidate")
{
@@ -1828,17 +1897,22 @@ bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData)
{
// if we have to invalidate all of the window, ignore
// any part invalidation message
- const auto invAllExist = std::any_of(m_queue.rbegin(), m_queue.rend(),
- [&nLOKWindowId] (const queue_type::value_type& elem)
- {
- if (elem.Type != LOK_CALLBACK_WINDOW)
- return false;
-
- const boost::property_tree::ptree& aOldTree = elem.getJson();
- return nLOKWindowId == aOldTree.get<unsigned>("id", 0)
- && aOldTree.get<std::string>("action", "") == "invalidate"
- && aOldTree.get<std::string>("rectangle", "").empty();
- });
+ bool invAllExist = false;
+ auto it1 = m_queue1.rbegin();
+ auto it2 = m_queue2.rbegin();
+ for (;it1 != m_queue1.rend(); ++it1, ++it2)
+ {
+ if (*it1 != LOK_CALLBACK_WINDOW)
+ continue;
+ const boost::property_tree::ptree& aOldTree = it2->getJson();
+ if (nLOKWindowId == aOldTree.get<unsigned>("id", 0)
+ && aOldTree.get<std::string>("action", "") == "invalidate"
+ && aOldTree.get<std::string>("rectangle", "").empty())
+ {
+ invAllExist = true;
+ break;
+ }
+ }
// we found a invalidate-all window callback
if (invAllExist)
@@ -1856,11 +1930,11 @@ bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData)
tools::Rectangle aNewRect(nLeft, nTop, nLeft + nWidth, nTop + nHeight);
bool currentIsRedundant = false;
removeAll([&aNewRect, &nLOKWindowId,
- &currentIsRedundant](const queue_type::value_type& elem) {
- if (elem.Type != LOK_CALLBACK_WINDOW)
+ &currentIsRedundant](int elemType, const CallbackData& elemData) {
+ if (elemType != LOK_CALLBACK_WINDOW)
return false;
- const boost::property_tree::ptree& aOldTree = elem.getJson();
+ const boost::property_tree::ptree& aOldTree = elemData.getJson();
if (aOldTree.get<std::string>("action", "") == "invalidate")
{
// Not possible that we encounter an empty rectangle here; we already handled this case above.
@@ -1931,10 +2005,10 @@ bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData)
else if (aAction == "created")
{
// Remove all previous actions on same dialog, if we are creating it anew.
- removeAll([&nLOKWindowId](const queue_type::value_type& elem) {
- if (elem.Type == LOK_CALLBACK_WINDOW)
+ removeAll([&nLOKWindowId](int elemType, const CallbackData& elemData) {
+ if (elemType == LOK_CALLBACK_WINDOW)
{
- const boost::property_tree::ptree& aOldTree = elem.getJson();
+ const boost::property_tree::ptree& aOldTree = elemData.getJson();
if (nLOKWindowId == aOldTree.get<unsigned>("id", 0))
return true;
}
@@ -1959,10 +2033,10 @@ bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData)
{
// A size change is practically re-creation of the window.
// But at a minimum it's a full invalidation.
- removeAll([&nLOKWindowId](const queue_type::value_type& elem) {
- if (elem.Type == LOK_CALLBACK_WINDOW)
+ removeAll([&nLOKWindowId](int elemType, const CallbackData& elemData) {
+ if (elemType == LOK_CALLBACK_WINDOW)
{
- const boost::property_tree::ptree& aOldTree = elem.getJson();
+ const boost::property_tree::ptree& aOldTree = elemData.getJson();
if (nLOKWindowId == aOldTree.get<unsigned>("id", 0))
{
const std::string aOldAction = aOldTree.get<std::string>("action", "");
@@ -1986,12 +2060,14 @@ void CallbackFlushHandler::Invoke()
{
std::scoped_lock<std::mutex> lock(m_mutex);
- SAL_INFO("lok", "Flushing " << m_queue.size() << " elements.");
- for (const auto& rCallbackData : m_queue)
+ SAL_INFO("lok", "Flushing " << m_queue1.size() << " elements.");
+ auto it1 = m_queue1.begin();
+ auto it2 = m_queue2.begin();
+ for (; it1 != m_queue1.end(); ++it1, ++it2)
{
- const int type = rCallbackData.Type;
- const auto& payload = rCallbackData.PayloadString;
- const int viewId = lcl_isViewCallbackType(type) ? lcl_getViewId(rCallbackData) : -1;
+ const int type = *it1;
+ const auto& payload = it2->PayloadString;
+ const int viewId = lcl_isViewCallbackType(type) ? lcl_getViewId(*it2) : -1;
if (viewId == -1)
{
@@ -2039,20 +2115,32 @@ void CallbackFlushHandler::Invoke()
m_pCallback(type, payload.c_str(), m_pData);
}
- m_queue.clear();
+ m_queue1.clear();
+ m_queue2.clear();
+ m_TimeoutIdle.Stop();
}
}
-bool CallbackFlushHandler::removeAll(const std::function<bool (const CallbackFlushHandler::queue_type::value_type&)>& rTestFunc)
+bool CallbackFlushHandler::removeAll(const std::function<bool (int, const CallbackData&)>& rTestFunc)
{
- auto newEnd = std::remove_if(m_queue.begin(), m_queue.end(), rTestFunc);
- if (newEnd != m_queue.end())
+ bool bErased = false;
+ auto it1 = m_queue1.begin();
+ auto it2 = m_queue2.begin();
+ while (it1 != m_queue1.end())
{
- m_queue.erase(newEnd, m_queue.end());
- return true;
+ if (rTestFunc(*it1, *it2))
+ {
+ it1 = m_queue1.erase(it1);
+ it2 = m_queue2.erase(it2);
+ bErased = true;
+ }
+ else
+ {
+ ++it1;
+ ++it2;
+ }
}
-
- return false;
+ return bErased;
}
void CallbackFlushHandler::addViewStates(int viewId)
@@ -2292,7 +2380,7 @@ static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis,
Application::SetDialogCancelMode(DialogCancelMode::LOKSilent);
}
- uno::Sequence<css::beans::PropertyValue> aFilterOptions(3);
+ uno::Sequence<css::beans::PropertyValue> aFilterOptions(4);
aFilterOptions[0] = css::beans::PropertyValue( "FilterOptions",
0,
uno::makeAny(aOptions),
@@ -2339,6 +2427,13 @@ static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis,
aFilterOptions[3].Value <<= nUpdateDoc;
*/
+ // set this explicitly false to be able to load template files
+ // as regular files, otherwise we cannot save them; it will try
+ // to bring saveas dialog which cannot work with LOK case
+ aFilterOptions[3].Name = "AsTemplate";
+ aFilterOptions[3].Value <<= false;
+
+
const int nThisDocumentId = nDocumentIdCounter++;
SfxViewShell::SetCurrentDocId(ViewShellDocId(nThisDocumentId));
uno::Reference<lang::XComponent> xComponent = xComponentLoader->loadComponentFromURL(
@@ -2648,6 +2743,34 @@ static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* sUrl, const cha
bool bFullSheetPreview = sFullSheetPreview == "true";
+ // Select a pdf version if specified a valid one. If invalid then fail.
+ // If not specified then ignore.
+ sal_Int32 pdfVer = 0;
+ if ((aIndex = aFilterOptions.indexOf(",PDFVer=")) >= 0)
+ {
+ int bIndex = aFilterOptions.indexOf("PDFVEREND");
+ OUString sPdfVer = aFilterOptions.copy(aIndex+8, bIndex-(aIndex+8));
+
+ OUString temp = aFilterOptions.copy(0, aIndex);
+ aFilterOptions = temp + aFilterOptions.copy(bIndex+9);
+
+ if (sPdfVer.equalsIgnoreAsciiCase("PDF/A-1b"))
+ pdfVer = 1;
+ else if (sPdfVer.equalsIgnoreAsciiCase("PDF/A-2b"))
+ pdfVer = 2;
+ else if (sPdfVer.equalsIgnoreAsciiCase("PDF/A-3b"))
+ pdfVer = 3;
+ else if (sPdfVer.equalsIgnoreAsciiCase("PDF-1.5"))
+ pdfVer = 15;
+ else if (sPdfVer.equalsIgnoreAsciiCase("PDF-1.6"))
+ pdfVer = 16;
+ else
+ {
+ SetLastExceptionMsg("wrong PDF version");
+ return false;
+ }
+ }
+
// 'TakeOwnership' == this is a 'real' SaveAs (that is, the document
// gets a new name). When this is not provided, the meaning of
// saveAs() is more like save-a-copy, which allows saving to any
@@ -2684,6 +2807,9 @@ static int doc_saveAs(LibreOfficeKitDocument* pThis, const char* sUrl, const cha
if (bFullSheetPreview)
aFilterDataMap["SinglePageSheets"] <<= true;
+ if (pdfVer)
+ aFilterDataMap["SelectPdfVersion"] <<= pdfVer;
+
if (!aFilterDataMap.empty())
{
aSaveMediaDescriptor["FilterData"] <<= aFilterDataMap.getAsConstPropertyValueList();
@@ -2743,6 +2869,7 @@ static void doc_iniUnoCommands ()
OUString(".uno:IncrementIndent"),
OUString(".uno:Italic"),
OUString(".uno:JustifyPara"),
+ OUString(".uno:JumpToMark"),
OUString(".uno:OutlineFont"),
OUString(".uno:LeftPara"),
OUString(".uno:LanguageStatus"),
@@ -2759,6 +2886,9 @@ static void doc_iniUnoCommands ()
OUString(".uno:InsertPage"),
OUString(".uno:DeletePage"),
OUString(".uno:DuplicatePage"),
+ OUString(".uno:InsertSlide"),
+ OUString(".uno:DeleteSlide"),
+ OUString(".uno:DuplicateSlide"),
OUString(".uno:Cut"),
OUString(".uno:Copy"),
OUString(".uno:Paste"),
@@ -3331,6 +3461,7 @@ static void doc_paintPartTile(LibreOfficeKitDocument* pThis,
int nOrigPart = 0;
const bool isText = (doc_getDocumentType(pThis) == LOK_DOCTYPE_TEXT);
int nViewId = nOrigViewId;
+ int nLastNonEditorView = nViewId;
if (!isText)
{
// Check if just switching to another view is enough, that has
@@ -3340,9 +3471,15 @@ static void doc_paintPartTile(LibreOfficeKitDocument* pThis,
SfxViewShell* pViewShell = SfxViewShell::GetFirst();
while (pViewShell)
{
- if (pViewShell->getPart() == nPart)
+ bool bIsInEdit = pViewShell->GetDrawView() &&
+ pViewShell->GetDrawView()->GetTextEditOutliner();
+ if (!bIsInEdit)
+ nLastNonEditorView = pViewShell->GetViewShellId().get();
+
+ if (pViewShell->getPart() == nPart && !bIsInEdit)
{
nViewId = static_cast<sal_Int32>(pViewShell->GetViewShellId());
+ nLastNonEditorView = nViewId;
doc_setView(pThis, nViewId);
break;
}
@@ -3350,6 +3487,14 @@ static void doc_paintPartTile(LibreOfficeKitDocument* pThis,
}
}
+ // if not found view with correct part - at least avoid rendering active textbox
+ SfxViewShell* pCurrentViewShell = SfxViewShell::Current();
+ if (pCurrentViewShell && pCurrentViewShell->GetDrawView() &&
+ pCurrentViewShell->GetDrawView()->GetTextEditOutliner())
+ {
+ doc_setView(pThis, nLastNonEditorView);
+ }
+
nOrigPart = doc_getPart(pThis);
if (nPart != nOrigPart)
{
@@ -3554,6 +3699,12 @@ static void doc_postKeyEvent(LibreOfficeKitDocument* pThis, int nType, int nChar
}
}
+static void doc_setBlockedCommandList(LibreOfficeKitDocument* /*pThis*/, int nViewId, const char* bolckedCommandList)
+{
+ SolarMutexGuard aGuard;
+ SfxLokHelper::setBlockedCommandList(nViewId, bolckedCommandList);
+}
+
static void doc_postWindowExtTextInputEvent(LibreOfficeKitDocument* pThis, unsigned nWindowId, int nType, const char* pText)
{
comphelper::ProfileZone aZone("doc_postWindowExtTextInputEvent");
@@ -3710,6 +3861,7 @@ static size_t doc_renderShapeSelection(LibreOfficeKitDocument* pThis, char** pOu
}
aMediaDescriptor["SelectionOnly"] <<= true;
aMediaDescriptor["OutputStream"] <<= xOut;
+ aMediaDescriptor["IsPreview"] <<= true; // will down-scale graphics
xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList());
@@ -3904,6 +4056,7 @@ static void lo_setOption(LibreOfficeKit* /*pThis*/, const char *pOption, const c
{
if (strcmp(pValue, "start") == 0)
{
+ comphelper::TraceEvent::setBufferSizeAndCallback(100, TraceEventDumper::flushRecordings);
comphelper::TraceEvent::startRecording();
if (traceEventDumper == nullptr)
traceEventDumper = new TraceEventDumper();
@@ -4749,43 +4902,25 @@ static char* getFonts (const char* pCommand)
static char* getFontSubset (const OString& aFontName)
{
OUString aFoundFont(::rtl::Uri::decode(OStringToOUString(aFontName, RTL_TEXTENCODING_UTF8), rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8));
- SfxObjectShell* pDocSh = SfxObjectShell::Current();
- const SvxFontListItem* pFonts = static_cast<const SvxFontListItem*>(
- pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
- const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr;
boost::property_tree::ptree aTree;
aTree.put("commandName", ".uno:FontSubset");
boost::property_tree::ptree aValues;
- if ( pList && !aFoundFont.isEmpty() )
+ if (const vcl::Font* pFont = FindFont(aFoundFont))
{
- sal_uInt16 nFontCount = pList->GetFontNameCount();
- sal_uInt16 nItFont = 0;
- for (; nItFont < nFontCount; ++nItFont)
- {
- if (aFoundFont == pList->GetFontName(nItFont).GetFamilyName())
- {
- break;
- }
- }
+ FontCharMapRef xFontCharMap (new FontCharMap());
+ auto aDevice(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT));
- if ( nItFont < nFontCount )
- {
- FontCharMapRef xFontCharMap (new FontCharMap());
- auto aDevice(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT));
- const vcl::Font& aFont(pList->GetFontName(nItFont));
+ aDevice->SetFont(*pFont);
+ aDevice->GetFontCharMap(xFontCharMap);
+ SubsetMap aSubMap(xFontCharMap);
- aDevice->SetFont(aFont);
- aDevice->GetFontCharMap(xFontCharMap);
- SubsetMap aSubMap(xFontCharMap);
-
- for (auto const& subset : aSubMap.GetSubsetMap())
- {
- boost::property_tree::ptree aChild;
- aChild.put("", static_cast<int>(ublock_getCode(subset.GetRangeMin())));
- aValues.push_back(std::make_pair("", aChild));
- }
+ for (auto const& subset : aSubMap.GetSubsetMap())
+ {
+ boost::property_tree::ptree aChild;
+ aChild.put("", static_cast<int>(ublock_getCode(subset.GetRangeMin())));
+ aValues.push_back(std::make_pair("", aChild));
}
}
@@ -5406,98 +5541,80 @@ unsigned char* doc_renderFontOrientation(SAL_UNUSED_PARAMETER LibreOfficeKitDocu
SolarMutexGuard aGuard;
SetLastExceptionMsg();
- OString aSearchedFontName(pFontName);
- OUString aText(OStringToOUString(pChar, RTL_TEXTENCODING_UTF8));
- SfxObjectShell* pDocSh = SfxObjectShell::Current();
- const SvxFontListItem* pFonts = static_cast<const SvxFontListItem*>(
- pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
- const FontList* pList = pFonts ? pFonts->GetFontList() : nullptr;
-
const int nDefaultFontSize = 25;
- if ( pList )
- {
- sal_uInt16 nFontCount = pList->GetFontNameCount();
- for (sal_uInt16 i = 0; i < nFontCount; ++i)
- {
- const FontMetric& rFontMetric = pList->GetFontName(i);
- const OUString& aFontName = rFontMetric.GetFamilyName();
- if (aSearchedFontName != aFontName.toUtf8())
- continue;
-
- if (aText.isEmpty())
- aText = rFontMetric.GetFamilyName();
+ auto aFont = FindFont_FallbackToDefault(OStringToOUString(pFontName, RTL_TEXTENCODING_UTF8));
- auto aDevice(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT));
- ::tools::Rectangle aRect;
- vcl::Font aFont(rFontMetric);
- aFont.SetFontSize(Size(0, nDefaultFontSize));
- aFont.SetOrientation(pOrientation);
- aDevice->SetFont(aFont);
- aDevice->GetTextBoundRect(aRect, aText);
- if (aRect.IsEmpty())
- break;
+ OUString aText(OStringToOUString(pChar, RTL_TEXTENCODING_UTF8));
+ if (aText.isEmpty())
+ aText = aFont.GetFamilyName();
+
+ auto aDevice(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT));
+ ::tools::Rectangle aRect;
+ aFont.SetFontSize(Size(0, nDefaultFontSize));
+ aFont.SetOrientation(pOrientation);
+ aDevice->SetFont(aFont);
+ aDevice->GetTextBoundRect(aRect, aText);
+ if (aRect.IsEmpty())
+ return nullptr;
- int nFontWidth = aRect.BottomRight().X() + 1;
- int nFontHeight = aRect.BottomRight().Y() + 1;
+ int nFontWidth = aRect.BottomRight().X() + 1;
+ int nFontHeight = aRect.BottomRight().Y() + 1;
- if (!(nFontWidth > 0 && nFontHeight > 0))
- break;
+ if (!(nFontWidth > 0 && nFontHeight > 0))
+ return nullptr;
- if (*pFontWidth > 0 && *pFontHeight > 0)
- {
- double fScaleX = *pFontWidth / static_cast<double>(nFontWidth) / 1.5;
- double fScaleY = *pFontHeight / static_cast<double>(nFontHeight) / 1.5;
+ if (*pFontWidth > 0 && *pFontHeight > 0)
+ {
+ double fScaleX = *pFontWidth / static_cast<double>(nFontWidth) / 1.5;
+ double fScaleY = *pFontHeight / static_cast<double>(nFontHeight) / 1.5;
- double fScale = std::min(fScaleX, fScaleY);
+ double fScale = std::min(fScaleX, fScaleY);
- if (fScale >= 1.0)
- {
- int nFontSize = fScale * nDefaultFontSize;
- aFont.SetFontSize(Size(0, nFontSize));
- aDevice->SetFont(aFont);
- }
+ if (fScale >= 1.0)
+ {
+ int nFontSize = fScale * nDefaultFontSize;
+ aFont.SetFontSize(Size(0, nFontSize));
+ aDevice->SetFont(aFont);
+ }
- aRect = tools::Rectangle(0, 0, *pFontWidth, *pFontHeight);
+ aRect = tools::Rectangle(0, 0, *pFontWidth, *pFontHeight);
- nFontWidth = *pFontWidth;
- nFontHeight = *pFontHeight;
+ nFontWidth = *pFontWidth;
+ nFontHeight = *pFontHeight;
- }
+ }
- unsigned char* pBuffer = static_cast<unsigned char*>(malloc(4 * nFontWidth * nFontHeight));
- if (!pBuffer)
- break;
+ unsigned char* pBuffer = static_cast<unsigned char*>(malloc(4 * nFontWidth * nFontHeight));
+ if (!pBuffer)
+ return nullptr;
- memset(pBuffer, 0, nFontWidth * nFontHeight * 4);
- aDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
- aDevice->SetOutputSizePixelScaleOffsetAndBuffer(
- Size(nFontWidth, nFontHeight), Fraction(1.0), Point(),
- pBuffer);
+ memset(pBuffer, 0, nFontWidth * nFontHeight * 4);
+ aDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
+ aDevice->SetOutputSizePixelScaleOffsetAndBuffer(
+ Size(nFontWidth, nFontHeight), Fraction(1.0), Point(),
+ pBuffer);
- if (*pFontWidth > 0 && *pFontHeight > 0)
- {
- DrawTextFlags const nStyle =
- DrawTextFlags::Center
- | DrawTextFlags::VCenter
- | DrawTextFlags::MultiLine
- | DrawTextFlags::WordBreak;// | DrawTextFlags::WordBreakHyphenation ;
+ if (*pFontWidth > 0 && *pFontHeight > 0)
+ {
+ DrawTextFlags const nStyle =
+ DrawTextFlags::Center
+ | DrawTextFlags::VCenter
+ | DrawTextFlags::MultiLine
+ | DrawTextFlags::WordBreak;// | DrawTextFlags::WordBreakHyphenation ;
- aDevice->DrawText(aRect, aText, nStyle);
- }
- else
- {
- *pFontWidth = nFontWidth;
- *pFontHeight = nFontHeight;
+ aDevice->DrawText(aRect, aText, nStyle);
+ }
+ else
+ {
+ *pFontWidth = nFontWidth;
+ *pFontHeight = nFontHeight;
- aDevice->DrawText(Point(0,0), aText);
- }
+ aDevice->DrawText(Point(0,0), aText);
+ }
- return pBuffer;
- }
- }
- return nullptr;
+ return pBuffer;
}
@@ -6042,7 +6159,7 @@ static void lo_runLoop(LibreOfficeKit* /*pThis*/,
static bool bInitialized = false;
-static void lo_status_indicator_callback(void *data, comphelper::LibreOfficeKit::statusIndicatorCallbackType type, int percent)
+static void lo_status_indicator_callback(void *data, comphelper::LibreOfficeKit::statusIndicatorCallbackType type, int percent, const char* pText)
{
LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(data);
@@ -6052,7 +6169,7 @@ static void lo_status_indicator_callback(void *data, comphelper::LibreOfficeKit:
switch (type)
{
case comphelper::LibreOfficeKit::statusIndicatorCallbackType::Start:
- pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START, nullptr, pLib->mpCallbackData);
+ pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_START, pText, pLib->mpCallbackData);
break;
case comphelper::LibreOfficeKit::statusIndicatorCallbackType::SetValue:
pLib->mpCallback(LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE,
@@ -6173,6 +6290,25 @@ static void activateNotebookbar(const OUString& rApp)
aAppNode.commit();
}
}
+void setCertificateDir()
+{
+ const char* pEnvVarString = ::getenv("LO_CERTIFICATE_DATABASE_PATH");
+ if (pEnvVarString)
+ {
+ OUString aCertificateDatabasePath = OStringToOUString(pEnvVarString, RTL_TEXTENCODING_UTF8);
+ try
+ {
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Security::Scripting::CertDir::set(aCertificateDatabasePath, pBatch);
+ officecfg::Office::Common::Security::Scripting::ManualCertDir::set(aCertificateDatabasePath, pBatch);
+ pBatch->commit();
+ }
+ catch (uno::Exception const& rException)
+ {
+ SAL_WARN("lok", "Failed to set the NSS certificate database directory: " << rException.Message);
+ }
+ }
+}
static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char* pUserProfileUrl)
{
@@ -6481,6 +6617,8 @@ static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char
}
#endif
+ setCertificateDir();
+
if (bNotebookbar)
{
activateNotebookbar("Writer");