Copy a layout and all its components


My problem:

In a layout there are some components shown and a button. If a user clicks this button, other components will be shown inside the same layout (all the other components will be removed). One of the new components is also a button. If this button will be clicked, the components which were visible before should be shown again.


My need:

Is there a possibility to copy a layout and all its components?


My workaround:

First I save all available components in a list. If a user clicks then on the button, I will remove all available components on the layout and add instead a new layout with new components to the existing layout. If a user clicks then on the other button, I will remove the new added layout and add all components which I saved before in the list.

Problem:
The components couldn’t have the same order like before (e.g. if they were saved in a GridLayout)…
So that’s the reason why I wanted to copy a whole layout to just replace it…

If i understood you correctly, there is no need to copy stuff…

public class Layout extends VerticalLayout implements Button.ClickListener {
    
    private VerticalLayout layout1 = new VerticalLayout();
    private VerticalLayout layout2 = new VerticalLayout();
    
    private Button button1 = new Button();
    private Button button2 = new Button();
    
    public Layout() {
        initLayout1();
        initLayout2();
        addComponent(layout1);
    }
    
    private void initLayout1() {
        ...add components...
        layout1.addComponent(button1);
    }
    
    private void initLayout2() {
        ...add components...
        layout2.addComponent(button2);
    }

    @Override
    public void buttonClick(ClickEvent event) {
        removeAllComponents();
        if (event.getButton() == button1) addComponent(layout2);
        if (event.getButton() == button2) addComponent(layout1);
    }
}

This works yeah… but it’s not helpful for my case.
I want to copy the layout in an external class.
So the developer just creates a layout, put some components on it and then want to use the helper class. In the constructor he can give the layout as a parameter (AbstractLayout). So in the helper class I don’t know which layout the developer used and which components are on it. I just want to copy it. I don’t want to force the developer always to create the layout twice…

I don’t get it… Can you provide some (pseudo) code so i can see what your case looks like?

Of course!
I tried in another way now: With css style “disable” I set the display into none and with “enable” I set the visibility into visible. But now clicking the infoButton first, its no problem. Clicking this button another time, then the textarea will be shown on another place. It seems that it takes the next column in the parent layout (in this example its a gridlayout)… Also with clicking the closeButton, the content will be visible a little bit higher (it seems that there were more empty rows added…).
I hope you could understand, it’s a bit complicated to explain… :wink:

public class MyUI
extends UI
{ @Override
protected void init(VaadinRequest request)
{
Panel panel = new Panel();
GridLayout layout = new GridLayout(3, 2);
LabelInfo labelInfo = new LabelInfo(layout, …);

  layout.addComponent(labelInfo);
  layout.addComponent(new Label(""));
  layout.addComponent(new Label(""));
  layout.addComponent(new Label(""));
  layout.space();
  layout.addComponent(new Label(""));

  layout.setSpacing(true);
  layout.setSizeFull();
  
  panel.setContent(layout);
  setContent(panel);

}


public class LabelInfo
extends CustomComponent
{
private HorizontalLayout componentLayout;
private Label label;
private TextArea infoText;
private AbstractLayout parentLayout;
private VerticalLayout infoLayout;

public LabelInfo(AbstractLayout layout, …)
{
parentLayout = layout;

  buildMainLayout(...);
  setCompositionRoot(componentLayout);

}

private void buildMainLayout(…)
{
componentLayout = new HorizontalLayout();
label = new Label(“”);
infoText = new TextArea(“”);
Button infoButton = new Button(“”);

  componentLayout.addComponent(label);
  componentLayout.addComponent(infoButton);

  infoButton.addClickListener(new ClickListener() {
     @Override
     public void buttonClick(ClickEvent e)
     {
        showInfo();
     }
  });

}

private void showInfo()
{
Button closeButton = new Button(“”);

  // Remove content from the view, which was available before showing the info
  Iterator<Component> iterator = parentLayout.iterator();
  while (iterator.hasNext()) {
     iterator.next().addStyleName("disable");
  }

  infoLayout = new VerticalLayout();
  infoLayout.addComponent(infoText);
  infoLayout.addComponent(closeButton);
  infoLayout.setSpacing(true);
  parentLayout.addComponent(infoLayout);

  // With closing the information view, all components which were available before will be
  // shown again
  closeButton.addClickListener(new ClickListener() {
     @Override
     public void buttonClick(ClickEvent event)
     {
        parentLayout.removeComponent(infoLayout);

        Iterator<Component> iterator = parentLayout.iterator();
        while (iterator.hasNext()) {
           Component currentComponent = iterator.next();
           currentComponent.removeStyleName("disable");
           currentComponent.addStyleName("enable");
        }
     }
  });

}

}

Ok now I found a solution. I just set the content of the parent panel into another layout :slight_smile:

Thats just what i told you in first place :wink: But i’m glad you solved your problem!