Wrapping grid header (WrappingGrid class)

I am currently using the excellent WrappingGrid in https://vaadin.com/directory/component/gridextensionpack-add-on/1.1.1 (org.vaadin.teemusa.gridextensions.wrappinggrid.WrappingGrid). The wrapping of the header looks rather good, but it seems the frontend code is confused as to the amount of space between the header and the footer. I think this because even with a super simple class that mimics a demo I found, it won’t show the last line when I enable wrapping via a button. What am I doing wrong?

Example class, easy to repeat by calling HeaderWrappingDemoWindow.open(false):

import java.util.Random;

import org.vaadin.teemusa.gridextensions.cachestrategy.CacheStrategyExtension;
import org.vaadin.teemusa.gridextensions.client.tableselection.TableSelectionState.TableSelectionMode;
import org.vaadin.teemusa.gridextensions.tableselection.TableSelectionModel;
import org.vaadin.teemusa.gridextensions.wrappinggrid.WrappingGrid;

import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.server.Responsive;
import com.vaadin.shared.ui.MarginInfo;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Component;
import com.vaadin.ui.Grid;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.themes.ValoTheme;

@SuppressWarnings("serial")
public class HeaderWrappingDemoWindow extends Window {

	public static final String ID = "plan-info-window";
	private HeaderWrappingDemoWindow(boolean wrapInitially ) {
		addStyleName("profile-window");
		setId(ID);
		Responsive.makeResponsive(this);

		setModal(true);
		addCloseShortcut(KeyCode.ESCAPE, null);
		setResizable(true);
		setHeight(90.0f, Unit.PERCENTAGE);
		setWidth(75.0f, Unit.PERCENTAGE);
		setClosable(false);

		VerticalLayout content = new VerticalLayout();
		content.setSizeFull();
		content.setMargin(new MarginInfo(true, false, false, false));
		setContent(content);
		
		content.addComponent(buildHeader());
		
		HeaderWrapExtensionLayout info = new HeaderWrapExtensionLayout(wrapInitially);
		content.addComponent(info);
		content.setExpandRatio(info, 1f);
		
		content.addComponent(buildFooter());
	}

	private Component buildHeader() {
		HorizontalLayout footer = new HorizontalLayout();
		footer.addStyleName(ValoTheme.WINDOW_BOTTOM_TOOLBAR);
		footer.setWidth(100.0f, Unit.PERCENTAGE);

		Button ok = new Button("Close");
		ok.addStyleName(ValoTheme.BUTTON_PRIMARY);
		ok.addClickListener(e->close());
		ok.focus();
		footer.addComponent(ok);
		footer.setComponentAlignment(ok, Alignment.TOP_RIGHT);
		return footer;
	}
	
	private Component buildFooter() {
		HorizontalLayout footer = new HorizontalLayout();
		footer.addStyleName(ValoTheme.WINDOW_BOTTOM_TOOLBAR);
		footer.setWidth(100.0f, Unit.PERCENTAGE);
		
		return footer;
	}

	public static void open(boolean wrapInitially ) {
		Window w = new HeaderWrappingDemoWindow(wrapInitially);
		UI.getCurrent().addWindow(w);
		w.focus();
	}
	
	private class HeaderWrapExtensionLayout extends VerticalLayout {

		private static final String BUTTON_WRAPPING_ENABLED_TEXT = "Turn wrapping off";
		private static final String BUTTON_WRAPPING_DISABLED_TEXT = "Turn wrapping on";
		private int state;

