clipboard: Copying of complex data with detection

Complex data is now flagged based on Core's
feedback and/or the size of the payload.

Download now works as expected and copying
to the clipboard is also functional.

Change-Id: I7405517e3a6afcc4c8f5843130476578c1ff06f6
This commit is contained in:
Ashod Nakashian 2019-06-25 22:42:15 -04:00 committed by Michael Meeks
parent 00a4fc0cd7
commit 8ce397b758
5 changed files with 98 additions and 36 deletions

View file

@ -351,6 +351,56 @@ public:
return mpDoc->pClass->getTextSelection(mpDoc, pMimeType, pUsedMimeType);
}
/**
* Gets the type of the selected content.
*
* @return an element of the LibreOfficeKitSelectionType enum.
*/
int getSelectionType()
{
return mpDoc->pClass->getSelectionType(mpDoc);
}
/**
* 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.
*
* @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 getClipboard(const char **pMimeTypes,
size_t *pOutCount,
char ***pOutMimeTypes,
size_t **pOutSizes,
char ***pOutStreams)
{
return mpDoc->pClass->getClipboard(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.
*

View file

@ -917,7 +917,31 @@ bool ChildSession::getTextSelection(const char* /*buffer*/, int /*length*/, cons
return false;
}
sendTextFrame("textselectioncontent: " + getTextSelectionInternal(mimeType));
if (getLOKitDocument()->getDocumentType() != LOK_DOCTYPE_TEXT)
{
const std::string selection = getTextSelectionInternal(mimeType);
if (selection.size() >= 1024 * 1024) // Don't return huge data.
{
// Flag complex data so the client will download async.
sendTextFrame("complexselection:");
return true;
}
sendTextFrame("textselectioncontent: " + selection);
return true;
}
std::string selection;
const int selectionType = getLOKitDocument()->getSelectionType();
if (selectionType == LOK_SELTYPE_LARGE_TEXT || selectionType == LOK_SELTYPE_COMPLEX ||
(selection = getTextSelectionInternal(mimeType)).size() >= 1024 * 1024) // Don't return huge data.
{
// Flag complex data so the client will download async.
sendTextFrame("complexselection:");
return true;
}
sendTextFrame("textselectioncontent: " + selection);
return true;
}
@ -996,7 +1020,7 @@ bool ChildSession::setClipboard(const char* buffer, int length, const std::vecto
// data.dumpState(std::cerr);
size_t nInCount = data.size();
size_t pInSizes[nInCount] = { 0, };
size_t pInSizes[nInCount];
const char *pInMimeTypes[nInCount];
const char *pInStreams[nInCount];

View file

@ -53,6 +53,7 @@ L.Control.DownloadProgress = L.Control.extend({
confirmCopy.style.alignment = 'center';
confirmCopy.style.height = 20 + 'px';
L.DomEvent.on(confirmCopy, 'click', this._onConfirmCopyAction, this);
this._closed = false;
},
show: function () {
@ -62,6 +63,10 @@ L.Control.DownloadProgress = L.Control.extend({
this._container.style.visibility = '';
},
isClosed: function () {
return this._closed;
},
setURI: function (uri) {
// set up data uri to be downloaded
this._uri = uri;
@ -112,8 +117,8 @@ L.Control.DownloadProgress = L.Control.extend({
this._content.appendChild(this._confirmPasteButton);
},
_onConfirmCopyAction: function (ev) {
this._map._clip.copy(ev);
_onConfirmCopyAction: function () {
this._map._clip.filterExecCopyPaste('.uno:Copy');
this._map._clip._downloadProgress = null;
this._onClose();
},
@ -127,6 +132,7 @@ L.Control.DownloadProgress = L.Control.extend({
this._content.removeChild(this._progress);
this._map.focus();
this.remove();
this._closed = true;
},
_download: function () {
@ -138,12 +144,12 @@ L.Control.DownloadProgress = L.Control.extend({
// annoying async parse of the blob ...
var reader = new FileReader();
reader.onload = function() {
console.log('async clipboard parse done: ' + text.substring(0, 256))
var text = reader.result;
console.log('async clipboard parse done: ' + text.substring(0, 256))
var idx = text.indexOf('<!DOCTYPE HTML');
if (idx > 0)
text = text.substring(idx, text.length());
that._map._clip.setSelection(text);
text = text.substring(idx, text.length);
that._map._clip.setTextSelectionContent(text);
// TODO: now swap to the 'copy' button (?)
};
// TODO: failure to parse ? ...

View file

@ -585,7 +585,7 @@ L.TileLayer = L.GridLayer.extend({
// message is received from lowsd, *then* a 'celladdress' message.
var address = textMsg.substring(13);
if (!this._map['wopi'].DisableCopy) {
this._map._clip.setSelection(this._lastFormula);
this._map._clip.setTextSelectionContent(this._lastFormula);
}
this._map.fire('celladdress', {address: address});
},
@ -2636,17 +2636,6 @@ L.TileLayer = L.GridLayer.extend({
}
},
_selectionType: function() {
if (this._graphicSelection !== null &&
!this._isEmptyRectangle(this._graphicSelection)) {
return 'complex'; // FIXME: Ash - complex ...
} else if (this._selections.getLayers().length > 0) {
return 'simpletext';
} else {
return null;
}
},
_onCopy: function (e) {
e = e.originalEvent;
this._map._clip.copy(e);

View file

@ -13,6 +13,7 @@ L.Clipboard = L.Class.extend({
initialize: function(map) {
this._map = map;
this._selectionContent = '';
this._selectionType = null;
this._accessKey = [ '', '' ];
this._clipboardSerial = 0; // incremented on each operation
@ -273,12 +274,11 @@ L.Clipboard = L.Class.extend({
},
populateClipboard: function(ev) {
var t = this._map._docLayer._selectionType();
var text;
if (t === null) {
if (this._selectionType === null) {
console.log('Copy/Cut with no selection!');
text = this.getStubHtml();
} else if (t === 'complex') {
} else if (this._selectionType === 'complex') {
console.log('Copy/Cut with complex/graphical selection');
text = this.getStubHtml();
this._onDownloadOnLargeCopyPaste();
@ -468,26 +468,19 @@ L.Clipboard = L.Class.extend({
clearSelection: function() {
this._selectionContent = '';
},
setSelection: function(content) {
this._selectionContent = content;
this._selectionType = null;
},
// textselectioncontent: message
setTextSelectionContent: function(text) {
this.setSelection(text);
this._selectionType = 'text';
this._selectionContent = text;
},
// complexselection: message
onComplexSelection: function (text) {
// Put in the clipboard a helpful explanation of what the user should do.
// Currently we don't have a payload, though we might in the future
text = _('Please use the following link to download the selection from you document and paste into other applications on your device')
+ ': '; //FIXME: MISSING URL
this.setSelection(text);
//TODO: handle complex selection download.
onComplexSelection: function (/*text*/) {
// Mark this selection as complex.
this._selectionType = 'complex';
},
_startProgress: function() {
@ -501,7 +494,7 @@ L.Clipboard = L.Class.extend({
},
_onDownloadOnLargeCopyPaste: function () {
if (!this._downloadProgress) {
if (!this._downloadProgress || this._downloadProgress.isClosed()) {
this._warnFirstLargeCopyPaste();
this._startProgress();
}