Mark Tielemans
Mark Tielemans

Reputation: 1568

GXT Grid in ContentPanel messes up BorderLayout

EDIT

Although, thanks to Colin, the problems with the Grid itself are now fixed, the BorderLayoutPanel still initializes the grid on a strange (small) height and the middle border is nowhere to be found.

--

I have a GWT application that has a GXT viewport, containing a BorderLayoutContainer containing another BorderLayoutContainer, like so: Page structure sketch

Now this works fine if I substitute my Grid for a GXT ContentPanel: working with ContentPanel instead of Grid

However, I am unpleasantly surprised when I implement the Grid:

The grid disapproves of my coding

The grid suddenly brings the size of the North component back to something smaller, it hides further under the header (the north component already has a margin-top of 10px), and the line between the grid and TabPanel can no longer be grabbed to resize the viewports. Also, one'd expect the grid to show scrollbars in this scenario. Also, on collapsing the Grid's ContentPanel, the center component doesn't proceed to fill up the leftover space as it should.

The Grid worked fine back when I used GWT panels (DockLayoutPanel, SplitLayoutPanel), so I proceeded to wrap the grid in a VerticalPanel (within a GXT ContentPanel). No changes ensued.

DocGrid UiBinder

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">

<ui:with type="com.sencha.gxt.widget.core.client.grid.ColumnModel"
    field="cm"></ui:with>
<ui:with type="com.sencha.gxt.data.shared.ListStore" field="store"></ui:with>

<ui:with type="com.sencha.gxt.widget.core.client.grid.GridView"
    field="view">
    <ui:attributes stripeRows="true" forceFit="true"></ui:attributes>
</ui:with>

<gxt:ContentPanel ui:field="contentPanel" height="100%" width="100%">
    <row:VerticalLayoutContainer borders="false">
        <row:child>
            <grid:Grid ui:field="grid" cm="{cm}" store="{store}" view="{view}"
                loadMask="true" columnReordering="true" borders="false"
                height="500px">
            </grid:Grid>
        </row:child>
        <row:child>
            <toolbar:PagingToolBar pageSize="20" ui:field="toolBar" width="100%"></toolbar:PagingToolBar>
        </row:child>
    </row:VerticalLayoutContainer>
</gxt:ContentPanel>

Any help or clues are greatly appreciated.

EDIT

by request, DocGrid.java

package nl.opensatisfaction.postkamer.client.ui;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import com.google.gwt.cell.client.DateCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.core.client.IdentityValueProvider;
import com.sencha.gxt.core.client.Style.SelectionMode;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.widget.core.client.ContentPanel;
import com.sencha.gxt.widget.core.client.box.MessageBox;
import com.sencha.gxt.widget.core.client.grid.CheckBoxSelectionModel;
import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
import com.sencha.gxt.widget.core.client.grid.ColumnModel;
import com.sencha.gxt.widget.core.client.grid.Grid;
import com.sencha.gxt.widget.core.client.grid.GridView;
import com.sencha.gxt.widget.core.client.grid.filters.DateFilter;
import com.sencha.gxt.widget.core.client.grid.filters.GridFilters;
import com.sencha.gxt.widget.core.client.grid.filters.StringFilter;
import com.sencha.gxt.widget.core.client.toolbar.PagingToolBar;

public class DocGrid implements IsWidget {
private static final DocumentNodeProperties props = GWT
        .create(DocumentNodeProperties.class);
AlfrescoServiceAsync metadata = GWT.create(AlfrescoService.class);

interface MyUiBinder extends UiBinder<Widget, DocGrid> {
}

private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);

@UiField
ColumnModel<DocumentNode> cm;

@UiField
ListStore<DocumentNode> store;

@UiField
Grid<DocumentNode> grid;

@UiField
GridView<DocumentNode> view;

@UiField
PagingToolBar toolBar;

@UiField
ContentPanel contentPanel;

