[Libreoffice-commits] core.git: Branch 'feature/lok-clipboard' - 18 commits - desktop/qa desktop/source include/LibreOfficeKit sc/source sfx2/source sw/source vcl/source
Michael Meeks (via logerrit)
logerrit at kemper.freedesktop.org
Fri Jul 26 20:39:41 UTC 2019
Rebased ref, commits from common ancestor:
commit 111e7a59f7b415c21115e2eb31dc5e2a4e8ecb17
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Thu Jul 25 19:02:47 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:39 2019 -0400
clipboard: repair unit test to be run in lok mode.
SwTransferable::AddSupporteFormats needs kit to be active.
Change-Id: I1e494edcb857399ca4e981fcf716d0204653ba3d
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 7ad2f1e45817..39be487931f3 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -2635,6 +2635,9 @@ void DesktopLOKTest::testShowHideDialog()
void DesktopLOKTest::testComplexSelection()
{
+ // needed for SwTransferable to cope with the selection.
+ comphelper::LibreOfficeKit::setActive();
+
// Start with a blank text file and add contents.
LibLODocument_Impl* pDocument = loadDoc("blank_text.odt");
static const OString aText("hello world");
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 37f7899be01f..6e2ca6d37a07 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -878,7 +878,6 @@ ITiledRenderable* getTiledRenderable(LibreOfficeKitDocument* pThis)
* we also need to ensure that this works for the first view which
* has no clear 'createView' called for it (unfortunately).
*/
-
rtl::Reference<LOKClipboard> forceSetClipboardForCurrentView(LibreOfficeKitDocument *pThis)
{
ITiledRenderable* pDoc = getTiledRenderable(pThis);
commit 06c9fe38702e6f9167392ebc50d0dff1164c371c
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Mon Jul 22 19:00:23 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:38 2019 -0400
clipboard: log before erasing
Change-Id: I6d59cdd31c62bbc7db81ccb8985745f68d19cd28
diff --git a/desktop/source/lib/lokclipboard.cxx b/desktop/source/lib/lokclipboard.cxx
index 7eefd09370d1..f44f4e9fed81 100644
--- a/desktop/source/lib/lokclipboard.cxx
+++ b/desktop/source/lib/lokclipboard.cxx
@@ -51,8 +51,8 @@ void LOKClipboardFactory::releaseClipboardForView(int nViewId)
auto it = gClipboards.get()->find(nViewId);
if (it != gClipboards.get()->end())
{
+ SAL_INFO("lok", "Releasing clip: " << it->second.get() << " for destroyed " << nViewId);
gClipboards.get()->erase(it);
- SAL_INFO("lok", "Released clip: " << it->second.get() << " for destroyed " << nViewId);
}
}
}
commit 27127e3b168c7ae4cae827efb99b6338ea867f23
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jul 23 09:49:11 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:37 2019 -0400
clipboard: check for null.
Change-Id: I07060035a9744642c98d4a0946695408dc0f6b42
diff --git a/desktop/source/lib/lokclipboard.cxx b/desktop/source/lib/lokclipboard.cxx
index 3285965c846f..7eefd09370d1 100644
--- a/desktop/source/lib/lokclipboard.cxx
+++ b/desktop/source/lib/lokclipboard.cxx
@@ -37,7 +37,6 @@ rtl::Reference<LOKClipboard> LOKClipboardFactory::getClipboardForCurView()
return xClip;
}
-/// FIXME: should really copy and stash its content for a bit.
void LOKClipboardFactory::releaseClipboardForView(int nViewId)
{
osl::MutexGuard aGuard(gMutex);
@@ -47,7 +46,7 @@ void LOKClipboardFactory::releaseClipboardForView(int nViewId)
gClipboards.get()->clear();
SAL_INFO("lok", "Released all clipboards on doc destroy\n");
}
- else
+ else if (gClipboards.get())
{
auto it = gClipboards.get()->find(nViewId);
if (it != gClipboards.get()->end())
commit 2749cb5ea4ca0d6cdd13bb7e38b958f5d3d59641
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Mon Jul 22 09:48:46 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:36 2019 -0400
lok: share more of the clipboard mime-type handling code.
Change-Id: I98fc9fa0fd1b5afa00c33b642d2d504eab0b62ba
diff --git a/desktop/source/lib/lokclipboard.cxx b/desktop/source/lib/lokclipboard.cxx
index 17a9c5c54e4f..3285965c846f 100644
--- a/desktop/source/lib/lokclipboard.cxx
+++ b/desktop/source/lib/lokclipboard.cxx
@@ -189,20 +189,7 @@ LOKTransferable::LOKTransferable(const size_t nInCount, const char** pInMimeType
m_aFlavors = css::uno::Sequence<css::datatransfer::DataFlavor>(nInCount);
for (size_t i = 0; i < nInCount; ++i)
{
- OUString aMimeType = OUString::fromUtf8(pInMimeTypes[i]);
-
- // cf. sot/source/base/exchange.cxx for these two exceptional types.
- if (aMimeType.startsWith("text/plain"))
- {
- aMimeType = "text/plain;charset=utf-16";
- m_aFlavors[i].DataType = cppu::UnoType<OUString>::get();
- }
- else if (aMimeType == "application/x-libreoffice-tsvc")
- m_aFlavors[i].DataType = cppu::UnoType<OUString>::get();
- else
- m_aFlavors[i].DataType = cppu::UnoType<uno::Sequence<sal_Int8>>::get();
- m_aFlavors[i].MimeType = aMimeType;
- m_aFlavors[i].HumanPresentableName = aMimeType;
+ initFlavourFromMime(m_aFlavors[i], OUString::fromUtf8(pInMimeTypes[i]));
uno::Any aContent;
if (m_aFlavors[i].DataType == cppu::UnoType<OUString>::get())
commit daf09d987722351b3ab1ce1c747a93c9c639e2c0
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Jul 20 11:22:09 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:36 2019 -0400
clipboard: encourage paste to show up by having some dummy content.
Having an empty system clipboard is a hyper-unusual state, but
this is quite common for new lok instances. If we populate some dummy
state we can hide that.
Allows context-menu paste into new documents.
Change-Id: Ia180dd370c180d2d666cc57330db6c1385578a36
diff --git a/desktop/source/lib/lokclipboard.cxx b/desktop/source/lib/lokclipboard.cxx
index f53202903761..17a9c5c54e4f 100644
--- a/desktop/source/lib/lokclipboard.cxx
+++ b/desktop/source/lib/lokclipboard.cxx
@@ -69,6 +69,9 @@ LOKClipboard::LOKClipboard()
: cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard,
css::lang::XServiceInfo>(m_aMutex)
{
+ // Encourage 'paste' menu items to always show up.
+ uno::Reference<datatransfer::XTransferable> xTransferable(new LOKTransferable());
+ setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>());
}
Sequence<OUString> LOKClipboard::getSupportedServiceNames_static()
@@ -150,6 +153,18 @@ LOKTransferable::LOKTransferable(const OUString& sMimeType,
aContent <<= aSequence;
m_aContent.push_back(aContent);
}
+
+/// Use to ensure we have some dummy content on the clipboard to allow a 1st 'paste'
+LOKTransferable::LOKTransferable()
+{
+ m_aContent.reserve(1);
+ m_aFlavors = css::uno::Sequence<css::datatransfer::DataFlavor>(1);
+ initFlavourFromMime(m_aFlavors[0], "text/plain");
+ uno::Any aContent;
+ aContent <<= OUString();
+ m_aContent.push_back(aContent);
+}
+
// cf. sot/source/base/exchange.cxx for these two exceptional types.
void LOKTransferable::initFlavourFromMime(css::datatransfer::DataFlavor& rFlavor,
OUString aMimeType)
diff --git a/desktop/source/lib/lokclipboard.hxx b/desktop/source/lib/lokclipboard.hxx
index 1ade5c0a3e0b..3b8f9d8ee7c9 100644
--- a/desktop/source/lib/lokclipboard.hxx
+++ b/desktop/source/lib/lokclipboard.hxx
@@ -77,6 +77,7 @@ class LOKTransferable : public cppu::WeakImplHelper<css::datatransfer::XTransfer
void initFlavourFromMime(css::datatransfer::DataFlavor& rFlavor, OUString sMimeType);
public:
+ LOKTransferable();
LOKTransferable(const size_t nInCount, const char** pInMimeTypes, const size_t* pInSizes,
const char** pInStreams);
LOKTransferable(const OUString& sMimeType, const css::uno::Sequence<sal_Int8>& aSequence);
diff --git a/vcl/source/treelist/transfer.cxx b/vcl/source/treelist/transfer.cxx
index 10782592f5a2..5e41bde0378d 100644
--- a/vcl/source/treelist/transfer.cxx
+++ b/vcl/source/treelist/transfer.cxx
@@ -392,7 +392,7 @@ sal_Bool SAL_CALL TransferableHelper::isComplex()
{
// By default everything is complex, until proven otherwise
// in the respective document type transferable handler.
- return sal_True;
+ return true;
}
Sequence< DataFlavor > SAL_CALL TransferableHelper::getTransferDataFlavors()
commit 26d3711339a29cc4d839994b2bef8f15663a9938
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Jun 28 18:36:15 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:35 2019 -0400
Try harder to generate HTML from text.
Change-Id: I5b4778cceefc652274a72b779cd6c060a50bf06c
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index a0d8b9436d52..37f7899be01f 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -3429,6 +3429,54 @@ static OUString getGenerator()
static bool getFromTransferrable(
const css::uno::Reference<css::datatransfer::XTransferable> &xTransferable,
+ const OString &aInMimeType, OString &aRet);
+
+static bool encodeImageAsHTML(
+ const css::uno::Reference<css::datatransfer::XTransferable> &xTransferable,
+ const OString &aMimeType, OString &aRet)
+{
+ if (!getFromTransferrable(xTransferable, aMimeType, aRet))
+ return false;
+
+ // Encode in base64.
+ auto aSeq = Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(aRet.getStr()),
+ aRet.getLength());
+ OUStringBuffer aBase64Data;
+ comphelper::Base64::encode(aBase64Data, aSeq);
+
+ // Embed in HTML.
+ aRet = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
+ "<html><head>"
+ "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
+ "name=\"generator\" content=\""
+ + getGenerator().toUtf8()
+ + "\"/>"
+ "</head><body><img src=\"data:" + aMimeType + ";base64,"
+ + aBase64Data.makeStringAndClear().toUtf8() + "\"/></body></html>";
+
+ return true;
+}
+
+static bool encodeTextAsHTML(
+ const css::uno::Reference<css::datatransfer::XTransferable> &xTransferable,
+ const OString &aMimeType, OString &aRet)
+{
+ if (!getFromTransferrable(xTransferable, aMimeType, aRet))
+ return false;
+
+ // Embed in HTML - FIXME: needs some escaping.
+ aRet = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
+ "<html><head>"
+ "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
+ "name=\"generator\" content=\""
+ + getGenerator().toUtf8()
+ + "\"/></head><body><pre>" + aRet + "</pre></body></html>";
+
+ return true;
+}
+
+static bool getFromTransferrable(
+ const css::uno::Reference<css::datatransfer::XTransferable> &xTransferable,
const OString &aInMimeType, OString &aRet)
{
OString aMimeType(aInMimeType);
@@ -3454,28 +3502,15 @@ static bool getFromTransferrable(
if (!xTransferable->isDataFlavorSupported(aFlavor))
{
- // If html is not supported, might be a graphic-selection, which supports png.
- if (aInMimeType == "text/html" && getFromTransferrable(xTransferable, "image/png", aRet))
+ // Try harder for HTML it is our copy/paste meta-file format
+ if (aInMimeType == "text/html")
{
- // Encode in base64.
- auto aSeq = Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(aRet.getStr()),
- aRet.getLength());
- OUStringBuffer aBase64Data;
- comphelper::Base64::encode(aBase64Data, aSeq);
-
- // Embed in HTML.
- static const OString aHeader
- = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">"
- "<html><head>"
- "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
- "name=\"generator\" content=\""
- + getGenerator().toUtf8()
- + "\"/>"
- "</head><body><img src=\"data:image/png;charset=utf-8;base64,";
-
- aRet = aHeader + aBase64Data.makeStringAndClear().toUtf8() + "\"/></body></html>";
-
- return true;
+ // Desperate measures - convert text to HTML instead.
+ if (encodeTextAsHTML(xTransferable, "text/plain;charset=utf-8", aRet))
+ return true;
+ // If html is not supported, might be a graphic-selection,
+ if (encodeImageAsHTML(xTransferable, "image/png", aRet))
+ return true;
}
SetLastExceptionMsg("Flavor " + aFlavor.MimeType + " is not supported");
@@ -3593,7 +3628,7 @@ static int doc_getSelectionType(LibreOfficeKitDocument* pThis)
if (!bSuccess)
return LOK_SELTYPE_NONE;
- if (aRet.getLength() > 1000) // About 2 paragraphs.
+ if (aRet.getLength() > 10000)
return LOK_SELTYPE_COMPLEX;
return aRet.getLength() ? LOK_SELTYPE_TEXT : LOK_SELTYPE_NONE;
commit a5b5ca847624929058904aa78095b2bf2e08e7c2
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Jul 20 11:15:05 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:34 2019 -0400
lok: minimal implementation of isComplex for calc for now.
Change-Id: Ic4141d30a0ff48a9ec5ecc8e6119d9d779c4a0fc
diff --git a/sc/source/ui/app/seltrans.cxx b/sc/source/ui/app/seltrans.cxx
index 79a0437f6061..3a1c2128d560 100644
--- a/sc/source/ui/app/seltrans.cxx
+++ b/sc/source/ui/app/seltrans.cxx
@@ -413,4 +413,16 @@ void ScSelectionTransferObj::ObjectReleased()
TransferableHelper::ObjectReleased();
}
+sal_Bool SAL_CALL ScSelectionTransferObj::isComplex()
+{
+ switch (eMode)
+ {
+ case SC_SELTRANS_CELL:
+ case SC_SELTRANS_CELLS:
+ return false;
+ default:
+ return true;
+ }
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/transobj.cxx b/sc/source/ui/app/transobj.cxx
index c78e8ae9e859..0ed12820fb3c 100644
--- a/sc/source/ui/app/transobj.cxx
+++ b/sc/source/ui/app/transobj.cxx
@@ -234,6 +234,42 @@ void ScTransferObj::AddSupportedFormats()
}
}
+static ScRange lcl_reduceBlock(ScDocumentUniquePtr &pDoc, ScRange aReducedBlock, bool bIncludeVisual = false)
+{
+ if ((aReducedBlock.aEnd.Col() == MAXCOL || aReducedBlock.aEnd.Row() == MAXROW) &&
+ aReducedBlock.aStart.Tab() == aReducedBlock.aEnd.Tab())
+ {
+ // Shrink the block here so we don't waste time creating huge
+ // output when whole columns or rows are selected.
+
+ SCCOL nPrintAreaEndCol = 0;
+ SCROW nPrintAreaEndRow = 0;
+ if (bIncludeVisual)
+ pDoc->GetPrintArea( aReducedBlock.aStart.Tab(), nPrintAreaEndCol, nPrintAreaEndRow, true );
+
+ // Shrink the area to allow pasting to external applications.
+ // Shrink to real data area for HTML, RTF and RICHTEXT, but include
+ // all objects and top-left area for BITMAP and PNG.
+ SCCOL nStartCol = aReducedBlock.aStart.Col();
+ SCROW nStartRow = aReducedBlock.aStart.Row();
+ SCCOL nEndCol = aReducedBlock.aEnd.Col();
+ SCROW nEndRow = aReducedBlock.aEnd.Row();
+ bool bShrunk = false;
+ pDoc->ShrinkToUsedDataArea( bShrunk, aReducedBlock.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow,
+ false, bIncludeVisual /*bStickyTopRow*/, bIncludeVisual /*bStickyLeftCol*/,
+ bIncludeVisual /*bConsiderCellNotes*/, bIncludeVisual /*bConsiderCellDrawObjects*/);
+
+ if ( nPrintAreaEndRow > nEndRow )
+ nEndRow = nPrintAreaEndRow;
+
+ if ( nPrintAreaEndCol > nEndCol )
+ nEndCol = nPrintAreaEndCol;
+
+ aReducedBlock = ScRange(nStartCol, nStartRow, aReducedBlock.aStart.Tab(), nEndCol, nEndRow, aReducedBlock.aEnd.Tab());
+ }
+ return aReducedBlock;
+}
+
bool ScTransferObj::GetData( const datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
{
SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
@@ -250,39 +286,11 @@ bool ScTransferObj::GetData( const datatransfer::DataFlavor& rFlavor, const OUSt
|| nFormat == SotClipboardFormatId::BITMAP
|| nFormat == SotClipboardFormatId::PNG;
- if (bReduceBlockFormat && (m_aBlock.aEnd.Col() == MAXCOL || m_aBlock.aEnd.Row() == MAXROW) &&
- m_aBlock.aStart.Tab() == m_aBlock.aEnd.Tab())
- {
- // Shrink the block here so we don't waste time creating huge
- // output when whole columns or rows are selected.
-
- SCCOL nPrintAreaEndCol = 0;
- SCROW nPrintAreaEndRow = 0;
- const bool bIncludeVisual = (nFormat == SotClipboardFormatId::BITMAP ||
- nFormat == SotClipboardFormatId::PNG);
- if (bIncludeVisual)
- m_pDoc->GetPrintArea( m_aBlock.aStart.Tab(), nPrintAreaEndCol, nPrintAreaEndRow, true );
-
- // Shrink the area to allow pasting to external applications.
- // Shrink to real data area for HTML, RTF and RICHTEXT, but include
- // all objects and top-left area for BITMAP and PNG.
- SCCOL nStartCol = aReducedBlock.aStart.Col();
- SCROW nStartRow = aReducedBlock.aStart.Row();
- SCCOL nEndCol = aReducedBlock.aEnd.Col();
- SCROW nEndRow = aReducedBlock.aEnd.Row();
- bool bShrunk = false;
- m_pDoc->ShrinkToUsedDataArea( bShrunk, aReducedBlock.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow,
- false, bIncludeVisual /*bStickyTopRow*/, bIncludeVisual /*bStickyLeftCol*/,
- bIncludeVisual /*bConsiderCellNotes*/, bIncludeVisual /*bConsiderCellDrawObjects*/);
-
- if ( nPrintAreaEndRow > nEndRow )
- nEndRow = nPrintAreaEndRow;
-
- if ( nPrintAreaEndCol > nEndCol )
- nEndCol = nPrintAreaEndCol;
-
- aReducedBlock = ScRange(nStartCol, nStartRow, aReducedBlock.aStart.Tab(), nEndCol, nEndRow, aReducedBlock.aEnd.Tab());
- }
+ const bool bIncludeVisual = (nFormat == SotClipboardFormatId::BITMAP ||
+ nFormat == SotClipboardFormatId::PNG);
+
+ if (bReduceBlockFormat)
+ aReducedBlock = lcl_reduceBlock(m_pDoc, m_aBlock, bIncludeVisual);
if ( nFormat == SotClipboardFormatId::LINKSRCDESCRIPTOR || nFormat == SotClipboardFormatId::OBJECTDESCRIPTOR )
{
@@ -535,6 +543,15 @@ bool ScTransferObj::WriteObject( tools::SvRef<SotStorageStream>& rxOStm, void* p
return bRet;
}
+sal_Bool SAL_CALL ScTransferObj::isComplex()
+{
+ ScRange aReduced = lcl_reduceBlock(m_pDoc, m_aBlock);
+ size_t nCells = ( (aReduced.aEnd.Col() - aReduced.aStart.Col() + 1) *
+ (aReduced.aEnd.Row() - aReduced.aStart.Row() + 1) *
+ (aReduced.aEnd.Tab() - aReduced.aStart.Tab() + 1) );
+ return nCells > 1000;
+}
+
void ScTransferObj::DragFinished( sal_Int8 nDropAction )
{
if ( nDropAction == DND_ACTION_MOVE && !m_bDragWasInternal && !(m_nDragSourceFlags & ScDragSrc::Navigator) )
diff --git a/sc/source/ui/inc/seltrans.hxx b/sc/source/ui/inc/seltrans.hxx
index af73f0adf896..83adb2c11eb2 100644
--- a/sc/source/ui/inc/seltrans.hxx
+++ b/sc/source/ui/inc/seltrans.hxx
@@ -67,6 +67,7 @@ public:
virtual void AddSupportedFormats() override;
virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
virtual void ObjectReleased() override;
+ virtual sal_Bool SAL_CALL isComplex() override;
};
#endif
diff --git a/sc/source/ui/inc/transobj.hxx b/sc/source/ui/inc/transobj.hxx
index 5b7f405fb55e..1ebfd1a4e892 100644
--- a/sc/source/ui/inc/transobj.hxx
+++ b/sc/source/ui/inc/transobj.hxx
@@ -76,6 +76,7 @@ public:
virtual bool WriteObject( tools::SvRef<SotStorageStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId,
const css::datatransfer::DataFlavor& rFlavor ) override;
virtual void DragFinished( sal_Int8 nDropAction ) override;
+ virtual sal_Bool SAL_CALL isComplex() override;
ScDocument* GetDocument() const { return m_pDoc.get(); } // owned by ScTransferObj
const ScRange& GetRange() const { return m_aBlock; }
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
index 798b3dd23e3a..f4b8bf904532 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -419,7 +419,7 @@ namespace
}
}
-sal_Bool SwTransferable::isComplex()
+sal_Bool SAL_CALL SwTransferable::isComplex()
{
// Copy into a new Doc so we don't mess with the existing one.
//FIXME: We *should* be able to avoid this and improve the performance.
diff --git a/sw/source/uibase/inc/swdtflvr.hxx b/sw/source/uibase/inc/swdtflvr.hxx
index 0b15b8f15acf..c19bc8efc075 100644
--- a/sw/source/uibase/inc/swdtflvr.hxx
+++ b/sw/source/uibase/inc/swdtflvr.hxx
@@ -151,7 +151,7 @@ protected:
const css::datatransfer::DataFlavor& rFlavor ) override;
virtual void DragFinished( sal_Int8 nDropAction ) override;
virtual void ObjectReleased() override;
- virtual sal_Bool isComplex() override;
+ virtual sal_Bool SAL_CALL isComplex() override;
using TransferableHelper::StartDrag;
commit 1b6ad765fe5bc791e54a3185f3b900bafcecaf38
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Jun 28 12:30:40 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:33 2019 -0400
lok: vital to quote nested JSON inserted into a json property.
Somehow this managed to work fine in most browsers, but when
the Kit/Poco tried to parse JSON to extract viewID it could explode.
Change-Id: I39d2ecc9ee95b7e6f67a23c8b15f9a1d01769ddc
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index a7828287205d..55b157ef6cb2 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -143,11 +143,26 @@ void SfxLokHelper::setViewLanguage(int nId, const OUString& rBcp47LanguageTag)
}
}
+static OString lcl_escapeQuotes(const OString &rStr)
+{
+ if (rStr.getLength() < 1)
+ return rStr;
+ // FIXME: need an optimized 'escape' method for O[U]String.
+ OStringBuffer aBuf(rStr.getLength() + 8);
+ for (sal_Int32 i = 0; i < rStr.getLength(); ++i)
+ {
+ if (rStr[i] == '"' || rStr[i] == '\\')
+ aBuf.append('\\');
+ aBuf.append(rStr[i]);
+ }
+ return aBuf.makeStringAndClear();
+}
+
void SfxLokHelper::notifyOtherView(SfxViewShell* pThisView, SfxViewShell const* pOtherView, int nType, const OString& rKey, const OString& rPayload)
{
OString aPayload = OString("{ \"viewId\": \"") + OString::number(SfxLokHelper::getView(pThisView)) +
"\", \"part\": \"" + OString::number(pThisView->getPart()) +
- "\", \"" + rKey + "\": \"" + rPayload + "\" }";
+ "\", \"" + rKey + "\": \"" + lcl_escapeQuotes(rPayload) + "\" }";
pOtherView->libreOfficeKitViewCallback(nType, aPayload.getStr());
}
commit ed8258ae6d8e7661440c660f8958fed95fe6c986
Author: Szymon Kłos <szymon.klos at collabora.com>
AuthorDate: Sat Jul 20 11:07:56 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:32 2019 -0400
Set clipboard for a window when created
This allows to paste in dialogs input using tunneled context menu.
Change-Id: Ie6cc6f1a6cd453734c8f6084b0bd50d1d7ab6c09
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 3925eeec00b2..a0d8b9436d52 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -1527,6 +1527,18 @@ bool CallbackFlushHandler::processWindowEvent(CallbackData& aCallbackData)
}
return false;
});
+
+ VclPtr<Window> pWindow = vcl::Window::FindLOKWindow(nLOKWindowId);
+ if (!pWindow)
+ {
+ gImpl->maLastExceptionMsg = "Document doesn't support dialog rendering, or window not found.";
+ return false;
+ }
+
+ auto xClip = forceSetClipboardForCurrentView(m_pDocument);
+
+ uno::Reference<datatransfer::clipboard::XClipboard> xClipboard(xClip.get());
+ pWindow->SetClipboard(xClipboard);
}
else if (aAction == "size_changed")
{
commit 7467b8e2b26f8244d872348ea0872d6a19920186
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Jul 20 11:07:01 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:31 2019 -0400
LOK: Copy Graphics as embedded PNG in HTML
Change-Id: Id8c14d7304d30bfcd956b126dfe291ef044f62bf
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 88dfaf79d990..3925eeec00b2 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -47,6 +47,7 @@
#include <rtl/strbuf.hxx>
#include <rtl/uri.hxx>
#include <cppuhelper/bootstrap.hxx>
+#include <comphelper/base64.hxx>
#include <comphelper/dispatchcommand.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/processfactory.hxx>
@@ -3405,6 +3406,15 @@ static void doc_setTextSelection(LibreOfficeKitDocument* pThis, int nType, int n
pDoc->setTextSelection(nType, nX, nY);
}
+static OUString getGenerator()
+{
+ OUString sGenerator(
+ Translate::ExpandVariables("%PRODUCTNAME %PRODUCTVERSION%PRODUCTEXTENSION (%1)"));
+ OUString os("$_OS");
+ ::rtl::Bootstrap::expandMacros(os);
+ return sGenerator.replaceFirst("%1", os);
+}
+
static bool getFromTransferrable(
const css::uno::Reference<css::datatransfer::XTransferable> &xTransferable,
const OString &aInMimeType, OString &aRet)
@@ -3432,6 +3442,30 @@ static bool getFromTransferrable(
if (!xTransferable->isDataFlavorSupported(aFlavor))
{
+ // If html is not supported, might be a graphic-selection, which supports png.
+ if (aInMimeType == "text/html" && getFromTransferrable(xTransferable, "image/png", aRet))
+ {
+ // Encode in base64.
+ auto aSeq = Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(aRet.getStr()),
+ aRet.getLength());
+ OUStringBuffer aBase64Data;
+ comphelper::Base64::encode(aBase64Data, aSeq);
+
+ // Embed in HTML.
+ static const OString aHeader
+ = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">"
+ "<html><head>"
+ "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/><meta "
+ "name=\"generator\" content=\""
+ + getGenerator().toUtf8()
+ + "\"/>"
+ "</head><body><img src=\"data:image/png;charset=utf-8;base64,";
+
+ aRet = aHeader + aBase64Data.makeStringAndClear().toUtf8() + "\"/></body></html>";
+
+ return true;
+ }
+
SetLastExceptionMsg("Flavor " + aFlavor.MimeType + " is not supported");
return false;
}
@@ -3468,7 +3502,7 @@ static bool getFromTransferrable(
aRet = OString(reinterpret_cast<sal_Char*>(aSequence.getArray()), aSequence.getLength());
}
- return true;;
+ return true;
}
// Tolerate embedded \0s etc.
diff --git a/vcl/source/treelist/transfer.cxx b/vcl/source/treelist/transfer.cxx
index c5f61cb850c4..10782592f5a2 100644
--- a/vcl/source/treelist/transfer.cxx
+++ b/vcl/source/treelist/transfer.cxx
@@ -390,7 +390,8 @@ Any SAL_CALL TransferableHelper::getTransferData2( const DataFlavor& rFlavor, co
sal_Bool SAL_CALL TransferableHelper::isComplex()
{
- //FIXME: get from each document.
+ // By default everything is complex, until proven otherwise
+ // in the respective document type transferable handler.
return sal_True;
}
commit 060ea1b232ea67d1025e60d57ad4142b7db9f194
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Jul 20 11:05:49 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:30 2019 -0400
lok: cleanup clipboards associated with a view on destruction.
Also defer destruction potentially indefinitely for bad users who
quit without destroying views, documents, shutting down nicely etc.
Change-Id: Ieea6ad00b2983d372b745179bfe3b884c3c64eb0
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 950a4eed0074..88dfaf79d990 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -1648,6 +1648,8 @@ static void doc_destroy(LibreOfficeKitDocument *pThis)
SolarMutexGuard aGuard;
+ LOKClipboardFactory::releaseClipboardForView(-1);
+
LibLODocument_Impl *pDocument = static_cast<LibLODocument_Impl*>(pThis);
delete pDocument;
}
@@ -4359,6 +4361,8 @@ static void doc_destroyView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis
SolarMutexGuard aGuard;
SetLastExceptionMsg();
+ LOKClipboardFactory::releaseClipboardForView(nId);
+
SfxLokHelper::destroyView(nId);
}
diff --git a/desktop/source/lib/lokclipboard.cxx b/desktop/source/lib/lokclipboard.cxx
index ef52a4596c43..f53202903761 100644
--- a/desktop/source/lib/lokclipboard.cxx
+++ b/desktop/source/lib/lokclipboard.cxx
@@ -8,14 +8,16 @@
*/
#include "lokclipboard.hxx"
+#include <vcl/lazydelete.hxx>
#include <sfx2/lokhelper.hxx>
#include <cppuhelper/supportsservice.hxx>
using namespace css;
using namespace css::uno;
-osl::Mutex LOKClipboardFactory::gMutex;
-std::unordered_map<int, rtl::Reference<LOKClipboard>> LOKClipboardFactory::gClipboards;
+/* static */ osl::Mutex LOKClipboardFactory::gMutex;
+static vcl::DeleteOnDeinit<std::unordered_map<int, rtl::Reference<LOKClipboard>>>
+gClipboards(new std::unordered_map<int, rtl::Reference<LOKClipboard>>());
rtl::Reference<LOKClipboard> LOKClipboardFactory::getClipboardForCurView()
{
@@ -23,18 +25,39 @@ rtl::Reference<LOKClipboard> LOKClipboardFactory::getClipboardForCurView()
osl::MutexGuard aGuard(gMutex);
- auto it = gClipboards.find(nViewId);
- if (it != gClipboards.end())
+ auto it = gClipboards.get()->find(nViewId);
+ if (it != gClipboards.get()->end())
{
SAL_INFO("lok", "Got clip: " << it->second.get() << " from " << nViewId);
return it->second;
}
rtl::Reference<LOKClipboard> xClip(new LOKClipboard());
- gClipboards[nViewId] = xClip;
+ (*gClipboards.get())[nViewId] = xClip;
SAL_INFO("lok", "Created clip: " << xClip.get() << " for viewId " << nViewId);
return xClip;
}
+/// FIXME: should really copy and stash its content for a bit.
+void LOKClipboardFactory::releaseClipboardForView(int nViewId)
+{
+ osl::MutexGuard aGuard(gMutex);
+
+ if (nViewId < 0) // clear all
+ {
+ gClipboards.get()->clear();
+ SAL_INFO("lok", "Released all clipboards on doc destroy\n");
+ }
+ else
+ {
+ auto it = gClipboards.get()->find(nViewId);
+ if (it != gClipboards.get()->end())
+ {
+ gClipboards.get()->erase(it);
+ SAL_INFO("lok", "Released clip: " << it->second.get() << " for destroyed " << nViewId);
+ }
+ }
+}
+
uno::Reference<uno::XInterface>
SAL_CALL LOKClipboardFactory::createInstanceWithArguments(const Sequence<Any>& /* rArgs */)
{
diff --git a/desktop/source/lib/lokclipboard.hxx b/desktop/source/lib/lokclipboard.hxx
index 54c1b37945ff..1ade5c0a3e0b 100644
--- a/desktop/source/lib/lokclipboard.hxx
+++ b/desktop/source/lib/lokclipboard.hxx
@@ -92,7 +92,6 @@ public:
class LOKClipboardFactory : public ::cppu::WeakComponentImplHelper<css::lang::XSingleServiceFactory>
{
static osl::Mutex gMutex;
- static std::unordered_map<int, rtl::Reference<LOKClipboard>> gClipboards;
public:
LOKClipboardFactory()
@@ -106,7 +105,12 @@ public:
}
css::uno::Reference<css::uno::XInterface> SAL_CALL
createInstanceWithArguments(const css::uno::Sequence<css::uno::Any>& /* rArgs */) override;
+
+ /// Fetch clipboard from the gobal pool.
static rtl::Reference<LOKClipboard> getClipboardForCurView();
+
+ /// Release a clipboard before its document dies, nViewId of -1 clears all.
+ static void releaseClipboardForView(int nViewId);
};
#endif
commit a23251016cf4543425e77ad3a5e82a2acd958e4a
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Tue Jun 25 23:45:37 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:29 2019 -0400
LOK: Improved selection complexity detection
Only Graphics and OLE now unconditionally
trigger 'complex' case, and for all others,
we actually tally the number of text characters.
Currently anything above 512KB is flagged as 'complex'.
Change-Id: I19fbef72f2eb725648b2a18c1ee41b1612d2bac0
diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx
index bd6609c321a4..517a38a50527 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -356,7 +356,7 @@ public:
*
* @return an element of the LibreOfficeKitSelectionType enum.
*/
- int getSelectionType(LibreOfficeKitDocument* /*pThis*/)
+ int getSelectionType()
{
return mpDoc->pClass->getSelectionType(mpDoc);
}
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
index 223ed806bc32..798b3dd23e3a 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -421,15 +421,6 @@ namespace
sal_Bool SwTransferable::isComplex()
{
- const SelectionType nSelectionType = m_pWrtShell->GetSelectionType();
-
- // Anything other than text is complex by definition.
- if (nSelectionType != SelectionType::Text)
- return true;
-
- if (m_pWrtShell->IsFrameSelected() || m_pWrtShell->IsObjSelected())
- return true;
-
// Copy into a new Doc so we don't mess with the existing one.
//FIXME: We *should* be able to avoid this and improve the performance.
m_pClpDocFac.reset(new SwDocFac);
@@ -439,21 +430,29 @@ sal_Bool SwTransferable::isComplex()
.LockExpFields(); // never update fields - leave text as it is
lclOverWriteDoc(*m_pWrtShell, *pTmpDoc);
- bool isComplex = false;
+ sal_Int32 nTextLength = 0;
+ const SwNode* pEndOfContent = &m_pWrtShell->GetDoc()->GetNodes().GetEndOfContent();
SwNodes& aNodes = pTmpDoc->GetNodes();
for( sal_uLong nIndex = 0; nIndex < aNodes.Count(); ++nIndex)
{
SwNode& rNd = *aNodes[nIndex];
- if (rNd.IsContentNode() && !rNd.IsTextNode())
- {
- isComplex = true;
+ if (&rNd == pEndOfContent)
break;
+
+ if (rNd.IsOLENode() || rNd.IsGrfNode())
+ return true; // Complex
+
+ SwTextNode* pTextNode = rNd.GetTextNode();
+ if (pTextNode)
+ {
+ nTextLength += pTextNode->GetText().getLength();
+ if (nTextLength >= 1024 * 512)
+ return true; // Complex
}
- else if (&rNd == &m_pWrtShell->GetDoc()->GetNodes().GetEndOfContent())
- break;
}
- return isComplex;
+ // Simple
+ return false;
}
bool SwTransferable::GetData( const DataFlavor& rFlavor, const OUString& rDestDoc )
commit 337e905836723bc7e2d7f0cf21c62d89383124bd
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Jul 20 11:01:38 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:28 2019 -0400
LOK: Enable embedding images in text/html format output
Change-Id: Ibd8bed796678ee26de2ceb6e434dce24da4eab05
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 2b57c88fb9b9..7ad2f1e45817 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -2676,7 +2676,7 @@ void DesktopLOKTest::testComplexSelection()
pText = pDocument->pClass->getTextSelection(pDocument, "text/html", nullptr);
CPPUNIT_ASSERT(pText != nullptr);
CPPUNIT_ASSERT(std::string(pText).find(aText.getStr()) != std::string::npos); // Must have the text.
- // CPPUNIT_ASSERT(std::string(pText).find("<img") != std::string::npos); // Must have the image as well.
+ CPPUNIT_ASSERT(std::string(pText).find("<img") != std::string::npos); // Must have the image as well.
free(pText);
// We expect this to be complex.
diff --git a/sw/source/filter/html/wrthtml.cxx b/sw/source/filter/html/wrthtml.cxx
index 54afa80ba7c9..5c1a6ab52a42 100644
--- a/sw/source/filter/html/wrthtml.cxx
+++ b/sw/source/filter/html/wrthtml.cxx
@@ -91,7 +91,7 @@ using namespace css;
static sal_Char sIndentTabs[MAX_INDENT_LEVEL+2] =
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
-SwHTMLWriter::SwHTMLWriter( const OUString& rBaseURL )
+SwHTMLWriter::SwHTMLWriter( const OUString& rBaseURL, const OUString& rFilterOptions )
: m_pNumRuleInfo(new SwHTMLNumRuleInfo)
, m_nHTMLMode(0)
, m_eCSS1Unit(FieldUnit::NONE)
@@ -163,6 +163,8 @@ SwHTMLWriter::SwHTMLWriter( const OUString& rBaseURL )
mpTempBaseURL->EnableKillingFile();
SetBaseURL(mpTempBaseURL->GetURL());
}
+
+ SetupFilterOptions(rFilterOptions);
}
SwHTMLWriter::~SwHTMLWriter()
@@ -185,21 +187,26 @@ void SwHTMLWriter::SetupFilterOptions(SfxMedium& rMedium)
return;
- OUString sFilterOptions = static_cast<const SfxStringItem*>(pItem)->GetValue();
- if (sFilterOptions == "SkipImages")
+ const OUString sFilterOptions = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ SetupFilterOptions(sFilterOptions);
+}
+
+void SwHTMLWriter::SetupFilterOptions(const OUString& rFilterOptions)
+{
+ if (rFilterOptions == "SkipImages")
{
mbSkipImages = true;
}
- else if (sFilterOptions == "SkipHeaderFooter")
+ else if (rFilterOptions == "SkipHeaderFooter")
{
mbSkipHeaderFooter = true;
}
- else if (sFilterOptions == "EmbedImages" )
+ else if (rFilterOptions == "EmbedImages")
{
mbEmbedImages = true;
}
- uno::Sequence<OUString> aOptionSeq = comphelper::string::convertCommaSeparated(sFilterOptions);
+ uno::Sequence<OUString> aOptionSeq = comphelper::string::convertCommaSeparated(rFilterOptions);
const OUString aXhtmlNsKey("xhtmlns=");
for (const auto& rOption : aOptionSeq)
{
@@ -823,13 +830,6 @@ void SwHTMLWriter::Out_SwDoc( SwPaM* pPam )
OutHTML_Section( *this, *rNd.GetSectionNode() );
m_nBkmkTabPos = m_bWriteAll ? FindPos_Bkmk( *m_pCurrentPam->GetPoint() ) : -1;
}
- else if( rNd.IsGrfNode() )
- {
- SwGrfNode* pGrfNd = rNd.GetGrfNode();
- assert(pGrfNd && !"FIXME: Implement Graphic copy as HTML.");
- // if (pGrfNd)
- // OutHTML_SwGrfNode( *this, *pGrfNd );
- }
else if( &rNd == &m_pDoc->GetNodes().GetEndOfContent() )
break;
@@ -1555,9 +1555,9 @@ HTMLSaveData::~HTMLSaveData()
}
}
-void GetHTMLWriter( const OUString&, const OUString& rBaseURL, WriterRef& xRet )
+void GetHTMLWriter( const OUString& rFilterOptions, const OUString& rBaseURL, WriterRef& xRet )
{
- xRet = new SwHTMLWriter( rBaseURL );
+ xRet = new SwHTMLWriter( rBaseURL, rFilterOptions );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/wrthtml.hxx b/sw/source/filter/html/wrthtml.hxx
index 47893227f98f..98c9005fe095 100644
--- a/sw/source/filter/html/wrthtml.hxx
+++ b/sw/source/filter/html/wrthtml.hxx
@@ -269,6 +269,8 @@ class SW_DLLPUBLIC SwHTMLWriter : public Writer
void AddLinkTarget( const OUString& rURL );
void CollectLinkTargets();
+ void SetupFilterOptions(const OUString& rFilterOptions);
+
protected:
ErrCode WriteStream() override;
void SetupFilterOptions(SfxMedium& rMedium) override;
@@ -403,7 +405,9 @@ public:
/// Tracks which text portion attributes are currently open: a which id -> open count map.
std::map<sal_uInt16, int> maStartedAttributes;
- explicit SwHTMLWriter( const OUString& rBaseURL );
+ /// Construct an instance of SwHTMLWriter and optionally give it
+ /// the filter options directly, which can also be set via SetupFilterOptions().
+ explicit SwHTMLWriter( const OUString& rBaseURL, const OUString& rFilterOptions = "" );
virtual ~SwHTMLWriter() override;
void Out_SwDoc( SwPaM* ); // write the marked range
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
index 847ec3481590..223ed806bc32 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -432,7 +432,7 @@ sal_Bool SwTransferable::isComplex()
// Copy into a new Doc so we don't mess with the existing one.
//FIXME: We *should* be able to avoid this and improve the performance.
- m_pClpDocFac = new SwDocFac;
+ m_pClpDocFac.reset(new SwDocFac);
SwDoc* const pTmpDoc = lcl_GetDoc(*m_pClpDocFac);
pTmpDoc->getIDocumentFieldsAccess()
@@ -773,8 +773,12 @@ bool SwTransferable::WriteObject( tools::SvRef<SotStorageStream>& xStream,
break;
case SWTRANSFER_OBJECTTYPE_HTML:
- GetHTMLWriter(OUString(), OUString(), xWrt);
+ {
+ // LOK is interested in getting images embedded for copy/paste support.
+ const OUString aFilterOptions("EmbedImages");
+ GetHTMLWriter( comphelper::LibreOfficeKit::isActive() ? aFilterOptions : OUString(), OUString(), xWrt );
break;
+ }
case SWTRANSFER_OBJECTTYPE_RTF:
case SWTRANSFER_OBJECTTYPE_RICHTEXT:
commit 749ef00e253e8b07c4bf34a61162df7c28ed29a2
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Tue Jun 25 12:36:52 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:27 2019 -0400
LOK: detect Graphics in isComplex for Writer
Change-Id: I814d71a21fa5352a9a1051f5477cb452a0dc5c2f
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 259aa9920fa5..2b57c88fb9b9 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -2680,7 +2680,7 @@ void DesktopLOKTest::testComplexSelection()
free(pText);
// We expect this to be complex.
- // CPPUNIT_ASSERT_EQUAL((int)LOK_SELTYPE_COMPLEX, pDocument->pClass->getSelectionType(pDocument)); // Fails!
+ CPPUNIT_ASSERT_EQUAL((int)LOK_SELTYPE_COMPLEX, pDocument->pClass->getSelectionType(pDocument));
}
namespace {
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
index 79a2f34d7d83..847ec3481590 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -430,6 +430,8 @@ sal_Bool SwTransferable::isComplex()
if (m_pWrtShell->IsFrameSelected() || m_pWrtShell->IsObjSelected())
return true;
+ // Copy into a new Doc so we don't mess with the existing one.
+ //FIXME: We *should* be able to avoid this and improve the performance.
m_pClpDocFac = new SwDocFac;
SwDoc* const pTmpDoc = lcl_GetDoc(*m_pClpDocFac);
@@ -437,36 +439,18 @@ sal_Bool SwTransferable::isComplex()
.LockExpFields(); // never update fields - leave text as it is
lclOverWriteDoc(*m_pWrtShell, *pTmpDoc);
- // in CORE a new one was created (OLE-objects copied!)
- m_aDocShellRef = pTmpDoc->GetTmpDocShell();
- if (m_aDocShellRef.Is())
- SwTransferable::InitOle(m_aDocShellRef);
- pTmpDoc->SetTmpDocShell(nullptr);
-
- SwPaM aOrigPam(pTmpDoc->GetNodes().GetEndOfContent());
- aOrigPam.Move(fnMoveBackward, GoInDoc);
- aOrigPam.SetMark();
- aOrigPam.Move(fnMoveForward, GoInDoc);
-
- SwPaM aPam(*aOrigPam.End(), *aOrigPam.Start());
-
bool isComplex = false;
- while (aPam.GetPoint()->nNode.GetIndex() < aPam.GetMark()->nNode.GetIndex()
- || (aPam.GetPoint()->nNode.GetIndex() == aPam.GetMark()->nNode.GetIndex()
- && aPam.GetPoint()->nContent.GetIndex() <= aPam.GetMark()->nContent.GetIndex()))
+ SwNodes& aNodes = pTmpDoc->GetNodes();
+ for( sal_uLong nIndex = 0; nIndex < aNodes.Count(); ++nIndex)
{
- SwNode& rNd = aPam.GetNode();
-
+ SwNode& rNd = *aNodes[nIndex];
if (rNd.IsContentNode() && !rNd.IsTextNode())
{
- //FIXME: this doesn't detect GrfNode, which we need to detect complex selections.
isComplex = true;
break;
}
else if (&rNd == &m_pWrtShell->GetDoc()->GetNodes().GetEndOfContent())
break;
-
- ++aPam.GetPoint()->nNode;
}
return isComplex;
commit 07343166b18f36aa8c7563e2be346887e0779b69
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Mon Jun 24 22:07:08 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:26 2019 -0400
LOK: Implement getSelectionType
Detects all complex scenarios, except for Graphics.
DesktopLOKTest::testComplexSelection() has commented
out check that currently fails due to the missing
detection of Graphics nodes.
Change-Id: Ifce17192d26daba218d2c3d38577cccec0699e99
diff --git a/desktop/qa/data/objects.odt b/desktop/qa/data/objects.odt
new file mode 100644
index 000000000000..45c2b39cc1a4
Binary files /dev/null and b/desktop/qa/data/objects.odt differ
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 2fa09a23322b..259aa9920fa5 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -2637,12 +2637,17 @@ void DesktopLOKTest::testComplexSelection()
{
// Start with a blank text file and add contents.
LibLODocument_Impl* pDocument = loadDoc("blank_text.odt");
- // LibLODocument_Impl* pDocument = loadDoc("sheet_with_image.ods");
static const OString aText("hello world");
+ // Certainly not complex.
+ CPPUNIT_ASSERT_EQUAL((int)LOK_SELTYPE_NONE, pDocument->pClass->getSelectionType(pDocument));
+
// Paste text.
CPPUNIT_ASSERT(pDocument->pClass->paste(pDocument, "text/plain;charset=utf-8", aText.getStr(), aText.getLength()));
+ // No selection.
+ CPPUNIT_ASSERT_EQUAL((int)LOK_SELTYPE_NONE, pDocument->pClass->getSelectionType(pDocument));
+
// Paste an image.
OUString aFileURL;
createFileURL("paste.jpg", aFileURL);
@@ -2654,10 +2659,6 @@ void DesktopLOKTest::testComplexSelection()
pDocument->pClass->postUnoCommand(pDocument, ".uno:SelectAll", nullptr, false);
Scheduler::ProcessEventsToIdle();
- // We expect this to be complex.
- const int type = pDocument->pClass->getSelectionType(pDocument);
- CPPUNIT_ASSERT_EQUAL((int)LOK_SELTYPE_COMPLEX, type);
-
// Export as plain text, we should get only the text part "hello".
char* pText = pDocument->pClass->getTextSelection(pDocument, "text/plain;charset=utf-8", nullptr);
CPPUNIT_ASSERT(pText != nullptr);
@@ -2677,6 +2678,9 @@ void DesktopLOKTest::testComplexSelection()
CPPUNIT_ASSERT(std::string(pText).find(aText.getStr()) != std::string::npos); // Must have the text.
// CPPUNIT_ASSERT(std::string(pText).find("<img") != std::string::npos); // Must have the image as well.
free(pText);
+
+ // We expect this to be complex.
+ // CPPUNIT_ASSERT_EQUAL((int)LOK_SELTYPE_COMPLEX, pDocument->pClass->getSelectionType(pDocument)); // Fails!
}
namespace {
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
index 351e7782c273..79a2f34d7d83 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -419,6 +419,59 @@ namespace
}
}
+sal_Bool SwTransferable::isComplex()
+{
+ const SelectionType nSelectionType = m_pWrtShell->GetSelectionType();
+
+ // Anything other than text is complex by definition.
+ if (nSelectionType != SelectionType::Text)
+ return true;
+
+ if (m_pWrtShell->IsFrameSelected() || m_pWrtShell->IsObjSelected())
+ return true;
+
+ m_pClpDocFac = new SwDocFac;
+ SwDoc* const pTmpDoc = lcl_GetDoc(*m_pClpDocFac);
+
+ pTmpDoc->getIDocumentFieldsAccess()
+ .LockExpFields(); // never update fields - leave text as it is
+ lclOverWriteDoc(*m_pWrtShell, *pTmpDoc);
+
+ // in CORE a new one was created (OLE-objects copied!)
+ m_aDocShellRef = pTmpDoc->GetTmpDocShell();
+ if (m_aDocShellRef.Is())
+ SwTransferable::InitOle(m_aDocShellRef);
+ pTmpDoc->SetTmpDocShell(nullptr);
+
+ SwPaM aOrigPam(pTmpDoc->GetNodes().GetEndOfContent());
+ aOrigPam.Move(fnMoveBackward, GoInDoc);
+ aOrigPam.SetMark();
+ aOrigPam.Move(fnMoveForward, GoInDoc);
+
+ SwPaM aPam(*aOrigPam.End(), *aOrigPam.Start());
+
+ bool isComplex = false;
+ while (aPam.GetPoint()->nNode.GetIndex() < aPam.GetMark()->nNode.GetIndex()
+ || (aPam.GetPoint()->nNode.GetIndex() == aPam.GetMark()->nNode.GetIndex()
+ && aPam.GetPoint()->nContent.GetIndex() <= aPam.GetMark()->nContent.GetIndex()))
+ {
+ SwNode& rNd = aPam.GetNode();
+
+ if (rNd.IsContentNode() && !rNd.IsTextNode())
+ {
+ //FIXME: this doesn't detect GrfNode, which we need to detect complex selections.
+ isComplex = true;
+ break;
+ }
+ else if (&rNd == &m_pWrtShell->GetDoc()->GetNodes().GetEndOfContent())
+ break;
+
+ ++aPam.GetPoint()->nNode;
+ }
+
+ return isComplex;
+}
+
bool SwTransferable::GetData( const DataFlavor& rFlavor, const OUString& rDestDoc )
{
SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
diff --git a/sw/source/uibase/inc/swdtflvr.hxx b/sw/source/uibase/inc/swdtflvr.hxx
index 1b3cf2536964..0b15b8f15acf 100644
--- a/sw/source/uibase/inc/swdtflvr.hxx
+++ b/sw/source/uibase/inc/swdtflvr.hxx
@@ -151,6 +151,7 @@ protected:
const css::datatransfer::DataFlavor& rFlavor ) override;
virtual void DragFinished( sal_Int8 nDropAction ) override;
virtual void ObjectReleased() override;
+ virtual sal_Bool isComplex() override;
using TransferableHelper::StartDrag;
commit 59de73c837b1092d46cd6c31d34272f541204af6
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Jul 20 10:55:35 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:25 2019 -0400
clipboard: get view setting correct before setClipboard.
Change-Id: If8e9b057b819074f035c598569e3bf6d3d2fff00
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index ed24302897bd..950a4eed0074 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -3579,12 +3579,12 @@ static int doc_getClipboard(LibreOfficeKitDocument* pThis,
}
rtl::Reference<LOKClipboard> xClip(LOKClipboardFactory::getClipboardForCurView());
- SAL_INFO("lok", "Got clipboard for view " << xClip.get());
css::uno::Reference<css::datatransfer::XTransferable> xTransferable = xClip->getContents();
+ SAL_INFO("lok", "Got from clip: " << xClip.get() << " transferrable: " << xTransferable);
if (!xTransferable)
{
- SetLastExceptionMsg("No selection available");
+ SetLastExceptionMsg("No clipboard content available");
return 0;
}
@@ -3657,6 +3657,8 @@ static int doc_setClipboard(LibreOfficeKitDocument* pThis,
auto xClip = forceSetClipboardForCurrentView(pThis);
xClip->setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>());
+ SAL_INFO("lok", "Set clip: " << xClip.get() << " to: " << xTransferable);
+
if (!pDoc->isMimeTypeSupported())
{
SetLastExceptionMsg("Document doesn't support this mime type");
diff --git a/desktop/source/lib/lokclipboard.cxx b/desktop/source/lib/lokclipboard.cxx
index a959258269a1..ef52a4596c43 100644
--- a/desktop/source/lib/lokclipboard.cxx
+++ b/desktop/source/lib/lokclipboard.cxx
@@ -25,10 +25,13 @@ rtl::Reference<LOKClipboard> LOKClipboardFactory::getClipboardForCurView()
auto it = gClipboards.find(nViewId);
if (it != gClipboards.end())
+ {
+ SAL_INFO("lok", "Got clip: " << it->second.get() << " from " << nViewId);
return it->second;
+ }
rtl::Reference<LOKClipboard> xClip(new LOKClipboard());
gClipboards[nViewId] = xClip;
- SAL_INFO("lok", "Created clipboard for view " << nViewId << " as " << xClip.get());
+ SAL_INFO("lok", "Created clip: " << xClip.get() << " for viewId " << nViewId);
return xClip;
}
@@ -81,6 +84,7 @@ void LOKClipboard::setContents(
std::vector<Reference<datatransfer::clipboard::XClipboardListener>> aListeners(m_aListeners);
datatransfer::clipboard::ClipboardEvent aEv;
aEv.Contents = m_xTransferable;
+ SAL_INFO("lok", "Clip: " << this << " set contents to " << m_xTransferable);
aGuard.clear();
commit 9c18813cc09248f2c9495ce3feaa43720699b48a
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Jul 20 10:52:51 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:24 2019 -0400
lok: clipboard: per view clipboard creation.
A bit brutal, but the mess around clipboard instantiation is awful.
Change-Id: I62d6af8bf6813e6bab81123417ea8bfb28394e29
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 594ec25c7f97..2fa09a23322b 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -588,7 +588,7 @@ void DesktopLOKTest::testPasteWriter()
free(pText);
// textt/plain should be rejected.
- CPPUNIT_ASSERT(!pDocument->pClass->paste(pDocument, "text/plain;charset=utf-8", aText.getStr(), aText.getLength()));
+ CPPUNIT_ASSERT(!pDocument->pClass->paste(pDocument, "textt/plain;charset=utf-8", aText.getStr(), aText.getLength()));
// Writer is expected to support text/html.
CPPUNIT_ASSERT(pDocument->pClass->paste(pDocument, "text/html", aText.getStr(), aText.getLength()));
@@ -2766,7 +2766,7 @@ void DesktopLOKTest::testABI()
CPPUNIT_ASSERT_EQUAL(documentClassOffset(49), offsetof(struct _LibreOfficeKitDocumentClass, selectPart));
CPPUNIT_ASSERT_EQUAL(documentClassOffset(50), offsetof(struct _LibreOfficeKitDocumentClass, moveSelectedParts));
CPPUNIT_ASSERT_EQUAL(documentClassOffset(51), offsetof(struct _LibreOfficeKitDocumentClass, resizeWindow));
- CPPUNIT_ASSERT_EQUAL(documentClassOffset(52), offsetof(struct _LibreOfficeKitDocumentClass, getSelection));
+ CPPUNIT_ASSERT_EQUAL(documentClassOffset(52), offsetof(struct _LibreOfficeKitDocumentClass, getClipboard));
CPPUNIT_ASSERT_EQUAL(documentClassOffset(53), offsetof(struct _LibreOfficeKitDocumentClass, setClipboard));
CPPUNIT_ASSERT_EQUAL(documentClassOffset(54), offsetof(struct _LibreOfficeKitDocumentClass, getSelectionType));
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index b08c49604667..ed24302897bd 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -3640,9 +3640,6 @@ static int doc_setClipboard(LibreOfficeKitDocument* pThis,
const size_t *pInSizes,
const char **pInStreams)
{
- SolarMutexGuard aGuard;
- if (gImpl)
-
comphelper::ProfileZone aZone("doc_paste");
SolarMutexGuard aGuard;
diff --git a/desktop/source/lib/lokclipboard.cxx b/desktop/source/lib/lokclipboard.cxx
index 74e5131f435d..a959258269a1 100644
--- a/desktop/source/lib/lokclipboard.cxx
+++ b/desktop/source/lib/lokclipboard.cxx
@@ -9,6 +9,7 @@
#include "lokclipboard.hxx"
#include <sfx2/lokhelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
using namespace css;
using namespace css::uno;
@@ -105,17 +106,38 @@ void LOKClipboard::removeClipboardListener(
m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), listener),
m_aListeners.end());
}
-
-LOKTransferable::LOKTransferable(const char* pMimeType, const char* pData, std::size_t nSize)
- : m_aMimeType(OUString::fromUtf8(pMimeType))
- , m_aSequence(reinterpret_cast<const sal_Int8*>(pData), nSize)
+LOKTransferable::LOKTransferable(const OUString& sMimeType,
+ const css::uno::Sequence<sal_Int8>& aSequence)
{
-}
+ m_aContent.reserve(1);
+ m_aFlavors = css::uno::Sequence<css::datatransfer::DataFlavor>(1);
+ initFlavourFromMime(m_aFlavors[0], sMimeType);
-LOKTransferable::LOKTransferable(OUString sMimeType, const css::uno::Sequence<sal_Int8>& aSequence)
- : m_aMimeType(std::move(sMimeType))
- , m_aSequence(aSequence)
+ uno::Any aContent;
+ if (m_aFlavors[0].DataType == cppu::UnoType<OUString>::get())
+ {
+ auto pText = reinterpret_cast<const sal_Char*>(aSequence.getConstArray());
+ aContent <<= OUString(pText, aSequence.getLength(), RTL_TEXTENCODING_UTF8);
+ }
+ else
+ aContent <<= aSequence;
+ m_aContent.push_back(aContent);
+}
+// cf. sot/source/base/exchange.cxx for these two exceptional types.
+void LOKTransferable::initFlavourFromMime(css::datatransfer::DataFlavor& rFlavor,
+ OUString aMimeType)
{
+ if (aMimeType.startsWith("text/plain"))
+ {
+ aMimeType = "text/plain;charset=utf-16";
+ rFlavor.DataType = cppu::UnoType<OUString>::get();
+ }
+ else if (aMimeType == "application/x-libreoffice-tsvc")
+ rFlavor.DataType = cppu::UnoType<OUString>::get();
+ else
+ rFlavor.DataType = cppu::UnoType<uno::Sequence<sal_Int8>>::get();
+ rFlavor.MimeType = aMimeType;
+ rFlavor.HumanPresentableName = aMimeType;
}
LOKTransferable::LOKTransferable(const size_t nInCount, const char** pInMimeTypes,
@@ -152,7 +174,7 @@ LOKTransferable::LOKTransferable(const size_t nInCount, const char** pInMimeType
uno::Any SAL_CALL LOKTransferable::getTransferData(const datatransfer::DataFlavor& rFlavor)
{
- assert(m_aContent.size() == m_aFlavors.getLength());
+ assert(m_aContent.size() == (size_t)m_aFlavors.getLength());
for (size_t i = 0; i < m_aContent.size(); ++i)
{
if (m_aFlavors[i].MimeType == rFlavor.MimeType)
diff --git a/desktop/source/lib/lokclipboard.hxx b/desktop/source/lib/lokclipboard.hxx
index d917a377eb11..54c1b37945ff 100644
--- a/desktop/source/lib/lokclipboard.hxx
+++ b/desktop/source/lib/lokclipboard.hxx
@@ -29,6 +29,7 @@ class LOKClipboard
css::lang::XServiceInfo>
{
osl::Mutex m_aMutex;
+ css::uno::Reference<css::datatransfer::XTransferable> m_xTransferable;
css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner;
std::vector<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>> m_aListeners;
@@ -73,9 +74,12 @@ class LOKTransferable : public cppu::WeakImplHelper<css::datatransfer::XTransfer
css::uno::Sequence<css::datatransfer::DataFlavor> m_aFlavors;
std::vector<css::uno::Any> m_aContent;
+ void initFlavourFromMime(css::datatransfer::DataFlavor& rFlavor, OUString sMimeType);
+
public:
LOKTransferable(const size_t nInCount, const char** pInMimeTypes, const size_t* pInSizes,
const char** pInStreams);
+ LOKTransferable(const OUString& sMimeType, const css::uno::Sequence<sal_Int8>& aSequence);
css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override;
commit 304b4578b454e91010fcfdacef0d87b0a03f50ae
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Jul 20 10:43:39 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Jul 26 16:38:23 2019 -0400
lok: clipboard: per view clipboard creation.
A bit brutal, but the mess around clipboard instantiation is awful.
Change-Id: I62d6af8bf6813e6bab81123417ea8bfb28394e29
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index aa236cd658c4..594ec25c7f97 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -2766,9 +2766,13 @@ void DesktopLOKTest::testABI()
CPPUNIT_ASSERT_EQUAL(documentClassOffset(49), offsetof(struct _LibreOfficeKitDocumentClass, selectPart));
CPPUNIT_ASSERT_EQUAL(documentClassOffset(50), offsetof(struct _LibreOfficeKitDocumentClass, moveSelectedParts));
CPPUNIT_ASSERT_EQUAL(documentClassOffset(51), offsetof(struct _LibreOfficeKitDocumentClass, resizeWindow));
+ CPPUNIT_ASSERT_EQUAL(documentClassOffset(52), offsetof(struct _LibreOfficeKitDocumentClass, getSelection));
+ CPPUNIT_ASSERT_EQUAL(documentClassOffset(53), offsetof(struct _LibreOfficeKitDocumentClass, setClipboard));
+ CPPUNIT_ASSERT_EQUAL(documentClassOffset(54), offsetof(struct _LibreOfficeKitDocumentClass, getSelectionType));
+
// Extending is fine, update this, and add new assert for the offsetof the
// new method
- CPPUNIT_ASSERT_EQUAL(documentClassOffset(52), sizeof(struct _LibreOfficeKitDocumentClass));
+ CPPUNIT_ASSERT_EQUAL(documentClassOffset(55), sizeof(struct _LibreOfficeKitDocumentClass));
}
CPPUNIT_TEST_SUITE_REGISTRATION(DesktopLOKTest);
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 956a382a248b..b08c49604667 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -790,7 +790,7 @@ static char* doc_getTextSelection(LibreOfficeKitDocument* pThis,
const char* pMimeType,
char** pUsedMimeType);
static int doc_getSelectionType(LibreOfficeKitDocument* pThis);
-static int doc_getSelection (LibreOfficeKitDocument* pThis,
+static int doc_getClipboard (LibreOfficeKitDocument* pThis,
const char **pMimeTypes,
size_t *pOutCount,
char ***pOutMimeTypes,
@@ -863,6 +863,34 @@ static size_t doc_renderShapeSelection(LibreOfficeKitDocument* pThis, char** pOu
static void doc_resizeWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId,
const int nWidth, const int nHeight);
+} // extern "C"
+
+namespace {
+ITiledRenderable* getTiledRenderable(LibreOfficeKitDocument* pThis)
+{
+ LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
+ return dynamic_cast<ITiledRenderable*>(pDocument->mxComponent.get());
+}
+
+/*
+ * Unfortunately clipboard creation using UNO is insanely baroque.
+ * we also need to ensure that this works for the first view which
+ * has no clear 'createView' called for it (unfortunately).
+ */
+
+rtl::Reference<LOKClipboard> forceSetClipboardForCurrentView(LibreOfficeKitDocument *pThis)
+{
+ ITiledRenderable* pDoc = getTiledRenderable(pThis);
+ rtl::Reference<LOKClipboard> xClip(LOKClipboardFactory::getClipboardForCurView());
+
+ SAL_INFO("lok", "Set to clipboard for view " << xClip.get());
+ // FIXME: using a hammer here - should not be necessary if all tests used createView.
+ pDoc->setClipboard(uno::Reference<datatransfer::clipboard::XClipboard>(xClip->getXI(), UNO_QUERY));
+
+ return xClip;
+}
+} // anonymous namespace
+
LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XComponent> &xComponent)
: mxComponent(xComponent)
{
@@ -901,7 +929,7 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone
m_pDocumentClass->setTextSelection = doc_setTextSelection;
m_pDocumentClass->getTextSelection = doc_getTextSelection;
m_pDocumentClass->getSelectionType = doc_getSelectionType;
- m_pDocumentClass->getSelection = doc_getSelection;
+ m_pDocumentClass->getClipboard = doc_getClipboard;
m_pDocumentClass->setClipboard = doc_setClipboard;
m_pDocumentClass->paste = doc_paste;
m_pDocumentClass->setGraphicSelection = doc_setGraphicSelection;
@@ -942,6 +970,8 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone
gDocumentClass = m_pDocumentClass;
}
pClass = m_pDocumentClass.get();
+
+ forceSetClipboardForCurrentView(this);
}
LibLODocument_Impl::~LibLODocument_Impl()
@@ -1691,12 +1721,6 @@ LibLibreOffice_Impl::~LibLibreOffice_Impl()
namespace
{
-ITiledRenderable* getTiledRenderable(LibreOfficeKitDocument* pThis)
-{
- LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
- return dynamic_cast<ITiledRenderable*>(pDocument->mxComponent.get());
-}
-
#ifdef IOS
void paintTileToCGContext(ITiledRenderable* pDocument,
void* rCGContext, const Size nCanvasSize,
@@ -3527,7 +3551,7 @@ static int doc_getSelectionType(LibreOfficeKitDocument* pThis)
return aRet.getLength() ? LOK_SELTYPE_TEXT : LOK_SELTYPE_NONE;
}
-static int doc_getSelection(LibreOfficeKitDocument* pThis,
+static int doc_getClipboard(LibreOfficeKitDocument* pThis,
const char **pMimeTypes,
size_t *pOutCount,
char ***pOutMimeTypes,
@@ -3554,7 +3578,10 @@ static int doc_getSelection(LibreOfficeKitDocument* pThis,
return 0;
}
- css::uno::Reference<css::datatransfer::XTransferable> xTransferable = pDoc->getSelection();
+ rtl::Reference<LOKClipboard> xClip(LOKClipboardFactory::getClipboardForCurView());
+ SAL_INFO("lok", "Got clipboard for view " << xClip.get());
+
+ css::uno::Reference<css::datatransfer::XTransferable> xTransferable = xClip->getContents();
if (!xTransferable)
{
SetLastExceptionMsg("No selection available");
@@ -3629,9 +3656,9 @@ static int doc_setClipboard(LibreOfficeKitDocument* pThis,
}
uno::Reference<datatransfer::XTransferable> xTransferable(new LOKTransferable(nInCount, pInMimeTypes, pInSizes, pInStreams));
- uno::Reference<datatransfer::clipboard::XClipboard> xClipboard(new LOKClipboard);
- xClipboard->setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>());
- pDoc->setClipboard(xClipboard);
+
+ auto xClip = forceSetClipboardForCurrentView(pThis);
+ xClip->setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>());
if (!pDoc->isMimeTypeSupported())
{
@@ -4297,7 +4324,7 @@ static void doc_setOutlineState(LibreOfficeKitDocument* pThis, bool bColumn, int
pDoc->setOutlineState(bColumn, nLevel, nIndex, bHidden);
}
-static int doc_createViewWithOptions(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/,
+static int doc_createViewWithOptions(LibreOfficeKitDocument* pThis,
const char* pOptions)
{
comphelper::ProfileZone aZone("doc_createView");
@@ -4314,7 +4341,11 @@ static int doc_createViewWithOptions(SAL_UNUSED_PARAMETER LibreOfficeKitDocument
comphelper::LibreOfficeKit::setLanguageTag(LanguageTag(aLanguage));
}
- return SfxLokHelper::createView();
+ int nId = SfxLokHelper::createView();
+
+ forceSetClipboardForCurrentView(pThis);
+
+ return nId;
}
static int doc_createView(LibreOfficeKitDocument* pThis)
@@ -5490,8 +5521,6 @@ static void lo_destroy(LibreOfficeKit* pThis)
SAL_INFO("lok", "LO Destroy Done");
}
-}
-
#ifdef IOS
// Used by the unmaintained LibreOfficeLight app. Once that has been retired, get rid of this, too.
diff --git a/desktop/source/lib/lokclipboard.cxx b/desktop/source/lib/lokclipboard.cxx
index 015690bd9bc4..74e5131f435d 100644
--- a/desktop/source/lib/lokclipboard.cxx
+++ b/desktop/source/lib/lokclipboard.cxx
@@ -8,23 +8,103 @@
*/
#include "lokclipboard.hxx"
-#include <comphelper/sequence.hxx>
+#include <sfx2/lokhelper.hxx>
-using namespace com::sun::star;
+using namespace css;
+using namespace css::uno;
-uno::Reference<datatransfer::XTransferable> SAL_CALL LOKClipboard::getContents()
+osl::Mutex LOKClipboardFactory::gMutex;
+std::unordered_map<int, rtl::Reference<LOKClipboard>> LOKClipboardFactory::gClipboards;
+
+rtl::Reference<LOKClipboard> LOKClipboardFactory::getClipboardForCurView()
+{
+ int nViewId = SfxLokHelper::getView(); // currently active.
+
+ osl::MutexGuard aGuard(gMutex);
+
+ auto it = gClipboards.find(nViewId);
+ if (it != gClipboards.end())
+ return it->second;
+ rtl::Reference<LOKClipboard> xClip(new LOKClipboard());
+ gClipboards[nViewId] = xClip;
+ SAL_INFO("lok", "Created clipboard for view " << nViewId << " as " << xClip.get());
+ return xClip;
+}
+
+uno::Reference<uno::XInterface>
+ SAL_CALL LOKClipboardFactory::createInstanceWithArguments(const Sequence<Any>& /* rArgs */)
+{
+ return uno::Reference<uno::XInterface>(
+ static_cast<cppu::OWeakObject*>(getClipboardForCurView().get()));
+}
+
+LOKClipboard::LOKClipboard()
+ : cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard,
+ css::lang::XServiceInfo>(m_aMutex)
+{
+}
+
+Sequence<OUString> LOKClipboard::getSupportedServiceNames_static()
+{
+ Sequence<OUString> aRet{ "com.sun.star.datatransfer.clipboard.SystemClipboard" };
+ return aRet;
+}
+
+OUString LOKClipboard::getImplementationName()
+{
+ return OUString("com.sun.star.datatransfer.LOKClipboard");
+}
+
+Sequence<OUString> LOKClipboard::getSupportedServiceNames()
+{
+ return getSupportedServiceNames_static();
+}
+
+sal_Bool LOKClipboard::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Reference<css::datatransfer::XTransferable> LOKClipboard::getContents() { return m_xTransferable; }
+
+void LOKClipboard::setContents(
+ const Reference<css::datatransfer::XTransferable>& xTrans,
+ const Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner)
{
- return m_xTransferable;
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+ Reference<datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner);
+ Reference<datatransfer::XTransferable> xOldContents(m_xTransferable);
+ m_xTransferable = xTrans;
+ m_aOwner = xClipboardOwner;
+
+ std::vector<Reference<datatransfer::clipboard::XClipboardListener>> aListeners(m_aListeners);
+ datatransfer::clipboard::ClipboardEvent aEv;
+ aEv.Contents = m_xTransferable;
+
+ aGuard.clear();
+
+ if (xOldOwner.is() && xOldOwner != xClipboardOwner)
+ xOldOwner->lostOwnership(this, xOldContents);
+ for (auto const& listener : aListeners)
+ {
+ listener->changedContents(aEv);
+ }
}
-void SAL_CALL LOKClipboard::setContents(
- const uno::Reference<datatransfer::XTransferable>& xTransferable,
- const uno::Reference<datatransfer::clipboard::XClipboardOwner>& /*xClipboardOwner*/)
+void LOKClipboard::addClipboardListener(
+ const Reference<datatransfer::clipboard::XClipboardListener>& listener)
{
- m_xTransferable = xTransferable;
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+ m_aListeners.push_back(listener);
}
-OUString SAL_CALL LOKClipboard::getName() { return OUString(); }
+void LOKClipboard::removeClipboardListener(
+ const Reference<datatransfer::clipboard::XClipboardListener>& listener)
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+ m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), listener),
+ m_aListeners.end());
+}
LOKTransferable::LOKTransferable(const char* pMimeType, const char* pData, std::size_t nSize)
: m_aMimeType(OUString::fromUtf8(pMimeType))
diff --git a/desktop/source/lib/lokclipboard.hxx b/desktop/source/lib/lokclipboard.hxx
index 5da8b3e2b63e..d917a377eb11 100644
--- a/desktop/source/lib/lokclipboard.hxx
+++ b/desktop/source/lib/lokclipboard.hxx
@@ -11,24 +11,60 @@
#define INCLUDED_DESKTOP_SOURCE_LIB_LOKCLIPBOARD_HXX
#include <vector>
+#include <unordered_map>
+#include <rtl/ref.hxx>
#include <cppuhelper/implbase.hxx>
-#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/sequence.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/datatransfer/clipboard/XSystemClipboard.hpp>
+
+using namespace css::uno;
/// A clipboard implementation for LibreOfficeKit.
-class LOKClipboard : public cppu::WeakImplHelper<css::datatransfer::clipboard::XClipboard>
+class LOKClipboard
+ : public cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard,
+ css::lang::XServiceInfo>
{
- css::uno::Reference<css::datatransfer::XTransferable> m_xTransferable;
+ osl::Mutex m_aMutex;
+ css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner;
+ std::vector<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>> m_aListeners;
public:
- css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL getContents() override;
+ LOKClipboard();
+
+ /// get an XInterface easily.
+ css::uno::Reference<css::uno::XInterface> getXI()
+ {
+ return css::uno::Reference<css::uno::XInterface>(static_cast<cppu::OWeakObject*>(this));
+ }
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+ static Sequence<OUString> getSupportedServiceNames_static();
+ // XClipboard
+ css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL getContents() override;
void SAL_CALL setContents(
const css::uno::Reference<css::datatransfer::XTransferable>& xTransferable,
const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner)
override;
+ OUString SAL_CALL getName() override { return OUString("CLIPBOARD"); }
+
+ // XClipboardEx
+ sal_Int8 SAL_CALL getRenderingCapabilities() override { return 0; }
- OUString SAL_CALL getName() override;
+ // XClipboardNotifier
+ void SAL_CALL addClipboardListener(
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
+ override;
+ void SAL_CALL removeClipboardListener(
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
+ override;
};
/// Represents the contents of LOKClipboard.
@@ -38,10 +74,8 @@ class LOKTransferable : public cppu::WeakImplHelper<css::datatransfer::XTransfer
std::vector<css::uno::Any> m_aContent;
public:
- LOKTransferable(const size_t nInCount,
- const char **pInMimeTypes,
- const size_t *pInSizes,
- const char **pInStreams);
+ LOKTransferable(const size_t nInCount, const char** pInMimeTypes, const size_t* pInSizes,
+ const char** pInStreams);
css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override;
@@ -50,6 +84,27 @@ public:
sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) override;
};
+/// Theoretically to hook into the (horrible) vcl dtranscomp.cxx code.
+class LOKClipboardFactory : public ::cppu::WeakComponentImplHelper<css::lang::XSingleServiceFactory>
+{
+ static osl::Mutex gMutex;
+ static std::unordered_map<int, rtl::Reference<LOKClipboard>> gClipboards;
+
+public:
+ LOKClipboardFactory()
+ : cppu::WeakComponentImplHelper<css::lang::XSingleServiceFactory>(gMutex)
+ {
+ }
+
+ css::uno::Reference<css::uno::XInterface> SAL_CALL createInstance() override
+ {
+ return createInstanceWithArguments(css::uno::Sequence<css::uno::Any>());
+ }
+ css::uno::Reference<css::uno::XInterface> SAL_CALL
+ createInstanceWithArguments(const css::uno::Sequence<css::uno::Any>& /* rArgs */) override;
+ static rtl::Reference<LOKClipboard> getClipboardForCurView();
+};
+
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h
index abdc9863c1f0..93b430f5da0b 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -390,8 +390,8 @@ struct _LibreOfficeKitDocumentClass
const int width, const int height);
/// Pass a nullptr terminated array of mime-type strings
- /// @see lok::Document::getSelection for more details
- int (*getSelection) (LibreOfficeKitDocument* pThis,
+ /// @see lok::Document::getClipboard for more details
+ int (*getClipboard) (LibreOfficeKitDocument* pThis,
const char **pMimeTypes,
size_t *pOutCount,
char ***pOutMimeTypes,
diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx
index f38d2b5109f6..bd6609c321a4 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -362,7 +362,7 @@ public:
}
/**
- * Gets the selected content for the current view as a series of binary streams.
+ * Gets the content on the clipboard for the current view as a series of binary streams.
*
* NB. returns a complete set of possible selection types if nullptr is passed for pMimeTypes.
*
@@ -374,13 +374,13 @@ public:
*
* @returns: true on success, false on error.
*/
- bool getSelection(const char **pMimeTypes,
+ bool getClipboard(const char **pMimeTypes,
size_t *pOutCount,
char ***pOutMimeTypes,
size_t **pOutSizes,
char ***pOutStreams)
{
- return mpDoc->pClass->getSelection(mpDoc, pMimeTypes, pOutCount, pOutMimeTypes, pOutSizes, pOutStreams);
+ return mpDoc->pClass->getClipboard(mpDoc, pMimeTypes, pOutCount, pOutMimeTypes, pOutSizes, pOutStreams);
}
/**
More information about the Libreoffice-commits
mailing list