blob: 60216f01a7fb469f49a9a983e19787ed3f3f937e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014-2015 BSI Business Systems Integration AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
******************************************************************************/
scout.TableLayout = function(table) {
scout.TableLayout.parent.call(this);
this.table = table;
this._dataHeightPositive = false;
};
scout.inherits(scout.TableLayout, scout.AbstractLayout);
scout.TableLayout.prototype.layout = function($container) {
var menuBarHeight = 0,
menuBarSize,
footerHeight = 0,
headerHeight = 0,
controlContainerHeight = 0,
controlContainerInsets,
$data = this.table.$data,
dataMargins = scout.graphics.margins($data),
dataMarginsHeight = dataMargins.top + dataMargins.bottom,
menuBar = this.table.menuBar,
footer = this.table.footer,
header = this.table.header,
visibleColumns = this.table.visibleColumns(),
lastColumn = visibleColumns[visibleColumns.length - 1],
htmlMenuBar = menuBar.htmlComp,
htmlContainer = this.table.htmlComp,
containerSize = htmlContainer.availableSize().subtract(htmlContainer.insets());
if (menuBar.visible) {
menuBarSize = scout.MenuBarLayout.size(htmlMenuBar, containerSize);
htmlMenuBar.setSize(menuBarSize);
menuBarHeight = menuBarSize.height;
}
if (header) {
headerHeight = scout.graphics.size(header.$container).height;
}
if (footer) {
// Layout table footer and add size of footer (including the control content) to 'height'
footerHeight = scout.graphics.size(footer.$container).height;
controlContainerHeight = footer.computeControlContainerHeight(this.table, footer.selectedControl, !this._dataHeightPositive);
controlContainerInsets = scout.graphics.insets(footer.$controlContainer);
if (!footer.animating) { // closing or opening: height is about to be changed
footer.$controlContainer.cssHeight(controlContainerHeight);
footer.$controlContent.outerHeight(controlContainerHeight - controlContainerInsets.vertical());
footer.revalidateLayout();
}
}
$data.css('height', 'calc(100% - ' + (dataMarginsHeight + menuBarHeight + controlContainerHeight + footerHeight + headerHeight) + 'px)');
this._dataHeightPositive = $data.height() > 0;
if (this.table.autoResizeColumns) {
this._layoutColumns();
}
// Size of last column may have to be adjusted due to the header menu items
if (header) {
header.resizeHeaderItem(lastColumn);
}
this.table.setViewRangeSize(this.table.calculateViewRangeSize());
if (!htmlContainer.layouted) {
this.table._renderScrollTop();
}
// Always render viewport (not only when viewRangeSize changes), because view range depends on scroll position and data height
this.table._renderViewport();
// Make sure tooltips and editor popup are at correct position after layouting (e.g after window resizing)
this.table.tooltips.forEach(function(tooltip) {
tooltip.position();
}.bind(this));
if (this.table.cellEditorPopup && this.table.cellEditorPopup.rendered) {
this.table.cellEditorPopup.position();
this.table.cellEditorPopup.pack();
}
this.table.updateScrollbars();
};
/**
* Resizes the columns to make them use all the available space.
*/
scout.TableLayout.prototype._layoutColumns = function() {
var newWidth, weight,
relevantColumns = [],
currentWidth = 0,
totalInitialWidth = 0,
availableWidth = Math.floor(this.table.$data.width() - this.table.rowBorderWidth);
// Handle fixed columns
this.table.visibleColumns().forEach(function(column) {
if (column.fixedWidth) {
availableWidth -= column.width;
} else {
relevantColumns.push(column);
currentWidth += column.width;
totalInitialWidth += column.initialWidth;
}
}.bind(this));
if (availableWidth === currentWidth) {
// Columns already use the available space, no need to resize
return;
}
var remainingWidth = availableWidth;
// First, filter columns which would get smaller than their minimal size
var minWidthColumns = relevantColumns.filter(function(column) {
// Use initial width as preferred width for auto resize columns.
// This makes sure the column doesn't get too small on small screens. The user can still make the column smaller though.
var minWidth = Math.max(column.minWidth, column.initialWidth);
if (totalInitialWidth === 0) {
weight = 1 / relevantColumns.length;
} else {
weight = column.initialWidth / totalInitialWidth;
}
newWidth = Math.floor(weight * remainingWidth);
if (newWidth < minWidth) {
newWidth = minWidth;
remainingWidth = Math.max(remainingWidth - newWidth, 0);
return true;
}
return false;
}.bind(this));
// Resize them to their minimal width
minWidthColumns.forEach(function(column, index) {
var minWidth = Math.max(column.minWidth, column.initialWidth);
scout.arrays.remove(relevantColumns, column);
newWidth = minWidth;
totalInitialWidth -= column.initialWidth;
// If this is the last column, add remaining space (due to rounding) to this column
if (index === minWidthColumns.length - 1 && remainingWidth > 0 && relevantColumns.length === 0) {
newWidth += remainingWidth;
remainingWidth = 0;
}
if (newWidth !== column.width) {
this.table.resizeColumn(column, newWidth);
}
}.bind(this));
// Then resize the others
availableWidth = remainingWidth;
relevantColumns.forEach(function(column, index) {
if (totalInitialWidth === 0) {
weight = 1 / relevantColumns.length;
} else {
weight = column.initialWidth / totalInitialWidth;
}
newWidth = Math.floor(weight * availableWidth);
remainingWidth -= newWidth;
// If this is the last column, add remaining space (due to rounding) to this column
if (index === relevantColumns.length - 1 && remainingWidth > 0) {
newWidth += remainingWidth;
remainingWidth = 0;
}
if (newWidth !== column.width) {
this.table.resizeColumn(column, newWidth);
}
}.bind(this));
};