@Override
public Widget asWidget() {
    IdentityValueProvider<DocumentNode> identity = new IdentityValueProvider<DocumentNode>();
    final CheckBoxSelectionModel<DocumentNode> sm = new CheckBoxSelectionModel<DocumentNode>(identity);
    sm.setSelectionMode(SelectionMode.MULTI);

    ColumnConfig<DocumentNode, String> nameCol = new ColumnConfig<DocumentNode, String>(
            props.nodeRef(), 100, "nodeRef");
    ColumnConfig<DocumentNode, String> documentIdCol = new ColumnConfig<DocumentNode, String>(
            props.documentIdentificatie(), 100, "Document ID");
    ColumnConfig<DocumentNode, Date> ontvangenCol = new ColumnConfig<DocumentNode, Date>(
            props.documentOntvangstdatum(), 100, "Ontvangen");
    ontvangenCol.setCell(new DateCell(OpenPostModule.DATE_FORMAT));
    ColumnConfig<DocumentNode, Date> aanschrijfCol = new ColumnConfig<DocumentNode, Date>(
            props.documentAanschrijfdatum(), 100, "Aangeschreven");
    aanschrijfCol.setCell(new DateCell(OpenPostModule.DATE_FORMAT));
    ColumnConfig<DocumentNode, String> doctypeCol = new ColumnConfig<DocumentNode, String>(
            props.documentTypeOmschrijving(), 100, "Type");
    ColumnConfig<DocumentNode, String> subjectCol = new ColumnConfig<DocumentNode, String>(
            props.afzenderIdentificatie(), 100, "BSN/KVK");
    ColumnConfig<DocumentNode, AlfrescoUser> behandelaarCol = new ColumnConfig<DocumentNode, AlfrescoUser>(
            props.documentBehandelaar(), 100, "Behandelaar"); 
    ColumnConfig<DocumentNode, AlfrescoObject> groepCol = new ColumnConfig<DocumentNode, AlfrescoObject>(
            props.documentGroep(), 100, "Groep");


    List<ColumnConfig<DocumentNode, ?>> l = new ArrayList<ColumnConfig<DocumentNode, ?>>();
    l.add(sm.getColumn());
    l.add(documentIdCol);
    l.add(ontvangenCol);
    l.add(aanschrijfCol);
    l.add(doctypeCol);
    l.add(subjectCol);
    l.add(groepCol);
    l.add(behandelaarCol);

    cm = new ColumnModel<DocumentNode>(l);
    store = new ListStore<DocumentNode>(props.key());

    Widget component = uiBinder.createAndBindUi(this);
    contentPanel.setCollapsible(true);
    contentPanel.setAnimCollapse(true);

    view.setAutoExpandColumn(nameCol);
    grid.setSelectionModel(sm);

    // Column filters
    StringFilter<DocumentNode> nameFilter = new StringFilter<DocumentNode>(props.documentIdentificatie());
    DateFilter<DocumentNode> dateFilter = new DateFilter<DocumentNode>(props.documentOntvangstdatum());
    DateFilter<DocumentNode> dateFilter2 = new DateFilter<DocumentNode>(props.documentAanschrijfdatum());
    StringFilter<DocumentNode> docTypeFilter = new StringFilter<DocumentNode>(props.documentTypeOmschrijving());
    StringFilter<DocumentNode> subjectFilter = new StringFilter<DocumentNode>(props.documentTitel());
    StringFilter<DocumentNode> groepFilter = new StringFilter<DocumentNode>(props.documentGroepLabel());
    StringFilter<DocumentNode> behandelaarFilter = new StringFilter<DocumentNode>(props.documentBehandelaarLabel());

    GridFilters<DocumentNode> filters = new GridFilters<DocumentNode>();
    filters.initPlugin(grid);
    filters.setLocal(true);
    filters.addFilter(nameFilter);
    filters.addFilter(dateFilter);
    filters.addFilter(dateFilter2);
    filters.addFilter(docTypeFilter);
    filters.addFilter(subjectFilter);
    filters.addFilter(groepFilter);
    filters.addFilter(behandelaarFilter);

    return component;
}

@UiFactory
ColumnModel<DocumentNode> createColumnModel() {
    return cm;
}

@UiFactory
ListStore<DocumentNode> createListStore() {
    return store;
}

public void fillGrid(AlfrescoUser user) {
    metadata.getPoststukken(user, new AsyncCallback<ArrayList<DocumentNode>>() {

        @Override
        public void onSuccess(ArrayList<DocumentNode> result) {
            // Sorts DocumentNode by its generatedPriority
            Collections.sort(result);
            store.addAll(result);
            if(result.size()==0) {
                new MessageBox("", "er zijn geen poststukken gevonden.").show();
            }
        }

        @Override
        public void onFailure(Throwable caught) {
            if(caught instanceof CustomException) {
                new MessageBox(((CustomException) caught).getTitle(), caught.getMessage()).show();
                if(caught instanceof CustomException) {
                    // TODO: move logic to PostCenter, then act appropriately
                    new MessageBox("Uitgelogd", "U bent uitgelogd.");
                }
            }
        }
    });
}

public void removeDocument(String documentIdentificatie) {
    for(DocumentNode doc : grid.getStore().getAll()) {
        if(doc.getDocumentIdentificatie().equals(documentIdentificatie)) {
            DebugClient.debug("Removing row with id " + doc.getDocumentIdentificatie(), this.getClass());
            grid.getStore().remove(doc);
            break;
        }
    }
}

public void updateRow(DocumentNode node) {
    DebugClient.debug("Updating row with id " + node.getDocumentIdentificatie(), this.getClass());
    grid.getStore().update(node);
}

}

EDIT: BLP UiBinder

This is the UiBinder code that includes the DocGrid. This is the one directly on the RootPanel.

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">

<ui:style>
    .important {
        font-weight: bold;
    }
</ui:style>

<ui:with type="com.sencha.gxt.core.client.util.Margins" field="zeroMargins">
    <ui:attributes top="0" right="0" bottom="0" left="0" />
</ui:with>
<ui:with type="com.sencha.gxt.core.client.util.Margins" field="correctionMargins">
    <ui:attributes top="10" right="0" bottom="0" left="0" />
</ui:with>

