Java tutorial
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.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; 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.InputElement; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.EventListener; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ComputedStyle; import com.vaadin.client.WidgetUtil; public class SheetTabSheet extends Widget { private static final String HIDDEN = "hidden"; public interface SheetTabSheetHandler { public void onSheetTabSelected(int tabIndex); public void onSheetRename(int selectedTabIndex, String value); public void onNewSheetCreated(); public void onSheetRenameCancel(); public void onFirstTabIndexChange(int tabScrollIndex); public void onSheetTabSheetFocus(); } private static final String SELECTED_TAB_CLASSNAME = "selected-tab"; private DivElement root = Document.get().createDivElement(); // div containing the tabs private DivElement container = Document.get().createDivElement(); private DivElement options = Document.get().createDivElement(); private DivElement scrollBeginning = Document.get().createDivElement(); private DivElement scrollEnd = Document.get().createDivElement(); private DivElement scrollLeft = Document.get().createDivElement(); private DivElement scrollRight = Document.get().createDivElement(); private DivElement addNewSheet = Document.get().createDivElement(); private InputElement input = Document.get().createTextInputElement(); private DivElement tempElement = Document.get().createDivElement(); private JsArray<JavaScriptObject> tabs = JsArray.createArray().cast(); private final SheetTabSheetHandler handler; private int selectedTabIndex = -1; private int tabScrollIndex; private double tabScrollMargin; private boolean readOnly; private boolean editing; private String cachedSheetName = ""; private DivElement infoLabel = Document.get().createDivElement(); public SheetTabSheet(SheetTabSheetHandler handler) { this.handler = handler; initDOM(); initListeners(); input.setMaxLength(31); } private void initDOM() { scrollBeginning.setClassName("scroll-tabs-beginning"); scrollEnd.setClassName("scroll-tabs-end"); scrollLeft.setClassName("scroll-tabs-left"); scrollRight.setClassName("scroll-tabs-right"); addNewSheet.setClassName("add-new-tab"); options.setClassName("sheet-tabsheet-options"); options.appendChild(scrollBeginning); options.appendChild(scrollLeft); options.appendChild(scrollRight); options.appendChild(scrollEnd); options.appendChild(addNewSheet); container.setClassName("sheet-tabsheet-container"); tempElement.setClassName("sheet-tabsheet-temp"); root.appendChild(tempElement); root.setClassName("sheet-tabsheet"); root.appendChild(options); root.appendChild(container); infoLabel.setClassName("sheet-tabsheet-infolabel"); root.appendChild(infoLabel); setElement(root); } private void initListeners() { Event.sinkEvents(root, Event.ONCLICK | Event.ONDBLCLICK); Event.setEventListener(root, new EventListener() { @Override public void onBrowserEvent(Event event) { final Element target = event.getEventTarget().cast(); final int type = event.getTypeInt(); if (target.equals(input)) { return; } event.stopPropagation(); if (type == Event.ONCLICK) { if (editing && !readOnly) { commitSheetName(); } handler.onSheetTabSheetFocus(); if (options.isOrHasChild(target) && !target.hasClassName(HIDDEN)) { if (target.equals(scrollBeginning)) { tabScrollMargin = 0; tabScrollIndex = 0; container.getStyle().setMarginLeft(tabScrollMargin, Unit.PX); showHideScrollIcons(); handler.onFirstTabIndexChange(tabScrollIndex); } else if (target.equals(scrollLeft)) { if (tabScrollIndex > 0) { tabScrollIndex--; if (tabScrollIndex == 0) { tabScrollMargin = 0; } else { tabScrollMargin += getTabWidth(tabScrollIndex); } container.getStyle().setMarginLeft(tabScrollMargin, Unit.PX); } showHideScrollIcons(); handler.onFirstTabIndexChange(tabScrollIndex); } else if (target.equals(scrollRight)) { if (tabScrollIndex < (tabs.length() - 1)) { tabScrollMargin -= getTabWidth(tabScrollIndex); container.getStyle().setMarginLeft(tabScrollMargin, Unit.PX); tabScrollIndex++; showHideScrollIcons(); handler.onFirstTabIndexChange(tabScrollIndex); } } else if (target.equals(scrollEnd)) { int tempIndex = getLastTabVisibleWithScrollIndex(); setFirstVisibleTab(tempIndex); handler.onFirstTabIndexChange(tabScrollIndex); } else if (target.equals(addNewSheet)) { if (!readOnly) { handler.onNewSheetCreated(); } } } else if (container.isOrHasChild(target)) { for (int i = 0; i < tabs.length(); i++) { if (tabs.get(i).equals(target)) { if (i != selectedTabIndex) { handler.onSheetTabSelected(i); } } } } } else if (type == Event.ONDBLCLICK) { if (!readOnly) { for (int i = 0; i < tabs.length(); i++) { if (tabs.get(i).equals(target)) { if (i != selectedTabIndex) { handler.onSheetTabSelected(i); } else { editing = true; Element e = tabs.get(i).cast(); cachedSheetName = e.getInnerText(); input.setValue(cachedSheetName); e.setInnerText(""); e.appendChild(input); input.focus(); updateInputSize(); } } } } } } }); Event.sinkEvents(input, Event.ONKEYDOWN | Event.ONKEYUP | Event.ONBLUR); Event.setEventListener(input, new EventListener() { @Override public void onBrowserEvent(Event event) { final int type = event.getTypeInt(); if (editing) { if (type == Event.ONBLUR) { commitSheetName(); } else { switch (event.getKeyCode()) { case KeyCodes.KEY_ENTER: case KeyCodes.KEY_TAB: commitSheetName(); break; case KeyCodes.KEY_ESCAPE: editing = false; input.removeFromParent(); Element element = (Element) tabs.get(selectedTabIndex).cast(); element.getStyle().clearWidth(); element.setInnerText(cachedSheetName); handler.onSheetRenameCancel(); break; default: doDeferredInputSizeUpdate(); break; } } } event.stopPropagation(); } }); } /** * Sets the content of the info label. * * @param value * the new content. Can not be HTML. */ public void setInfoLabelValue(String value) { if (value == null) { infoLabel.getStyle().setDisplay(Display.NONE); container.getStyle().setMarginRight(0, Unit.PX); } else { container.getStyle().setMarginRight(206, Unit.PX); infoLabel.getStyle().setDisplay(Display.INLINE); infoLabel.setInnerText(value); } } /** * @return current content of the info label. */ public String getInfoLabelValue() { return infoLabel.getInnerText(); } private double getTabWidth(int index) { Element tab = ((Element) tabs.get(index).cast()); double result = WidgetUtil.getRequiredWidthBoundingClientRectDouble(tab); ComputedStyle cs = new ComputedStyle(tab); result += cs.getMargin()[1]; result += cs.getMargin()[3]; return result; } private void doDeferredInputSizeUpdate() { Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { updateInputSize(); } }); } private int getLastTabVisibleWithScrollIndex() { return getTabVisibleWithScrollIndex(tabs.length() - 1); } private int getTabVisibleWithScrollIndex(int tabIndex) { int tempWidth = root.getOffsetWidth() - ((Element) options.cast()).getOffsetWidth(); if (!infoLabel.getStyle().getDisplay().equals("none")) { tempWidth -= ((Element) infoLabel.cast()).getOffsetWidth(); } tempWidth -= getTabWidth(tabIndex); while (tabIndex > 0 && tempWidth - getTabWidth(tabIndex - 1) > 0) { tabIndex--; tempWidth -= getTabWidth(tabIndex); } return tabIndex; } private void updateInputSize() { String text = input.getValue(); if (text.length() > 31) { text = text.substring(0, 31); input.setValue(text); } tempElement.setInnerText(text); int textWidth = tempElement.getOffsetWidth(); if (textWidth < 50) { textWidth = 50; } // check that the edited tab doesn't overflow the tab sheet Element selectedTab = (Element) tabs.get(selectedTabIndex).cast(); int rootAbsoluteRight = root.getAbsoluteRight(); int selectedTabAbsoluteRight = selectedTab.getAbsoluteRight() + 10; while (selectedTabAbsoluteRight > rootAbsoluteRight && tabScrollIndex < (tabs.length() - 1)) { double width = getTabWidth(tabScrollIndex); selectedTabAbsoluteRight -= width; tabScrollMargin -= width; tabScrollIndex++; } container.getStyle().setMarginLeft(tabScrollMargin, Unit.PX); input.getStyle().setWidth(textWidth + 5, Unit.PX); selectedTab.getStyle().setWidth(textWidth, Unit.PX); } private void commitSheetName() { editing = false; input.removeFromParent(); Element selectedTab = tabs.get(selectedTabIndex).cast(); selectedTab.getStyle().clearWidth(); String value = input.getValue(); if (validateSheetName(value) && !cachedSheetName.equals(value)) { for (int i = 0; i < tabs.length(); i++) { // value cannot be the same as with another sheet if (value.equals(((Element) tabs.get(i).cast()).getInnerText())) { selectedTab.setInnerText(cachedSheetName); return; } } handler.onSheetRename(selectedTabIndex, value); selectedTab.setInnerText(value); showHideScrollIcons(); } else { // TODO show error ? selectedTab.setInnerText(cachedSheetName); } } private boolean validateSheetName(String sheetName) { if (sheetName == null) { return false; } int len = sheetName.length(); if (len < 1 || len > 31) { return false; } for (int i = 0; i < len; i++) { char ch = sheetName.charAt(i); switch (ch) { case '/': case '\\': case '?': case '*': case ']': case '[': case ':': return false; default: // all other chars OK continue; } } if (sheetName.charAt(0) == '\'' || sheetName.charAt(len - 1) == '\'') { return false; } return true; } private Element createTabElement(String tabName) { final Element e = Document.get().createDivElement(); e.setInnerText(tabName); e.setClassName("sheet-tabsheet-tab"); return e; } public void addTabs(String[] tabNames) { for (String tabName : tabNames) { Element e = createTabElement(tabName); container.appendChild(e); tabs.push(e); } showHideScrollIcons(); } public void setTabs(String[] tabNames, boolean clearScrollPosition) { // remove unnecessary tabs if (clearScrollPosition) { container.getStyle().clearMarginLeft(); tabScrollIndex = 0; tabScrollMargin = 0; } for (int i = tabNames.length; i < tabs.length(); i++) { ((Element) tabs.get(i).cast()).removeFromParent(); } tabs.setLength(tabNames.length); for (int i = 0; i < tabNames.length; i++) { JavaScriptObject jso = tabs.get(i); if (jso != null) { ((Element) jso.cast()).setInnerText(tabNames[i]); } else { Element newTab = createTabElement(tabNames[i]); container.appendChild(newTab); tabs.set(i, newTab); } } if (selectedTabIndex >= (tabs.length())) { selectedTabIndex = -1; } showHideScrollIcons(); } public void removeAllTabs() { for (int i = 0; i < tabs.length(); i++) { Element e = tabs.get(i).cast(); e.removeFromParent(); } container.getStyle().clearMarginLeft(); tabs.setLength(0); selectedTabIndex = -1; tabScrollIndex = 0; } /** * * @param sheetIndex * 1-based */ public void setSelectedTab(int sheetIndex) { if (selectedTabIndex != -1) { ((Element) tabs.get(selectedTabIndex).cast()).removeClassName(SELECTED_TAB_CLASSNAME); } selectedTabIndex = sheetIndex - 1; Element selectedTab = ((Element) tabs.get(selectedTabIndex).cast()); selectedTab.addClassName(SELECTED_TAB_CLASSNAME); if (tabScrollIndex > selectedTabIndex) { setFirstVisibleTab(selectedTabIndex); } else if (root.getAbsoluteRight() < selectedTab.getAbsoluteRight() && !editing) { int tempIndex = getTabVisibleWithScrollIndex(selectedTabIndex); setFirstVisibleTab(tempIndex); } } public void setReadOnly(boolean readOnly) { this.readOnly = readOnly; addNewSheet.getStyle().setDisplay(readOnly ? Display.NONE : Display.INLINE_BLOCK); } public void setFirstVisibleTab(int firstVisibleTab) { if (tabScrollIndex < firstVisibleTab) { do { tabScrollMargin -= getTabWidth(tabScrollIndex); tabScrollIndex++; } while (tabScrollIndex < firstVisibleTab); container.getStyle().setMarginLeft(tabScrollMargin, Unit.PX); } else if (tabScrollIndex > firstVisibleTab) { do { tabScrollIndex--; tabScrollMargin += getTabWidth(tabScrollIndex); } while (tabScrollIndex > firstVisibleTab); container.getStyle().setMarginLeft(tabScrollMargin, Unit.PX); } showHideScrollIcons(); } private void showHideScrollIcons() { if (tabScrollIndex == 0) { scrollLeft.addClassName(HIDDEN); scrollBeginning.addClassName(HIDDEN); } else { scrollLeft.removeClassName(HIDDEN); scrollBeginning.removeClassName(HIDDEN); } int lastTabVisibleWithScrollIndex = getLastTabVisibleWithScrollIndex(); if (tabScrollIndex < lastTabVisibleWithScrollIndex) { scrollRight.removeClassName(HIDDEN); scrollEnd.removeClassName(HIDDEN); } else { scrollRight.addClassName(HIDDEN); scrollEnd.addClassName(HIDDEN); } } public void onWidgetResize() { // check if we need to display scroll buttons showHideScrollIcons(); } }