[Libreoffice-commits] online.git: loleaflet/src
Marco Cecchetti
marco.cecchetti at collabora.com
Wed Nov 29 11:42:47 UTC 2017
loleaflet/src/control/Control.ColumnHeader.js | 181 +++++++++-------
loleaflet/src/control/Control.Header.js | 294 +++++++++++++++++++++-----
loleaflet/src/control/Control.RowHeader.js | 166 ++++++++------
3 files changed, 435 insertions(+), 206 deletions(-)
New commits:
commit 94591b22f2087b8ac72b0ccfdfe349466b742146
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date: Thu Nov 9 18:58:09 2017 +0100
loleaflet: sc: handle header data subdiveded in ranges
Change-Id: I54b8bc80af91414d8a804e54a478a2eb452510e3
Reviewed-on: https://gerrit.libreoffice.org/44674
Reviewed-by: Marco Cecchetti <mrcekets at gmail.com>
Tested-by: Marco Cecchetti <mrcekets at gmail.com>
diff --git a/loleaflet/src/control/Control.ColumnHeader.js b/loleaflet/src/control/Control.ColumnHeader.js
index 27765ec7..264fea4d 100644
--- a/loleaflet/src/control/Control.ColumnHeader.js
+++ b/loleaflet/src/control/Control.ColumnHeader.js
@@ -57,8 +57,7 @@ L.Control.ColumnHeader = L.Control.Header.extend({
callback: function(key, options) {
var index = colHeaderObj._lastMouseOverIndex;
if (index) {
- var colAlpha = colHeaderObj._data[index].text;
- colHeaderObj.insertColumn.call(colHeaderObj, colAlpha);
+ colHeaderObj.insertColumn.call(colHeaderObj, index);
}
}
},
@@ -67,8 +66,7 @@ L.Control.ColumnHeader = L.Control.Header.extend({
callback: function(key, options) {
var index = colHeaderObj._lastMouseOverIndex;
if (index) {
- var colAlpha = colHeaderObj._data[index].text;
- colHeaderObj.deleteColumn.call(colHeaderObj, colAlpha);
+ colHeaderObj.deleteColumn.call(colHeaderObj, index);
}
}
},
@@ -77,8 +75,7 @@ L.Control.ColumnHeader = L.Control.Header.extend({
callback: function(key, options) {
var index = colHeaderObj._lastMouseOverIndex;
if (index) {
- var colAlpha = colHeaderObj._data[index].text;
- colHeaderObj.optimalWidth.call(colHeaderObj, colAlpha);
+ colHeaderObj.optimalWidth.call(colHeaderObj, index);
}
}
},
@@ -87,8 +84,7 @@ L.Control.ColumnHeader = L.Control.Header.extend({
callback: function(key, options) {
var index = colHeaderObj._lastMouseOverIndex;
if (index) {
- var colAlpha = colHeaderObj._data[index].text;
- colHeaderObj.hideColumn.call(colHeaderObj, colAlpha);
+ colHeaderObj.hideColumn.call(colHeaderObj, index);
}
}
},
@@ -97,8 +93,7 @@ L.Control.ColumnHeader = L.Control.Header.extend({
callback: function(key, options) {
var index = colHeaderObj._lastMouseOverIndex;
if (index) {
- var colAlpha = colHeaderObj._data[index].text;
- colHeaderObj.showColumn.call(colHeaderObj, colAlpha);
+ colHeaderObj.showColumn.call(colHeaderObj, index);
}
}
}
@@ -107,50 +102,50 @@ L.Control.ColumnHeader = L.Control.Header.extend({
});
},
- optimalWidth: function(colAlpha) {
+ optimalWidth: function(index) {
if (!this._dialog) {
this._dialog = L.control.metricInput(this._onDialogResult, this,
this._map._docLayer.twipsToHMM(this._map._docLayer.STD_EXTRA_WIDTH),
{title: _('Optimal Column Width')});
}
if (this._map._docLayer._selections.getLayers().length === 0) {
- this._selectColumn(colAlpha, 0);
+ this._selectColumn(index, 0);
}
this._dialog.addTo(this._map);
this._map.enable(false);
this._dialog.show();
},
- insertColumn: function(colAlpha) {
+ insertColumn: function(index) {
// First select the corresponding column because
// .uno:InsertColumn doesn't accept any column number
// as argument and just inserts before the selected column
if (this._map._docLayer._selections.getLayers().length === 0) {
- this._selectColumn(colAlpha, 0);
+ this._selectColumn(index, 0);
}
this._map.sendUnoCommand('.uno:InsertColumns');
this._updateColumnHeader();
},
- deleteColumn: function(colAlpha) {
+ deleteColumn: function(index) {
if (this._map._docLayer._selections.getLayers().length === 0) {
- this._selectColumn(colAlpha, 0);
+ this._selectColumn(index, 0);
}
this._map.sendUnoCommand('.uno:DeleteColumns');
this._updateColumnHeader();
},
- hideColumn: function(colAlpha) {
+ hideColumn: function(index) {
if (this._map._docLayer._selections.getLayers().length === 0) {
- this._selectColumn(colAlpha, 0);
+ this._selectColumn(index, 0);
}
this._map.sendUnoCommand('.uno:HideColumn');
this._updateColumnHeader();
},
- showColumn: function(colAlpha) {
+ showColumn: function(index) {
if (this._map._docLayer._selections.getLayers().length === 0) {
- this._selectColumn(colAlpha, 0);
+ this._selectColumn(index, 0);
}
this._map.sendUnoCommand('.uno:ShowColumn');
this._updateColumnHeader();
@@ -171,50 +166,44 @@ L.Control.ColumnHeader = L.Control.Header.extend({
},
_onUpdateSelection: function (e) {
- var data = this._data;
- if (!data)
- return;
var start = e.start.x;
var end = e.end.x;
- var twips;
if (start !== -1) {
- twips = new L.Point(start, start);
- start = Math.round(data.converter.call(data.context, twips).x);
+ start = this._twipsToPixels(start);
}
if (end !== -1) {
- twips = new L.Point(end, end);
- end = Math.round(data.converter.call(data.context, twips).x);
+ end = this._twipsToPixels(end);
}
- this.updateSelection(data, start, end);
+ this.updateSelection(this._data, start, end);
},
_onUpdateCurrentColumn: function (e) {
- var data = this._data;
- if (!data)
- return;
var x = e.x;
if (x !== -1) {
- var twips = new L.Point(x, x);
- x = Math.round(data.converter.call(data.context, twips).x);
+ x = this._twipsToPixels(x);
}
- this.updateCurrent(data, x);
+ this.updateCurrent(this._data, x);
},
_updateColumnHeader: function () {
this._map.fire('updaterowcolumnheaders', {x: this._map._getTopLeftPoint().x, y: 0, offset: {x: undefined, y: 0}});
},
- drawHeaderEntry: function (index, isOver) {
- if (!index || index <= 0 || index >= this._data.length)
+ drawHeaderEntry: function (entry, isOver, isHighlighted) {
+ if (!entry)
return;
var ctx = this._canvasContext;
- var content = this._data[index].text;
- var start = this._data[index - 1].pos - this._leftOffset;
- var end = this._data[index].pos - this._leftOffset;
+ var content = this._colIndexToAlpha(entry.index + this._leftmostColumn);
+ var start = entry.pos - entry.size - this._leftOffset;
+ var end = entry.pos - this._leftOffset;
var width = end - start;
var height = this._headerCanvas.height;
- var isHighlighted = this._data[index].selected;
+
+ if (isHighlighted !== true && isHighlighted !== false) {
+ isHighlighted = this.isHighlighted(entry.index);
+ }
+
if (width <= 0)
return;
@@ -249,22 +238,23 @@ L.Control.ColumnHeader = L.Control.Header.extend({
},
getHeaderEntryBoundingClientRect: function (index) {
- if (!index)
- index = this._mouseOverIndex; // use last mouse over position
+ var entry = this._mouseOverEntry;
+ if (index)
+ entry = this._data.get(index);
- if (!index || !this._data[index])
+ if (!entry)
return;
var rect = this._headerCanvas.getBoundingClientRect();
- var colStart = this._data[index - 1].pos + this._position;
- var colEnd = this._data[index].pos + this._position;
+ var colStart = entry.pos - entry.size + this._position;
+ var colEnd = entry.pos + this._position;
var left = rect.left + colStart;
var right = rect.left + colEnd;
var top = rect.top;
var bottom = rect.bottom;
- return { left: left, right: right, top: top, bottom: bottom };
+ return {left: left, right: right, top: top, bottom: bottom};
},
viewRowColumnHeaders: function (e) {
@@ -274,31 +264,57 @@ L.Control.ColumnHeader = L.Control.Header.extend({
},
fillColumns: function (columns, converter, context) {
- var iterator, twip, width;
+ if (columns.length < 2)
+ return;
- this._data = new Array(columns.length);
- this._data.converter = converter;
- this._data.context = context;
+ var entry, index, iterator, pos, width;
var canvas = this._headerCanvas;
canvas.width = parseInt(L.DomUtil.getStyle(this._headersContainer, 'width'));
canvas.height = parseInt(L.DomUtil.getStyle(this._headersContainer, 'height'));
-
this._canvasContext.clearRect(0, 0, canvas.width, canvas.height);
- var leftmostOffset = new L.Point(columns[0].size, columns[0].size);
+ // update first header index and reset no more valid variables
this._leftmostColumn = parseInt(columns[0].text);
- this._leftOffset = Math.round(converter.call(context, leftmostOffset).x);
+ this._current = -1; // no more valid
+ this._selection.start = this._selection.end = -1; // no more valid
+ this._mouseOverEntry = null;
+ this._lastMouseOverIndex = undefined;
+
+ // create header data handler instance
+ this._data = new L.Control.Header.DataImpl();
+
+ // setup conversion routine
+ this.converter = L.Util.bind(converter, context);
+ this._data.converter = L.Util.bind(this._twipsToPixels, this);
+
+ var startOffsetTw = parseInt(columns[0].size);
+ this._leftOffset = this._twipsToPixels(startOffsetTw);
+
+ this._data.pushBack(0, {pos: startOffsetTw, size: 0});
+ var prevPos = startOffsetTw;
+ var nextIndex = parseInt(columns[1].text);
+ var last = columns.length - 1;
+ for (iterator = 1; iterator < last; iterator++) {
+ index = nextIndex;
+ pos = parseInt(columns[iterator].size);
+ nextIndex = parseInt(columns[iterator+1].text);
+ width = pos - prevPos;
+ prevPos = Math.round(pos + width * (nextIndex - index - 1));
+ index = index - this._leftmostColumn;
+ entry = {pos: pos, size: width};
+ this._data.pushBack(index, entry);
+ }
- this._data[0] = { pos: this._leftOffset, text: '', selected: false };
+ // setup last header entry
+ pos = parseInt(columns[last].size);
+ this._data.pushBack(nextIndex - this._leftmostColumn, {pos: pos, size: pos - prevPos});
- for (iterator = 1; iterator < columns.length; iterator++) {
- twip = new L.Point(columns[iterator].size, columns[iterator].size);
- this._data[iterator] = { pos: Math.round(converter.call(context, twip).x), text: columns[iterator].text, selected: false };
- width = this._data[iterator].pos - this._data[iterator - 1].pos;
- if (width > 0) {
- this.drawHeaderEntry(iterator, false);
- }
+ // draw header
+ entry = this._data.getFirst();
+ while (entry) {
+ this.drawHeaderEntry(entry, false);
+ entry = this._data.getNext();
}
this.mouseInit(canvas);
@@ -320,13 +336,26 @@ L.Control.ColumnHeader = L.Control.Header.extend({
return res;
},
- _selectColumn: function(colAlpha, modifier) {
- var colNumber = this._colAlphaToNumber(colAlpha);
+ _colIndexToAlpha: function(columnNumber) {
+ var offset = 'A'.charCodeAt();
+ var dividend = columnNumber;
+ var columnName = '';
+ var modulo;
+
+ while (dividend > 0) {
+ modulo = (dividend - 1) % 26;
+ columnName = String.fromCharCode(offset + modulo) + columnName;
+ dividend = Math.floor((dividend - modulo) / 26);
+ }
+
+ return columnName;
+ },
+ _selectColumn: function(colNumber, modifier) {
var command = {
Col: {
type: 'unsigned short',
- value: parseInt(colNumber - 1)
+ value: colNumber - 1
},
Modifier: {
type: 'unsigned short',
@@ -338,10 +367,10 @@ L.Control.ColumnHeader = L.Control.Header.extend({
},
_onHeaderClick: function (e) {
- if (!this._mouseOverIndex)
+ if (!this._mouseOverEntry)
return;
- var colAlpha = this._data[this._mouseOverIndex].text;
+ var col = this._mouseOverEntry.index + this._leftmostColumn;
var modifier = 0;
if (e.shiftKey) {
@@ -351,7 +380,7 @@ L.Control.ColumnHeader = L.Control.Header.extend({
modifier += this._map.keyboard.keyModifier.ctrl;
}
- this._selectColumn(colAlpha, modifier);
+ this._selectColumn(col, modifier);
},
_onCornerHeaderClick: function() {
@@ -403,14 +432,14 @@ L.Control.ColumnHeader = L.Control.Header.extend({
var end = new L.Point(e.clientX + offset.x, e.clientY);
var distance = this._map._docLayer._pixelsToTwips(end.subtract(start));
- if (this._mouseOverIndex) {
- var clickedColumn = this._data[this._mouseOverIndex];
- var width = clickedColumn.pos - this._data[this._mouseOverIndex - 1];
- var column = this._mouseOverIndex + this._leftmostColumn;
+ var clickedColumn = this._mouseOverEntry;
+ if (clickedColumn) {
+ var width = clickedColumn.size;
+ var column = clickedColumn.index + this._leftmostColumn;
- if (this._data[this._mouseOverIndex + 1]
- && this._data[this._mouseOverIndex + 1].pos === clickedColumn.pos) {
+ if (this._data.isZeroSize(clickedColumn.index + 1)) {
column += 1;
+ width = 0;
}
if (width !== distance.x) {
@@ -436,11 +465,11 @@ L.Control.ColumnHeader = L.Control.Header.extend({
onDragClick: function (item, clicks, e) {
this._map.removeLayer(this._vertLine);
- if (!this._mouseOverIndex)
+ if (!this._mouseOverEntry)
return;
if (clicks === 2) {
- var column = this._mouseOverIndex + this._leftmostColumn;
+ var column = this._mouseOverEntry.index + this._leftmostColumn;
var command = {
Col: {
type: 'unsigned short',
diff --git a/loleaflet/src/control/Control.Header.js b/loleaflet/src/control/Control.Header.js
index a94663a2..d7689ee0 100644
--- a/loleaflet/src/control/Control.Header.js
+++ b/loleaflet/src/control/Control.Header.js
@@ -8,11 +8,13 @@ L.Control.Header = L.Control.extend({
},
initialize: function () {
+ this.converter = null;
+
this._headerCanvas = null;
this._clicks = 0;
this._current = -1;
this._selection = {start: -1, end: -1};
- this._mouseOverIndex = undefined;
+ this._mouseOverEntry = null;
this._lastMouseOverIndex = undefined;
this._hitResizeArea = false;
@@ -77,65 +79,82 @@ L.Control.Header = L.Control.extend({
L.DomEvent.on(element, 'mousedown', this._onMouseDown, this);
},
- select: function (data, index) {
- if (!data[index])
- return;
- data[index].selected = true;
- this.drawHeaderEntry(index, false);
+ select: function (entry) {
+ this.drawHeaderEntry(entry, /*isOver=*/false, /*isHighlighted=*/true);
},
- unselect: function (data, index) {
- if (!data[index])
- return;
- data[index].selected = false;
- this.drawHeaderEntry(index, false);
+ unselect: function (entry) {
+ this.drawHeaderEntry(entry, /*isOver=*/false, /*isHighlighted=*/false);
+ },
+
+ isHighlighted: function (index) {
+ if (this._selection.start === -1 && this._selection.end === -1) {
+ return index === this._current;
+ }
+ return (this._selection.start <= index && index <= this._selection.end);
},
clearSelection: function (data) {
if (this._selection.start === -1 && this._selection.end === -1)
return;
- var start = (this._selection.start === -1) ? 0 : this._selection.start;
+ var start = (this._selection.start < 1) ? 1 : this._selection.start;
var end = this._selection.end + 1;
- for (var iterator = start; iterator < end; iterator++) {
- this.unselect(data, iterator);
+
+ var entry = data.getAt(start);
+
+ while (entry && entry.index < end) {
+ this.unselect(entry);
+ entry = data.getNext(start);
}
this._selection.start = this._selection.end = -1;
// after clearing selection, we need to select the header entry for the current cursor position,
// since we can't be sure that the selection clearing is due to click on a cell
// different from the one where the cursor is already placed
- this.select(data, this._current);
+ this.select(data.get(this._current));
},
updateSelection: function(data, start, end) {
- if (!data)
+ if (!data || data.isEmpty())
return;
var x0 = 0, x1 = 0;
var itStart = -1, itEnd = -1;
var selected = false;
- var iterator = 0;
- for (var len = data.length; iterator < len; iterator++) {
- x0 = (iterator > 0 ? data[iterator - 1].pos : 0);
- x1 = data[iterator].pos;
- // 'start < x1' not '<=' or we get highlighted also the `start-row - 1` and `start-column - 1` headers
+
+ // if the start selection position is above/on the left of the first header entry,
+ // but the end selection position is below/on the right of it
+ // then we set the start selected entry to the first header entry.
+ var entry = data.getFirst();
+ if (entry) {
+ x0 = entry.pos - entry.size;
+ if (start < x0 && end > x0) {
+ selected = true;
+ itStart = 1;
+ }
+ }
+
+ while (entry) {
+ x0 = entry.pos - entry.size;
+ x1 = entry.pos;
if (x0 <= start && start < x1) {
selected = true;
- itStart = iterator;
+ itStart = entry.index;
}
if (selected) {
- this.select(data, iterator);
+ this.select(entry);
}
if (x0 <= end && end <= x1) {
- itEnd = iterator;
+ itEnd = entry.index;
break;
}
+ entry = data.getNext();
}
// if end is greater than the last fetched header position set itEnd to the max possible value
// without this hack selecting a whole row and then a whole column (or viceversa) leads to an incorrect selection
if (itStart !== -1 && itEnd === -1) {
- itEnd = data.length - 1;
+ itEnd = data.getLength() - 1;
}
// we need to unselect the row (column) header entry for the current cell cursor position
@@ -143,17 +162,22 @@ L.Control.Header = L.Control.extend({
// does not start by clicking on a cell
if (this._current !== -1 && itStart !== -1 && itEnd !== -1) {
if (this._current < itStart || this._current > itEnd) {
- this.unselect(data, this._current);
+ this.unselect(data.get(this._current));
}
}
+
if (this._selection.start !== -1 && itStart !== -1 && itStart > this._selection.start) {
- for (iterator = this._selection.start; iterator < itStart; iterator++) {
- this.unselect(data, iterator);
+ entry = data.getAt(this._selection.start);
+ while (entry && entry.index < itStart) {
+ this.unselect(entry);
+ entry = data.getNext();
}
}
if (this._selection.end !== -1 && itEnd !== -1 && itEnd < this._selection.end) {
- for (iterator = itEnd + 1; iterator <= this._selection.end; iterator++) {
- this.unselect(data, iterator);
+ entry = data.getAt(itEnd + 1);
+ while (entry && entry.index <= this._selection.end) {
+ this.unselect(entry);
+ entry = data.getNext();
}
}
this._selection.start = itStart;
@@ -161,30 +185,33 @@ L.Control.Header = L.Control.extend({
},
updateCurrent: function (data, start) {
- if (!data)
+ if (!data || data.isEmpty())
return;
+
if (start < 0) {
- this.unselect(data, this._current);
+ this.unselect(data.get(this._current));
this._current = -1;
return;
}
var x0 = 0, x1 = 0;
- for (var iterator = 1, len = data.length; iterator < len; iterator++) {
- x0 = (iterator > 0 ? data[iterator - 1].pos : 0);
- x1 = data[iterator].pos;
+ var entry = data.getFirst();
+ while (entry) {
+ x0 = entry.pos - entry.size;
+ x1 = entry.pos;
if (x0 <= start && start < x1) {
// when a whole row (column) is selected the cell cursor is moved to the first column (row)
// but this action should not cause to select/unselect anything, on the contrary we end up
// with all column (row) header entries selected but the one where the cell cursor was
// previously placed
if (this._selection.start === -1 && this._selection.end === -1) {
- this.unselect(data, this._current);
- this.select(data, iterator);
+ this.unselect(data.get(this._current));
+ this.select(entry);
}
- this._current = iterator;
+ this._current = entry.index;
break;
}
+ entry = data.getNext();
}
},
@@ -197,10 +224,10 @@ L.Control.Header = L.Control.extend({
},
_onMouseOut: function (e) {
- if (this._mouseOverIndex) {
- this.drawHeaderEntry(this._mouseOverIndex, false);
- this._lastMouseOverIndex = this._mouseOverIndex; // used by context menu
- this._mouseOverIndex = undefined;
+ if (this._mouseOverEntry) {
+ this.drawHeaderEntry(this._mouseOverEntry, false);
+ this._lastMouseOverIndex = this._mouseOverEntry.index; // used by context menu
+ this._mouseOverEntry = null;
}
this._hitResizeArea = false;
L.DomUtil.setStyle(this._headerCanvas, 'cursor', this._cursor);
@@ -217,25 +244,24 @@ L.Control.Header = L.Control.extend({
var pos = this._getPos(this._mouseEventToCanvasPos(this._headerCanvas, e));
pos = pos - this._position;
- var mouseOverIndex = this._mouseOverIndex;
- for (var iterator = 1; iterator < this._data.length; ++iterator) {
- var start = this._data[iterator - 1].pos;
- var end = this._data[iterator].pos;
+ var mouseOverIndex = this._mouseOverEntry ? this._mouseOverEntry.index : undefined;
+ var entry = this._data.getFirst();
+ while (entry) {
+ var start = entry.pos - entry.size;
+ var end = entry.pos;
if (pos > start && pos <= end) {
- mouseOverIndex = iterator;
+ mouseOverIndex = entry.index;
var resizeAreaStart = Math.max(start, end - 3);
isMouseOverResizeArea = (pos > resizeAreaStart);
break;
}
+ entry = this._data.getNext();
}
- if (mouseOverIndex !== this._mouseOverIndex) {
- if (this._mouseOverIndex) {
- this.drawHeaderEntry(this._mouseOverIndex, false);
- }
- if (mouseOverIndex) {
- this.drawHeaderEntry(mouseOverIndex, true);
- }
+ if (mouseOverIndex && (!this._mouseOverEntry || mouseOverIndex !== this._mouseOverEntry.index)) {
+ this.drawHeaderEntry(this._mouseOverEntry, false);
+ this.drawHeaderEntry(entry, true);
+ this._mouseOverEntry = entry;
}
if (isMouseOverResizeArea !== this._hitResizeArea) {
@@ -249,8 +275,6 @@ L.Control.Header = L.Control.extend({
L.DomUtil.setStyle(this._headerCanvas, 'cursor', cursor);
this._hitResizeArea = isMouseOverResizeArea;
}
-
- this._mouseOverIndex = mouseOverIndex;
},
_onMouseDown: function (e) {
@@ -311,6 +335,13 @@ L.Control.Header = L.Control.extend({
this._dragging = false;
},
+ _twipsToPixels: function (twips) {
+ if (!this.converter)
+ return 0;
+ var point = new L.Point(twips, twips);
+ return Math.round(this._getPos(this.converter(point)));
+ },
+
onDragStart: function () {},
onDragMove: function () {},
onDragEnd: function () {},
@@ -319,3 +350,154 @@ L.Control.Header = L.Control.extend({
drawHeaderEntry: function () {},
_getPos: function () {}
});
+
+(function () {
+
+ L.Control.Header.DataImpl = L.Class.extend({
+ initialize: function () {
+ this.converter = null;
+
+ this._currentIndex = undefined;
+ this._currentRange = undefined;
+ this._dataMap = {};
+ this._indexes = [];
+ this._endIndex = -1;
+ this._skipZeroSize = true;
+ },
+
+ _get: function (index, setCurrentIndex) {
+ if (index < 1 || index > this._endIndex)
+ return null;
+
+ var range = this._getFirstIndexLessOrEqual(index);
+ if (range !== undefined) {
+ if (setCurrentIndex) {
+ this._currentRange = range;
+ this._currentIndex = index;
+ }
+ return this._computeEntry(this._indexes[range], index);
+ }
+ },
+
+ get: function (index) {
+ return this._get(index, false);
+ },
+
+ getAt: function (index) {
+ return this._get(index, true);
+ },
+
+ getFirst: function () {
+ this._currentRange = 0;
+ this._currentIndex = this._indexes[this._currentRange];
+ return this.getNext();
+ },
+
+ getNext: function () {
+ if (this._currentIndex === undefined || this._currentRange === undefined)
+ return null; // you need to call getFirst on initial step
+
+ this._currentIndex += 1;
+ if (this._currentIndex >= this._endIndex) {
+ // we iterated over all entries, reset everything
+ this._currentIndex = undefined;
+ this._currentRange = undefined;
+ this._skipZeroSize = false;
+ return null;
+ }
+
+ if (this._indexes[this._currentRange+1] === this._currentIndex) {
+ // new range
+ this._currentRange += 1;
+
+ if (this._skipZeroSize) {
+ var index, i, len = this._indexes.length;
+ for (i = this._currentRange; i < len; ++i) {
+ index = this._indexes[i];
+ if (this._dataMap[index].size > 0) {
+ break;
+ }
+ }
+ this._currentRange = i;
+ this._currentIndex = index;
+ }
+ }
+
+ var startIndex = this._indexes[this._currentRange];
+ return this._computeEntry(startIndex, this._currentIndex);
+ },
+
+ pushBack: function (index, value) {
+ if (index <= this._endIndex)
+ return;
+ this._dataMap[index] = value;
+ this._indexes.push(index);
+ this._endIndex = index;
+ },
+
+ isZeroSize: function (index) {
+ if (!(index > 0 && index < this._endIndex)) {
+ return true;
+ }
+
+ var range = this._getFirstIndexLessOrEqual(index);
+ return this._dataMap[this._indexes[range]].size === 0;
+ },
+
+ getLength: function () {
+ return this._endIndex;
+ },
+
+ isEmpty: function () {
+ return this._indexes.length === 0;
+ },
+
+ _binaryIndexOf: function (collection, searchElement) {
+ var minIndex = 0;
+ var maxIndex = collection.length - 1;
+ var currentIndex;
+ var currentElement;
+
+ while (minIndex <= maxIndex) {
+ currentIndex = (minIndex + maxIndex) / 2 | 0;
+ currentElement = collection[currentIndex];
+
+ if (currentElement < searchElement) {
+ minIndex = currentIndex + 1;
+ }
+ else if (currentElement > searchElement) {
+ maxIndex = currentIndex - 1;
+ }
+ else {
+ return currentIndex;
+ }
+ }
+
+ if (currentIndex > maxIndex)
+ return currentIndex - 1;
+ if (currentIndex < minIndex)
+ return currentIndex;
+ },
+
+ _getFirstIndexLessOrEqual: function (index) {
+ return this._binaryIndexOf(this._indexes, index);
+ },
+
+ _twipsToPixels: function (twips) {
+ if (!this.converter)
+ return 0;
+
+ return this.converter(twips);
+ },
+
+ _computeEntry: function (startIndex, index) {
+ var entry = this._dataMap[startIndex];
+ var pos = entry.pos + (index - startIndex) * entry.size;
+ pos = this._twipsToPixels(pos);
+ var size = this._twipsToPixels(entry.size);
+ return {index: index, pos: pos, size: size};
+ }
+
+ });
+
+})();
\ No newline at end of file
diff --git a/loleaflet/src/control/Control.RowHeader.js b/loleaflet/src/control/Control.RowHeader.js
index 520a0893..4763f1b1 100644
--- a/loleaflet/src/control/Control.RowHeader.js
+++ b/loleaflet/src/control/Control.RowHeader.js
@@ -55,8 +55,7 @@ L.Control.RowHeader = L.Control.Header.extend({
callback: function(key, options) {
var index = rowHeaderObj._lastMouseOverIndex;
if (index) {
- var row = rowHeaderObj._data[index].text;
- rowHeaderObj.insertRow.call(rowHeaderObj, row);
+ rowHeaderObj.insertRow.call(rowHeaderObj, index);
}
}
},
@@ -65,8 +64,7 @@ L.Control.RowHeader = L.Control.Header.extend({
callback: function(key, options) {
var index = rowHeaderObj._lastMouseOverIndex;
if (index) {
- var row = rowHeaderObj._data[index].text;
- rowHeaderObj.deleteRow.call(rowHeaderObj, row);
+ rowHeaderObj.deleteRow.call(rowHeaderObj, index);
}
}
},
@@ -75,8 +73,7 @@ L.Control.RowHeader = L.Control.Header.extend({
callback: function(key, options) {
var index = rowHeaderObj._lastMouseOverIndex;
if (index) {
- var row = rowHeaderObj._data[index].text;
- rowHeaderObj.optimalHeight.call(rowHeaderObj, row);
+ rowHeaderObj.optimalHeight.call(rowHeaderObj, index);
}
}
},
@@ -85,8 +82,7 @@ L.Control.RowHeader = L.Control.Header.extend({
callback: function(key, options) {
var index = rowHeaderObj._lastMouseOverIndex;
if (index) {
- var row = rowHeaderObj._data[index].text;
- rowHeaderObj.hideRow.call(rowHeaderObj, row);
+ rowHeaderObj.hideRow.call(rowHeaderObj, index);
}
}
},
@@ -95,8 +91,7 @@ L.Control.RowHeader = L.Control.Header.extend({
callback: function(key, options) {
var index = rowHeaderObj._lastMouseOverIndex;
if (index) {
- var row = rowHeaderObj._data[index].text;
- rowHeaderObj.showRow.call(rowHeaderObj, row);
+ rowHeaderObj.showRow.call(rowHeaderObj, index);
}
}
}
@@ -105,45 +100,45 @@ L.Control.RowHeader = L.Control.Header.extend({
});
},
- optimalHeight: function(row) {
+ optimalHeight: function(index) {
if (!this._dialog) {
this._dialog = L.control.metricInput(this._onDialogResult, this, 0, {title: _('Optimal Row Height')});
}
if (this._map._docLayer._selections.getLayers().length === 0) {
- this._selectRow(row, 0);
+ this._selectRow(index, 0);
}
this._dialog.addTo(this._map);
this._map.enable(false);
this._dialog.show();
},
- insertRow: function(row) {
+ insertRow: function(index) {
// First select the corresponding row because
// .uno:InsertRows doesn't accept any row number
// as argument and just inserts before the selected row
if (this._map._docLayer._selections.getLayers().length === 0) {
- this._selectRow(row, 0);
+ this._selectRow(index, 0);
}
this._map.sendUnoCommand('.uno:InsertRows');
},
- deleteRow: function(row) {
+ deleteRow: function(index) {
if (this._map._docLayer._selections.getLayers().length === 0) {
- this._selectRow(row, 0);
+ this._selectRow(index, 0);
}
this._map.sendUnoCommand('.uno:DeleteRows');
},
- hideRow: function(row) {
+ hideRow: function(index) {
if (this._map._docLayer._selections.getLayers().length === 0) {
- this._selectRow(row, 0);
+ this._selectRow(index, 0);
}
this._map.sendUnoCommand('.uno:HideRow');
},
- showRow: function(row) {
+ showRow: function(index) {
if (this._map._docLayer._selections.getLayers().length === 0) {
- this._selectRow(row, 0);
+ this._selectRow(index, 0);
}
this._map.sendUnoCommand('.uno:ShowRow');
},
@@ -163,50 +158,43 @@ L.Control.RowHeader = L.Control.Header.extend({
},
_onUpdateSelection: function (e) {
- var data = this._data;
- if (!data)
- return;
var start = e.start.y;
var end = e.end.y;
- var twips;
if (start !== -1) {
- twips = new L.Point(start, start);
- start = Math.round(data.converter.call(data.context, twips).y);
+ start = this._twipsToPixels(start);
}
if (end !== -1) {
- twips = new L.Point(end, end);
- end = Math.round(data.converter.call(data.context, twips).y);
+ end = this._twipsToPixels(end);
}
- this.updateSelection(data, start, end);
+ this.updateSelection(this._data, start, end);
},
_onUpdateCurrentRow: function (e) {
- var data = this._data;
- if (!data)
- return;
var y = e.y;
if (y !== -1) {
- var twips = new L.Point(y, y);
- y = Math.round(data.converter.call(data.context, twips).y);
+ y = this._twipsToPixels(y);
}
- this.updateCurrent(data, y);
+ this.updateCurrent(this._data, y);
},
_updateRowHeader: function () {
this._map.fire('updaterowcolumnheaders', {x: 0, y: this._map._getTopLeftPoint().y, offset: {x: 0, y: undefined}});
},
- drawHeaderEntry: function (index, isOver) {
- if (!index || index <= 0 || index >= this._data.length)
+ drawHeaderEntry: function (entry, isOver, isHighlighted) {
+ if (!entry)
return;
var ctx = this._canvasContext;
- var content = this._data[index].text;
- var start = this._data[index - 1].pos - this._topOffset;
- var end = this._data[index].pos - this._topOffset;
+ var content = entry.index + this._topRow;
+ var start = entry.pos - entry.size - this._topOffset;
+ var end = entry.pos - this._topOffset;
var height = end - start;
var width = this._headerCanvas.width;
- var isHighlighted = this._data[index].selected;
+
+ if (isHighlighted !== true && isHighlighted !== false) {
+ isHighlighted = this.isHighlighted(entry.index);
+ }
if (height <= 0)
return;
@@ -241,22 +229,23 @@ L.Control.RowHeader = L.Control.Header.extend({
},
getHeaderEntryBoundingClientRect: function (index) {
- if (!index)
- index = this._mouseOverIndex; // use last mouse over position
+ var entry = this._mouseOverEntry;
+ if (index)
+ entry = this._data.get(index);
- if (!index || !this._data[index])
+ if (!entry)
return;
var rect = this._headerCanvas.getBoundingClientRect();
- var rowStart = this._data[index - 1].pos + this._position;
- var rowEnd = this._data[index].pos + this._position;
+ var rowStart = entry.pos - entry.size + this._position;
+ var rowEnd = entry.pos + this._position;
var left = rect.left;
var right = rect.right;
var top = rect.top + rowStart;
var bottom = rect.top + rowEnd;
- return { left: left, right: right, top: top, bottom: bottom };
+ return {left: left, right: right, top: top, bottom: bottom};
},
viewRowColumnHeaders: function (e) {
@@ -266,31 +255,60 @@ L.Control.RowHeader = L.Control.Header.extend({
},
fillRows: function (rows, converter, context) {
- var iterator, twip, height;
+ if (rows.length < 2)
+ return;
- this._data = new Array(rows.length);
- this._data.converter = converter;
- this._data.context = context;
+ var entry, index, iterator, height, pos;
var canvas = this._headerCanvas;
canvas.width = parseInt(L.DomUtil.getStyle(this._headersContainer, 'width'));
canvas.height = parseInt(L.DomUtil.getStyle(this._headersContainer, 'height'));
-
this._canvasContext.clearRect(0, 0, canvas.width, canvas.height);
- var topOffset = new L.Point(rows[0].size, rows[0].size);
+ // update first header index and reset no more valid variables
this._topRow = parseInt(rows[0].text);
- this._topOffset = Math.round(converter.call(context, topOffset).y);
-
- this._data[0] = { pos: this._topOffset, text: '', selected: false };
+ this._current = -1;
+ this._selection.start = this._selection.end = -1;
+ this._mouseOverEntry = null;
+ this._lastMouseOverIndex = undefined;
+
+ // create header data handler instance
+ this._data = new L.Control.Header.DataImpl();
+
+ // setup conversion routine
+ this.converter = L.Util.bind(converter, context);
+ this._data.converter = L.Util.bind(this._twipsToPixels, this);
+
+ var startOffsetTw = parseInt(rows[0].size);
+ this._topOffset = this._twipsToPixels(startOffsetTw);
+
+ this._data.pushBack(0, {pos: startOffsetTw, size: 0});
+ var prevPos = startOffsetTw;
+ var nextIndex = parseInt(rows[1].text);
+ var last = rows.length - 1;
+
+ for (iterator = 1; iterator < last; iterator++) {
+ index = nextIndex;
+ pos = parseInt(rows[iterator].size);
+ nextIndex = parseInt(rows[iterator+1].text);
+ height = pos - prevPos;
+ prevPos = Math.round(pos + height * (nextIndex - index - 1));
+ index = index - this._topRow;
+ entry = {pos: pos, size: height};
+ this._data.pushBack(index, entry);
+ }
- for (iterator = 1; iterator < rows.length; iterator++) {
- twip = new L.Point(rows[iterator].size, rows[iterator].size);
- this._data[iterator] = { pos: Math.round(converter.call(context, twip).y), text: rows[iterator].text, selected: false };
- height = this._data[iterator].pos - this._data[iterator - 1].pos;
- if (height > 0) {
- this.drawHeaderEntry(iterator, false);
- }
+ // setup last header entry
+ index = nextIndex - this._topRow;
+ pos = parseInt(rows[last].size);
+ height = pos - prevPos;
+ this._data.pushBack(index, {pos: pos, size: height});
+
+ // draw header
+ entry = this._data.getFirst();
+ while (entry) {
+ this.drawHeaderEntry(entry, false);
+ entry = this._data.getNext();
}
this.mouseInit(canvas);
@@ -305,7 +323,7 @@ L.Control.RowHeader = L.Control.Header.extend({
var command = {
Row: {
type: 'long',
- value: parseInt(row - 1)
+ value: row - 1
},
Modifier: {
type: 'unsigned short',
@@ -317,10 +335,10 @@ L.Control.RowHeader = L.Control.Header.extend({
},
_onHeaderClick: function (e) {
- if (!this._mouseOverIndex)
+ if (!this._mouseOverEntry)
return;
- var row = this._mouseOverIndex + this._topRow;
+ var row = this._mouseOverEntry.index + this._topRow;
var modifier = 0;
if (e.shiftKey) {
@@ -378,14 +396,14 @@ L.Control.RowHeader = L.Control.Header.extend({
var end = new L.Point(e.clientX, e.clientY + offset.y);
var distance = this._map._docLayer._pixelsToTwips(end.subtract(start));
- if (this._mouseOverIndex) {
- var clickedRow = this._data[this._mouseOverIndex];
- var height = clickedRow.pos - this._data[this._mouseOverIndex - 1];
- var row = this._mouseOverIndex + this._topRow;
+ var clickedRow = this._mouseOverEntry;
+ if (clickedRow) {
+ var height = clickedRow.size;
+ var row = clickedRow.index + this._topRow;
- if (this._data[this._mouseOverIndex + 1]
- && this._data[this._mouseOverIndex + 1].pos === clickedRow.pos) {
+ if (this._data.isZeroSize(clickedRow.index + 1)) {
row += 1;
+ height = 0;
}
if (height !== distance.y) {
@@ -410,11 +428,11 @@ L.Control.RowHeader = L.Control.Header.extend({
onDragClick: function (item, clicks, e) {
this._map.removeLayer(this._horzLine);
- if (!this._mouseOverIndex)
+ if (!this._mouseOverEntry)
return;
if (clicks === 2) {
- var row = this._mouseOverIndex + this._topRow;
+ var row = this._mouseOverEntry.index + this._topRow;
var command = {
Row: {
type: 'long',
More information about the Libreoffice-commits
mailing list