Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2000-2024 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.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.HasStyle;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.Text;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.component.shared.HasPrefix;
import com.vaadin.flow.component.shared.HasSuffix;
import com.vaadin.flow.component.shared.HasThemeVariant;
import com.vaadin.flow.component.shared.SlotUtils;
import com.vaadin.flow.dom.Element;
import com.vaadin.flow.function.SerializableConsumer;
import com.vaadin.flow.shared.Registration;
/**
* TabSheet consists of a set of tabs and the content area. The content area
* displays a component associated with the selected tab.
*
* @author Vaadin Ltd.
*/
@Tag("vaadin-tabsheet")
@NpmPackage(value = "@vaadin/tabsheet", version = "24.4.9")
@JsModule("@vaadin/tabsheet/src/vaadin-tabsheet.js")
public class TabSheet extends Component implements HasPrefix, HasStyle, HasSize,
HasSuffix, HasThemeVariant {
private Tabs tabs = new Tabs();
private Map tabToContent = new HashMap<>();
/**
* The default constructor.
*/
public TabSheet() {
super();
SlotUtils.addToSlot(this, "tabs", tabs);
addSelectedChangeListener(e -> {
getElement().setProperty("selected", tabs.getSelectedIndex());
updateContent();
});
}
/**
* Adds a tab created from the given text and content.
*
* @param tabText
* the text of the tab
* @param content
* the content related to the tab
* @return the created tab
*/
public Tab add(String tabText, Component content) {
return add(new Tab(tabText), content);
}
/**
* Adds a tab created from the given tab content and content.
*
* @param tabContent
* the content of the tab
* @param content
* the content related to the tab
* @return the created tab
*/
public Tab add(Component tabContent, Component content) {
return add(new Tab(tabContent), content);
}
/**
* Adds a tab with the given content.
*
* @param tab
* the tab
* @param content
* the content related to the tab
* @return the added tab
*/
public Tab add(Tab tab, Component content) {
return add(tab, content, -1);
}
/**
* Adds a tab with the given content to the given position.
*
* @param tab
* the tab
* @param content
* the content related to the tab
* @param position
* the position where the tab should be added. If negative, the
* tab is added at the end.
* @return the added tab
*/
public Tab add(Tab tab, Component content, int position) {
Objects.requireNonNull(tab, "The tab to be added cannot be null");
Objects.requireNonNull(content,
"The content to be added cannot be null");
if (content instanceof Text) {
throw new IllegalArgumentException(
"Text as content is not supported. Consider wrapping the Text inside a Div.");
}
if (position < 0) {
tabs.add(tab);
} else {
tabs.addTabAtIndex(position, tab);
}
// Make sure possible old content related to the same tab gets removed
if (tabToContent.containsKey(tab)) {
tabToContent.get(tab).removeFromParent();
}
linkTabToContent(tab, content);
tabToContent.put(tab, content.getElement());
updateContent();
return tab;
}
private void linkTabToContent(Tab tab, Component content) {
runBeforeClientResponse(ui -> {
// On the client, content is associated with a tab by id
var tabId = tab.getId().orElse("tabsheet-tab-" + UUID.randomUUID());
tab.setId(tabId);
content.getElement().setAttribute("tab", tabId);
});
}
private void runBeforeClientResponse(SerializableConsumer command) {
getElement().getNode().runWhenAttached(ui -> ui
.beforeClientResponse(this, context -> command.accept(ui)));
}
/**
* Removes a tab.
*
* @param tab
* the non-null tab to be removed
*/
public void remove(Tab tab) {
Objects.requireNonNull(tab, "The tab to be removed cannot be null");
var content = tabToContent.remove(tab);
content.removeFromParent();
tabs.remove(tab);
}
/**
* Removes a tab based on the content
*
* @param content
* the non-null content related to the tab to be removed
*/
public void remove(Component content) {
Objects.requireNonNull(content,
"The content of the tab to be removed cannot be null");
if (content instanceof Text) {
throw new IllegalArgumentException(
"Text as content is not supported.");
}
var tab = getTab(content);
if (tab != null) {
remove(tab);
}
}
/**
* Removes the tab at the given position.
*
* @param position
* the position of the tab to be removed
*/
public void remove(int position) {
remove(getTabAt(position));
}
/**
* Gets the zero-based index of the currently selected tab.
*
* @return the zero-based index of the selected tab, or -1 if none of the
* tabs is selected
*/
public int getSelectedIndex() {
return tabs.getSelectedIndex();
}
/**
* Selects a tab based on its zero-based index.
*
* @param selectedIndex
* the zero-based index of the selected tab, -1 to unselect all
*/
public void setSelectedIndex(int selectedIndex) {
tabs.setSelectedIndex(selectedIndex);
}
/**
* Gets the currently selected tab.
*
* @return the selected tab, or {@code null} if none is selected
*/
public Tab getSelectedTab() {
return tabs.getSelectedTab();
}
/**
* Selects the given tab.
*
* @param selectedTab
* the tab to select, {@code null} to unselect all
* @throws IllegalArgumentException
* if {@code selectedTab} is not a child of this component
*/
public void setSelectedTab(Tab selectedTab) {
tabs.setSelectedTab(selectedTab);
}
/**
* Returns the tab at the given position.
*
* @param position
* the position of the tab, must be greater than or equals to 0
* and less than the number of tabs
* @return The tab at the given index
* @throws IllegalArgumentException
* if the index is less than 0 or greater than or equals to the
* number of tabs
*/
public Tab getTabAt(int position) {
return tabs.getTabAt(position);
}
/**
* Returns the index of the given tab.
*
* @param tab
* the tab to look up, can not be null
* @return the index of the tab or -1 if the tab is not added
*/
public int getIndexOf(Tab tab) {
return tabs.indexOf(tab);
}
/**
* Returns the {@link Tab} associated with the given component.
*
* @param content
* the component to look up, can not be null
* @return The tab instance associated with the given component, or
* null if the {@link TabSheet} does not contain the
* component.
*/
public Tab getTab(Component content) {
Objects.requireNonNull(content,
"The component to look for the tab cannot be null");
return tabToContent.entrySet().stream()
.filter(entry -> entry.getValue().equals(content.getElement()))
.map(Map.Entry::getKey).findFirst().orElse(null);
}
/**
* Returns the {@link Component} instance associated with the given tab.
*
* @param tab
* the tab to look up, can not be null
* @return The component instance associated with the given tab, or
* null if the {@link TabSheet} does not contain the
* tab.
*/
public Component getComponent(Tab tab) {
Objects.requireNonNull(tab,
"The tab to look for the component cannot be null");
var tabContent = tabToContent.get(tab);
if (tabContent == null) {
return null;
}
return tabContent.getComponent().orElse(null);
}
/**
* Adds a listener for {@link SelectedChangeEvent}.
*
* @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 tabs.addSelectedChangeListener(event -> {
listener.onComponentEvent(new SelectedChangeEvent(TabSheet.this,
event.getPreviousTab(), event.isFromClient(),
event.isInitialSelection()) {
@Override
public void unregisterListener() {
event.unregisterListener();
}
});
});
}
/**
* Marks the content related to the selected tab as enabled and adds it to
* the component if it is not already added. All the other content panels
* are disabled so they can't be interacted with.
*/
private void updateContent() {
for (Map.Entry entry : tabToContent.entrySet()) {
var tab = entry.getKey();
var content = entry.getValue();
if (tab.equals(tabs.getSelectedTab())) {
if (content.getParent() == null) {
getElement().appendChild(content);
}
content.setEnabled(true);
} else {
// Can't use setEnabled(false) because it would also mark the
// elements as disabled in the DOM. Navigating between tabs
// would then briefly show the content as disabled.
content.getNode().setEnabled(false);
}
}
}
/**
* An event to mark that the selected tab has changed.
*/
public static class SelectedChangeEvent extends ComponentEvent {
private final Tab selectedTab;
private final Tab previousTab;
private final boolean initialSelection;
/**
* Creates a new selected change event.
*
* @param source
* The TabSheet that fired the event.
* @param previousTab
* The previous selected tab.
* @param fromClient
* true for client-side events,
* false otherwise.
*/
public SelectedChangeEvent(TabSheet source, Tab previousTab,
boolean fromClient, boolean initialSelection) {
super(source, fromClient);
this.selectedTab = source.getSelectedTab();
this.initialSelection = initialSelection;
this.previousTab = previousTab;
}
/**
* Get selected tab for this event. Can be {@code null} when autoselect
* is set to false.
*
* @return the selected tab for this event
*/
public Tab getSelectedTab() {
return this.selectedTab;
}
/**
* Get previous selected tab for this event. Can be {@code null} when
* autoselect is set to false.
*
* @return the selected tab for this event
*/
public Tab getPreviousTab() {
return this.previousTab;
}
/**
* Checks if this event is initial TabSheet selection.
*
* @return true if the event is initial TabSheet selection,
* false otherwise
*/
public boolean isInitialSelection() {
return this.initialSelection;
}
}
}