All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vaadin.flow.component.tabs.Tabs Maven / Gradle / Ivy

/*
 * Copyright 2000-2017 Vaadin Ltd.
 *
 * 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.vaadin.flow.component.tabs;

import java.io.Serializable;
import java.util.Locale;
import java.util.Objects;

import com.vaadin.flow.component.ClientCallable;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.DomEvent;
import com.vaadin.flow.component.HasOrderedComponents;
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.Synchronize;
import com.vaadin.flow.shared.Registration;

/**
 * Server-side component for the {@code vaadin-tabs} element.
 *
 * @author Vaadin Ltd.
 */
public class Tabs extends GeneratedVaadinTabs
        implements HasOrderedComponents, HasSize {

    private static final String SELECTED = "selected";

    private transient Tab selectedTab;

    /**
     * The valid orientations of {@link Tabs} instances.
     */
    public enum Orientation {
        HORIZONTAL, VERTICAL
    }

    /**
     * Constructs an empty new object with {@link Orientation#HORIZONTAL
     * HORIZONTAL} orientation.
     */
    public Tabs() {
        getElement().addPropertyChangeListener(SELECTED,
                event -> updateSelectedTab());
    }

    /**
     * Constructs a new object enclosing the given tabs, with
     * {@link Orientation#HORIZONTAL HORIZONTAL} orientation.
     *
     * @param tabs
     *            the tabs to enclose
     */
    public Tabs(Tab... tabs) {
        this();
        add(tabs);
    }

    /**
     * Adds the given tabs to the component.
     *
     * @param tabs
     *            the tabs to enclose
     */
    public void add(Tab... tabs) {
        HasOrderedComponents.super.add(tabs);
    }

    /**
     * An event to mark that the selected tab has changed.
     */
    @DomEvent("selected-changed")
    public static class SelectedChangeEvent extends ComponentEvent {
        public SelectedChangeEvent(Tabs source, boolean fromClient) {
            super(source, fromClient);
        }
    }

    /**
     * Adds a listener for {@link SelectedChangeEvent}.
     * 

* NOTE: This method adds a listener for {@link SelectedChangeEvent} * which is a {@link DomEvent}. It means in particular that the listener * will be notified ONLY when event is fired from the * client-side. Even though the server-side may be the originator of the * event (via selection methods) the even will be fired only after the * client-side round-trip. *

* It means that you should not expect the event fired immediately when you * call e.g. {@link #setSelectedTab(Tab)} on the server-side. If you want to * get an event immediately on the server side then you should add a * property change listener for {@literal "selected"} property: * *

     * 
     * Tabs tab =...;
     * tabs.getElement().addPropertyChangeListener("selected", event->{});
     * 
     * 
* * @param listener * the listener to add, not null * @return a handle that can be used for removing the listener */ public Registration addSelectedChangeListener( ComponentEventListener listener) { return addListener(SelectedChangeEvent.class, listener); } /** * Gets the zero-based index of the currently selected tab. * * @return the zero-based index of the selected tab */ @Synchronize(property = SELECTED, value = "selected-changed") public int getSelectedIndex() { return getElement().getProperty(SELECTED, 0); } /** * Selects a tab based on its zero-based index. * * @param selectedIndex * the zero-based index of the selected tab */ public void setSelectedIndex(int selectedIndex) { getElement().setProperty(SELECTED, selectedIndex); } /** * Gets the currently selected tab. * * @return the selected tab */ public Tab getSelectedTab() { int selectedIndex = getSelectedIndex(); Component selectedComponent = getComponentAt(selectedIndex); if (!(selectedComponent instanceof Tab)) { throw new IllegalStateException( "Illegal component inside Tabs: " + selectedComponent); } return (Tab) selectedComponent; } /** * Selects the given tab. * * @param selectedTab * the tab to select * @throws IllegalArgumentException * if {@code selectedTab} is not a child of this component */ public void setSelectedTab(Tab selectedTab) { int selectedIndex = indexOf(selectedTab); if (selectedIndex < 0) { throw new IllegalArgumentException( "Tab to select must be a child: " + selectedTab); } getElement().setProperty(SELECTED, selectedIndex); } /** * Gets the orientation of this tab sheet. * * @return the orientation */ public Orientation getOrientation() { String orientation = getElement().getProperty("orientation"); if (orientation != null) { return Orientation.valueOf(orientation.toUpperCase(Locale.ROOT)); } return Orientation.HORIZONTAL; } /** * Sets the orientation of this tab sheet. * * @param orientation * the orientation */ public void setOrientation(Orientation orientation) { getElement().setProperty("orientation", orientation.name().toLowerCase()); } /** * Sets the flex grow property of all enclosed tabs. The flex grow property * specifies what amount of the available space inside the layout the * component should take up, proportionally to the other components. *

* For example, if all components have a flex grow property value set to 1, * the remaining space in the layout will be distributed equally to all * components inside the layout. If you set a flex grow property of one * component to 2, that component will take twice the available space as the * other components, and so on. *

* Setting to flex grow property value 0 disables the expansion of the * component. Negative values are not allowed. * * @param flexGrow * the proportion of the available space the enclosed tabs should * take up * @throws IllegalArgumentException * if {@code flexGrow} is negative */ public void setFlexGrowForEnclosedTabs(double flexGrow) { if (flexGrow < 0) { throw new IllegalArgumentException( "Flex grow property must not be negative"); } getChildren().forEach(tab -> ((Tab) tab).setFlexGrow(flexGrow)); } @ClientCallable private void itemsChanged() { Tab currentlySelected = getSelectedTab(); if (!Objects.equals(currentlySelected, selectedTab)) { selectedTab = currentlySelected; } } private void updateSelectedTab() { Tab selected = getSelectedTab(); if (selected.isEnabled()) { selectedTab = selected; getChildren().filter(Tab.class::isInstance).map(Tab.class::cast) .forEach(tab -> tab.setSelected(false)); selectedTab.setSelected(true); } else { updateEnabled(selected); setSelectedTab(selectedTab); } } private void updateEnabled(Tab tab) { boolean enabled = tab.isEnabled(); Serializable rawValue = tab.getElement().getPropertyRaw("disabled"); if (rawValue instanceof Boolean) { // convert the boolean value to a String to force update the // property value. Otherwise since the provided value is the same as // the current one the update don't do anything. tab.getElement().setProperty("disabled", enabled ? null : Boolean.TRUE.toString()); } else { tab.setEnabled(enabled); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy