diff --git a/browser/css/spreadsheet.css b/browser/css/spreadsheet.css index 6cfb0865d7..55176635e7 100644 --- a/browser/css/spreadsheet.css +++ b/browser/css/spreadsheet.css @@ -25,7 +25,8 @@ text-decoration: none; font: var(--default-font-size)/1.5 var(--cool-font); - display: inline-block; + display: inline-grid; + grid-auto-flow: column; border: 1px solid transparent; border-radius: var(--border-radius); background: var(--color-main-background); @@ -38,6 +39,13 @@ border: 1px solid var(--color-border-dark); } +.spreadsheet-tab.spreadsheet-tab-protected > .lock, .spreadsheet-tab.spreadsheet-tab-protected:hover > .lock { + width: 16px; + height: 16px; + background-image: url('images/lc_protect.svg') !important; + background-repeat: no-repeat !important; +} + #spreadsheet-tab-scroll button.spreadsheet-tab-selected:hover { background-color: var(--color-primary-dark) !important; color: var(--color-primary-text) !important; diff --git a/browser/src/control/Control.Tabs.js b/browser/src/control/Control.Tabs.js index 05d312dd07..b63d6ce395 100644 --- a/browser/src/control/Control.Tabs.js +++ b/browser/src/control/Control.Tabs.js @@ -203,6 +203,8 @@ L.Control.Tabs = L.Control.extend({ dropZoneIndicator.id = 'drop-zone-' + i; var id = 'spreadsheet-tab' + i; var tab = L.DomUtil.create('button', 'spreadsheet-tab', ssTabScroll); + L.DomUtil.create('div', 'lock', tab); + let label = L.DomUtil.create('div', '', tab); if (window.mode.isMobile() || window.mode.isTablet()) { (new Hammer(tab, {recognizers: [[Hammer.Press]]})) .on('press', function (j) { @@ -239,7 +241,13 @@ L.Control.Tabs = L.Control.extend({ }(i).bind(this)); } - tab.textContent = e.partNames[i]; + if (e.protectedParts[i]) { + L.DomUtil.addClass(tab, 'spreadsheet-tab-protected'); + } + else { + L.DomUtil.removeClass(tab, 'spreadsheet-tab-protected'); + } + label.textContent = e.partNames[i]; tab.id = id; L.DomEvent @@ -311,7 +319,7 @@ L.Control.Tabs = L.Control.extend({ }, _setPart: function (e) { - var part = e.target.id.match(/\d+/g)[0]; + var part = e.currentTarget.id.match(/\d+/g)[0]; if (part !== null) { this._setPartIndex(parseInt(part)); } diff --git a/browser/src/core/Socket.js b/browser/src/core/Socket.js index 869ad63c84..994bbada67 100644 --- a/browser/src/core/Socket.js +++ b/browser/src/core/Socket.js @@ -1760,6 +1760,13 @@ app.definitions.Socket = L.Class.extend({ command.rtlParts.push(parseInt(item)); }); } + else if (tokens[i].startsWith('protectedparts=')) { + let protectedParts = tokens[i].substring(15).split(','); + command.protectedParts = []; + protectedParts.forEach(function (item) { + command.protectedParts.push(parseInt(item)); + }); + } else if (tokens[i].startsWith('hash=')) { command.hash = tokens[i].substring('hash='.length); } diff --git a/browser/src/layer/tile/CalcTileLayer.js b/browser/src/layer/tile/CalcTileLayer.js index 3f10dd044b..43a668f21e 100644 --- a/browser/src/layer/tile/CalcTileLayer.js +++ b/browser/src/layer/tile/CalcTileLayer.js @@ -430,6 +430,14 @@ L.CalcTileLayer = L.CanvasTileLayer.extend({ this._updateMaxBounds(true); } this._hiddenParts = command.hiddenparts || []; + + let pparts = []; + pparts.length = command.parts; + this._protectedParts = pparts.fill(false, 0, command.parts); + if (command.protectedParts) { + command.protectedParts.forEach(i => this._protectedParts[i] = true); + } + this._handleRTLFlags(command); this._documentInfo = textMsg; var partNames = textMsg.match(/[^\r\n]+/g); @@ -441,6 +449,7 @@ L.CalcTileLayer = L.CanvasTileLayer.extend({ docType: this._docType, partNames: this._partNames, hiddenParts: this._hiddenParts, + protectedParts: this._protectedParts, source: 'status' }); this._resetPreFetching(true); diff --git a/kit/KitHelper.hpp b/kit/KitHelper.hpp index e2f987daa7..0b86c08cbd 100644 --- a/kit/KitHelper.hpp +++ b/kit/KitHelper.hpp @@ -14,6 +14,7 @@ #include #include +#include #include #define LOK_USE_UNSTABLE_API @@ -79,6 +80,7 @@ namespace LOKitHelper std::ostringstream hposs; std::ostringstream sposs; std::ostringstream rtlposs; + std::ostringstream protectss; std::string mode; for (int i = 0; i < parts; ++i) { @@ -103,6 +105,11 @@ namespace LOKitHelper if (prop.second == "1") rtlposs << i << ','; } + else if (name == "protected") + { + if (prop.second == "1") + protectss << i << ','; + } else if (name == "mode" && mode.empty()) { std::ostringstream modess; @@ -136,6 +143,13 @@ namespace LOKitHelper 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");