diff options
author | Michael Meeks <michael.meeks@collabora.com> | 2019-07-19 23:44:20 +0100 |
---|---|---|
committer | Michael Meeks <michael.meeks@collabora.com> | 2019-08-02 11:41:47 -0400 |
commit | 3dbf6e43ebd6a52b665fab906711f173f0e5ba82 (patch) | |
tree | fd6c4db33a2653871d5298bdb0a6775790d63308 | |
parent | a85b62cb8cbbbd25316f77b49055c1fb817c60e3 (diff) |
Add more powerful selection fetch & clipboard set methods.
Change-Id: I6633356d13480377a83a006588ec69ebcb56a93f
-rw-r--r-- | desktop/source/lib/init.cxx | 144 | ||||
-rw-r--r-- | desktop/source/lib/lokclipboard.cxx | 71 | ||||
-rw-r--r-- | desktop/source/lib/lokclipboard.hxx | 13 | ||||
-rw-r--r-- | include/LibreOfficeKit/LibreOfficeKit.h | 16 | ||||
-rw-r--r-- | include/LibreOfficeKit/LibreOfficeKit.hxx | 40 |
5 files changed, 236 insertions, 48 deletions
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index 4b808f4b1c1b..bb50736df0fe 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -170,6 +170,7 @@ static std::weak_ptr< LibreOfficeKitDocumentClass > gDocumentClass; static void SetLastExceptionMsg(const OUString& s = OUString()) { + SAL_WARN("lok", "lok exception " + s); if (gImpl) gImpl->maLastExceptionMsg = s; } @@ -787,6 +788,17 @@ static void doc_setTextSelection (LibreOfficeKitDocument* pThis, static char* doc_getTextSelection(LibreOfficeKitDocument* pThis, const char* pMimeType, char** pUsedMimeType); +static int doc_getSelection (LibreOfficeKitDocument* pThis, + const char **pMimeTypes, + size_t *pOutCount, + char ***pOutMimeTypes, + size_t **pOutSizes, + char ***pOutStreams); +static int doc_setClipboard (LibreOfficeKitDocument* pThis, + const size_t nInCount, + const char **pInMimeTypes, + const size_t *pInSizes, + const char **pInStreams); static bool doc_paste(LibreOfficeKitDocument* pThis, const char* pMimeType, const char* pData, @@ -886,6 +898,8 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone m_pDocumentClass->postUnoCommand = doc_postUnoCommand; m_pDocumentClass->setTextSelection = doc_setTextSelection; m_pDocumentClass->getTextSelection = doc_getTextSelection; + m_pDocumentClass->getSelection = doc_getSelection; + m_pDocumentClass->setClipboard = doc_setClipboard; m_pDocumentClass->paste = doc_paste; m_pDocumentClass->setGraphicSelection = doc_setGraphicSelection; m_pDocumentClass->resetSelection = doc_resetSelection; @@ -3372,10 +3386,11 @@ static void doc_setTextSelection(LibreOfficeKitDocument* pThis, int nType, int n static bool getFromTransferrable( const css::uno::Reference<css::datatransfer::XTransferable> &xTransferable, - const char *pMimeType, OString &aRet) + const OString &aInMimeType, OString &aRet) { + OString aMimeType(aInMimeType); + // Take care of UTF-8 text here. - OString aMimeType(pMimeType); bool bConvert = false; sal_Int32 nIndex = 0; if (aMimeType.getToken(0, ';', nIndex) == "text/plain") @@ -3435,6 +3450,14 @@ static bool getFromTransferrable( return true;; } +// Tolerate embedded \0s etc. +static char *convertOString(const OString &rStr) +{ + char* pMemory = static_cast<char*>(malloc(rStr.getLength() + 1)); + memcpy(pMemory, rStr.getStr(), rStr.getLength() + 1); + return pMemory; +} + static char* doc_getTextSelection(LibreOfficeKitDocument* pThis, const char* pMimeType, char** pUsedMimeType) { comphelper::ProfileZone aZone("doc_getTextSelection"); @@ -3461,30 +3484,107 @@ static char* doc_getTextSelection(LibreOfficeKitDocument* pThis, const char* pMi pType = "text/plain;charset=utf-8"; OString aRet; - bool bSuccess = getFromTransferrable(xTransferable, pType, aRet); + bool bSuccess = getFromTransferrable(xTransferable, OString(pType), aRet); if (!bSuccess) return nullptr; - char* pMemory = static_cast<char*>(malloc(aRet.getLength() + 1)); - assert(pMemory); // Don't handle OOM conditions - strcpy(pMemory, aRet.getStr()); - if (pUsedMimeType) // legacy { if (pMimeType) + *pUsedMimeType = strdup(pMimeType); + else + *pUsedMimeType = nullptr; + } + + return convertOString(aRet); +} + +static int doc_getSelection(LibreOfficeKitDocument* pThis, + const char **pMimeTypes, + size_t *pOutCount, + char ***pOutMimeTypes, + size_t **pOutSizes, + char ***pOutStreams) +{ + SolarMutexGuard aGuard; + SetLastExceptionMsg(); + + assert (pOutCount); + assert (pOutMimeTypes); + assert (pOutSizes); + assert (pOutStreams); + + *pOutCount = 0; + *pOutMimeTypes = nullptr; + *pOutSizes = nullptr; + *pOutStreams = nullptr; + + ITiledRenderable* pDoc = getTiledRenderable(pThis); + if (!pDoc) + { + SetLastExceptionMsg("Document doesn't support tiled rendering"); + return 0; + } + + css::uno::Reference<css::datatransfer::XTransferable> xTransferable = pDoc->getSelection(); + if (!xTransferable) + { + SetLastExceptionMsg("No selection available"); + return 0; + } + + std::vector<OString> aMimeTypes; + if (!pMimeTypes) // everything + { + uno::Sequence< css::datatransfer::DataFlavor > flavors = xTransferable->getTransferDataFlavors(); + if (!flavors.getLength()) + { + SetLastExceptionMsg("Flavourless selection"); + return 0; + } + for (auto &it : flavors) + aMimeTypes.push_back(OUStringToOString(it.MimeType, RTL_TEXTENCODING_UTF8)); + } + else + { + for (size_t i = 0; pMimeTypes[i]; ++i) + aMimeTypes.push_back(OString(pMimeTypes[i])); + } + + *pOutCount = aMimeTypes.size(); + *pOutSizes = static_cast<size_t *>(malloc(*pOutCount * sizeof(size_t))); + *pOutMimeTypes = static_cast<char **>(malloc(*pOutCount * sizeof(char *))); + *pOutStreams = static_cast<char **>(malloc(*pOutCount * sizeof(char *))); + for (size_t i = 0; i < aMimeTypes.size(); ++i) + { + (*pOutMimeTypes)[i] = strdup(aMimeTypes[i].getStr()); + + OString aRet; + bool bSuccess = getFromTransferrable(xTransferable, aMimeTypes[i], aRet); + if (!bSuccess || aRet.getLength() < 1) { - *pUsedMimeType = static_cast<char*>(malloc(strlen(pMimeType) + 1)); - strcpy(*pUsedMimeType, pMimeType); + (*pOutSizes)[i] = 0; + (*pOutStreams)[i] = nullptr; } else - *pUsedMimeType = nullptr; + { + (*pOutSizes)[i] = aRet.getLength(); + (*pOutStreams)[i] = convertOString(aRet); + } } - return pMemory; + return 1; } -static bool doc_paste(LibreOfficeKitDocument* pThis, const char* pMimeType, const char* pData, size_t nSize) +static int doc_setClipboard(LibreOfficeKitDocument* pThis, + const size_t nInCount, + const char **pInMimeTypes, + const size_t *pInSizes, + const char **pInStreams) { + SolarMutexGuard aGuard; + if (gImpl) + comphelper::ProfileZone aZone("doc_paste"); SolarMutexGuard aGuard; @@ -3497,16 +3597,34 @@ static bool doc_paste(LibreOfficeKitDocument* pThis, const char* pMimeType, cons return false; } - uno::Reference<datatransfer::XTransferable> xTransferable(new LOKTransferable(pMimeType, pData, nSize)); + 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); + if (!pDoc->isMimeTypeSupported()) { SetLastExceptionMsg("Document doesn't support this mime type"); return false; } + return true; +} + +static bool doc_paste(LibreOfficeKitDocument* pThis, const char* pMimeType, const char* pData, size_t nSize) +{ + SolarMutexGuard aGuard; + + const char *pInMimeTypes[1]; + const char *pInStreams[1]; + size_t pInSizes[1]; + pInMimeTypes[0] = pMimeType; + pInSizes[0] = nSize; + pInStreams[0] = pData; + + if (!doc_setClipboard(pThis, 1, pInMimeTypes, pInSizes, pInStreams)) + return false; + uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence( { {"AnchorType", uno::makeAny(static_cast<sal_uInt16>(text::TextContentAnchorType_AS_CHARACTER))}, diff --git a/desktop/source/lib/lokclipboard.cxx b/desktop/source/lib/lokclipboard.cxx index e5ba5fe9e80a..015690bd9bc4 100644 --- a/desktop/source/lib/lokclipboard.cxx +++ b/desktop/source/lib/lokclipboard.cxx @@ -38,50 +38,65 @@ LOKTransferable::LOKTransferable(OUString sMimeType, const css::uno::Sequence<sa { } -uno::Any SAL_CALL LOKTransferable::getTransferData(const datatransfer::DataFlavor& rFlavor) +LOKTransferable::LOKTransferable(const size_t nInCount, const char** pInMimeTypes, + const size_t* pInSizes, const char** pInStreams) { - uno::Any aRet; - if (rFlavor.DataType == cppu::UnoType<OUString>::get()) + m_aContent.reserve(nInCount); + m_aFlavors = css::uno::Sequence<css::datatransfer::DataFlavor>(nInCount); + for (size_t i = 0; i < nInCount; ++i) { - auto pText = reinterpret_cast<sal_Char*>(m_aSequence.getArray()); - aRet <<= OUString(pText, m_aSequence.getLength(), RTL_TEXTENCODING_UTF8); + 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; + + uno::Any aContent; + if (m_aFlavors[i].DataType == cppu::UnoType<OUString>::get()) + aContent <<= OUString(pInStreams[i], pInSizes[i], RTL_TEXTENCODING_UTF8); + else + aContent <<= css::uno::Sequence<sal_Int8>( + reinterpret_cast<const sal_Int8*>(pInStreams[i]), pInSizes[i]); + m_aContent.push_back(aContent); } - else - aRet <<= m_aSequence; - return aRet; } -std::vector<datatransfer::DataFlavor> LOKTransferable::getTransferDataFlavorsAsVector() +uno::Any SAL_CALL LOKTransferable::getTransferData(const datatransfer::DataFlavor& rFlavor) { - std::vector<datatransfer::DataFlavor> aRet; - datatransfer::DataFlavor aFlavor; - aFlavor.MimeType = m_aMimeType; - aFlavor.DataType = cppu::UnoType<uno::Sequence<sal_Int8>>::get(); - - sal_Int32 nIndex(0); - if (m_aMimeType.getToken(0, ';', nIndex) == "text/plain") + assert(m_aContent.size() == m_aFlavors.getLength()); + for (size_t i = 0; i < m_aContent.size(); ++i) { - if (m_aMimeType.getToken(0, ';', nIndex) != "charset=utf-16") - aFlavor.MimeType = "text/plain;charset=utf-16"; - aFlavor.DataType = cppu::UnoType<OUString>::get(); + if (m_aFlavors[i].MimeType == rFlavor.MimeType) + { + if (m_aFlavors[i].DataType != rFlavor.DataType) + SAL_WARN("lok", "Horror type mismatch!"); + return m_aContent[i]; + } } - aRet.push_back(aFlavor); - - return aRet; + return uno::Any(); } uno::Sequence<datatransfer::DataFlavor> SAL_CALL LOKTransferable::getTransferDataFlavors() { - return comphelper::containerToSequence(getTransferDataFlavorsAsVector()); + return m_aFlavors; } sal_Bool SAL_CALL LOKTransferable::isDataFlavorSupported(const datatransfer::DataFlavor& rFlavor) { - const std::vector<datatransfer::DataFlavor> aFlavors = getTransferDataFlavorsAsVector(); - return std::any_of(aFlavors.begin(), aFlavors.end(), - [&rFlavor](const datatransfer::DataFlavor& i) { - return i.MimeType == rFlavor.MimeType && i.DataType == rFlavor.DataType; - }); + return std::find_if(m_aFlavors.begin(), m_aFlavors.end(), + [&rFlavor](const datatransfer::DataFlavor& i) { + return i.MimeType == rFlavor.MimeType && i.DataType == rFlavor.DataType; + }) + != m_aFlavors.end(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/lib/lokclipboard.hxx b/desktop/source/lib/lokclipboard.hxx index db2c7380bb25..5da8b3e2b63e 100644 --- a/desktop/source/lib/lokclipboard.hxx +++ b/desktop/source/lib/lokclipboard.hxx @@ -34,15 +34,14 @@ public: /// Represents the contents of LOKClipboard. class LOKTransferable : public cppu::WeakImplHelper<css::datatransfer::XTransferable> { - OUString m_aMimeType; - css::uno::Sequence<sal_Int8> m_aSequence; - - /// Provides a list of flavors, used by getTransferDataFlavors() and isDataFlavorSupported(). - std::vector<css::datatransfer::DataFlavor> getTransferDataFlavorsAsVector(); + css::uno::Sequence<css::datatransfer::DataFlavor> m_aFlavors; + std::vector<css::uno::Any> m_aContent; public: - LOKTransferable(const char* pMimeType, const char* pData, std::size_t nSize); - LOKTransferable(OUString sMimeType, const css::uno::Sequence<sal_Int8>& aSequence); + 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; diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h index dedb75995930..14b7bb995b10 100644 --- a/include/LibreOfficeKit/LibreOfficeKit.h +++ b/include/LibreOfficeKit/LibreOfficeKit.h @@ -389,6 +389,22 @@ struct _LibreOfficeKitDocumentClass void (*resizeWindow) (LibreOfficeKitDocument* pThis, unsigned nWindowId, 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, + const char **pMimeTypes, + size_t *pOutCount, + char ***pOutMimeTypes, + size_t **pOutSizes, + char ***pOutStreams); + + /// @see lok::Document::setClipboard + int (*setClipboard) (LibreOfficeKitDocument* pThis, + const size_t nInCount, + const char **pInMimeTypes, + const size_t *pInSizes, + const char **pInStreams); + #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY }; diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx index c6f90dc1ae24..cb1ca1e4c2d3 100644 --- a/include/LibreOfficeKit/LibreOfficeKit.hxx +++ b/include/LibreOfficeKit/LibreOfficeKit.hxx @@ -352,6 +352,46 @@ public: } /** + * Gets the selected content 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. + * + * @param pMimeTypes passes in a nullptr terminated list of mime types to fetch + * @param pOutCount returns the size of the other @pOut arrays + * @param pOutMimeTypes returns an array of mime types + * @param pOutSizes returns the size of each pOutStream + * @param pOutStreams the content of each mime-type, of length in @pOutSizes + * + * @returns: true on success, false on error. + */ + bool getSelection(const char **pMimeTypes, + size_t *pOutCount, + char ***pOutMimeTypes, + size_t **pOutSizes, + char ***pOutStreams) + { + return mpDoc->pClass->getSelection(mpDoc, pMimeTypes, pOutCount, pOutMimeTypes, pOutSizes, pOutStreams); + } + + /** + * Populates the clipboard for this view with multiple types of content. + * + * @param nInCount the number of types to paste + * @param pInMimeTypes array of mime type strings + * @param pInSizes array of sizes of the data to paste + * @param pInStreams array containing the data of the various types + * + * @return if the supplied data was populated successfully. + */ + bool setClipboard(const size_t nInCount, + const char **pInMimeTypes, + const size_t *pInSizes, + const char **pInStreams) + { + return mpDoc->pClass->setClipboard(mpDoc, nInCount, pInMimeTypes, pInSizes, pInStreams); + } + + /** * Pastes content at the current cursor position. * * @param pMimeType format of pData, for example text/plain;charset=utf-8. |