/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.uberfire.ext.wires.core.grids.client.widget.grid.impl;
import java.util.List;
import com.ait.lienzo.client.core.event.NodeMouseClickEvent;
import com.ait.lienzo.client.core.event.NodeMouseClickHandler;
import com.ait.lienzo.client.core.shape.Group;
import com.ait.lienzo.client.core.types.Point2D;
import org.uberfire.ext.wires.core.grids.client.model.GridCell;
import org.uberfire.ext.wires.core.grids.client.model.GridColumn;
import org.uberfire.ext.wires.core.grids.client.model.GridData;
import org.uberfire.ext.wires.core.grids.client.model.GridRow;
import org.uberfire.ext.wires.core.grids.client.util.CoordinateUtilities;
import org.uberfire.ext.wires.core.grids.client.widget.grid.GridWidget;
import org.uberfire.ext.wires.core.grids.client.widget.grid.animation.MergableGridWidgetCollapseRowsAnimation;
import org.uberfire.ext.wires.core.grids.client.widget.grid.animation.MergableGridWidgetExpandRowsAnimation;
import org.uberfire.ext.wires.core.grids.client.widget.grid.renderers.grids.GridRenderer;
import org.uberfire.ext.wires.core.grids.client.widget.grid.renderers.grids.impl.BaseGridRendererHelper;
import org.uberfire.ext.wires.core.grids.client.widget.layer.GridSelectionManager;
/**
* Base MouseClickHandler to handle clicks to either the GridWidgets Header or Body. This implementation
* supports clicking on a "linked" column in the Header and delegating a response to the GridSelectionManager.
*/
public class BaseGridWidgetMouseClickHandler implements NodeMouseClickHandler {
protected GridData gridModel;
protected GridWidget gridWidget;
protected BaseGridRendererHelper rendererHelper;
protected GridSelectionManager selectionManager;
protected GridRenderer renderer;
public BaseGridWidgetMouseClickHandler(final GridWidget gridWidget,
final GridSelectionManager selectionManager,
final GridRenderer renderer) {
this.gridWidget = gridWidget;
this.gridModel = gridWidget.getModel();
this.rendererHelper = gridWidget.getRendererHelper();
this.selectionManager = selectionManager;
this.renderer = renderer;
}
@Override
public void onNodeMouseClick(final NodeMouseClickEvent event) {
if (!gridWidget.isVisible()) {
return;
}
if (!handleHeaderCellClick(event)) {
if (!handleBodyCellClick(event)) {
selectionManager.select(gridWidget);
}
}
}
/**
* Check if a MouseClickEvent happened on a "linked" column. If it does then
* delegate a response to GridSelectionManager.
* @param event
*/
boolean handleHeaderCellClick(final NodeMouseClickEvent event) {
//Convert Canvas co-ordinate to Grid co-ordinate
final Point2D ap = CoordinateUtilities.convertDOMToGridCoordinate(gridWidget,
new Point2D(event.getX(),
event.getY()));
final double cx = ap.getX();
final double cy = ap.getY();
final Group header = gridWidget.getHeader();
final double headerRowsYOffset = getHeaderRowsYOffset();
final double headerMinY = (header == null ? headerRowsYOffset : header.getY() + headerRowsYOffset);
final double headerMaxY = (header == null ? renderer.getHeaderHeight() : renderer.getHeaderHeight() + header.getY());
if (cx < 0 || cx > gridWidget.getWidth()) {
return false;
}
if (cy < headerMinY || cy > headerMaxY) {
return false;
}
//Get column index
final BaseGridRendererHelper.ColumnInformation ci = rendererHelper.getColumnInformation(cx);
final GridColumn<?> column = ci.getColumn();
if (column == null) {
return false;
}
//If linked scroll it into view
if (column.isLinked()) {
final GridColumn<?> link = column.getLink();
selectionManager.selectLinkedColumn(link);
return true;
}
return false;
}
private double getHeaderRowsYOffset() {
final GridData model = gridWidget.getModel();
final int headerRowCount = model.getHeaderRowCount();
final double headerHeight = renderer.getHeaderHeight();
final double headerRowHeight = renderer.getHeaderRowHeight();
final double headerRowsHeight = headerRowHeight * headerRowCount;
final double headerRowsYOffset = headerHeight - headerRowsHeight;
return headerRowsYOffset;
}
boolean handleBodyCellClick(final NodeMouseClickEvent event) {
//Convert Canvas co-ordinate to Grid co-ordinate
final Point2D ap = CoordinateUtilities.convertDOMToGridCoordinate(gridWidget,
new Point2D(event.getX(),
event.getY()));
final double cx = ap.getX();
final double cy = ap.getY();
final Group header = gridWidget.getHeader();
final double headerMaxY = (header == null ? renderer.getHeaderHeight() : renderer.getHeaderHeight() + header.getY());
if (cx < 0 || cx > gridWidget.getWidth()) {
return false;
}
if (cy < headerMaxY || cy > gridWidget.getHeight()) {
return false;
}
if (gridModel.getRowCount() == 0) {
return false;
}
//Get row index
GridRow row;
int uiRowIndex = 0;
double offsetY = cy - renderer.getHeaderHeight();
while ((row = gridModel.getRow(uiRowIndex)).getHeight() < offsetY) {
offsetY = offsetY - row.getHeight();
uiRowIndex++;
}
if (uiRowIndex < 0 || uiRowIndex > gridModel.getRowCount() - 1) {
return false;
}
//Get column index
final BaseGridRendererHelper.ColumnInformation ci = rendererHelper.getColumnInformation(cx);
final double offsetX = ci.getOffsetX();
final GridColumn<?> column = ci.getColumn();
final List<GridColumn<?>> columns = gridModel.getColumns();
if (column == null) {
return false;
}
final int uiColumnIndex = ci.getUiColumnIndex();
if (uiColumnIndex < 0 || uiColumnIndex > columns.size() - 1) {
return false;
}
//Check if the cell can be Grouped
final GridCell<?> cell = gridModel.getCell(uiRowIndex,
uiColumnIndex);
if (cell == null) {
return false;
}
if (cell.getMergedCellCount() < 2) {
return false;
}
//Check if the Grouping control has been clicked
final GridRow gridRow = gridModel.getRow(uiRowIndex);
final GridColumn<?> gridColumn = columns.get(uiColumnIndex);
final GridCell<?> nextRowCell = gridModel.getCell(uiRowIndex + 1,
uiColumnIndex);
final double cellX = cx - offsetX;
final double cellY = cy - rendererHelper.getRowOffset(uiRowIndex) - renderer.getHeaderHeight();
if (!gridWidget.onGroupingToggle(cellX,
cellY,
gridColumn.getWidth(),
gridRow.getHeight())) {
return false;
}
//Collapse or expand rows as needed
if (!nextRowCell.isCollapsed()) {
collapseRows(uiRowIndex,
uiColumnIndex,
cell.getMergedCellCount());
} else {
expandRows(uiRowIndex,
uiColumnIndex,
cell.getMergedCellCount());
}
return true;
}
void collapseRows(final int uiRowIndex,
final int uiColumnIndex,
final int rowCount) {
final MergableGridWidgetCollapseRowsAnimation a = new MergableGridWidgetCollapseRowsAnimation(gridWidget,
uiRowIndex,
uiColumnIndex,
rowCount);
a.run();
}
void expandRows(final int uiRowIndex,
final int uiColumnIndex,
final int rowCount) {
final MergableGridWidgetExpandRowsAnimation a = new MergableGridWidgetExpandRowsAnimation(gridWidget,
uiRowIndex,
uiColumnIndex,
rowCount);
a.run();
}
}