package com.vaadin.addon.spreadsheet.client;
/*
* #%L
* Vaadin Spreadsheet
* %%
* Copyright (C) 2013 - 2015 Vaadin Ltd
* %%
* This program is available under Commercial Vaadin Add-On License 3.0
* (CVALv3).
*
* See the file license.html distributed with this software for more
* information about licensing.
*
* You should have received a copy of the CVALv3 along with this program.
* If not, see <http://vaadin.com/license/cval-3>.
* #L%
*/
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.dom.client.TextAreaElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.FlowPanel;
import com.vaadin.client.ui.VLabel;
import com.vaadin.client.ui.VOverlay;
public class CellComment extends VOverlay {
protected static final String COMMENT_OVERLAY_LINE_CLASSNAME = "comment-overlay-line";
private static final String COMMENT_OVERLAY_CLASSNAME = "v-spreadsheet-comment-overlay";
private static final String COMMENT_OVERLAY_AUTHOR_CLASSNAME = "comment-overlay-author";
private static final String COMMENT_OVERLAY_INVALIDFORMULA_CLASSNAME = "comment-overlay-invalidformula";
private static final String COMMENT_OVERLAY_SEPARATOR_CLASSNAME = "comment-overlay-separator";
private static final String COMMENT_OVERLAY_LABEL_CLASSNAME = "comment-overlay-label";
private static final String COMMENT_OVERLAY_INPUT_CLASSNAME = "comment-overlay-input";
private static final String COMMENT_OVERLAY_SHADOW_CLASSNAME = COMMENT_OVERLAY_CLASSNAME
+ "-shadow";
private final FlowPanel root;
private final VLabel author;
private final VLabel label;
private final VLabel invalidFormula;
private Element paneElement;
private final DivElement line;
private Element cellElement;
private String linePositionClassName;
private TextAreaElement input = Document.get().createTextAreaElement();
private int offsetWidth;
private int offsetHeight;
private int cellRow;
private int cellCol;
public CellComment(final SheetWidget owner, Element paneElement) {
this.paneElement = paneElement;
root = new FlowPanel();
add(root);
line = Document.get().createDivElement();
line.setClassName(COMMENT_OVERLAY_LINE_CLASSNAME);
author = new VLabel();
author.setVisible(false);
author.setStyleName(COMMENT_OVERLAY_AUTHOR_CLASSNAME);
label = new VLabel();
label.setVisible(false);
label.setStyleName(COMMENT_OVERLAY_LABEL_CLASSNAME);
setStyleName(COMMENT_OVERLAY_CLASSNAME);
addStyleName(COMMENT_OVERLAY_SHADOW_CLASSNAME);
setOwner(owner);
setAnimationEnabled(false);
setVisible(false);
setZIndex(30);
invalidFormula = new VLabel();
invalidFormula.setVisible(false);
invalidFormula.setStyleName(COMMENT_OVERLAY_INVALIDFORMULA_CLASSNAME);
root.add(invalidFormula);
root.add(author);
root.add(label);
// Comment editor
input.addClassName(COMMENT_OVERLAY_INPUT_CLASSNAME);
input.getStyle().setDisplay(Display.NONE);
getElement().appendChild(input);
input.setRows(4);
input.getStyle().setWidth(200, Unit.PX);
ClickHandler clickHandler = new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
owner.onCellCommentFocus(CellComment.this);
}
};
author.addClickHandler(clickHandler);
label.addClickHandler(clickHandler);
}
public void bringForward() {
setZIndex(35);
}
public void pushBack() {
setZIndex(30);
}
@Override
public void hide() {
super.hide();
line.removeFromParent();
}
public void setCommentText(String text) {
label.setText(text);
hideIfNoContent(label);
showOrHideSeparator();
}
public int getCol() {
return cellCol;
}
public int getRow() {
return cellRow;
}
public void show(Element cellElement, int row, int col) {
this.cellElement = cellElement;
cellRow = row;
cellCol = col;
setVisible(false);
show();
offsetHeight = getOffsetHeight();
offsetWidth = getOffsetWidth();
calculatePosition();
setVisible(true);
}
public void showDependingToCellRightCorner(Element cellElement, int row,
int col) {
this.cellElement = cellElement;
cellRow = row;
cellCol = col;
setVisible(false);
show();
offsetHeight = getOffsetHeight();
offsetWidth = getOffsetWidth();
refreshPositionAccordingToCellRightCorner();
}
public void refreshPositionAccordingToCellRightCorner() {
// do not set overlay visible if the cell top-right corner is not
// visible on sheet
if (cellElement != null) {
int cellRight = cellElement.getAbsoluteRight();
int cellTop = cellElement.getAbsoluteTop();
if (cellRight >= paneElement.getAbsoluteLeft()
&& cellRight < paneElement.getAbsoluteRight()
&& cellTop >= paneElement.getAbsoluteTop()
&& cellTop <= paneElement.getAbsoluteBottom()) {
calculatePosition();
setVisible(true);
if (!isShowing()) {
show();
}
} else {
setVisible(false);
}
} else {
setVisible(false);
hide();
}
}
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
line.getStyle().setVisibility(
visible ? Visibility.VISIBLE : Visibility.HIDDEN);
}
private void calculatePosition() {
// display the overlay on the right side of the
// cell if possible, move it up/down if necessary. if there is not
// enough space on the right side, move it to the left.
int cellRight = cellElement.getAbsoluteRight();
int cellOffsetLeft = cellElement.getOffsetLeft();
int cellOffsetWidth = cellElement.getOffsetWidth();
int cellOffsetTop = cellElement.getOffsetTop();
int cellTop = cellElement.getAbsoluteTop();
int popupLeft = cellRight + 15;
if (popupLeft + offsetWidth > paneElement.getAbsoluteRight()) {
// move to left side if it fits there
int temp = cellElement.getAbsoluteLeft() - 15 - offsetWidth;
if (paneElement.getAbsoluteLeft() < temp) {
popupLeft = temp;
}
}
int popupTop = cellTop - 15;
int sheetBottom = paneElement.getAbsoluteBottom();
if (popupTop + offsetHeight > sheetBottom) {
// move upwards as much possible to make it fit
popupTop -= (popupTop + offsetHeight - sheetBottom + 5);
int sheetTop = paneElement.getAbsoluteTop();
if (popupTop < sheetTop) {
popupTop = sheetTop;
}
} else if (popupTop < paneElement.getAbsoluteTop()) {
popupTop += (paneElement.getAbsoluteTop() - popupTop);
}
setPopupPosition(popupLeft, popupTop);
if (linePositionClassName != null) {
line.removeClassName(linePositionClassName);
}
linePositionClassName = "col" + cellCol + " row" + cellRow;
// Increase the target position to account for rounded corner
popupTop += 2;
popupLeft += 2;
int a;
int b = cellTop - popupTop;
double deg;
if (popupLeft > cellRight) {
// draw the line to overlay top-left corner
a = popupLeft - cellRight;
if (b > 0) {
deg = -1 * Math.toDegrees(Math.atan((double) b / (double) a));
} else {
b = Math.abs(b);
deg = 0;
}
} else {
// Decrease the left offset of target position to account for
// rounded corner
popupLeft -= 2;
// draw the line to overlay top-right corner
a = cellRight - (popupLeft + offsetWidth);
if (b > 0) {
deg = -180 + Math.toDegrees(Math.atan((double) b / (double) a));
} else {
b = Math.abs(b);
deg = -180;
}
}
double c = Math.sqrt(a * a + b * b) + 1;
line.getStyle().setWidth(c, Unit.PX);
line.getStyle().setTop(cellOffsetTop, Unit.PX);
line.getStyle().setLeft(cellOffsetLeft + cellOffsetWidth, Unit.PX);
line.getStyle().setProperty("transform", "rotate(" + deg + "deg)");
line.getStyle().setProperty("msTransform", "rotate(" + deg + "deg)");
line.getStyle()
.setProperty("webkitTransform", "rotate(" + deg + "deg)");
line.addClassName(linePositionClassName);
paneElement.appendChild(line);
}
public void setSheetElement(Element paneElement) {
this.paneElement = paneElement;
}
public void setEditMode(boolean editMode) {
if (editMode) {
input.setValue(label.getText());
label.setVisible(false);
input.getStyle().setDisplay(Display.BLOCK);
input.focus();
input.select();
} else {
label.setText(input.getValue());
label.setVisible(true);
input.getStyle().setDisplay(Display.NONE);
((SheetWidget) getOwner()).commitComment(label.getText(), getCol(),
getRow());
}
showOrHideSeparator();
}
public void setAuthor(String authorName) {
author.setText(authorName);
hideIfNoContent(author);
showOrHideSeparator();
}
public void setInvalidFormulaMessage(String invalidFormulaMessage) {
invalidFormula.setText(invalidFormulaMessage);
hideIfNoContent(invalidFormula);
showOrHideSeparator();
}
private void hideIfNoContent(VLabel label) {
if(label.getText().isEmpty()) {
label.setVisible(false);
} else {
label.setVisible(true);
}
}
private void showOrHideSeparator() {
if(invalidFormula.isVisible() && (author.isVisible() || label.isVisible()
|| Display.BLOCK.equals(input.getStyle().getDisplay()) )) {
if(!invalidFormula.getStyleName().contains(COMMENT_OVERLAY_SEPARATOR_CLASSNAME)) {
invalidFormula.addStyleName(COMMENT_OVERLAY_SEPARATOR_CLASSNAME);
}
} else {
if(invalidFormula.getStyleName().contains(COMMENT_OVERLAY_SEPARATOR_CLASSNAME)) {
invalidFormula.removeStyleName(COMMENT_OVERLAY_SEPARATOR_CLASSNAME);
}
}
}
}