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 java.util.ArrayList; import java.util.List; import com.google.gwt.core.client.Scheduler; 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.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.event.logical.shared.HasCloseHandlers; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.ui.FocusWidget; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ui.VOverlay; public class PopupButtonWidget extends FocusWidget implements ClickHandler, HasCloseHandlers<PopupPanel> { protected static final String BUTTON_CLASSNAME = "popupbutton"; protected static final String POPUP_OVERLAY_CLASSNAME = "v-spreadsheet-" + BUTTON_CLASSNAME + "-overlay"; protected static final String POPUP_OVERLAY_LAYOUT_CLASSNAME = "overlay-layout"; protected static final String BUTTON_ACTIVE_CLASSNAME = "active"; private final DivElement root = Document.get().createDivElement(); private PositionCallback callback = new PositionCallback() { @Override public void setPosition(int offsetWidth, int offsetHeight) { Element parentElement = root.getParentElement(); final int absoluteBottom = parentElement.getAbsoluteBottom(); final int absoluteRight = parentElement.getAbsoluteRight(); int left = absoluteRight - offsetWidth; if (left < sheet.getAbsoluteLeft()) { left = absoluteRight; } int top = absoluteBottom; if ((top + offsetHeight) > sheet.getAbsoluteBottom()) { top = parentElement.getAbsoluteTop() - offsetHeight; } if (top < sheet.getAbsoluteTop()) { top = sheet.getAbsoluteTop(); } popup.setPopupPosition(left, top); } }; private final VOverlay popup; private final PopupButtonHeader popupHeader; private final VerticalPanel popupLayout; private final List<Widget> popupChildrenWidgets = new ArrayList<Widget>(); private DivElement sheet; private int col; private int row; private SheetWidget owner; public PopupButtonWidget() { root.setClassName(BUTTON_CLASSNAME); root.setAttribute("role", "button"); popup = new VOverlay(true, false); popup.setStyleName(POPUP_OVERLAY_CLASSNAME); popupLayout = new VerticalPanel(); popupLayout.setStylePrimaryName(POPUP_OVERLAY_LAYOUT_CLASSNAME); popupHeader = new PopupButtonHeader(); popupHeader.setPopup(popup); popupLayout.add(popupHeader); popup.add(popupLayout); setElement(root); addClickHandler(this); } public void setSheetWidget(SheetWidget owner, DivElement sheet) { this.sheet = sheet; this.owner = owner; popup.setOwner(owner); popupHeader.setSheet(owner); } /** * 1-based * * @return the col */ public int getCol() { return col; } /** * 1-based * * @param col * the col to set */ public void setCol(int col) { this.col = col; } /** * 1-based * * @return the row */ public int getRow() { return row; } /** * 1-based * * @param row * the row to set */ public void setRow(int row) { this.row = row; } /** * 1-based * * @param row * @param col */ public void setRowCol(int row, int col) { Widget owner = popup.getOwner(); if (owner != null && owner instanceof SheetWidget) { ((SheetWidget) owner).updatePopupButtonPosition(this, this.row, this.col, row, col); } getElement().removeClassName("c" + this.col + "r" + this.row); this.col = col; this.row = row; getElement().addClassName("c" + this.col + "r" + this.row); } @Override public void onClick(ClickEvent event) { openPopupOverlay(); event.stopPropagation(); } protected void openPopupOverlay() { Element parentElement = root.getParentElement(); if (parentElement != null) { popup.setPopupPositionAndShow(callback); } else { Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { popup.setPopupPositionAndShow(callback); } }); } if (owner != null) { popupHeader.setCaption(owner.getCellValue(col, row)); } } public void markActive(boolean active) { if (active) { root.addClassName(BUTTON_ACTIVE_CLASSNAME); } else { root.removeClassName(BUTTON_ACTIVE_CLASSNAME); } } public void addPopupComponent(Widget widget) { popupChildrenWidgets.add(widget); popupLayout.add(widget); } public void removePopupComponent(Widget widget) { popupChildrenWidgets.remove(widget); popupLayout.remove(widget); } public void setPopupHeight(String popupHeight) { if (popupHeight != null) { ((PopupPanel) popup).setHeight(popupHeight); } else { ((PopupPanel) popup).setHeight(""); } } public void setPopupWidth(String popupWidth) { if (popupWidth != null) { ((PopupPanel) popup).setWidth(popupWidth); } else { ((PopupPanel) popup).setWidth(""); } } /** * Override the position callback method for the button's popup. * * @param positionCallback * not null */ public void setPopupPositionCallback(PositionCallback positionCallback) { if (positionCallback != null) { callback = positionCallback; } } /** * Returns the position callback method used for the button's popup. * * @return */ public PositionCallback getPositionCallback() { return callback; } public void setPopupHeaderHidden(boolean headerHidden) { popupHeader.setHidden(headerHidden); } public boolean isPopupHeaderHidden() { return popupHeader.isHidden(); } @Override public void setStyleName(String style, boolean add) { super.setStyleName(style, add); popup.setStyleName(style, add); } @Override public HandlerRegistration addCloseHandler(CloseHandler<PopupPanel> handler) { return popup.addCloseHandler(handler); } public boolean isPopupOpen() { return popup.isShowing(); } public void closePopup() { popup.hide(); } public void openPopup() { if (owner != null && owner.isCellRendered(col, row)) { openPopupOverlay(); } } @Override protected void onDetach() { closePopup(); super.onDetach(); } }