docs: protected void layoutGroups() {
  		log.debug("Starting groups layout...");
  		for (DJGroup columnsGroup : getReport().getColumnsGroups()) {
  			JRDesignGroup jgroup = getJRGroupFromDJGroup(columnsGroup);
  
  			jgroup.setStartNewPage(columnsGroup.isStartInNewPage());
  			jgroup.setStartNewColumn(columnsGroup.isStartInNewColumn());
  			jgroup.setReprintHeaderOnEachPage(columnsGroup.isReprintHeaderOnEachPage());
  			jgroup.setResetPageNumber(columnsGroup.isResetPageNumber());
  
  			JRDesignSection headerSection = (JRDesignSection) jgroup.getGroupHeaderSection();
  			JRDesignSection footerSection = (JRDesignSection) jgroup.getGroupFooterSection();
  
  			JRDesignBand header = LayoutUtils.getBandFromSection(headerSection);
  			JRDesignBand footer = LayoutUtils.getBandFromSection(footerSection);
  
  			//double check to prevent NPE
  			if (header == null) {
  				header = new JRDesignBand();
  				headerSection.addBand(header);
  			}
  			if (footer == null) {
  				footer = new JRDesignBand();
  				footerSection.addBand(footer);
  			}
  
  			header.setHeight(columnsGroup.getHeaderHeight());
  			footer.setHeight(columnsGroup.getFooterHeight());
  
  			header.setSplitType(LayoutUtils.getSplitTypeFromBoolean(columnsGroup.isAllowHeaderSplit()));
  			footer.setSplitType(LayoutUtils.getSplitTypeFromBoolean(columnsGroup.isAllowFooterSplit()));
  
  			if (columnsGroup.getLayout().isPrintHeaders()) {
  				boolean found = false;
  				boolean skipPreviousGroupHeaders = false;
  				int groupIdx = getReport().getColumnsGroups().indexOf(columnsGroup);
  				if (groupIdx > 0) {
  					DJGroup prevG = getReport().getColumnsGroups().get(groupIdx - 1);
  					if (!(prevG.getColumnToGroupBy() instanceof GlobalGroupColumn))
  						skipPreviousGroupHeaders = !prevG.getLayout().isShowValueForEachRow();
  				}
  				for (Object o : getVisibleColumns()) {
  					AbstractColumn col = (AbstractColumn) o;
  
  					//If in a nested group, header for column prior to this groups column
  					//depends on configuration
  
  					if (col.equals(columnsGroup.getColumnToGroupBy())) {
  						found = true;
  					}
  
  					if (!found && skipPreviousGroupHeaders) {
  						continue;
  					}
  
  					JRDesignTextField designTextField = createColumnNameTextField(columnsGroup, col);
  					designTextField.setPositionType(PositionTypeEnum.FLOAT); //XXX changed to see what happens  (must come from the column position property)
  					designTextField.setStretchType(StretchTypeEnum.NO_STRETCH); //XXX changed to see what happens (must come from the column property)
  					header.addElement(designTextField);
  				}
  			}
  
  			DJGroupLabel label = columnsGroup.getFooterLabel();
  			if (label != null) {
  				List<DJGroupVariable> footerVariables = columnsGroup.getFooterVariables();
  				PropertyColumn col = columnsGroup.getColumnToGroupBy();
  				int x = 0, y = 0;
  				//max width
  				int width = getDesign().getPageWidth() - getDesign().getLeftMargin() - getDesign().getRightMargin();
  				int height = label.getHeight();
  				int yOffset = 0;
  				if (label.getLabelPosition() == LabelPosition.LEFT) {
  					DJGroupVariable lmvar = findLeftMostColumn(footerVariables);
  
  					x = col.getPosX(); //label starts in the column-to-group-by x position
  					y = findYOffsetForGroupLabel(footer);
  					if (lmvar != null) {
  						AbstractColumn lmColumn = lmvar.getColumnToApplyOperation();
  						width = lmColumn.getPosX() - x;
  					} else
  						width -= x;
  					height = getFooterVariableHeight(columnsGroup);
  				} else if (label.getLabelPosition() == LabelPosition.RIGHT) {
  					DJGroupVariable rmvar = findRightMostColumn(footerVariables);
  
  					if (rmvar != null) {
  						AbstractColumn rmColumn = rmvar.getColumnToApplyOperation();
  						x = rmColumn.getPosX() + rmColumn.getWidth();
  					} else
  						x = col.getPosX(); //label starts in the column-to-group-by x position
  					y = findYOffsetForGroupLabel(footer);
  					width -= x;
  					height = getFooterVariableHeight(columnsGroup);
  				} else if (label.getLabelPosition() == LabelPosition.TOP) {
  					x = col.getPosX(); //label starts in the column-to-group-by x position
  					width -= x;
  					yOffset = height;
  				} else if (label.getLabelPosition() == LabelPosition.BOTTOM) {
  					x = col.getPosX(); //label starts in the column-to-group-by x position
  					y = getFooterVariableHeight(columnsGroup);
  					width -= x;
  				}
  				layoutGroupFooterLabels(columnsGroup, jgroup, x, y, width, height);
  				layoutGroupVariables(columnsGroup, jgroup, yOffset);
  			} else {
  				layoutGroupVariables(columnsGroup, jgroup, 0);
  			}
  
  			layoutGroupSubreports(columnsGroup, jgroup);
  			layoutGroupCrosstabs(columnsGroup, jgroup);
  		}
  	}