com.vaadin.addon.spreadsheet.elements.SpreadsheetElement.java Source code

Java tutorial

Introduction

Here is the source code for com.vaadin.addon.spreadsheet.elements.SpreadsheetElement.java

Source

package com.vaadin.addon.spreadsheet.elements;

/*
 * #%L
 * Vaadin Spreadsheet Testbench API
 * %%
 * Copyright (C) 2013 - 2016 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.List;

import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import com.vaadin.testbench.TestBenchElement;
import com.vaadin.testbench.elementsbase.AbstractElement;
import com.vaadin.testbench.elementsbase.ServerClass;

/**
 * This is the base element class for accessing a Vaadin Spreadsheet component
 * for TestBench testing.
 * 
 * @author Vaadin Ltd.
 */
@ServerClass("com.vaadin.addon.spreadsheet.Spreadsheet")
public class SpreadsheetElement extends AbstractElement {

    /**
     * Gets the cell element at the given coordinates for the currently active
     * sheet. Throws NoSuchElementException if the cell is outside the visible
     * area.
     * 
     * @param row
     *            Row index, 1-based
     * @param column
     *            Column index, 1-based
     * @return Cell element at the given index.
     * @throws NoSuchElementException
     *             if the cell at (row, column) is not found.
     */
    public SheetCellElement getCellAt(int row, int column) {
        String cellSelector = String.format(".col%d.row%d.cell", column, row);
        // If there are multiple cells return the merged cell
        if (findElements(By.cssSelector(cellSelector)).size() > 1) {
            cellSelector += ".merged-cell";
        }
        TestBenchElement cell = (TestBenchElement) findElement(By.cssSelector(cellSelector));
        SheetCellElement cellElement = cell.wrap(SheetCellElement.class);
        cellElement.setParent(this);
        return cellElement;
    }

    /**
     * Gets the cell element at the given cell address for the currently active
     * sheet. Throws NoSuchElementException if the cell is outside the visible
     * area.
     * 
     * @param cellAddress
     *            Target address, e.g. A3
     * @return Cell element at the given index.
     * @throws NoSuchElementException
     *             if the cell at (cellAddress) is not found.
     */
    public SheetCellElement getCellAt(String cellAddress) {
        Point point = AddressUtil.addressToPoint(cellAddress);
        return getCellAt(point.getY(), point.getX());
    }

    /**
     * Gets the row header element at the given index.
     * 
     * @param rowIndex
     *            Index of target row, 1-based
     * @return Header of the row at the given index
     */
    public SheetHeaderElement getRowHeader(int rowIndex) {
        TestBenchElement cell = (TestBenchElement) findElement(
                By.cssSelector(String.format(".rh.row%d", rowIndex)));
        return cell.wrap(SheetHeaderElement.class);
    }

    /**
     * Gets the column header element at the given index.
     * 
     * @param columnIndex
     *            Index of target column, 1-based
     * @return Header of the column at the given index
     */
    public SheetHeaderElement getColumnHeader(int columnIndex) {
        TestBenchElement cell = (TestBenchElement) findElement(
                By.cssSelector(String.format(".ch.col%d", columnIndex)));
        return cell.wrap(SheetHeaderElement.class);
    }

    /**
     * Gets the address field. The address field contains the address of the
     * cell that was last clicked, or A1 if no clicks have yet been made.
     * 
     * @return Address field element
     */
    public TestBenchElement getAddressField() {
        return (TestBenchElement) findElement(By.className("addressfield"));
    }

    /**
     * Gets the formula field. This field is where the user can input data for
     * the cell whose address the address field currently contains.
     * 
     * @return Formula field element
     */
    public TestBenchElement getFormulaField() {
        return (TestBenchElement) findElement(By.className("functionfield"));
    }

