diff --git a/browser/css/toolbar.css b/browser/css/toolbar.css
index 5e7910f5e251..07b3e9ddb702 100644
--- a/browser/css/toolbar.css
+++ b/browser/css/toolbar.css
@@ -1099,6 +1099,8 @@ button.leaflet-control-search-next
.w2ui-icon.freezepanescolumn{ background: url('images/lc_freezepanescolumn.svg') no-repeat center; }
.w2ui-icon.freezepanesrow{ background: url('images/lc_freezepanesrow.svg') no-repeat center; }
.w2ui-icon.navigator{ background: url('images/lc_navigator.svg') no-repeat center; }
+.w2ui-icon.gridvisible{ background: url('images/lc_gridvisible.svg') no-repeat center; }
+.w2ui-icon.griduse{ background: url('images/lc_griduse.svg') no-repeat center; }
.w2ui-icon.flipvertical { background: url('images/lc_flipvertical.svg') no-repeat center; }
.w2ui-icon.fliphorizontal { background: url('images/lc_fliphorizontal.svg') no-repeat center; }
diff --git a/browser/images/dark/lc_griduse.svg b/browser/images/dark/lc_griduse.svg
new file mode 100644
index 000000000000..96af9867ba3f
--- /dev/null
+++ b/browser/images/dark/lc_griduse.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/browser/images/dark/lc_gridvisible.svg b/browser/images/dark/lc_gridvisible.svg
new file mode 100644
index 000000000000..75c947e1cf12
--- /dev/null
+++ b/browser/images/dark/lc_gridvisible.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/browser/images/lc_griduse.svg b/browser/images/lc_griduse.svg
new file mode 100644
index 000000000000..2b4176477e4e
--- /dev/null
+++ b/browser/images/lc_griduse.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/browser/images/lc_gridvisible.svg b/browser/images/lc_gridvisible.svg
new file mode 100644
index 000000000000..59367555626c
--- /dev/null
+++ b/browser/images/lc_gridvisible.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/browser/src/app/GraphicSelectionMiddleware.ts b/browser/src/app/GraphicSelectionMiddleware.ts
index 4cb10b90c7e8..805b071dd081 100644
--- a/browser/src/app/GraphicSelectionMiddleware.ts
+++ b/browser/src/app/GraphicSelectionMiddleware.ts
@@ -101,13 +101,11 @@ class GraphicSelection {
// When a shape is selected, the rectangles of other shapes are also sent from the core side.
// They are in twips units.
static convertObjectRectangleTwipsToPixels() {
- const correction = 0.567; // Correction for impress case.
-
if (this.extraInfo && this.extraInfo.ObjectRectangles) {
for (let i = 0; i < this.extraInfo.ObjectRectangles.length; i++) {
for (let j = 0; j < 4; j++)
this.extraInfo.ObjectRectangles[i][j] *=
- app.twipsToPixels * correction;
+ app.twipsToPixels * app.impress.twipsCorrection;
}
}
}
diff --git a/browser/src/canvas/sections/CellCursorSection.ts b/browser/src/canvas/sections/CellCursorSection.ts
index 12d9c8d3b3c1..b04c410adc97 100644
--- a/browser/src/canvas/sections/CellCursorSection.ts
+++ b/browser/src/canvas/sections/CellCursorSection.ts
@@ -84,7 +84,7 @@ class CellCursorSection extends CanvasSectionObject {
}
let x: number = 0;
- if (app.isCalcRTL()) {
+ if (app.calc.isRTL()) {
const rightMost = this.containerObject.getDocumentAnchor()[0] + this.containerObject.getDocumentAnchorSection().size[0];
x = rightMost - penX * 2 - app.calc.cellCursorRectangle.pWidth;
}
diff --git a/browser/src/canvas/sections/CommentListSection.ts b/browser/src/canvas/sections/CommentListSection.ts
index 1965a2e5265e..3681173d4b6f 100644
--- a/browser/src/canvas/sections/CommentListSection.ts
+++ b/browser/src/canvas/sections/CommentListSection.ts
@@ -1601,7 +1601,7 @@ export class CommentSection extends app.definitions.canvasSectionObject {
private adjustCommentFileBasedView (comment: any): void {
// Below calculations are the same with the ones we do while drawing tiles in fileBasedView.
var partHeightTwips = this.sectionProperties.docLayer._partHeightTwips + this.sectionProperties.docLayer._spaceBetweenParts;
- var index = app.impress.partHashes.indexOf(String(comment.parthash));
+ var index = app.impress.getIndexFromSlideHash(comment.parthash);
var yAddition = index * partHeightTwips;
comment.yAddition = yAddition; // We'll use this while we save the new position of the comment.
@@ -1747,7 +1747,7 @@ export class CommentSection extends app.definitions.canvasSectionObject {
if (selectedComment) {
const posX = (this.sectionProperties.showSelectedBigger ?
- Math.round((document.getElementById('document-container').getBoundingClientRect().width - subList[i].sectionProperties.container.getBoundingClientRect().width)/2) :
+ Math.round((document.getElementById('document-container').getBoundingClientRect().width - subList[i].sectionProperties.container.getBoundingClientRect().width)/2) :
Math.round(actualPosition[0] / app.dpiScale) - this.sectionProperties.deflectionOfSelectedComment * (isRTL ? -1 : 1));
(new L.PosAnimation()).run(subList[i].sectionProperties.container, {x: posX, y: Math.round(lastY / app.dpiScale)}, this.getAnimationDuration());
}
diff --git a/browser/src/canvas/sections/CommentSection.ts b/browser/src/canvas/sections/CommentSection.ts
index 0f00f8dd38bc..b7baacbd920a 100644
--- a/browser/src/canvas/sections/CommentSection.ts
+++ b/browser/src/canvas/sections/CommentSection.ts
@@ -117,7 +117,7 @@ export class Comment extends CanvasSectionObject {
if (this.sectionProperties.docLayer._docType === 'presentation' || this.sectionProperties.docLayer._docType === 'drawing') {
this.sectionProperties.parthash = this.sectionProperties.data.parthash;
- this.sectionProperties.partIndex = app.impress.partHashes.indexOf(String(this.sectionProperties.parthash));
+ this.sectionProperties.partIndex = app.impress.getIndexFromSlideHash(this.sectionProperties.parthash);
}
this.sectionProperties.isHighlighted = false;
@@ -693,7 +693,7 @@ export class Comment extends CanvasSectionObject {
}),
draggable: true
});
- if (app.impress.partHashes[this.sectionProperties.docLayer._selectedPart] === this.sectionProperties.data.parthash || app.file.fileBasedView)
+ if (app.impress.partList[this.sectionProperties.docLayer._selectedPart].hash === parseInt(this.sectionProperties.data.parthash) || app.file.fileBasedView)
this.map.addLayer(this.sectionProperties.annotationMarker);
}
if (this.sectionProperties.data.rectangle != null) {
diff --git a/browser/src/canvas/sections/ShapeHandleScalingSubSection.ts b/browser/src/canvas/sections/ShapeHandleScalingSubSection.ts
index 53e0f302bd2a..df6440aa3e7b 100644
--- a/browser/src/canvas/sections/ShapeHandleScalingSubSection.ts
+++ b/browser/src/canvas/sections/ShapeHandleScalingSubSection.ts
@@ -214,7 +214,10 @@ class ShapeHandleScalingSubSection extends CanvasSectionObject {
e.stopPropagation();
this.sectionProperties.parentHandlerSection.sectionProperties.svg.style.opacity = 0.5;
this.moveHandlesOnDrag(point);
- this.sectionProperties.parentHandlerSection.checkObjectsBoundaries([this.position[0]], [this.position[1]]);
+
+ // Here we are checking a point, so the size 0. dragDistance is also 0 because we already set the new position (moveHandlesOnDrag).
+ this.sectionProperties.parentHandlerSection.checkHelperLinesAndSnapPoints([0, 0], this.position, [0, 0]);
+
this.containerObject.requestReDraw();
this.sectionProperties.parentHandlerSection.showSVG();
}
diff --git a/browser/src/canvas/sections/ShapeHandlesSection.ts b/browser/src/canvas/sections/ShapeHandlesSection.ts
index 63a16b8d01c5..a364119cfa1c 100644
--- a/browser/src/canvas/sections/ShapeHandlesSection.ts
+++ b/browser/src/canvas/sections/ShapeHandlesSection.ts
@@ -751,14 +751,108 @@ class ShapeHandlesSection extends CanvasSectionObject {
else this.sectionProperties.closestY = null;
}
+ private cloneSelectedPartInfoForGridSnap() {
+ const selectedPart = Object.assign({}, app.impress.partList[app.map._docLayer._selectedPart]);
+ selectedPart.leftBorder *= app.impress.twipsCorrection;
+ selectedPart.upperBorder *= app.impress.twipsCorrection;
+ selectedPart.rightBorder *= app.impress.twipsCorrection;
+ selectedPart.lowerBorder *= app.impress.twipsCorrection;
+ selectedPart.gridCoarseWidth *= app.impress.twipsCorrection;
+ selectedPart.gridCoarseHeight *= app.impress.twipsCorrection;
+
+ return selectedPart;
+ }
+
+ private getInnerRecrangleForGridSnap(selectedPart: any) {
+ return new cool.SimpleRectangle(
+ selectedPart.leftBorder,
+ selectedPart.upperBorder,
+ (selectedPart.width - selectedPart.leftBorder - selectedPart.rightBorder),
+ (selectedPart.height - selectedPart.upperBorder - selectedPart.lowerBorder)
+ );
+ }
+
+ private getCornerPointsForGridSnap(size: number[], position: number[], dragDistance: number[]) {
+ return [
+ new cool.SimplePoint((position[0] + dragDistance[0]) * app.pixelsToTwips, (position[1] + dragDistance[1]) * app.pixelsToTwips),
+ new cool.SimplePoint((size[0] + position[0] + dragDistance[0]) * app.pixelsToTwips, (position[1] + dragDistance[1]) * app.pixelsToTwips),
+ new cool.SimplePoint((position[0] + dragDistance[0]) * app.pixelsToTwips, (size[1] + position[1] + dragDistance[1]) * app.pixelsToTwips),
+ new cool.SimplePoint((size[0] + position[0] + dragDistance[0]) * app.pixelsToTwips, (size[1] + position[1] + dragDistance[1]) * app.pixelsToTwips),
+ ];
+ }
+
+ private findClosestGridPoint(size: number[], position: number[], dragDistance: number[]) {
+ // First rule of snap-to-grid: If you enable snap-to-grid, you have to snap.
+
+ const selectedPart = this.cloneSelectedPartInfoForGridSnap();
+
+ // The 4 corners of selected object's rectangle.
+ const checkList = this.getCornerPointsForGridSnap(size, position, dragDistance);
+
+ // The rectangle that is shaped by the page margins.
+ const innerRectangle = this.getInnerRecrangleForGridSnap(selectedPart);
+
+ const gapX = selectedPart.gridCoarseWidth / (selectedPart.innerSpacesX > 0 ? selectedPart.innerSpacesX : 1);
+ const gapY = selectedPart.gridCoarseHeight / (selectedPart.innerSpacesY > 0 ? selectedPart.innerSpacesY : 1);
+
+ let minX = 100000;
+ let minY = 100000;
+ for (let i = 0; i < 1; i++) {
+ if (innerRectangle.containsPoint(checkList[i].toArray())) {
+
+ const countX = Math.round((checkList[i].x - innerRectangle.x1) / gapX);
+ const countY = Math.round((checkList[i].y - innerRectangle.y1) / gapY);
+
+ const diffX = Math.abs(checkList[i].x - innerRectangle.x1 - gapX * countX);
+ const diffY = Math.abs(checkList[i].y - innerRectangle.y1 - gapY * countY);
+
+ if (diffX < minX) {
+ minX = diffX;
+ this.sectionProperties.closestX = innerRectangle.x1 + (countX * gapX);
+ this.sectionProperties.pickedIndexX = [1, 3].includes(i) ? 0 : 1; // Do we substract width or not.
+ }
+ if (diffY < minY) {
+ minY = diffY;
+ this.sectionProperties.closestY = innerRectangle.y1 + (countY * gapY);
+ this.sectionProperties.pickedIndexY = [2, 3].includes(i) ? 0 : 1; // Do we substract height or not.
+ }
+ }
+ }
+
+ this.sectionProperties.closestX *= app.twipsToPixels;
+ this.sectionProperties.closestY *= app.twipsToPixels;
+ }
+
public checkObjectsBoundaries(xListToCheck: number[], yListToCheck: number[]) {
if (app.map._docLayer._docType === 'presentation') {
this.findClosestX(xListToCheck);
this.findClosestY(yListToCheck);
- this.containerObject.requestReDraw();
}
}
+ public checkHelperLinesAndSnapPoints(size: number[], position: number[], dragDistance: number[]) {
+ /*
+ We will first check if grid-snap is enabled and if we are close to a grid point.
+ If there is a grid point to snap to, then we'll ignore helper lines.
+ Because core side doesn't know about our helper lines, and it'll ignore them if it can snap to a grid point.
+ */
+
+ this.sectionProperties.closestX = null;
+ this.sectionProperties.closestY = null;
+
+ if (app.map.stateChangeHandler.getItemValue('.uno:GridUse') === 'true') {
+ this.findClosestGridPoint(size, position, dragDistance)
+ }
+ else {
+ this.checkObjectsBoundaries(
+ [position[0] + dragDistance[0], position[0] + dragDistance[0] + size[0]],
+ [position[1] + dragDistance[1], position[1] + dragDistance[1] + size[1]]
+ );
+ }
+
+ this.containerObject.requestReDraw();
+ }
+
onMouseMove(position: number[], dragDistance: number[]) {
if (this.containerObject.isDraggingSomething() && this.sectionProperties.svg) {
(window as any).IgnorePanning = true;
@@ -767,10 +861,7 @@ class ShapeHandlesSection extends CanvasSectionObject {
this.sectionProperties.svg.style.top = String((this.myTopLeft[1] + dragDistance[1]) / app.dpiScale) + 'px';
this.sectionProperties.svg.style.opacity = 0.5;
this.sectionProperties.lastDragDistance = [dragDistance[0], dragDistance[1]];
- this.checkObjectsBoundaries(
- [this.position[0] + dragDistance[0], this.position[0] + dragDistance[0] + this.size[0]],
- [this.position[1] + dragDistance[1], this.position[1] + dragDistance[1] + this.size[1]]
- );
+ this.checkHelperLinesAndSnapPoints(this.size, this.position, dragDistance);
this.showSVG();
}
@@ -874,10 +965,15 @@ class ShapeHandlesSection extends CanvasSectionObject {
this.context.restore();
}
+ private anythingToDraw(): boolean {
+ return this.sectionProperties.closestX !== null ||
+ this.sectionProperties.closestY !== null;
+ }
+
public onDraw() {
if (!this.showSection || !this.isVisible)
this.hideSVG();
- else if (this.sectionProperties.closestX !== null || this.sectionProperties.closestY !== null) {
+ else if (this.anythingToDraw()) {
this.drawGuides();
}
}
diff --git a/browser/src/control/Control.Menubar.js b/browser/src/control/Control.Menubar.js
index b3157bbaee43..12594dad597a 100644
--- a/browser/src/control/Control.Menubar.js
+++ b/browser/src/control/Control.Menubar.js
@@ -441,6 +441,9 @@ L.Control.Menubar = L.Control.extend({
{name: _UNO('.uno:ZoomMinus', 'presentation'), id: 'zoomout', type: 'action'},
{name: _('Reset zoom'), id: 'zoomreset', type: 'action'},
]).concat([
+ {type: 'separator'},
+ {uno: '.uno:GridVisible', name: _UNO('.uno:GridVisible')},
+ {uno: '.uno:GridUse', name: _UNO('.uno:GridUse')},
{type: 'separator'},
{name: _('Toggle UI Mode'), id: 'toggleuimode', type: 'action'},
{name: _('Show Ruler'), id: 'showruler', type: 'action'},
@@ -594,6 +597,9 @@ L.Control.Menubar = L.Control.extend({
{name: _UNO('.uno:ZoomMinus', 'presentation'), id: 'zoomout', type: 'action'},
{name: _('Reset zoom'), id: 'zoomreset', type: 'action'},
]).concat([
+ {type: 'separator'},
+ {uno: '.uno:GridVisible', name: _UNO('.uno:GridVisible')},
+ {uno: '.uno:GridUse', name: _UNO('.uno:GridUse')},
{type: 'separator'},
{name: _('Toggle UI Mode'), id: 'toggleuimode', type: 'action'},
{name: _('Dark Mode'), id: 'toggledarktheme', type: 'action'},
@@ -1789,12 +1795,12 @@ L.Control.Menubar = L.Control.extend({
$(aItem).text(_('Use Tabbed view'));
}
} else if (id === 'showslide') {
- if (!self._map._docLayer.isHiddenSlide(self._map.getCurrentPartNumber()))
+ if (!app.impress.isSlideHidden(self._map.getCurrentPartNumber()))
$(aItem).hide();
else
$(aItem).show();
} else if (id === 'hideslide') {
- if (self._map._docLayer.isHiddenSlide(self._map.getCurrentPartNumber()))
+ if (app.impress.isSlideHidden(self._map.getCurrentPartNumber()))
$(aItem).hide();
else
$(aItem).show();
diff --git a/browser/src/control/Control.Notebookbar.js b/browser/src/control/Control.Notebookbar.js
index df99f7d82858..43f87856cc04 100644
--- a/browser/src/control/Control.Notebookbar.js
+++ b/browser/src/control/Control.Notebookbar.js
@@ -447,12 +447,12 @@ L.Control.Notebookbar = L.Control.extend({
},
onSlideHideToggle: function() {
- if (!this.map._docLayer.isHiddenSlide(this.map.getCurrentPartNumber()))
+ if (!app.impress.isSlideHidden(this.map.getCurrentPartNumber()))
$('#showslide').hide();
else
$('#showslide').show();
- if (this.map._docLayer.isHiddenSlide(this.map.getCurrentPartNumber()))
+ if (app.impress.isSlideHidden(this.map.getCurrentPartNumber()))
$('#hideslide').hide();
else
$('#hideslide').show();
diff --git a/browser/src/control/Control.NotebookbarBuilder.js b/browser/src/control/Control.NotebookbarBuilder.js
index 6bd167d6f38a..03c86a83df04 100644
--- a/browser/src/control/Control.NotebookbarBuilder.js
+++ b/browser/src/control/Control.NotebookbarBuilder.js
@@ -121,7 +121,6 @@ L.Control.NotebookbarBuilder = L.Control.JSDialogBuilder.extend({
/*Draw Home Tab*/
this._toolitemHandlers['.uno:ObjectAlign'] = function() {};
- this._toolitemHandlers['.uno:GridVisible'] = function() {};
/*Graphic Tab*/
this._toolitemHandlers['.uno:Crop'] = function() {};
diff --git a/browser/src/control/Control.NotebookbarDraw.js b/browser/src/control/Control.NotebookbarDraw.js
index 86e1be7e3e6d..5139aee33843 100644
--- a/browser/src/control/Control.NotebookbarDraw.js
+++ b/browser/src/control/Control.NotebookbarDraw.js
@@ -406,6 +406,26 @@ L.Control.NotebookbarDraw = L.Control.NotebookbarImpress.extend({
'text': _('Collapse Tabs'),
'accessibility': { focusBack: true, combination: 'CU', de: null }
},
+ {
+ 'type': 'toolbox',
+ 'children': [
+ {
+ 'id': 'home-grid-visible',
+ 'type': 'toolitem',
+ 'text': _UNO('.uno:GridVisible'),
+ 'command': '.uno:GridVisible',
+ 'accessibility': { focusBack: true, combination: 'GV', de: null }
+ },
+ {
+ 'id': 'home-grid-use',
+ 'type': 'toolitem',
+ 'text': _UNO('.uno:GridUse'),
+ 'command': '.uno:GridUse',
+ 'accessibility': { focusBack: true, combination: 'GU', de: null }
+ }
+ ],
+ 'vertical': 'true'
+ },
{
'id':'toggledarktheme',
'type': 'bigcustomtoolitem',
diff --git a/browser/src/control/Control.NotebookbarImpress.js b/browser/src/control/Control.NotebookbarImpress.js
index b2f6a7ca9746..30e14e29bde0 100644
--- a/browser/src/control/Control.NotebookbarImpress.js
+++ b/browser/src/control/Control.NotebookbarImpress.js
@@ -468,6 +468,26 @@ L.Control.NotebookbarImpress = L.Control.NotebookbarWriter.extend({
'command': '.uno:SlideMasterPage',
'accessibility': { focusBack: true, combination: 'MP', de: null }
},
+ {
+ 'type': 'toolbox',
+ 'children': [
+ {
+ 'id': 'home-grid-visible',
+ 'type': 'toolitem',
+ 'text': _('Show Grid'),
+ 'command': '.uno:GridVisible',
+ 'accessibility': { focusBack: true, combination: 'GV', de: null }
+ },
+ {
+ 'id': 'home-grid-use',
+ 'type': 'toolitem',
+ 'text': _('Snap to Grid'),
+ 'command': '.uno:GridUse',
+ 'accessibility': { focusBack: true, combination: 'GU', de: null }
+ }
+ ],
+ 'vertical': 'true'
+ },
{
'id':'toggledarktheme',
'class': 'unotoggledarktheme',
diff --git a/browser/src/control/Control.PartsPreview.js b/browser/src/control/Control.PartsPreview.js
index 2db1e3552b2f..66f5bf266ac6 100644
--- a/browser/src/control/Control.PartsPreview.js
+++ b/browser/src/control/Control.PartsPreview.js
@@ -69,14 +69,10 @@ L.Control.PartsPreview = L.Control.extend({
this._partsPreviewCont.style.whiteSpace = 'nowrap';
},
- _updateDisabled: function (e) {
- var parts = e.parts;
- var selectedPart = e.selectedPart;
- var selectedParts = e.selectedParts;
- var docType = e.docType;
- if (docType === 'text' || isNaN(parts)) {
- return;
- }
+ _updateDisabled: function () {
+ const selectedPart = app.map._docLayer._selectedPart;
+
+ const docType = app.map._docLayer._docType;
if (docType === 'presentation' || docType === 'drawing') {
if (!this._previewInitialized)
@@ -103,8 +99,8 @@ L.Control.PartsPreview = L.Control.extend({
}
// Create the preview parts
- for (var i = 0; i < parts; i++) {
- this._previewTiles.push(this._createPreview(i, e.partNames[i]));
+ for (var i = 0; i < app.impress.partList.length; i++) {
+ this._previewTiles.push(this._createPreview(i, app.impress.partList[i].hash));
}
if (!app.file.fileBasedView)
L.DomUtil.addClass(this._previewTiles[selectedPart], 'preview-img-currentpart');
@@ -113,18 +109,16 @@ L.Control.PartsPreview = L.Control.extend({
}
else
{
- if (e.partNames !== undefined) {
- this._syncPreviews(e);
- }
+ this._syncPreviews();
if (!app.file.fileBasedView) {
// change the border style of the selected preview.
- for (var j = 0; j < parts; j++) {
+ for (let j = 0; j < app.impress.partList.length; j++) {
L.DomUtil.removeClass(this._previewTiles[j], 'preview-img-currentpart');
L.DomUtil.removeClass(this._previewTiles[j], 'preview-img-selectedpart');
if (j === selectedPart)
L.DomUtil.addClass(this._previewTiles[j], 'preview-img-currentpart');
- else if (selectedParts.indexOf(j) >= 0)
+ else if (app.impress.partList[j].selected)
L.DomUtil.addClass(this._previewTiles[j], 'preview-img-selectedpart');
}
}
@@ -146,10 +140,10 @@ L.Control.PartsPreview = L.Control.extend({
addPreviewFrame = 'preview-frame-portrait';
}
- for (i = 0; i < parts; i++) {
+ for (i = 0; i < app.impress.partList.length; i++) {
L.DomUtil.removeClass(this._previewTiles[i], removePreviewImg);
L.DomUtil.addClass(this._previewTiles[i], addPreviewImg);
- if (this._map._docLayer._hiddenSlides.has(i))
+ if (app.impress.isSlideHidden(i))
L.DomUtil.addClass(this._previewTiles[i], 'hidden-slide');
else
L.DomUtil.removeClass(this._previewTiles[i], 'hidden-slide');
@@ -343,7 +337,7 @@ L.Control.PartsPreview = L.Control.extend({
},
visible: function(key, options) {
var part = that._findClickedPart(options.$trigger[0].parentNode);
- return that._map._docLayer._docType == 'presentation' && that._map._docLayer.isHiddenSlide(parseInt(part) - 1);
+ return that._map._docLayer._docType === 'presentation' && app.impress.isSlideHidden(parseInt(part) - 1);
}
},
hideslide: {
@@ -356,7 +350,7 @@ L.Control.PartsPreview = L.Control.extend({
},
visible: function(key, options) {
var part = that._findClickedPart(options.$trigger[0].parentNode);
- return that._map._docLayer._docType == 'presentation' && !that._map._docLayer.isHiddenSlide(parseInt(part) - 1);
+ return that._map._docLayer._docType === 'presentation' && !app.impress.isSlideHidden(parseInt(part) - 1);
}
}
}
@@ -486,7 +480,7 @@ L.Control.PartsPreview = L.Control.extend({
if (this.firstSelection === undefined)
this.firstSelection = this._map._docLayer._selectedPart;
- //deselect all slide
+ //deselect all slides
this._map.deselectAll();
//reselect the first origianl selection
@@ -503,6 +497,7 @@ L.Control.PartsPreview = L.Control.extend({
}
}
} else {
+ this._map.deselectAll();
this._map.setPart(partId);
this._map.selectPart(partId, 1, false); // And select.
this.firstSelection = partId;
@@ -516,27 +511,27 @@ L.Control.PartsPreview = L.Control.extend({
}
},
- _syncPreviews: function (e) {
+ _syncPreviews: function () {
var it = 0;
- var parts = e.parts;
- if (parts !== this._previewTiles.length) {
- if (Math.abs(parts - this._previewTiles.length) === 1) {
- if (parts > this._previewTiles.length) {
- for (it = 0; it < parts; it++) {
+
+ if (app.impress.partList.length !== this._previewTiles.length) {
+ if (Math.abs(app.impress.partList.length - this._previewTiles.length) === 1) {
+ if (app.impress.partList.length > this._previewTiles.length) {
+ for (it = 0; it < app.impress.partList.length; it++) {
if (it === this._previewTiles.length) {
- this._insertPreview({selectedPart: it - 1, hashCode: e.partNames[it]});
+ this._insertPreview({selectedPart: it - 1, hashCode: app.impress.partList[it].hash});
break;
}
- if (this._previewTiles[it].hash !== e.partNames[it]) {
- this._insertPreview({selectedPart: it, hashCode: e.partNames[it]});
+ if (this._previewTiles[it].hash !== app.impress.partList[it].hash) {
+ this._insertPreview({selectedPart: it, hashCode: app.impress.partList[it].hash});
break;
}
}
}
else {
for (it = 0; it < this._previewTiles.length; it++) {
- if (it === e.partNames.length ||
- this._previewTiles[it].hash !== e.partNames[it]) {
+ if (it === app.impress.partList.length ||
+ this._previewTiles[it].hash !== app.impress.partList[it].hash) {
this._deletePreview({selectedPart: it});
break;
}
@@ -545,17 +540,17 @@ L.Control.PartsPreview = L.Control.extend({
}
else {
// sync all, should never happen
- while (this._previewTiles.length < e.partNames.length) {
+ while (this._previewTiles.length < app.impress.partList.length) {
this._insertPreview({selectedPart: this._previewTiles.length - 1,
- hashCode: e.partNames[this._previewTiles.length]});
+ hashCode: app.impress.partList[this._previewTiles.length].hash});
}
- while (this._previewTiles.length > e.partNames.length) {
+ while (this._previewTiles.length > app.impress.partList.length) {
this._deletePreview({selectedPart: this._previewTiles.length - 1});
}
- for (it = 0; it < e.partNames.length; it++) {
- this._previewTiles[it].hash = e.partNames[it];
+ for (it = 0; it < app.impress.partList.length; it++) {
+ this._previewTiles[it].hash = app.impress.partList[it].hash;
this._previewTiles[it].src = document.querySelector('meta[name="previewSmile"]').content;
this._previewTiles[it].fetched = false;
}
@@ -563,9 +558,9 @@ L.Control.PartsPreview = L.Control.extend({
}
else {
// update hash code when user click insert slide.
- for (it = 0; it < parts; it++) {
- if (this._previewTiles[it].hash !== e.partNames[it]) {
- this._previewTiles[it].hash = e.partNames[it];
+ for (it = 0; it < app.impress.partList.length; it++) {
+ if (this._previewTiles[it].hash !== app.impress.partList[it].hash) {
+ this._previewTiles[it].hash = app.impress.partList[it].hash;
this._map.getPreview(it, it, this.options.maxWidth, this.options.maxHeight, {autoUpdate: this.options.autoUpdate});
}
}
@@ -764,10 +759,11 @@ L.Control.PartsPreview = L.Control.extend({
_handleDragStart: function (e) {
// To avoid having to add a new message to move an arbitrary part, let's select the
// slide that is being dragged.
- var part = this.partsPreview._findClickedPart(e.target.parentNode);
+ const targetNode = (e.target.id.startsWith('preview') ? e.target : e.target.parentNode);
+ var part = this.partsPreview._findClickedPart(targetNode);
if (part !== null) {
var partId = parseInt(part) - 1; // The first part is just a drop-site for reordering.
- if (this.partsPreview._map._docLayer && !this.partsPreview._map._docLayer._selectedParts.indexOf(partId) >= 0)
+ if (this.partsPreview._map._docLayer && !app.impress.isSlideSelected(partId))
{
this.partsPreview._map.setPart(partId);
this.partsPreview._map.selectPart(partId, 1, false); // And select.
diff --git a/browser/src/control/Control.PresentationBar.js b/browser/src/control/Control.PresentationBar.js
index 132145f68197..bbb7ab0fb396 100644
--- a/browser/src/control/Control.PresentationBar.js
+++ b/browser/src/control/Control.PresentationBar.js
@@ -200,15 +200,14 @@ class PresentationBar {
if (this.map.getDocType() !== 'presentation')
return;
- if (!this.map._docLayer.isHiddenSlide(this.map.getCurrentPartNumber()))
+ if (!app.impress.isSlideHidden(this.map.getCurrentPartNumber())) {
this.showItem('showslide', false);
- else
- this.showItem('showslide', true);
-
- if (this.map._docLayer.isHiddenSlide(this.map.getCurrentPartNumber()))
this.showItem('hideslide', false);
- else
+ }
+ else {
+ this.showItem('showslide', true);
this.showItem('hideslide', true);
+ }
}
}
diff --git a/browser/src/control/Control.Tabs.js b/browser/src/control/Control.Tabs.js
index 33e5eecde9b7..f7a0e6099cd6 100644
--- a/browser/src/control/Control.Tabs.js
+++ b/browser/src/control/Control.Tabs.js
@@ -40,7 +40,7 @@ L.Control.Tabs = L.Control.extend({
var map = this._map;
var tableCell = document.getElementById('spreadsheet-toolbar');
this._tabsCont = L.DomUtil.create('div', 'spreadsheet-tabs-container', tableCell);
- var that = this;
+
function areTabsMultiple() {
var numItems = $('.spreadsheet-tab').length;
if (numItems === 1) {
@@ -77,7 +77,7 @@ L.Control.Tabs = L.Control.extend({
name: _UNO('.uno:Show', 'spreadsheet', true),
callback: (this._showSheet).bind(this),
visible: function() {
- return that._map.hasAnyHiddenPart();
+ return app.calc.isAnyPartHidden();
}
},
'.uno:Hide': {
@@ -163,12 +163,12 @@ L.Control.Tabs = L.Control.extend({
'Name' : this._menuItem['.uno:Name'],
}
);
- if (this._map.hasAnyHiddenPart()) {
+ if (app.calc.isAnyPartHidden()) {
Object.assign(menuItemMobile, {
'Show' : this._menuItem['.uno:Show'],
});
}
- if (this._map.getNumberOfVisibleParts() !== 1) {
+ if (app.calc.getVisiblePartCount() !== 1) {
Object.assign(menuItemMobile,
{
'Remove': this._menuItem['.uno:Remove'],
@@ -191,7 +191,7 @@ L.Control.Tabs = L.Control.extend({
}
for (var i = 0; i < parts; i++) {
- if (e.hiddenParts.indexOf(i) !== -1)
+ if (app.calc.isPartHidden(i))
continue;
// create a drop zone indicator for the sheet tab
@@ -238,7 +238,7 @@ L.Control.Tabs = L.Control.extend({
}(i).bind(this));
}
- if (e.protectedParts[i]) {
+ if (app.calc.isPartProtected(i)) {
L.DomUtil.addClass(tab, 'spreadsheet-tab-protected');
}
else {
diff --git a/browser/src/control/Control.TopToolbar.js b/browser/src/control/Control.TopToolbar.js
index 58f7a31414a0..e8068d0c82f4 100644
--- a/browser/src/control/Control.TopToolbar.js
+++ b/browser/src/control/Control.TopToolbar.js
@@ -177,6 +177,8 @@ class TopToolbar extends JSDialog.Toolbar {
{type: 'toolitem', id: 'numberformatdecdecimals', text: _UNO('.uno:NumberFormatDecDecimals', 'spreadsheet', true), visible: false, command: '.uno:NumberFormatDecDecimals'},
{type: 'toolitem', id: 'numberformatincdecimals', text: _UNO('.uno:NumberFormatIncDecimals', 'spreadsheet', true), visible: false, command: '.uno:NumberFormatIncDecimals'},
{type: 'separator', orientation: 'vertical', id: 'break-number', visible: false},
+ {type: 'button', id: 'gridvisible', img: 'gridvisible', hint: _UNO('.uno:GridVisible'), uno: 'GridVisible', hidden: true},
+ {type: 'button', id: 'griduse', img: 'griduse', hint: _UNO('.uno:GridUse'), uno: 'GridUse', hidden: true},
{type: 'menubutton', id: 'inserttable:InsertTableMenu', command: 'inserttable', noLabel: true, text: _('Insert table'), visible: false, lockUno: '.uno:InsertTable'},
{type: 'menubutton', id: 'menugraphic:InsertImageMenu', noLabel: true, command: '.uno:InsertGraphic', text: _UNO('.uno:InsertGraphic', '', true), visible: false, lockUno: '.uno:InsertGraphic'},
{type: 'toolitem', id: 'insertobjectchart', text: _UNO('.uno:InsertObjectChart', '', true), command: '.uno:InsertObjectChart'},
@@ -317,6 +319,7 @@ class TopToolbar extends JSDialog.Toolbar {
if (this.parentContainer) {
['resetimpress', 'breaksidebar', 'modifypage',
'leftpara', 'centerpara', 'rightpara', 'justifypara', 'breakpara', 'linespacing',
+ 'gridvisible', 'griduse',
'breakspacing', 'defaultbullet', 'defaultnumbering', 'breakbullet', 'inserttextbox', 'inserttable', 'insertannotation', 'backcolor',
'breaksidebar', 'modifypage', 'slidechangewindow', 'customanimation', 'masterslidespanel', 'navigator'
].forEach((id) => {
@@ -328,7 +331,7 @@ class TopToolbar extends JSDialog.Toolbar {
break;
case 'drawing':
if (this.parentContainer) {
- ['leftpara', 'centerpara', 'rightpara', 'justifypara', 'breakpara', 'linespacing',
+ ['leftpara', 'centerpara', 'rightpara', 'justifypara', 'breakpara', 'linespacing', 'gridvisible', 'griduse',
'breakspacing', 'defaultbullet', 'defaultnumbering', 'breakbullet', 'inserttextbox', 'inserttable', 'backcolor',
'breaksidebar', 'sidebar', 'insertconnectors'
].forEach((id) => {
diff --git a/browser/src/control/Parts.js b/browser/src/control/Parts.js
index 46e8ddf84fca..0435c1b2284b 100644
--- a/browser/src/control/Parts.js
+++ b/browser/src/control/Parts.js
@@ -28,15 +28,15 @@ L.Map.include({
var docLayer = this._docLayer;
var docType = docLayer._docType;
- var isTheSamePart = true;
+ var isTheSamePart = false;
// check hashes, when we add/delete/move parts they can have the same part number as before
if (docType === 'spreadsheet') {
isTheSamePart =
app.calc.partHashes[docLayer._prevSelectedPart] === app.calc.partHashes[part];
- } else if (docType === 'presentation' || docType === 'drawing') {
- isTheSamePart =
- app.impress.partHashes[docLayer._prevSelectedPart] === app.impress.partHashes[part];
+ } else if ((docType === 'presentation' || docType === 'drawing')) {
+ if (docLayer._prevSelectedPart !== undefined && part < app.impress.partList.length)
+ isTheSamePart = app.impress.partList[docLayer._prevSelectedPart].hash === app.impress.partList[part].hash;
} else if (docType !== 'text') {
console.error('Unknown docType: ' + docType);
}
@@ -50,7 +50,7 @@ L.Map.include({
docLayer._clearMsgReplayStore(true /* notOtherMsg*/);
docLayer._prevSelectedPart = docLayer._selectedPart;
- docLayer._selectedParts = [];
+
if (part === 'prev') {
if (docLayer._selectedPart > 0) {
docLayer._selectedPart -= 1;
@@ -95,7 +95,6 @@ L.Map.include({
this.fire('scrolltopart');
- docLayer._selectedParts.push(docLayer._selectedPart);
if (app.file.textCursor.visible) {
// a click outside the slide to clear any selection
app.socket.sendMessage('resetselection');
@@ -105,7 +104,6 @@ L.Map.include({
this.fire('updateparts', {
selectedPart: docLayer._selectedPart,
- selectedParts: docLayer._selectedParts,
parts: docLayer._parts,
docType: docLayer._docType
});
@@ -129,46 +127,31 @@ L.Map.include({
// part is the part index/id
// how is 0 to deselect, 1 to select, and 2 to toggle selection
- selectPart: function (part, how, external) {
- //TODO: Update/track selected parts(?).
- var docLayer = this._docLayer;
- var oldParts = docLayer._selectedParts.slice();
- var newParts = docLayer._selectedParts;
- var index = docLayer._selectedParts.indexOf(part);
- if (index >= 0 && how != 1) {
- // Remove (i.e. deselect)
- docLayer._selectedParts.splice(index, 1);
- }
- else if (how != 0) {
- // Add (i.e. select)
- docLayer._selectedParts.push(part);
- }
+ // This function is Impress only.
+ selectPart: function (part, how, external, fireEvent = true) {
+ const currentSelectedCount = app.impress.getSelectedSlidesCount();
- // did we change anything?
- if (oldParts.length === newParts.length &&
- oldParts.every((value, index) => { return value === newParts[index]; })) {
- return;
- }
+ const targetPart = app.impress.partList[part];
- this.fire('updateparts', {
- selectedPart: docLayer._selectedPart,
- selectedParts: docLayer._selectedParts,
- parts: docLayer._parts,
- docType: docLayer._docType
- });
+ if (how < 2) targetPart.selected = how;
+ else targetPart.selected = targetPart.selected === 1 ? 0 : 1;
+
+ if (currentSelectedCount !== app.impress.getSelectedSlidesCount()) {
+ if (fireEvent) this.fire('updateparts', {});
- // If this wasn't triggered from the server,
- // then notify the server of the change.
- if (!external) {
- app.socket.sendMessage('selectclientpart part=' + part + ' how=' + how);
+ // If this wasn't triggered from the server,
+ // then notify the server of the change.
+ if (!external) {
+ app.socket.sendMessage('selectclientpart part=' + part + ' how=' + how);
+ }
}
},
deselectAll: function() {
- var docLayer = this._docLayer;
- while (docLayer._selectedParts.length > 0) {
- this.selectPart(docLayer._selectedParts[0], 0, false);
+ for (let i = 0; i < app.impress.partList.length; i++) {
+ this.selectPart(i, 0, false, false);
}
+ this.fire('updateparts', {});
},
_processPreviewQueue: function() {
@@ -434,7 +417,7 @@ L.Map.include({
return;
}
- if (this.getDocType() === 'spreadsheet' && docLayer._parts <= docLayer.hiddenParts() + 1) {
+ if (this.getDocType() === 'spreadsheet' && docLayer._parts <= app.calc.getHiddenPartCount() + 1) {
return;
}
@@ -478,21 +461,20 @@ L.Map.include({
},
showPage: function () {
- if (this.getDocType() === 'spreadsheet' && this.hasAnyHiddenPart()) {
- var partNames_ = this._docLayer._partNames;
- var hiddenParts_ = this._docLayer._hiddenParts;
+ if (this.getDocType() === 'spreadsheet' && app.calc.isAnyPartHidden()) {
+ var hiddenParts = app.calc.getHiddenPartNameArray();
- if (hiddenParts_.length > 0) {
+ if (app.calc.isAnyPartHidden()) {
var container = document.createElement('div');
container.style.maxHeight = '300px';
container.style.overflowY = 'auto';
- for (var i = 0; i < hiddenParts_.length; i++) {
+ for (var i = 0; i < hiddenParts.length; i++) {
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
- checkbox.id = 'hidden-part-checkbox-' + String(hiddenParts_[i]);
+ checkbox.id = 'hidden-part-checkbox-' + hiddenParts[i];
var label = document.createElement('label');
- label.htmlFor = 'hidden-part-checkbox-' + String(hiddenParts_[i]);
- label.innerText = partNames_[hiddenParts_[i]];
+ label.htmlFor = 'hidden-part-checkbox-' + hiddenParts[i];
+ label.innerText = hiddenParts[i];
var newLine = document.createElement('br');
container.appendChild(checkbox);
container.appendChild(label);
@@ -504,7 +486,7 @@ L.Map.include({
var checkboxList = document.querySelectorAll('input[id^="hidden-part-checkbox"]');
for (var i = 0; i < checkboxList.length; i++) {
if (checkboxList[i].checked === true) {
- var partName_ = partNames_[parseInt(checkboxList[i].id.replace('hidden-part-checkbox-', ''))];
+ var partName_ = checkboxList[i].id.replace('hidden-part-checkbox-', '');
var argument = {aTableName: {type: 'string', value: partName_}};
app.socket.sendMessage('uno .uno:Show ' + JSON.stringify(argument));
}
@@ -512,22 +494,24 @@ L.Map.include({
};
this.uiManager.showInfoModal('show-sheets-modal', '', ' ', ' ', _('Close'), callback, true, 'show-sheets-modal-response');
- document.getElementById('show-sheets-modal').querySelectorAll('label')[0].outerHTML = container.outerHTML;
+ const modal = document.getElementById('show-sheets-modal');
+ modal.insertBefore(container, modal.children[0]);
}
},
hidePage: function (tabNumber) {
- if (this.getDocType() === 'spreadsheet' && this.getNumberOfVisibleParts() > 1) {
+ if (this.getDocType() === 'spreadsheet' && app.calc.getVisiblePartCount() > 1) {
var argument = {nTabNumber: {type: 'int16', value: tabNumber}};
app.socket.sendMessage('uno .uno:Hide ' + JSON.stringify(argument));
}
},
hideSlide: function() {
- for (var index = 0; index < this._docLayer._selectedParts.length; index++) {
- var id = this._docLayer._selectedParts[index];
- L.DomUtil.addClass(this._docLayer._preview._previewTiles[id], 'hidden-slide');
- this._docLayer._hiddenSlides.add(id);
+ for (let i = 0; i < app.impress.partList.length; i++) {
+ if (app.impress.partList[i].selected) {
+ app.impress.partList[i].visible = 0;
+ L.DomUtil.addClass(this._docLayer._preview._previewTiles[i], 'hidden-slide');
+ }
}
app.socket.sendMessage('uno .uno:HideSlide');
@@ -535,36 +519,21 @@ L.Map.include({
},
showSlide: function() {
- for (var index = 0; index < this._docLayer._selectedParts.length; index++) {
- var id = this._docLayer._selectedParts[index];
- L.DomUtil.removeClass(this._docLayer._preview._previewTiles[id], 'hidden-slide');
- this._docLayer._hiddenSlides.delete(id);
+ for (let i = 0; i < app.impress.partList.length; i++) {
+ if (app.impress.partList[i].selected) {
+ app.impress.partList[i].visible = 1;
+ L.DomUtil.removeClass(this._docLayer._preview._previewTiles[i], 'hidden-slide');
+ }
}
app.socket.sendMessage('uno .uno:ShowSlide');
this.fire('toggleslidehide');
},
- isHiddenPart: function (part) {
- if (this.getDocType() !== 'spreadsheet')
- return false;
- return this._docLayer.isHiddenPart(part);
- },
-
- hasAnyHiddenPart: function () {
- if (this.getDocType() !== 'spreadsheet')
- return false;
- return this._docLayer.hasAnyHiddenPart();
- },
-
getNumberOfParts: function () {
return this._docLayer._parts;
},
- getNumberOfVisibleParts: function () {
- return this.getNumberOfParts() - this._docLayer.hiddenParts();
- },
-
getCurrentPartNumber: function () {
return this._docLayer._selectedPart;
},
diff --git a/browser/src/core/Socket.js b/browser/src/core/Socket.js
index fb2ec54b384f..fb2b67be9bf6 100644
--- a/browser/src/core/Socket.js
+++ b/browser/src/core/Socket.js
@@ -636,6 +636,7 @@ app.definitions.Socket = L.Class.extend({
this._logSocket('INCOMING', textMsg);
var command = this.parseServerCmd(textMsg);
+
if (textMsg.startsWith('coolserver ')) {
// This must be the first message, unless we reconnect.
var oldVersion = null;
@@ -1295,7 +1296,7 @@ app.definitions.Socket = L.Class.extend({
}
if (textMsg.startsWith('status:')) {
- this._onStatusMsg(textMsg, command);
+ this._onStatusMsg(textMsg, JSON.parse(textMsg.replace('status:', '').replace('statusupdate:', '')));
return;
}
@@ -1814,13 +1815,6 @@ app.definitions.Socket = L.Class.extend({
command.hiddenparts.push(parseInt(item));
});
}
- else if (tokens[i].startsWith('selectedparts=')) {
- var selectedParts = tokens[i].substring(14).split(',');
- command.selectedParts = [];
- selectedParts.forEach(function (item) {
- command.selectedParts.push(parseInt(item));
- });
- }
else if (tokens[i].startsWith('rtlparts=')) {
var rtlParts = tokens[i].substring(9).split(',');
command.rtlParts = [];
diff --git a/browser/src/docstate.js b/browser/src/docstate.js
index a0f372cdd60e..afca6e9e4f48 100644
--- a/browser/src/docstate.js
+++ b/browser/src/docstate.js
@@ -31,8 +31,9 @@ window.app = {
partHashes: null, // hashes used to distinguish parts (we use sheet name)
},
impress: {
- partHashes: null, // hashes used to distinguish parts
- notesMode: false // Contrary to "NormalMultiPaneGUI"
+ partList: null, // Info for parts.
+ notesMode: false, // Opposite of "NormalMultiPaneGUI".
+ twipsCorrection: 0.567 // There is a constant ratio between tiletwips and impress page twips. For now, this seems safe to use.
},
map: null, // Make map object a part of this.
dispatcher: null, // A Dispatcher class instance is assigned to this.
diff --git a/browser/src/docstatefunctions.js b/browser/src/docstatefunctions.js
index 94e743fd60e1..f45cf402482e 100644
--- a/browser/src/docstatefunctions.js
+++ b/browser/src/docstatefunctions.js
@@ -134,10 +134,14 @@ app.isFollowingEditor = function () {
return app.following.mode === 'editor';
};
-app.isCalcRTL = function () {
- return (
- app.map._docLayer._rtlParts.indexOf(app.map._docLayer._selectedPart) >= 0
- );
+app.calc.isRTL = function () {
+ if (!app.map._docLayer || !app.map._docLayer._lastStatusJSON) return false;
+
+ const part =
+ app.map._docLayer._lastStatusJSON.parts[app.map._docLayer._selectedPart];
+
+ if (part) return part.rtllayout !== 0;
+ else return false;
};
app.setServerAuditFromCore = function (entries) {
@@ -150,3 +154,117 @@ app.isExperimentalMode = function () {
return app.socket.WSDServer.Options.indexOf('E') !== -1;
return false;
};
+
+app.calc.isPartHidden = function (part) {
+ if (!app.map._docLayer || !app.map._docLayer._lastStatusJSON) return false;
+
+ return app.map._docLayer._lastStatusJSON.parts[part].visible === 0; // ToDo: Move _lastStatusJSON into docstate.js
+};
+
+app.calc.isPartProtected = function (part) {
+ if (!app.map._docLayer || !app.map._docLayer._lastStatusJSON) return false;
+
+ return app.map._docLayer._lastStatusJSON.parts[part].protected === 1;
+};
+
+app.calc.isAnyPartHidden = function () {
+ if (!app.map._docLayer || !app.map._docLayer._lastStatusJSON) return false;
+
+ for (let i = 0; i < app.map._docLayer._lastStatusJSON.parts.length; i++) {
+ if (app.map._docLayer._lastStatusJSON.parts[i].visible === 0) return true;
+ }
+ return false;
+};
+
+app.calc.getHiddenPartCount = function () {
+ if (!app.map._docLayer || !app.map._docLayer._lastStatusJSON) return 0;
+
+ let count = 0;
+
+ for (let i = 0; i < app.map._docLayer._lastStatusJSON.parts.length; i++) {
+ if (app.map._docLayer._lastStatusJSON.parts[i].visible === 0) count++;
+ }
+
+ return count;
+};
+
+app.calc.getVisiblePartCount = function () {
+ if (!app.map._docLayer || !app.map._docLayer._lastStatusJSON) return 0;
+
+ let count = 0;
+
+ for (let i = 0; i < app.map._docLayer._lastStatusJSON.parts.length; i++) {
+ if (app.map._docLayer._lastStatusJSON.parts[i].visible === 1) count++;
+ }
+
+ return count;
+};
+
+app.calc.getHiddenPartNameArray = function () {
+ if (!app.map._docLayer || !app.map._docLayer._lastStatusJSON) return [];
+
+ let array = [];
+
+ for (let i = 0; i < app.map._docLayer._lastStatusJSON.parts.length; i++) {
+ let part = app.map._docLayer._lastStatusJSON.parts[i];
+ if (part.visible === 0) array.push(part.name);
+ }
+
+ return array;
+};
+
+app.impress.isSlideHidden = function (index) {
+ if (app.impress.partList) {
+ if (app.impress.partList.length > index)
+ return !app.impress.partList[index].visible;
+ else {
+ console.warn(
+ 'Index is bigger than the part count (isSlideHidden): ' + index,
+ );
+ return true;
+ }
+ } else return false;
+};
+
+app.impress.areAllSlidesHidden = function () {
+ if (app.impress.partList) {
+ for (let i = 0; i < app.impress.partList.length; i++) {
+ if (app.impress.partList[i].visible === 1) return false;
+ }
+ return true;
+ } else return false;
+};
+
+app.impress.getSelectedSlidesCount = function () {
+ let count = 0;
+
+ if (app.impress.partList) {
+ for (let i = 0; i < app.impress.partList.length; i++) {
+ if (app.impress.partList[i].selected === 1) count++;
+ }
+ }
+
+ return count;
+};
+
+app.impress.getIndexFromSlideHash = function (hash) {
+ if (app.impress.partList) {
+ for (let i = 0; i < app.impress.partList.length; i++) {
+ if (app.impress.partList[i].hash === hash) return i;
+ }
+
+ console.warn('No part with hash (getIndexFromSlideHash): ' + hash);
+
+ return 0;
+ } else return 0;
+};
+
+app.impress.isSlideSelected = function (index) {
+ if (
+ app.impress.partList &&
+ index >= 0 &&
+ index < app.impress.partList.length
+ ) {
+ return app.impress.partList[index].selected === 1;
+ } else return false;
+};
diff --git a/browser/src/layer/tile/CalcTileLayer.js b/browser/src/layer/tile/CalcTileLayer.js
index e93c8ff54cd2..0aa3c00a68f6 100644
--- a/browser/src/layer/tile/CalcTileLayer.js
+++ b/browser/src/layer/tile/CalcTileLayer.js
@@ -103,24 +103,6 @@ L.CalcTileLayer = L.CanvasTileLayer.extend({
this.requestCellCursor();
},
- isHiddenPart: function (part) {
- if (!this._hiddenParts)
- return false;
- return this._hiddenParts.indexOf(part) !== -1;
- },
-
- hiddenParts: function () {
- if (!this._hiddenParts)
- return 0;
- return this._hiddenParts.length;
- },
-
- hasAnyHiddenPart: function () {
- if (!this._hiddenParts)
- return false;
- return this.hiddenParts() !== 0;
- },
-
_onUpdateParts: function (e) {
if (typeof this._prevSelectedPart === 'number' && !e.source) {
this.refreshViewData(undefined, false /* compatDataSrcOnly */, true /* sheetGeometryChanged */);
@@ -234,7 +216,7 @@ L.CalcTileLayer = L.CanvasTileLayer.extend({
_onSetPartMsg: function (textMsg) {
var part = parseInt(textMsg.match(/\d+/g)[0]);
- if (!this.isHiddenPart(part)) {
+ if (!app.calc.isPartHidden(part)) {
this.refreshViewData(undefined, true /* compatDataSrcOnly */, false /* sheetGeometryChanged */);
this._replayPrintTwipsMsgAllViews('cellviewcursor');
this._replayPrintTwipsMsgAllViews('textviewselection');
@@ -368,53 +350,87 @@ L.CalcTileLayer = L.CanvasTileLayer.extend({
}
},
- _handleRTLFlags: function (command) {
- var rtlChanged = command.rtlParts === undefined;
- rtlChanged = rtlChanged || this._rtlParts !== undefined && (
- command.rtlParts.length !== this._rtlParts.length
- || this._rtlParts.some(function (part, index) {
- return part !== command.rtlParts[index];
- }));
- this._rtlParts = command.rtlParts || [];
- if (rtlChanged) {
- this._adjustCanvasSectionsForLayoutChange();
+ _hasPartsCountOrNamesChanged(lastStatusJSON, statusJSON) {
+ if (!lastStatusJSON)
+ return true;
+
+ if (lastStatusJSON.parts.length !== statusJSON.parts.length)
+ return true;
+ else {
+ for (let i = 0; i < statusJSON.parts.length; i++) {
+ if (statusJSON.parts[i].name !== lastStatusJSON.parts[i].name)
+ return true;
+ }
+ return false;
+ }
+ },
+
+ _refreshPartNames(statusJSON) {
+ this._partNames = [];
+
+ for (let i = 0; i < statusJSON.parts.length; i++) {
+ this._partNames.push(statusJSON.parts[i].name);
+ }
+ },
+
+ _refreshPartHashes(statusJSON) {
+ app.calc.partHashes = [];
+
+ for (let i = 0; i < statusJSON.parts.length; i++) {
+ app.calc.partHashes.push(statusJSON.parts[i].hash);
}
},
_onStatusMsg: function (textMsg) {
console.log('DEBUG: onStatusMsg: ' + textMsg);
- var command = app.socket.parseServerCmd(textMsg);
- if (command.width && command.height && this._documentInfo !== textMsg) {
+
+ const statusJSON = JSON.parse(textMsg.replace('status:', '').replace('statusupdate:', ''));
+
+ if (statusJSON.width && statusJSON.height && this._documentInfo !== textMsg) {
+ const temp = this._lastStatusJSON ? Object.assign({}, this._lastStatusJSON): null;
+ this._lastStatusJSON = statusJSON;
+ this._documentInfo = textMsg;
+
var firstSelectedPart = (typeof this._selectedPart !== 'number');
- if (command.readonly === 1)
- this._map.setPermission('readonly');
- this._docWidthTwips = command.width;
- this._docHeightTwips = command.height;
+
+ if (statusJSON.readonly) this._map.setPermission('readonly');
+
+ this._docWidthTwips = statusJSON.width;
+ this._docHeightTwips = statusJSON.height;
+
app.file.size.twips = [this._docWidthTwips, this._docHeightTwips];
app.file.size.pixels = [Math.round(this._tileSize * (this._docWidthTwips / this._tileWidthTwips)), Math.round(this._tileSize * (this._docHeightTwips / this._tileHeightTwips))];
app.view.size.pixels = app.file.size.pixels.slice();
- this._docType = command.type;
- this._parts = command.parts;
+
+ this._docType = statusJSON.type;
+ this._parts = statusJSON.partscount;
+
if (app.socket._reconnecting) {
app.socket.sendMessage('setclientpart part=' + this._selectedPart);
this._resetInternalState();
window.keyboard.hintOnscreenKeyboard(window.keyboard.onscreenKeyboardHint);
} else {
- this._selectedPart = command.selectedPart;
+ this._selectedPart = statusJSON.selectedpart;
}
- this._lastColumn = command.lastcolumn;
- this._lastRow = command.lastrow;
- this._selectedMode = (command.mode !== undefined) ? command.mode : 0;
+
+ this._lastColumn = statusJSON.lastcolumn;
+ this._lastRow = statusJSON.lastrow;
+ this._selectedMode = (statusJSON.mode !== undefined) ? statusJSON.mode : 0;
+
if (this.sheetGeometry && this._selectedPart != this.sheetGeometry.getPart()) {
// Core initiated sheet switch, need to get full sheetGeometry data for the selected sheet.
this.requestSheetGeometryData();
}
- this._viewId = parseInt(command.viewid);
+
+ this._viewId = statusJSON.viewid;
+
console.assert(this._viewId >= 0, 'Incorrect viewId received: ' + this._viewId);
+
var mapSize = this._map.getSize();
var sizePx = this._twipsToPixels(new L.Point(this._docWidthTwips, this._docHeightTwips));
var width = sizePx.x;
var height = sizePx.y;
+
if (width < mapSize.x || height < mapSize.y) {
width = Math.max(width, mapSize.x);
height = Math.max(height, mapSize.y);
@@ -427,43 +443,30 @@ L.CalcTileLayer = L.CanvasTileLayer.extend({
else {
this._updateMaxBounds(true);
}
- this._hiddenParts = command.hiddenparts || [];
-
- var pparts = [];
- pparts.length = command.parts;
- this._protectedParts = pparts.fill(false, 0, command.parts);
- if (command.protectedParts) {
- command.protectedParts.forEach(function(i) {
- return this._protectedParts[i] = true;
- }.bind(this));
- }
- this._handleRTLFlags(command);
- this._documentInfo = textMsg;
- var partNames = textMsg.match(/[^\r\n]+/g);
- // only get the last matches
- var oldPartNames = this._partNames;
- this._partNames = partNames.slice(partNames.length - this._parts);
- app.calc.partHashes = this._partNames; // TODO: generate unique hash on the core side
+ this._adjustCanvasSectionsForLayoutChange();
+
+ this._refreshPartNames(statusJSON);
+ this._refreshPartHashes(statusJSON);
+
// if the number of parts, or order has changed then refresh comment positions
- if (oldPartNames !== this._partNames) {
+ if (this._hasPartsCountOrNamesChanged(temp, statusJSON))
app.socket.sendMessage('commandvalues command=.uno:ViewAnnotationsPosition');
- }
+
+
this._map.fire('updateparts', {
selectedPart: this._selectedPart,
parts: this._parts,
docType: this._docType,
- partNames: this._partNames,
- hiddenParts: this._hiddenParts,
- protectedParts: this._protectedParts,
- source: 'status'
+ source: 'status',
+ partNames: this._partNames
});
+
this._resetPreFetching(true);
- if (firstSelectedPart) {
- this._switchSplitPanesContext();
- }
+
+ if (firstSelectedPart) this._switchSplitPanesContext();
} else {
- this._handleRTLFlags(command);
+ this._adjustCanvasSectionsForLayoutChange();
}
var scrollSection = app.sectionContainer.getSectionWithName(L.CSections.Scroll.name);
@@ -639,7 +642,7 @@ L.CalcTileLayer = L.CanvasTileLayer.extend({
},
_adjustCanvasSectionsForLayoutChange: function () {
- var sheetIsRTL = this._rtlParts.indexOf(this._selectedPart) >= 0;
+ var sheetIsRTL = app.calc.isRTL();
if (sheetIsRTL && this._layoutIsRTL !== true) {
console.log('debug: in LTR -> RTL canvas section adjustments');
var sectionContainer = app.sectionContainer;
diff --git a/browser/src/layer/tile/ImpressTileLayer.js b/browser/src/layer/tile/ImpressTileLayer.js
index 497460624c5f..6b4bedf8b6e7 100644
--- a/browser/src/layer/tile/ImpressTileLayer.js
+++ b/browser/src/layer/tile/ImpressTileLayer.js
@@ -12,7 +12,7 @@
* Impress tile layer is used to display a presentation document
*/
-/* global app $ L Set */
+/* global app $ L */
L.ImpressTileLayer = L.CanvasTileLayer.extend({
@@ -24,7 +24,7 @@ L.ImpressTileLayer = L.CanvasTileLayer.extend({
}
this._preview = L.control.partsPreview();
- app.impress.partHashes = null;
+
if (window.mode.isMobile()) {
this._addButton = L.control.mobileSlide();
L.DomUtil.addClass(L.DomUtil.get('mobile-edit-button'), 'impress');
@@ -99,7 +99,7 @@ L.ImpressTileLayer = L.CanvasTileLayer.extend({
comment.anchorPos = [docTopLeft[0], docTopLeft[1]];
comment.rectangle = [docTopLeft[0], docTopLeft[1], 566, 566];
- comment.parthash = app.impress.partHashes[this._selectedPart];
+ comment.parthash = app.impress.partList[this._selectedPart].hash;
var annotation = app.sectionContainer.getSectionWithName(L.CSections.CommentList.name).add(comment);
app.sectionContainer.getSectionWithName(L.CSections.CommentList.name).modify(annotation);
},
@@ -253,24 +253,26 @@ L.ImpressTileLayer = L.CanvasTileLayer.extend({
_onSetPartMsg: function (textMsg) {
var part = parseInt(textMsg.match(/\d+/g)[0]);
if (part !== this._selectedPart) {
+ this._map.deselectAll(); // Deselect all first. This is a single selection.
this._map.setPart(part, true);
this._map.fire('setpart', {selectedPart: this._selectedPart});
}
},
_onStatusMsg: function (textMsg) {
- var command = app.socket.parseServerCmd(textMsg);
+ const statusJSON = JSON.parse(textMsg.replace('status:', '').replace('statusupdate:', ''));
+
// Since we have two status commands, remove them so we store and compare payloads only.
textMsg = textMsg.replace('status: ', '');
textMsg = textMsg.replace('statusupdate: ', '');
- if (command.width && command.height && this._documentInfo !== textMsg) {
- this._docWidthTwips = command.width;
- this._docHeightTwips = command.height;
- this._docType = command.type;
+ if (statusJSON.width && statusJSON.height && this._documentInfo !== textMsg) {
+ this._docWidthTwips = statusJSON.width;
+ this._docHeightTwips = statusJSON.height;
+ this._docType = statusJSON.type;
if (this._docType === 'drawing') {
L.DomUtil.addClass(L.DomUtil.get('presentation-controls-wrapper'), 'drawing');
}
- this._parts = command.parts;
+ this._parts = statusJSON.partscount;
this._partHeightTwips = this._docHeightTwips;
this._partWidthTwips = this._docWidthTwips;
@@ -284,31 +286,38 @@ L.ImpressTileLayer = L.CanvasTileLayer.extend({
app.file.size.pixels = [Math.round(this._tileSize * (this._docWidthTwips / this._tileWidthTwips)), Math.round(this._tileSize * (this._docHeightTwips / this._tileHeightTwips))];
app.view.size.pixels = app.file.size.pixels.slice();
+ app.impress.partList = Object.assign([], statusJSON.parts);
+
this._updateMaxBounds(true);
- this._documentInfo = textMsg;
- this._viewId = parseInt(command.viewid);
+
+ this._viewId = statusJSON.viewid;
console.assert(this._viewId >= 0, 'Incorrect viewId received: ' + this._viewId);
if (app.socket._reconnecting) {
app.socket.sendMessage('setclientpart part=' + this._selectedPart);
} else {
- this._selectedPart = command.selectedPart;
- this._selectedParts = command.selectedParts || [command.selectedPart];
+ this._selectedPart = statusJSON.selectedpart;
}
- this._selectedMode = (command.mode !== undefined) ? command.mode : 0;
+
+ this._selectedMode = (statusJSON.mode !== undefined) ? statusJSON.mode : (statusJSON.parts.length > 0 && statusJSON.parts[0].mode !== undefined ? statusJSON.parts[0].mode : 0);
+
+ if (statusJSON.gridSnapEnabled === true)
+ app.map.stateChangeHandler.setItemValue('.uno:GridUse', 'true');
+ else if (statusJSON.parts.length > 0 && statusJSON.parts[0].gridSnapEnabled === true)
+ app.map.stateChangeHandler.setItemValue('.uno:GridUse', 'true');
+
+ if (statusJSON.gridVisible === true)
+ app.map.stateChangeHandler.setItemValue('.uno:GridVisible', 'true');
+ else if (statusJSON.parts.length > 0 && statusJSON.parts[0].gridVisible === true)
+ app.map.stateChangeHandler.setItemValue('.uno:GridVisible', 'true');
+
this._resetPreFetching(true);
- var partMatch = textMsg.match(/[^\r\n]+/g);
- // only get the last matches
- var newPartHashes = partMatch.slice(partMatch.length - this._parts);
- var refreshAnnotation = app.impress.partHashes && (app.impress.partHashes.length !== newPartHashes.length || !app.impress.partHashes.every(function(element,i) { return element === newPartHashes[i]; }));
- app.impress.partHashes = newPartHashes;
- this._hiddenSlides = new Set(command.hiddenparts);
- this._map.fire('updateparts', {
- selectedPart: this._selectedPart,
- selectedParts: this._selectedParts,
- parts: this._parts,
- docType: this._docType,
- partNames: app.impress.partHashes
- });
+
+ var refreshAnnotation = this._documentInfo !== textMsg;
+
+ this._documentInfo = textMsg;
+
+ this._map.fire('updateparts', {});
+
if (refreshAnnotation)
app.socket.sendMessage('commandvalues command=.uno:ViewAnnotations');
}
@@ -332,18 +341,6 @@ L.ImpressTileLayer = L.CanvasTileLayer.extend({
this.lastWizardCommentHighlight.removeClass('impress-comment-highlight');
},
- isHiddenSlide: function(slideNum) {
- if (!this._hiddenSlides)
- return false;
- return this._hiddenSlides.has(slideNum);
- },
-
- hiddenSlides: function () {
- if (!this._hiddenSlides)
- return 0;
- return this._hiddenSlides.size;
- },
-
_invalidateAllPreviews: function () {
L.CanvasTileLayer.prototype._invalidateAllPreviews.call(this);
this._map.fire('invalidateparts');
diff --git a/browser/src/layer/tile/WriterTileLayer.js b/browser/src/layer/tile/WriterTileLayer.js
index 2e98c305b177..a0a714436336 100644
--- a/browser/src/layer/tile/WriterTileLayer.js
+++ b/browser/src/layer/tile/WriterTileLayer.js
@@ -124,7 +124,7 @@ L.WriterTileLayer = L.CanvasTileLayer.extend({
_onSetPartMsg: function (textMsg) {
var part = parseInt(textMsg.match(/\d+/g)[0]);
- if (part !== this._selectedPart) {
+ if (part !== this._currentPage) {
this._currentPage = part;
this._map.fire('pagenumberchanged', {
currentPage: part,
@@ -135,7 +135,8 @@ L.WriterTileLayer = L.CanvasTileLayer.extend({
},
_onStatusMsg: function (textMsg) {
- var command = app.socket.parseServerCmd(textMsg);
+ const statusJSON = JSON.parse(textMsg.replace('status:', '').replace('statusupdate:', ''));
+
if (app.socket._reconnecting) {
// persist cursor position on reconnection
// In writer, core always sends the cursor coordinates
@@ -145,33 +146,32 @@ L.WriterTileLayer = L.CanvasTileLayer.extend({
this._postMouseEvent('buttondown', this.lastCursorPos.center[0], this.lastCursorPos.center[1], 1, 1, 0);
this._postMouseEvent('buttonup', this.lastCursorPos.center[0], this.lastCursorPos.center[1], 1, 1, 0);
}
- if (!command.width || !command.height || this._documentInfo === textMsg)
+ if (!statusJSON.width || !statusJSON.height || this._documentInfo === textMsg)
return;
- var sizeChanged = command.width !== this._docWidthTwips || command.height !== this._docHeightTwips;
+ var sizeChanged = statusJSON.width !== this._docWidthTwips || statusJSON.height !== this._docHeightTwips;
+
+ if (statusJSON.viewid !== undefined) this._viewId = statusJSON.viewid;
- if (command.viewid !== undefined) {
- this._viewId = parseInt(command.viewid);
- }
console.assert(this._viewId >= 0, 'Incorrect viewId received: ' + this._viewId);
if (sizeChanged) {
- this._docWidthTwips = command.width;
- this._docHeightTwips = command.height;
+ this._docWidthTwips = statusJSON.width;
+ this._docHeightTwips = statusJSON.height;
app.file.size.twips = [this._docWidthTwips, this._docHeightTwips];
app.file.size.pixels = [Math.round(this._tileSize * (this._docWidthTwips / this._tileWidthTwips)), Math.round(this._tileSize * (this._docHeightTwips / this._tileHeightTwips))];
app.view.size.pixels = app.file.size.pixels.slice();
- this._docType = command.type;
+ this._docType = statusJSON.type;
this._updateMaxBounds(true);
}
this._documentInfo = textMsg;
this._selectedPart = 0;
- this._selectedMode = (command.mode !== undefined) ? command.mode : 0;
+ this._selectedMode = (statusJSON.mode !== undefined) ? statusJSON.mode : 0;
this._parts = 1;
- this._currentPage = command.selectedPart;
- this._pages = command.parts;
- app.file.writer.pageRectangleList = command.pageRectangleList.slice(); // Copy the array.
+ this._currentPage = statusJSON.selectedpart;
+ this._pages = statusJSON.partscount;
+ app.file.writer.pageRectangleList = statusJSON.pagerectangles.slice(); // Copy the array.
this._map.fire('pagenumberchanged', {
currentPage: this._currentPage,
pages: this._pages,
diff --git a/browser/src/map/handler/Map.Keyboard.js b/browser/src/map/handler/Map.Keyboard.js
index e8d9e406ea28..2efece9b1d9d 100644
--- a/browser/src/map/handler/Map.Keyboard.js
+++ b/browser/src/map/handler/Map.Keyboard.js
@@ -420,6 +420,8 @@ L.Map.Keyboard = L.Handler.extend({
if (!deletePart) {
var partToSelect = (ev.keyCode === this.keyCodes.UP || ev.keyCode === this.keyCodes.LEFT ||
ev.keyCode === this.keyCodes.PAGEUP) ? 'prev' : 'next';
+
+ this._map.deselectAll();
this._map.setPart(partToSelect);
if (app.file.fileBasedView)
this._map._docLayer._checkSelectedPart();
@@ -453,7 +455,7 @@ L.Map.Keyboard = L.Handler.extend({
}
ev.preventDefault();
}
-
+
},
// _handleKeyEvent - checks if the given keyboard event shall trigger
diff --git a/browser/src/map/handler/Map.SlideShow.js b/browser/src/map/handler/Map.SlideShow.js
index e4ab0570c2ac..f11d5c23b480 100644
--- a/browser/src/map/handler/Map.SlideShow.js
+++ b/browser/src/map/handler/Map.SlideShow.js
@@ -3,7 +3,7 @@
* L.Map.SlideShow is handling the slideShow action
*/
-/* global _ sanitizeUrl */
+/* global _ sanitizeUrl app */
L.Map.mergeOptions({
slideShow: true
});
@@ -51,7 +51,7 @@ L.Map.SlideShow = L.Handler.extend({
return;
}
- if (this._map._docLayer.hiddenSlides() >= this._map.getNumberOfParts()) {
+ if (app.impress.areAllSlidesHidden()) {
this._map.uiManager.showInfoModal('allslidehidden-modal', _('Empty Slide Show'),
'All slides are hidden!', '', _('OK'), function () { }, false, 'allslidehidden-modal-response');
return;
diff --git a/browser/src/slideshow/SlideShowPresenter.ts b/browser/src/slideshow/SlideShowPresenter.ts
index de5b81e415ee..d372affca82f 100644
--- a/browser/src/slideshow/SlideShowPresenter.ts
+++ b/browser/src/slideshow/SlideShowPresenter.ts
@@ -622,7 +622,7 @@ class SlideShowPresenter {
return false;
}
- if (this._map._docLayer.hiddenSlides() >= this._map.getNumberOfParts()) {
+ if (app.impress.areAllSlidesHidden()) {
this._notifyAllSlidesHidden();
return false;
}
diff --git a/browser/src/unocommands.js b/browser/src/unocommands.js
index f978a1a64d81..a3823966e094 100644
--- a/browser/src/unocommands.js
+++ b/browser/src/unocommands.js
@@ -228,6 +228,8 @@ var unoCommandsArray = {
'FunctionDialog':{spreadsheet:{menu:_('~Function...'),},},
'GoalSeekDialog':{spreadsheet:{menu:_('~Goal Seek...'),},},
'GraphicDialog':{text:{menu:_('~Properties...'),},},
+ 'GridUse':{global:{menu:_('Snap to Grid'),},},
+ 'GridVisible':{global:{context:_('Display Grid'),menu:_('~Display Grid'),},},
'Group':{global:{menu:_('~Group...'),},},
'GroupOutlineMenu':{spreadsheet:{menu:_('~Group and Outline'),},},
'GroupSparklines':{spreadsheet:{menu:_('Group Sparklines'),},},
diff --git a/cypress_test/integration_tests/desktop/calc/sheet_operation_spec.js b/cypress_test/integration_tests/desktop/calc/sheet_operation_spec.js
index 54f0b2e9d8dc..229fe557c455 100644
--- a/cypress_test/integration_tests/desktop/calc/sheet_operation_spec.js
+++ b/cypress_test/integration_tests/desktop/calc/sheet_operation_spec.js
@@ -76,7 +76,7 @@ describe(['tagdesktop', 'tagnextcloud', 'tagproxy'], 'Sheet Operations.', functi
//show sheet
calcHelper.selectOptionFromContextMenu('Show Sheet');
cy.cGet('#show-sheets-modal').should('exist');
- cy.cGet('#hidden-part-checkbox-1').check();
+ cy.cGet('#hidden-part-checkbox-Sheet2').check();
cy.cGet('#show-sheets-modal-response').click();
calcHelper.assertNumberofSheets(2);
});
diff --git a/cypress_test/integration_tests/mobile/calc/sheet_operation_spec.js b/cypress_test/integration_tests/mobile/calc/sheet_operation_spec.js
index c2eeaedcd73d..6752d368257e 100644
--- a/cypress_test/integration_tests/mobile/calc/sheet_operation_spec.js
+++ b/cypress_test/integration_tests/mobile/calc/sheet_operation_spec.js
@@ -91,7 +91,7 @@ describe(['tagmobile', 'tagnextcloud', 'tagproxy'], 'Sheet Operation', function
calcHelper.selectOptionMobileWizard('Show Sheet');
cy.cGet('#mobile-wizard-content-modal-dialog-show-sheets-modal').should('exist');
- cy.cGet('#hidden-part-checkbox-1').check();
+ cy.cGet('#hidden-part-checkbox-Sheet2').check();
cy.cGet('#show-sheets-modal-response').click();
calcHelper.assertNumberofSheets(2);
diff --git a/kit/KitHelper.hpp b/kit/KitHelper.hpp
index 3d9ed0d273a7..36fd16ee3d43 100644
--- a/kit/KitHelper.hpp
+++ b/kit/KitHelper.hpp
@@ -13,6 +13,7 @@
#include
#include
+#include
#include
#include
@@ -41,6 +42,89 @@ namespace LOKitHelper
}
}
+ inline std::string getPartData(LibreOfficeKitDocument *loKitDocument, int part)
+ {
+ char* ptrToData = loKitDocument->pClass->getPartInfo(loKitDocument, part);
+ std::string result(ptrToData);
+ std::free(ptrToData);
+ return result;
+ }
+
+ inline std::string MapToJSONString(std::unordered_map &map)
+ {
+ std::string resultingString = "{";
+ for (std::unordered_map::iterator i = map.begin(); i != map.end(); i++)
+ {
+ resultingString += "\"" + i->first + "\": " + i->second + ",";
+ }
+ resultingString.pop_back();
+ resultingString += "}";
+
+ return resultingString;
+ }
+
+ inline int getMode(const std::string &partData)
+ {
+ Poco::JSON::Parser parser;
+ Poco::Dynamic::Var partJsonVar = parser.parse(partData);
+ const Poco::SharedPtr& partObject = partJsonVar.extract();
+
+ if (partObject->has("mode"))
+ return std::atoi(partObject->get("mode").toString().c_str());
+ else
+ return 0;
+ }
+
+ inline void fetchPartsData(LibreOfficeKitDocument *loKitDocument, std::unordered_map &resultInfo, int partsCount, int &mode)
+ {
+ /*
+ Except for Writer.
+
+ Since parts should be an array, we will start an array and put parts into it.
+ We are building a JSON array.
+ */
+
+ std::string resultingPartsArray = "[";
+
+ for (int i = 0; i < partsCount; ++i)
+ {
+ std::string partData = getPartData(loKitDocument, i); // Part data is sent from the core side as JSON string.
+ resultingPartsArray += partData + (i < partsCount - 1 ? ", ": "]");
+
+ if (i == 0)
+ mode = getMode(partData);
+ }
+
+ resultInfo["parts"] = resultingPartsArray;
+ }
+
+ inline void fetchWriterSpecificData(LibreOfficeKitDocument *loKitDocument, std::unordered_map &resultInfo)
+ {
+ std::string rectangles = loKitDocument->pClass->getPartPageRectangles(loKitDocument);
+
+ rectangles = Util::replace(rectangles, ";", "], [");
+
+ resultInfo["pagerectangles"] = "[ [" + rectangles + "] ]";
+ }
+
+ inline void fetchCalcSpecificData(LibreOfficeKitDocument *loKitDocument, std::unordered_map &resultInfo, int part)
+ {
+ long lastColumn, lastRow;
+ loKitDocument->pClass->getDataArea(loKitDocument, part, &lastColumn, &lastRow);
+ resultInfo["lastcolumn"] = std::to_string(lastColumn);
+ resultInfo["lastrow"] = std::to_string(lastRow);
+
+ char* value = loKitDocument->pClass->getCommandValues(loKitDocument, ".uno:ReadOnly");
+ if (value)
+ {
+ const std::string isReadOnly = std::string(value);
+ std::free(value);
+
+ bool readOnly = (isReadOnly.find("true") != std::string::npos);
+ resultInfo["readonly"] = readOnly ? "true": "false";
+ }
+ }
+
inline std::string getDocumentTypeAsString(LibreOfficeKitDocument *loKitDocument)
{
assert(loKitDocument && "null loKitDocument");
@@ -50,146 +134,38 @@ namespace LOKitHelper
inline std::string documentStatus(LibreOfficeKitDocument *loKitDocument)
{
- char *ptrValue;
assert(loKitDocument && "null loKitDocument");
const auto type = static_cast(loKitDocument->pClass->getDocumentType(loKitDocument));
- const int parts = loKitDocument->pClass->getParts(loKitDocument);
- const int part = loKitDocument->pClass->getPart(loKitDocument);
- std::ostringstream oss;
- oss << "type=" << documentTypeToString(type)
- << " parts=" << parts
- << " current=" << part;
+ std::unordered_map resultInfo;
+
+ const int partsCount = loKitDocument->pClass->getParts(loKitDocument);
+ const int selectedPart = loKitDocument->pClass->getPart(loKitDocument);
long width, height;
loKitDocument->pClass->getDocumentSize(loKitDocument, &width, &height);
- oss << " width=" << width
- << " height=" << height
- << " viewid=" << loKitDocument->pClass->getView(loKitDocument);
+ int viewId = loKitDocument->pClass->getView(loKitDocument);
- if (type == LOK_DOCTYPE_SPREADSHEET)
- {
- long lastColumn, lastRow;
- loKitDocument->pClass->getDataArea(loKitDocument, part, &lastColumn, &lastRow);
- oss << " lastcolumn=" << lastColumn
- << " lastrow=" << lastRow;
- }
+ resultInfo["type"] = "\"" + documentTypeToString(type) + "\"";
+ resultInfo["partscount"] = std::to_string(partsCount);
+ resultInfo["selectedpart"] = std::to_string(selectedPart);
+ resultInfo["width"] = std::to_string(width);
+ resultInfo["height"] = std::to_string(height);
+ resultInfo["viewid"] = std::to_string(viewId);
- if (type == LOK_DOCTYPE_SPREADSHEET || type == LOK_DOCTYPE_PRESENTATION || type == LOK_DOCTYPE_DRAWING)
- {
- std::ostringstream hposs;
- std::ostringstream sposs;
- std::ostringstream rtlposs;
- std::ostringstream protectss;
- std::string mode;
- for (int i = 0; i < parts; ++i)
- {
- ptrValue = loKitDocument->pClass->getPartInfo(loKitDocument, i);
- const std::string partinfo(ptrValue);
- std::free(ptrValue);
- for (const auto& prop : JsonUtil::jsonToMap(partinfo))
- {
- const std::string& name = prop.first;
- if (name == "visible")
- {
- if (prop.second == "0")
- hposs << i << ',';
- }
- else if (name == "selected")
- {
- if (prop.second == "1")
- sposs << i << ',';
- }
- else if (name == "rtllayout")
- {
- if (prop.second == "1")
- rtlposs << i << ',';
- }
- else if (name == "protected")
- {
- if (prop.second == "1")
- protectss << i << ',';
- }
- else if (name == "mode" && mode.empty())
- {
- mode = prop.second;
- }
- }
- }
-
- if (!mode.empty())
- oss << " mode=" << mode;
-
- std::string hiddenparts = hposs.str();
- if (!hiddenparts.empty())
- {
- hiddenparts.pop_back(); // Remove last ','
- oss << " hiddenparts=" << hiddenparts;
- }
-
- std::string selectedparts = sposs.str();
- if (!selectedparts.empty())
- {
- selectedparts.pop_back(); // Remove last ','
- oss << " selectedparts=" << selectedparts;
- }
-
- std::string rtlparts = rtlposs.str();
- if (!rtlparts.empty())
- {
- rtlparts.pop_back(); // Remove last ','
- oss << " rtlparts=" << rtlparts;
- }
-
- std::string protectparts = protectss.str();
- if (!protectparts.empty())
- {
- protectparts.pop_back(); // Remove last ','
- oss << " protectedparts=" << protectparts;
- }
-
- if (type == LOK_DOCTYPE_SPREADSHEET)
- {
- char* values = loKitDocument->pClass->getCommandValues(loKitDocument, ".uno:ReadOnly");
- if (values)
- {
- const std::string isReadOnly = std::string(values);
- oss << " readonly=" << (isReadOnly.find("true") != std::string::npos);
- std::free(values);
- }
- }
-
- for (int i = 0; i < parts; ++i)
- {
- oss << '\n';
- ptrValue = loKitDocument->pClass->getPartName(loKitDocument, i);
- oss << ptrValue;
- std::free(ptrValue);
- }
-
- if (type == LOK_DOCTYPE_PRESENTATION || type == LOK_DOCTYPE_DRAWING)
- {
- for (int i = 0; i < parts; ++i)
- {
- oss << '\n';
- ptrValue = loKitDocument->pClass->getPartHash(loKitDocument, i);
- oss << ptrValue;
- std::free(ptrValue);
- }
- }
- }
+ int mode = 0;
- if (type == LOK_DOCTYPE_TEXT)
- {
- std::string rectangles = loKitDocument->pClass->getPartPageRectangles(loKitDocument);
+ if (type == LOK_DOCTYPE_SPREADSHEET)
+ fetchCalcSpecificData(loKitDocument, resultInfo, selectedPart);
+ else if (type == LOK_DOCTYPE_TEXT)
+ fetchWriterSpecificData(loKitDocument, resultInfo);
- std::string::iterator end_pos = std::remove(rectangles.begin(), rectangles.end(), ' ');
- rectangles.erase(end_pos, rectangles.end());
+ if (type == LOK_DOCTYPE_SPREADSHEET || type == LOK_DOCTYPE_PRESENTATION || type == LOK_DOCTYPE_DRAWING)
+ fetchPartsData(loKitDocument, resultInfo, partsCount, mode);
- oss << " pagerectangles=" << rectangles.c_str();
- }
+ resultInfo["mode"] = std::to_string(mode);
- return oss.str();
+ return MapToJSONString(resultInfo);
}
}
diff --git a/test/TileCacheTests.cpp b/test/TileCacheTests.cpp
index fdefaa8e1604..ce077b880af2 100644
--- a/test/TileCacheTests.cpp
+++ b/test/TileCacheTests.cpp
@@ -1236,45 +1236,21 @@ void TileCacheTests::testTileInvalidatePartImpress()
void TileCacheTests::checkTiles(std::shared_ptr& socket,
const std::string& docType, const std::string& testname)
{
- const std::string current = "current=";
- const std::string height = "height=";
- const std::string parts = "parts=";
- const std::string type = "type=";
- const std::string width = "width=";
-
int currentPart = -1;
int totalParts = 0;
int docHeight = 0;
int docWidth = 0;
+ int docViewId = -1;
// check total slides 10
sendTextFrame(socket, "status", testname);
const auto response = assertResponseString(socket, "status:", testname);
{
- std::string line;
- std::istringstream istr(response.substr(8));
- std::getline(istr, line);
-
- StringVector tokens(StringVector::tokenize(line, ' '));
-#if defined CPPUNIT_ASSERT_GREATEREQUAL
- if (docType == "presentation")
- CPPUNIT_ASSERT_GREATEREQUAL(static_cast(7),
- tokens.size()); // We have an extra field.
- else
- CPPUNIT_ASSERT_GREATEREQUAL(static_cast(6), tokens.size());
-#else
- if (docType == "presentation")
- LOK_ASSERT_EQUAL(static_cast(7), tokens.size()); // We have an extra field.
- else
- LOK_ASSERT_EQUAL(static_cast(6), tokens.size());
-#endif
+ std::string text = docType;
+
+ parseDocSize(response.substr(7), docType, currentPart, totalParts, docWidth, docHeight,
+ docViewId, testname);
- // Expected format is something like 'type= parts= current= width= height='.
- const std::string text = tokens[0].substr(type.size());
- totalParts = std::stoi(tokens[1].substr(parts.size()));
- currentPart = std::stoi(tokens[2].substr(current.size()));
- docWidth = std::stoi(tokens[3].substr(width.size()));
- docHeight = std::stoi(tokens[4].substr(height.size()));
LOK_ASSERT_EQUAL(docType, text);
LOK_ASSERT_EQUAL(10, totalParts);
LOK_ASSERT(currentPart > -1);
diff --git a/test/UnitInsertDelete.cpp b/test/UnitInsertDelete.cpp
index c29308a916cd..a470134fac65 100644
--- a/test/UnitInsertDelete.cpp
+++ b/test/UnitInsertDelete.cpp
@@ -27,52 +27,16 @@
namespace
{
-void getPartHashCodes(const std::string& testname, const std::string& response,
- std::vector& parts)
+std::vector getPartHashCodes(const Poco::SharedPtr status)
{
- std::string line;
- std::istringstream istr(response);
- std::getline(istr, line);
-
- TST_LOG("Reading parts from [" << response << "].");
-
- // Expected format is something like 'type= parts= current= width= height= viewid= [hiddenparts=]'.
- StringVector tokens(StringVector::tokenize(line, ' '));
-#if defined CPPUNIT_ASSERT_GREATEREQUAL
- CPPUNIT_ASSERT_GREATEREQUAL(static_cast(7), tokens.size());
-#else
- LOK_ASSERT_MESSAGE("Expected at least 7 tokens.", static_cast(7) <= tokens.size());
-#endif
-
- const std::string type = tokens[0].substr(std::string("type=").size());
- LOK_ASSERT_MESSAGE("Expected presentation or spreadsheet type to read part names/codes.",
- type == "presentation" || type == "spreadsheet");
-
- const int totalParts = std::stoi(tokens[1].substr(std::string("parts=").size()));
- TST_LOG("Status reports " << totalParts << " parts.");
-
- Poco::RegularExpression endLine("[^\n\r]+");
- Poco::RegularExpression number("^-?[0-9]+$");
- Poco::RegularExpression::MatchVec matches;
- int offset = 0;
-
- parts.clear();
- while (endLine.match(response, offset, matches) > 0)
- {
- LOK_ASSERT_EQUAL(1, (int)matches.size());
- const std::string str = response.substr(matches[0].offset, matches[0].length);
- if (number.match(str, 0))
- {
- parts.push_back(str);
- }
+ std::vector partHashes;
- offset = static_cast(matches[0].offset + matches[0].length);
+ for (std::size_t i = 0; i < status->getArray("parts")->size(); i++)
+ {
+ partHashes.push_back(status->getArray("parts")->getObject(i)->get("hash").toString());
}
- TST_LOG("Found " << parts.size() << " part names/codes.");
-
- // Validate that Core is internally consistent when emitting status messages.
- LOK_ASSERT_EQUAL(totalParts, (int)parts.size());
+ return partHashes;
}
}
@@ -97,7 +61,7 @@ UnitBase::TestResult UnitInsertDelete::testInsertDelete()
{
try
{
- std::vector parts;
+ std::vector currentPartHashes;
std::string response;
// Load a document
@@ -115,10 +79,16 @@ UnitBase::TestResult UnitInsertDelete::testInsertDelete()
helpers::sendTextFrame(socket, "status", testname);
response = helpers::getResponseString(socket, "status:", testname);
LOK_ASSERT_MESSAGE("did not receive a status: message as expected", !response.empty());
- getPartHashCodes(testname, response.substr(7), parts);
- LOK_ASSERT_EQUAL(1, (int)parts.size());
- const std::string slide1Hash = parts[0];
+ Poco::JSON::Parser parser;
+ Poco::Dynamic::Var statusJsonVar = parser.parse(response.substr(7));
+ const Poco::SharedPtr& statusJsonObject = statusJsonVar.extract();
+
+ currentPartHashes = getPartHashCodes(statusJsonObject);
+
+ LOK_ASSERT_EQUAL(static_cast(1), currentPartHashes.size());
+
+ const std::string slide1Hash = currentPartHashes[0];
// insert 10 slides
TST_LOG("Inserting 10 slides.");
@@ -128,13 +98,19 @@ UnitBase::TestResult UnitInsertDelete::testInsertDelete()
response = helpers::getResponseString(socket, "status:", testname);
LOK_ASSERT_MESSAGE("did not receive a status: message as expected",
!response.empty());
- getPartHashCodes(testname, response.substr(7), parts);
- LOK_ASSERT_EQUAL(it + 1, parts.size());
+
+ statusJsonVar = parser.parse(response.substr(7));
+ const Poco::SharedPtr& loopStatusJsonObject = statusJsonVar.extract();
+
+ currentPartHashes = getPartHashCodes(loopStatusJsonObject);
+
+ LOK_ASSERT_EQUAL(it + 1, currentPartHashes.size());
}
LOK_ASSERT_MESSAGE("Hash code of slide #1 changed after inserting extra slides.",
- parts[0] == slide1Hash);
- const std::vector parts_after_insert(parts.begin(), parts.end());
+ currentPartHashes[0] == slide1Hash);
+
+ const std::vector parts_after_insert = currentPartHashes;
// delete 10 slides
TST_LOG("Deleting 10 slides.");
@@ -146,12 +122,17 @@ UnitBase::TestResult UnitInsertDelete::testInsertDelete()
response = helpers::getResponseString(socket, "status:", testname);
LOK_ASSERT_MESSAGE("did not receive a status: message as expected",
!response.empty());
- getPartHashCodes(testname, response.substr(7), parts);
- LOK_ASSERT_EQUAL(11 - it, parts.size());
+
+ statusJsonVar = parser.parse(response.substr(7));
+ const Poco::SharedPtr& loopStatusJsonObject = statusJsonVar.extract();
+
+ currentPartHashes = getPartHashCodes(loopStatusJsonObject);
+
+ LOK_ASSERT_EQUAL(11 - it, currentPartHashes.size());
}
LOK_ASSERT_MESSAGE("Hash code of slide #1 changed after deleting extra slides.",
- parts[0] == slide1Hash);
+ currentPartHashes[0] == slide1Hash);
// undo delete slides
TST_LOG("Undoing 10 slide deletes.");
@@ -161,13 +142,20 @@ UnitBase::TestResult UnitInsertDelete::testInsertDelete()
response = helpers::getResponseString(socket, "status:", testname);
LOK_ASSERT_MESSAGE("did not receive a status: message as expected",
!response.empty());
- getPartHashCodes(testname, response.substr(7), parts);
- LOK_ASSERT_EQUAL(it + 1, parts.size());
+
+ statusJsonVar = parser.parse(response.substr(7));
+ const Poco::SharedPtr& loopStatusJsonObject = statusJsonVar.extract();
+
+ currentPartHashes = getPartHashCodes(loopStatusJsonObject);
+
+ LOK_ASSERT_EQUAL(it + 1, currentPartHashes.size());
}
LOK_ASSERT_MESSAGE("Hash code of slide #1 changed after undoing slide delete.",
- parts[0] == slide1Hash);
- const std::vector parts_after_undo(parts.begin(), parts.end());
+ currentPartHashes[0] == slide1Hash);
+
+ const std::vector parts_after_undo = currentPartHashes;
+
LOK_ASSERT_MESSAGE("Hash codes changed between deleting and undo.",
parts_after_insert == parts_after_undo);
@@ -179,20 +167,29 @@ UnitBase::TestResult UnitInsertDelete::testInsertDelete()
response = helpers::getResponseString(socket, "status:", testname);
LOK_ASSERT_MESSAGE("did not receive a status: message as expected",
!response.empty());
- getPartHashCodes(testname, response.substr(7), parts);
- LOK_ASSERT_EQUAL(11 - it, parts.size());
+
+ statusJsonVar = parser.parse(response.substr(7));
+ const Poco::SharedPtr& loopStatusJsonObject = statusJsonVar.extract();
+
+ currentPartHashes = getPartHashCodes(loopStatusJsonObject);
+
+ LOK_ASSERT_EQUAL(11 - it, currentPartHashes.size());
}
LOK_ASSERT_MESSAGE("Hash code of slide #1 changed after redoing slide delete.",
- parts[0] == slide1Hash);
+ currentPartHashes[0] == slide1Hash);
// check total slides 1
TST_LOG("Expecting 1 slide.");
helpers::sendTextFrame(socket, "status", testname);
response = helpers::getResponseString(socket, "status:", testname);
LOK_ASSERT_MESSAGE("did not receive a status: message as expected", !response.empty());
- getPartHashCodes(testname, response.substr(7), parts);
- LOK_ASSERT_EQUAL(1, (int)parts.size());
+
+ statusJsonVar = parser.parse(response.substr(7));
+ const Poco::SharedPtr& checkStatusJsonObject = statusJsonVar.extract();
+ currentPartHashes = getPartHashCodes(checkStatusJsonObject);
+
+ LOK_ASSERT_EQUAL((long unsigned int)1, currentPartHashes.size());
}
catch (const Poco::Exception& exc)
{
diff --git a/test/UnitLoadTorture.cpp b/test/UnitLoadTorture.cpp
index c782547f2d62..4abad0e3b446 100644
--- a/test/UnitLoadTorture.cpp
+++ b/test/UnitLoadTorture.cpp
@@ -79,7 +79,11 @@ void UnitLoadTorture::loadTorture(const std::string& name, const std::string& do
const std::string status = COOLProtocol::getFirstLine(message);
int viewid = -1;
- LOK_ASSERT(COOLProtocol::getTokenIntegerFromMessage(status, "viewid", viewid));
+ Poco::JSON::Parser parser;
+ Poco::Dynamic::Var statusJsonVar = parser.parse(status.substr(7));
+ const Poco::SharedPtr& statusJsonObject = statusJsonVar.extract();
+ if (statusJsonObject->has("viewid"))
+ viewid = std::atoi(statusJsonObject->get("viewid").toString().c_str());
LOK_ASSERT("Failed to create view in time " && viewid >= 0);
diff --git a/test/UnitRenderingOptions.cpp b/test/UnitRenderingOptions.cpp
index 5b89932b4951..08aab491c268 100644
--- a/test/UnitRenderingOptions.cpp
+++ b/test/UnitRenderingOptions.cpp
@@ -55,15 +55,11 @@ void UnitRenderingOptions::invokeWSDTest()
helpers::sendTextFrame(socket, "status", testname);
const auto status = helpers::assertResponseString(socket, "status:", testname);
- // Expected format is something like 'status: type=text parts=2 current=0 width=12808 height=1142'.
+ Poco::JSON::Parser parser;
+ Poco::Dynamic::Var statusJsonVar = parser.parse(status.substr(7));
+ const Poco::SharedPtr& statusJsonObject = statusJsonVar.extract();
- StringVector tokens(StringVector::tokenize(status, ' '));
- LOK_ASSERT_EQUAL(static_cast(8), tokens.size());
-
- const std::string token = tokens[5];
- const std::string prefix = "height=";
- LOK_ASSERT_EQUAL(static_cast(0), token.find(prefix));
- const int height = std::stoi(token.substr(prefix.size()));
+ const int height = std::stoi(statusJsonObject->get("height").toString());
// HideWhitespace was ignored, this was 32532, should be around 16706.
LOK_ASSERT(height < 20000);
}
diff --git a/test/helpers.hpp b/test/helpers.hpp
index 4fcfae720a88..48e3aed81d82 100644
--- a/test/helpers.hpp
+++ b/test/helpers.hpp
@@ -702,15 +702,16 @@ void parseDocSize(const std::string& message, const std::string& type,
int& part, int& parts, int& width, int& height, int& viewid,
const std::string& testname)
{
- StringVector tokens(StringVector::tokenize(message, ' '));
-
- // Expected format is something like 'type= parts= current= width= height='.
- const std::string text = tokens[0].substr(std::string("type=").size());
- parts = std::stoi(tokens[1].substr(std::string("parts=").size()));
- part = std::stoi(tokens[2].substr(std::string("current=").size()));
- width = std::stoi(tokens[3].substr(std::string("width=").size()));
- height = std::stoi(tokens[4].substr(std::string("height=").size()));
- viewid = std::stoi(tokens[5].substr(std::string("viewid=").size()));
+ Poco::JSON::Parser parser;
+ Poco::Dynamic::Var statusJsonVar = parser.parse(message);
+ const Poco::SharedPtr& statusJsonObject = statusJsonVar.extract();
+
+ const std::string text = statusJsonObject->get("type").toString();
+ parts = std::stoi(statusJsonObject->get("partscount").toString());
+ part = std::stoi(statusJsonObject->get("selectedpart").toString());
+ width = std::stoi(statusJsonObject->get("width").toString());
+ height = std::stoi(statusJsonObject->get("height").toString());
+ viewid = std::stoi(statusJsonObject->get("viewid").toString());
LOK_ASSERT_EQUAL(type, text);
LOK_ASSERT(parts > 0);
LOK_ASSERT(part >= 0);
diff --git a/tools/KitClient.cpp b/tools/KitClient.cpp
index cc29950d606f..82a25794eadc 100644
--- a/tools/KitClient.cpp
+++ b/tools/KitClient.cpp
@@ -114,10 +114,6 @@ class LOKitClient: public Application
continue;
}
std::cout << LOKitHelper::documentStatus(loKitDocument) << std::endl;
- for (int i = 0; i < loKitDocument->pClass->getParts(loKitDocument); i++)
- {
- std::cout << " " << i << ": '" << loKitDocument->pClass->getPartName(loKitDocument, i) << '\'' << std::endl;
- }
}
else if (tokens.equals(0, "tile"))
{
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 415186febe2e..97946d3a782b 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -2318,40 +2318,31 @@ bool ClientSession::handleKitToClientMessage(const std::shared_ptr& pay
docBroker->forwardToChild(client_from_this(), renderThumbnailCmd);
}
- for(auto &token : tokens)
- {
- // Need to get the initial part id from status message
- int part = -1;
- if(getTokenInteger(tokens.getParam(token), "current", part))
- {
- _clientSelectedPart = part;
- }
-
- int mode = 0;
- if(getTokenInteger(tokens.getParam(token), "mode", mode))
- _clientSelectedMode = static_cast(mode);
+ Poco::JSON::Parser parser;
+ Poco::Dynamic::Var statusJsonVar = parser.parse(firstLine.substr(7));
+ const Poco::SharedPtr& statusJsonObject = statusJsonVar.extract();
- // Get document type too
- std::string docType;
- if(getTokenString(tokens.getParam(token), "type", docType))
- {
- _isTextDocument = docType.find("text") != std::string::npos;
- }
+ if (statusJsonObject->has("selectedpart"))
+ _clientSelectedPart = std::atoi(statusJsonObject->get("selectedpart").toString().c_str());
- // Store our Kit ViewId
- int viewId = -1;
- if(getTokenInteger(tokens.getParam(token), "viewid", viewId))
- _kitViewId = viewId;
- }
+ if (statusJsonObject->has("mode"))
+ _clientSelectedMode = static_cast(std::atoi(statusJsonObject->get("mode").toString().c_str()));
+ if (statusJsonObject->has("type"))
+ _isTextDocument = statusJsonObject->get("type").toString() == "text";
+ if (statusJsonObject->has("viewid"))
+ _kitViewId = std::atoi(statusJsonObject->get("viewid").toString().c_str());
// Forward the status response to the client.
return forwardToClient(payload);
}
else if (tokens.equals(0, "statusupdate:"))
{
- uint32_t newValue;
- if (tokens.getUInt32(7, "mode", newValue))
- this->_clientSelectedMode = static_cast(newValue);
+ Poco::JSON::Parser parser;
+ Poco::Dynamic::Var statusJsonVar = parser.parse(firstLine.substr(13));
+ const Poco::SharedPtr& statusJsonObject = statusJsonVar.extract();
+
+ if (statusJsonObject->has("mode"))
+ _clientSelectedMode = static_cast(std::atoi(statusJsonObject->get("mode").toString().c_str()));
}
else if (tokens.equals(0, "commandvalues:"))
{