<ui:with
    type="com.sencha.gxt.widget.core.client.container.BorderLayoutContainer.BorderLayoutData"
    field="northData">
    <ui:attributes size="35" collapsible="false" split="false"
        margins="{zeroMargins}" />
</ui:with>
<ui:with
    type="com.sencha.gxt.widget.core.client.container.BorderLayoutContainer.BorderLayoutData"
    field="southData">
    <ui:attributes size="20" collapsible="false" split="false"
        margins="{zeroMargins}" />
</ui:with>
<ui:with
    type="com.sencha.gxt.widget.core.client.container.BorderLayoutContainer.BorderLayoutData"
    field="innerWestData">
    <ui:attributes size="600" collapsible="true" split="true"
        margins="{zeroMargins}" />
</ui:with>
<ui:with
    type="com.sencha.gxt.widget.core.client.container.BorderLayoutContainer.BorderLayoutData"
    field="gridContainerData">
    <ui:attributes size="500" collapsible="true" split="true"
        margins="{correctionMargins}" />
</ui:with>


<container:Viewport>
    <container:BorderLayoutContainer
        ui:field="dockPanel">
        <container:north layoutData="{northData}">
            <os:Header ui:field="osHeader" />
        </container:north>

        <container:west layoutData="{innerWestData}">

            <container:BorderLayoutContainer
                ui:field="innerSplitPanel">
                <container:north layoutData="{gridContainerData}">
                    <os:DocGrid ui:field="docGrid" />
                </container:north>
                <container:center>
                    <os:MetaTabPanel ui:field="metaTabs"></os:MetaTabPanel>
                    <!-- <gxt:ContentPanel /> -->
                </container:center>
            </container:BorderLayoutContainer>

            <!-- <g:SplitLayoutPanel ui:field="innerSplitPanel"> <g:north size="500"> 
                <os:DocGrid ui:field="docGrid" /> </g:north> <g:center> <os:MetaTabPanel 
                ui:field="metaTabs" /> </g:center> </g:SplitLayoutPanel> -->

        </container:west>

        <container:center>
            <g:Frame ui:field="viewport" width="100%" height="100%"
                styleName="pdfPanel" />
        </container:center>

        <container:south layoutData="{southData}">
            <container:HtmlLayoutContainer
                ui:field="footer" />
        </container:south>
    </container:BorderLayoutContainer>
</container:Viewport>

</ui:UiBinder>

The relevant java is as such (constructor of the UiBinder's class):

    initWidget(uiBinder.createAndBindUi(this));

    osHeader.setMenuLabel(this.user.getLabel());

    docGrid.fillGrid(user);

    // Docgrid selection handler
    docGrid.grid.getSelectionModel().addSelectionChangedHandler(new SelectionChangedHandler<DocumentNode>() {

        @Override
        public void onSelectionChanged(SelectionChangedEvent<DocumentNode> event) {
            List<DocumentNode> selected = event.getSelection();
            if (selected.size()>0) {
                documentSelected(selected.get(0));
            }
        }
    }); 

Upvotes: 0

Views: 3913

Answers (1)

Colin Alworth
Colin Alworth

Reputation: 18356

Add layout data to the Grid and PagingToolbar within the VLC in that widget. The toolbar probably should be set to be 100% width (i.e. width="1.0"), and use only the height it needs (height="-1"), and the Grid should use all width and all height (height="1.0" and `width="1.0"). This will probably look more or less like this (from http://www.sencha.com/examples/#ExamplePlace:paginguibindergrid)

<ui:with type="com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData" field="middleData">
  <ui:attributes width="1" height="1" />
</ui:with>

<ui:with type="com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData" field="bottomData">
  <ui:attributes width="1" height="-1" />
</ui:with>

<ui:with type="com.sencha.gxt.widget.core.client.grid.GridView" field="view">
  <ui:attributes stripeRows="true" forceFit="true"></ui:attributes>
</ui:with>

<gxt:FramedPanel ui:field="panel" headingText="Grid UiBinder Example" pixelSize="600, 300"
  collapsible="true" addStyleNames="margin-10">
  <row:VerticalLayoutContainer borders="true">
    <row:child layoutData="{middleData}">
      <grid:Grid ui:field="grid" cm="{cm}" store="{store}" view="{view}" loadMask="true" columnReordering="true"
        borders="false">
      </grid:Grid>

    </row:child>
    <row:child layoutData="{bottomData}">
      <toolbar:PagingToolBar pageSize="50" ui:field="toolBar"></toolbar:PagingToolBar>
    </row:child>
  </row:VerticalLayoutContainer>
</gxt:FramedPanel>

It is then also important that your class backing that xml file is capable of being resized by its parent. Either extend ResizeComposite to get that notification or implement RequiresResize and have that call the ContentPanel's own onResize function, or don't deal with Composite at all, but just implement IsWidget, and have asWidget() return the ContentPanel.

In this case you've got the Java resize wiring correct. However, if asWidget() is called multiple times, you will end up generating multiple copies of a widget - make sure this always returns the same one, probably by storing it in a field and checking if it is null (i.e. createAndBind hasn't been called yet).

Upvotes: 1

Related Questions