    /**
     * Gets the info label. Info label is the small text at the bottom right
     * corner of the Spreadsheet.
     * 
     * @return Info label element
     */
    public TestBenchElement getInfoLabel() {
        return (TestBenchElement) findElement(By.className("sheet-tabsheet-infolabel"));
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.vaadin.testbench.TestBenchElement#scroll(int)
     */
    @Override
    public void scroll(int scrollTop) {
        getBottomRightPane().scroll(scrollTop);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.vaadin.testbench.TestBenchElement#scrollLeft(int)
     */
    @Override
    public void scrollLeft(int scrollLeft) {
        getBottomRightPane().scrollLeft(scrollLeft);
    }

    /**
     * Scrolls the sheet selector to the beginning.
     * 
     * Has no effect if there are not enough sheets to require scrolling.
     */
    public void scrollSheetsToStart() {
        findElement(By.className("scroll-tabs-beginning")).click();
    }

    /**
     * Scrolls the sheet selector to the end.
     * 
     * Has no effect if there are not enough sheets to require scrolling.
     */
    public void scrollSheetsToEnd() {
        findElement(By.className("scroll-tabs-end")).click();
    }

    /**
     * Scrolls the sheet selector left or right by the given amount.
     * 
     * Has no effect if there are not enough sheets to require scrolling.
     * 
     * @param amount
     *            Amount to scroll. Positive numbers scroll to the right and
     *            negative numbers scroll to the left.
     */
    public void scrollSheets(int amount) {
        WebElement target = findElement(By.className(amount > 0 ? "scroll-tabs-right" : "scroll-tabs-left"));
        for (int i = 0; i < amount; i++) {
            target.click();
        }
    }

    /**
     * Selects the sheet at the given index. Indexes are counted only for
     * visible sheets.
     * 
     * @param sheetIndex
     *            Index of sheet to select, 0-based
     */
    public void selectSheetAt(int sheetIndex) {
        WebElement tabContainer = findElement(By.className("sheet-tabsheet-container"));
        List<WebElement> tabs = tabContainer.findElements(By.xpath(".//*"));
        WebElement target = tabs.get(sheetIndex);
        scrollSheetVisible(target);
        target.click();
    }

    /**
     * Selects the sheet with the given name. Only visible sheets can be
     * selected.
     * 
     * @param sheetName
     *            Name of sheet to select
     */
    public void selectSheet(String sheetName) {
        WebElement tabContainer = findElement(By.className("sheet-tabsheet-container"));
        List<WebElement> tabs = tabContainer.findElements(By.xpath(".//*"));
        for (WebElement tab : tabs) {
            if (tab.getText().equals(sheetName)) {
                scrollSheetVisible(tab);
                tab.click();
                break;
            }
        }
    }

    /**
     * Adds a new sheet with the given name. Sheet names should be unique within
     * a spreadsheet.
     * 
     * @param sheetName
     *            Name of the new sheet.
     */
    public void addSheet(String sheetName) {
        findElement(By.className("add-new-tab")).click();
    }

    /**
     * Fetches the context menu for the spreadsheet
     *
     * @return {@link com.vaadin.addon.spreadsheet.elements.SpreadsheetElement.ContextMenuElement}
     * @throws java.util.NoSuchElementException if the menu isn't open
     */
    public ContextMenuElement getContextMenu() {
        try {
            WebElement cm = getDriver().findElement(By.className("v-contextmenu"));
            return wrapElement(cm, getCommandExecutor()).wrap(ContextMenuElement.class);
        } catch (WebDriverException e) {
            throw new NoSuchElementException("Context menu not found", e);
        }
    }

    public static class ContextMenuElement extends AbstractElement {

        public WebElement getItem(String text) {
            return findElement(By.xpath(".//table//tr[*]//td//div[contains(text(), \"" + text + "\")]"));
        }

    }

    private void scrollSheetVisible(WebElement targetSheet) {
        // Make sure the target sheet is visible
        if (!targetSheet.isDisplayed()) {
            scrollSheetsToStart();
            while (!targetSheet.isDisplayed()) {
                scrollSheets(1);
            }
        }
    }

    // Current selection
    private WebElement sTop;
    private WebElement sBottom;
    private WebElement sRight;
    private Point sLocation;
    private Dimension sSize;

    boolean isElementSelected(WebElement element) {
        updateSelectionLocationAndSize();
        Point location = element.getLocation();
        location.x += element.getSize().getWidth() / 2;
        location.y += element.getSize().getHeight() / 2;
        return isInSelection(location) || isNonCoherentlySelected(element);
    }

    private void findSelectionOutline() {
        // sometimes the spreadsheet takes so long to load that the selection
        // widget elements are not found
        new WebDriverWait(getDriver(), 10)
                .until(ExpectedConditions.presenceOfElementLocated(By.className("s-top")));
        sTop = findElement(By.className("s-top"));
        sBottom = findElement(By.className("s-bottom"));
        // Just to make sure the left element is present
        findElement(By.className("s-left"));
        sRight = findElement(By.className("s-right"));
    }

    private boolean isNonCoherentlySelected(WebElement element) {
        // an element is non-coherently selected if the class attribute
        // contains "cell-range"
        return element.getAttribute("class").contains("cell-range")
                || "solid".equals(element.getCssValue("outline-style"));
    }

    private void updateSelectionLocationAndSize() {
        if (sTop == null) {
            findSelectionOutline();
        }
        sLocation = sTop.getLocation();
        int bottomY = sBottom.getLocation().getY();
        int bottomH = sBottom.getSize().getHeight();
        int rightX = sRight.getLocation().getX();
        int rightW = sRight.getSize().getWidth();
        sSize = new Dimension(rightX + rightW - sLocation.getX(), bottomY + bottomH - sLocation.getY());
    }

    private boolean intersectsSelection(Point location, Dimension size) {
        // Test top left corner
        if (location.getX() < sLocation.getX() || location.getY() < sLocation.getY()) {
            return false;
        }
        // Test lower right corner
        if (location.getX() + size.getWidth() > sLocation.getX() + sSize.getWidth()
                || location.getY() + size.getHeight() > sLocation.getY() + sSize.getHeight()) {
            return false;
        }
        // Everything is inside the selection
        return true;
    }

    private boolean isInSelection(Point location) {
        // Test top left corner
        if (location.getX() < sLocation.getX() || location.getY() < sLocation.getY()) {
            return false;
        }
        // Test lower right corner
        if (location.getX() - sLocation.getX() > sSize.getWidth()
                || location.getY() - sLocation.getY() > sSize.getHeight()) {
            return false;
        }
        // Everything is inside the selection
        return true;
    }

    public WebElement getCellValueInput() {
        return findElement(By.id("cellinput"));
    }

    /**
     * Determine if the pop-up of PopupuButton is currently visible
     */
    public boolean isPopupButtonPopupVisible() {
        List<WebElement> elements = getDriver().findElements(By.className("v-spreadsheet-popupbutton-overlay"));
        return !elements.isEmpty();
    }

    private TestBenchElement getBottomRightPane() {
        return wrapElement(findElement(By.className("bottom-right-pane")), getCommandExecutor());
    }
}