		public HeaderWrapExtensionLayout(boolean wrapInitially) {

			setMargin(true);

			final Grid grid = new Grid();
			final WrappingGrid wrap = WrappingGrid.extend(grid);

			TableSelectionModel selectionModel = new TableSelectionModel();
			selectionModel.setMode(TableSelectionMode.SHIFT);
			grid.setSelectionModel(selectionModel);

			generateData(grid, 5, 100);

			Grid.HeaderRow headerRow = grid.prependHeaderRow();
			headerRow.join(grid.getColumns().get(1).getPropertyId(), grid.getColumns().get(2).getPropertyId());

			Grid.HeaderRow headerRow1 = grid.appendHeaderRow();
			headerRow1.join(grid.getColumns().get(2).getPropertyId(), grid.getColumns().get(3).getPropertyId());
			
			grid.appendFooterRow();

			grid.setSizeFull();

			final Button button = new Button(BUTTON_WRAPPING_DISABLED_TEXT);
			button.addClickListener(new Button.ClickListener() {
//				int state = 0;

				public void buttonClick(ClickEvent event) {
//					state = (state + 1) % 2;
					switch (state) {
					case 0:
						// Disable wrapping, attempt to restore original behavior
						wrap.setWrapping(false);
						button.setCaption(BUTTON_WRAPPING_DISABLED_TEXT);
						state = 1;
						break;
					case 1:
						// Apply wrapping rules
						wrap.setWrapping(true);
						button.setCaption(BUTTON_WRAPPING_ENABLED_TEXT);
						state = 0;
						break;
					}
				}
			});

			addComponent(button);
			addComponent(grid);
			
			setSizeFull();
			setExpandRatio(grid, 1.0f);

			CacheStrategyExtension.extend(grid, 5, 0.2d);
			
			if(wrapInitially)
			{
				addAttachListener(e->{
					wrap.setWrapping(true);
					wrap.setWrapping(false);
					wrap.setWrapping(true);
					button.setCaption(BUTTON_WRAPPING_ENABLED_TEXT);
					state = 0;
				});
			}

		}

		private void generateData(Grid g, int cols, int rows) {
			g.addColumn("#");
			for (int x = 1; x < cols; ++x) {
				g.addColumn("Column with really long title " + (x + 1), String.class);
			}

			Random r = new Random();
			for (int y = 0; y < rows; ++y) {
				String[] values = new String[cols];
				values[0] = "" + (y + 1);
				for (int x = 1; x < cols; ++x) {
					values[x] = "" + r.nextInt() + " babies born last year";
				}
				g.addRow(values);
			}
		}
	}
}

My production code is different, of course, but this is the simplest approximation I could come up with. If you run it by calling HeaderWrappingDemoWindow.open(true), it is even worse on initial load because header rows are spaced apart, sort of covering top row, although at least this time you can see bottom row. Once you click button 2 times, header rows look good, but bottom row or two goes away (covered by footer).

I recall that the solution was somewhat prone to time glitches. Did you remember to recompile the widgetset? I do not remember exactly anymore the details, it is so long time ago I wrote it.

I compiled the widgetset, that did not fix it. That was worth a try, though. I guess something in the Vaadin layout gets confused with regards to the space used. I suppose it might not even be this add-on, but something else. If anyone can think of better questions to ask, I am open to hearing them.

My ultimate goal: When I load the data into my grid, the header and footer look good, and all lines are visible inside the grid, where the header and/or footer are not covering any lines when we get to the top or bottom of the data via scrolling.

Thanks.

Do you think it could be related to the margin around the grid data rows, as per this post? In other words, maybe I need to adjust the top and bottom margin slightly. If so, how would I calculate the new header height so I could adjust the margin around v-grid-body correctly? I don’t wrap the footer, so in theory that might fix itself, if we luck out.

Incidentally, if I am in the browser dev tools and add display:none to footer, last line shows up fine. So last line is under footer.

Also, above, I thought maybe the problem was the margin of the grid content, of the “v-grid-body”, because I saw a margin-top: ##px as part of the style attribute of the div, and “##” always matches the height of the header perfectly. Not really sure how that is calculated on the fly, but right now that doesn’t matter. I tried adding a margin-bottom: 29px to this style, in the browser dev tools, but it did nothing, changed nothing on the screen. Changing margin-top in browser dev tools value changed things right away, so I don’t think it is a refresh/redraw issue. If I disable the margin-top, the top few lines go “under” the header, sort of like the bottom line. The number of lines that go “under” the header exactly match the height of the header. So if the header is 113px, and each line is 26 px, then 4.34 lines will go “under” the header. When I get rid of margin-top, as defined above, it shifts all the lines up, and I can now see the bottom line. This makes sense.

So based on all this, I assumed using margin-bottom: 29px in the v-grid-body element would do something, but I guess not. I even tried adding top-margin: ##px; to the v-grid-footer element, but that did nothing as well.

I just need all the data lines to be entirely between v-grid-header and v-grid-footer. Any other ideas?