Java tutorial
/* * Copyright (c) 2008-2016 Haulmont. * * 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 com.haulmont.cuba.web.gui.components; import com.haulmont.cuba.core.entity.Entity; import com.haulmont.cuba.gui.ComponentsHelper; import com.haulmont.cuba.gui.components.*; import com.haulmont.cuba.gui.data.HierarchicalDatasource; import com.haulmont.cuba.gui.data.impl.CollectionDsListenersWrapper; import com.haulmont.cuba.web.toolkit.ui.CubaTree; import com.vaadin.event.ShortcutListener; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.CssLayout; import com.vaadin.ui.HorizontalLayout; import org.apache.commons.lang.StringUtils; import org.slf4j.LoggerFactory; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; public abstract class WebAbstractTree<T extends CubaTree, E extends Entity> extends WebAbstractList<T, E> implements Tree<E> { private static final String HAS_TOP_PANEL_STYLENAME = "has-top-panel"; // Style names used by tree itself protected List<String> internalStyles = new ArrayList<>(); protected List<Tree.StyleProvider> styleProviders; // lazily initialized List protected StyleGeneratorAdapter styleGenerator; // lazily initialized field protected CollectionDsListenersWrapper collectionDsListenersWrapper; protected ButtonsPanel buttonsPanel; protected HorizontalLayout topPanel; protected com.vaadin.ui.CssLayout componentComposition; protected Action enterPressAction; protected IconProvider<? super E> iconProvider; @Override public HierarchicalDatasource getDatasource() { return (HierarchicalDatasource) super.getDatasource(); } @Override public void collapseTree() { component.collapseAll(); } @Override public void expandTree() { component.expandAll(); } @Override public void collapse(Object itemId) { component.collapseItemRecursively(itemId); } @Override public void expand(Object itemId) { component.expandItemWithParents(itemId); } @Override public void expandUpTo(int level) { component.expandUpTo(level); } @Override public boolean isExpanded(Object itemId) { return component.isExpanded(itemId); } @Override public boolean isEditable() { return !component.isReadOnly(); } @Override public void setEditable(boolean editable) { component.setReadOnly(!editable); } @Override public String getIcon() { return icon; } @Override public void setIcon(String icon) { this.icon = icon; getComposition().setIcon(WebComponentsHelper.getIcon(icon)); } @Override public String getCaption() { return getComposition().getCaption(); } @Override public void setCaption(String caption) { getComposition().setCaption(caption); } @Override public String getDescription() { return getComposition().getDescription(); } @Override public void setDescription(String description) { if (getComposition() instanceof AbstractComponent) { ((AbstractComponent) getComposition()).setDescription(description); } } @Override public ButtonsPanel getButtonsPanel() { return buttonsPanel; } @Override public com.vaadin.ui.Component getComposition() { return componentComposition; } @Override public void setButtonsPanel(ButtonsPanel panel) { if (buttonsPanel != null && topPanel != null) { topPanel.removeComponent(buttonsPanel.unwrap(com.vaadin.ui.Component.class)); buttonsPanel.setParent(null); } buttonsPanel = panel; if (panel != null) { if (panel.getParent() != null && panel.getParent() != this) { throw new IllegalStateException("Component already has parent"); } if (topPanel == null) { topPanel = createTopPanel(); topPanel.setWidth("100%"); componentComposition.addComponentAsFirst(topPanel); } topPanel.addComponent(panel.unwrap(com.vaadin.ui.Component.class)); if (panel instanceof VisibilityChangeNotifier) { ((VisibilityChangeNotifier) panel) .addVisibilityChangeListener(event -> updateCompositionStylesTopPanelVisible()); } panel.setParent(this); } updateCompositionStylesTopPanelVisible(); } protected HorizontalLayout createTopPanel() { HorizontalLayout topPanel = new HorizontalLayout(); topPanel.setStyleName("c-tree-top"); return topPanel; } // if buttons panel becomes hidden we need to set top panel height to 0 protected void updateCompositionStylesTopPanelVisible() { if (topPanel != null) { boolean hasChildren = topPanel.getComponentCount() > 0; boolean anyChildVisible = false; for (com.vaadin.ui.Component childComponent : topPanel) { if (childComponent.isVisible()) { anyChildVisible = true; break; } } boolean topPanelVisible = hasChildren && anyChildVisible; if (!topPanelVisible) { componentComposition.removeStyleName(HAS_TOP_PANEL_STYLENAME); internalStyles.remove(HAS_TOP_PANEL_STYLENAME); } else { componentComposition.addStyleName(HAS_TOP_PANEL_STYLENAME); if (!internalStyles.contains(HAS_TOP_PANEL_STYLENAME)) { internalStyles.add(HAS_TOP_PANEL_STYLENAME); } } } } public void initComponent(CubaTree component) { componentComposition = new CssLayout(); componentComposition.setPrimaryStyleName("c-tree-composition"); componentComposition.setWidthUndefined(); componentComposition.addComponent(component); component.setSizeFull(); component.addShortcutListener( new ShortcutListener("tableEnter", com.vaadin.event.ShortcutAction.KeyCode.ENTER, null) { @Override public void handleAction(Object sender, Object target) { if (target == WebAbstractTree.this.component) { if (enterPressAction != null) { enterPressAction.actionPerform(WebAbstractTree.this); } else { handleClickAction(); } } } }); } protected void handleClickAction() { Action action = getItemClickAction(); if (action == null) { action = getEnterPressAction(); if (action == null) { action = getAction("edit"); if (action == null) { action = getAction("view"); } } } if (action != null && action.isEnabled()) { Window window = ComponentsHelper.getWindowImplementation(WebAbstractTree.this); if (window instanceof Window.Wrapper) { window = ((Window.Wrapper) window).getWrappedWindow(); } if (!(window instanceof Window.Lookup)) { action.actionPerform(WebAbstractTree.this); } else { Window.Lookup lookup = (Window.Lookup) window; com.haulmont.cuba.gui.components.Component lookupComponent = lookup.getLookupComponent(); if (lookupComponent != this) action.actionPerform(WebAbstractTree.this); else if (action.getId().equals(WindowDelegate.LOOKUP_ITEM_CLICK_ACTION_ID)) { action.actionPerform(WebAbstractTree.this); } } } } @Override public void setLookupSelectHandler(Runnable selectHandler) { component.setDoubleClickMode(true); component.addItemClickListener(event -> { if (event.isDoubleClick()) { if (event.getItem() != null) { component.setValue(event.getItemId()); selectHandler.run(); } } }); } @Override public Collection getLookupSelectedItems() { return getSelected(); } @Override protected String getAlternativeDebugId() { if (id != null) { return id; } if (datasource != null && StringUtils.isNotEmpty(datasource.getId())) { return getClass().getSimpleName() + "_" + datasource.getId(); } return getClass().getSimpleName(); } protected StyleGeneratorAdapter createStyleGenerator() { return new StyleGeneratorAdapter(); } @SuppressWarnings("unchecked") protected String getGeneratedStyle(Object itemId) { if (styleProviders == null) { return null; } Entity item = datasource.getItem(itemId); String joinedStyle = null; for (Tree.StyleProvider styleProvider : styleProviders) { String styleName = styleProvider.getStyleName(item); if (styleName != null) { if (joinedStyle == null) { joinedStyle = styleName; } else { joinedStyle += " " + styleName; } } } return joinedStyle; } @Override public void setMultiSelect(boolean multiselect) { super.setMultiSelect(multiselect); } @Override public void refresh() { datasource.refresh(); } @Override public void setStyleName(String name) { super.setStyleName(name); for (String internalStyle : internalStyles) { componentComposition.addStyleName(internalStyle); } } @Override public String getStyleName() { String styleName = super.getStyleName(); for (String internalStyle : internalStyles) { styleName = styleName.replace(internalStyle, ""); } return StringUtils.normalizeSpace(styleName); } @Override public void setStyleProvider(@Nullable Tree.StyleProvider<? super E> styleProvider) { if (styleProvider != null) { if (this.styleProviders == null) { this.styleProviders = new LinkedList<>(); } else { this.styleProviders.clear(); } this.styleProviders.add(styleProvider); } else { this.styleProviders = null; } if (this.styleGenerator == null) { this.styleGenerator = createStyleGenerator(); component.setItemStyleGenerator(this.styleGenerator); } else { component.markAsDirty(); } } @Override public void addStyleProvider(Tree.StyleProvider<? super E> styleProvider) { if (this.styleProviders == null) { this.styleProviders = new LinkedList<>(); } if (!this.styleProviders.contains(styleProvider)) { this.styleProviders.add(styleProvider); if (this.styleGenerator == null) { this.styleGenerator = createStyleGenerator(); component.setItemStyleGenerator(this.styleGenerator); } else { component.markAsDirty(); } } } @Override public void removeStyleProvider(Tree.StyleProvider<? super E> styleProvider) { if (this.styleProviders != null) { if (this.styleProviders.remove(styleProvider)) { component.markAsDirty(); } } } protected class StyleGeneratorAdapter implements com.vaadin.ui.Tree.ItemStyleGenerator { protected boolean exceptionHandled = false; public static final String CUSTOM_STYLE_NAME_PREFIX = "cs "; @Override public String getStyle(com.vaadin.ui.Tree source, Object itemId) { try { String style = null; if (styleProviders != null) { String generatedStyle = getGeneratedStyle(itemId); if (generatedStyle != null) { style = CUSTOM_STYLE_NAME_PREFIX + generatedStyle; } } return style == null ? null : (CUSTOM_STYLE_NAME_PREFIX + style); } catch (Exception e) { LoggerFactory.getLogger(WebAbstractTree.class).error("Uncautch exception in Tree StyleProvider", e); this.exceptionHandled = true; return null; } } public void resetExceptionHandledFlag() { this.exceptionHandled = false; } } @Override public void repaint() { component.markAsDirty(); } @Override public void setIconProvider(IconProvider<? super E> iconProvider) { if (this.iconProvider != iconProvider) { this.iconProvider = iconProvider; if (iconProvider == null) { component.setItemIconProvider(null); } else { component.setItemIconProvider(itemId -> { @SuppressWarnings("unchecked") E item = (E) datasource.getItem(itemId); if (item == null) { return null; } String resourceUrl = WebAbstractTree.this.iconProvider.getItemIcon(item); if (StringUtils.isBlank(resourceUrl)) { return null; } // noinspection ConstantConditions if (!resourceUrl.contains(":")) { resourceUrl = "theme:" + resourceUrl; } return WebComponentsHelper.getResource(resourceUrl); }); } } } @Override public void setEnterPressAction(Action action) { enterPressAction = action; } @Override public Action getEnterPressAction() { return enterPressAction; } @Override public int getTabIndex() { return component.getTabIndex(); } @Override public void setTabIndex(int tabIndex) { component.setTabIndex(tabIndex); } }