Data-Centric Applications with Vaadin 8
上QQ阅读APP看书,第一时间看更新

Implementing the ApplicationLayout interface

The next step is to implement the ApplicationLayout interface and add the required methods:

  • void addHeaderComponent(Component)
  • void addWorkingAreaComponent(WorkingAreaComponent)
  • Collection<Component> getHeaderComponents()
  • Collection<WorkingAreaComponent> getWorkingAreaComponents()
  • void addMenuOption(MenuOption, SerializableConsumer<MenuOption>)

Implementing the addHeaderComponent(Component) method is quite straightforward:

@Override
public void addHeaderComponent(Component component) {
component.setWidth(null);
header.addComponent(component);
header.setComponentAlignment(component,
Alignment.MIDDLE_RIGHT);
}

The addWorkingAreaComponent(WorkingAreaComponent) method should avoid adding two tabs with the same caption. Instead of adding the same tab twice it should select the corresponding existing tab. A Collection is used to keep track of the added components, as shown in the following code:

public class TabBasedApplicationLayout extends CustomComponent
implements ApplicationLayout {
...

private Collection<WorkingAreaComponent> workingAreaComponents
= new HashSet<>();

@Override
public void addWorkingAreaComponent(WorkingAreaComponent
component) {
addWorkingAreaComponent(component, true);
}

public void addWorkingAreaComponent(WorkingAreaComponent
component, boolean closable) {
if (!workingAreaComponents.contains(component)) {
TabSheet.Tab tab = tabSheet.addTab(
component.getComponent(),
component.getCaption());
tab.setClosable(closable);
tabSheet.setSelectedTab(tab);
workingAreaComponents.add(component);
} else {
showComponent(component.getCaption());
}
}

public void showComponent(String caption) {
IntStream.range(0, tabSheet.getComponentCount())
.mapToObj(tabSheet::getTab)
.filter(tab -> tab.getCaption().equals(caption))
.forEach(tabSheet::setSelectedTab);
}
}

Because this concrete implementation is based on a TabSheet where each tab can or cannot be closed, it makes sense to overload the ApplicationLayout.addWorkingAreaComponent(WorkingAreaComponent) method to allow clients to specify this behavior.

An interesting part of the previous code is the showComponent(String) method, which selects a tab by its caption. This method uses an IntStream to loop through the tabs in the TabSheet. This method is equivalent to the following one:

public void showComponent(String caption) {
for(int i = 0; i < tabSheet.getComponentCount(); i++) {
TabSheet.Tab tab = tabSheet.getTab(i);

if(tab.getCaption().equals(caption)) {
tabSheet.setSelectedTab(tab);
}
}
}
The implementation of showComponents(String) uses two Java 8 features called streams and pipelines. For more information on streams and pipelines, see  http://docs.oracle.com/javase/tutorial/collections/streams/index.html .

The next method to implement is getHeaderComponents():

@Override
public Collection<Component> getHeaderComponents() {
return IntStream.range(0, header.getComponentCount())
.mapToObj(header::getComponent)
.collect(Collectors.toList());
}

This method uses an IntStream similar to the one in the showComponent(String) method. A Collector is used to create a List containing all the components in the header.

Since we already have a Collection object with all the components in the working area, the getWorkingAreaComponents() method implementation is just a regular getter:

@Override
public Collection<WorkingAreaComponent> getWorkingAreaComponents() {
return workingAreaComponents;
}