@Override
	public void layoutContainer(Container parent) {
		synchronized(parent.getTreeLock()) {
			Insets insets = parent.getInsets();
			Component comps[] = parent.getComponents();
			
			if(comps.length == 0)
				return;
			
			int comp = 0;
			
			int wGaps = (cols - 1) * colGap;
			int wNoInsets = parent.getWidth() - (insets.left + insets.right);
			int wComponent = (wNoInsets - wGaps) / cols;
			int wExtra = (wNoInsets - (wComponent * cols + wGaps)) / 2;
			
			int hGaps = (rows - 1) * rowGap;
			int hNoInsets = parent.getHeight() - (insets.top + insets.bottom);
			int hComponent = (hNoInsets - hGaps) / rows;
			int hExtra = (hNoInsets - (hComponent * rows + hGaps)) / 2;
			
			/* wExtra and hExtra are used to center the layout in the parent
			 * container */

			int y = insets.top + hExtra;
			for(int r = 0;(r < rows) && (comp < comps.length);r++) {
				int x = insets.left + wExtra;
				for(int c = 0;(c < cols) && (comp < comps.length);c++) {
					int rowSpan = spans[r][c][0];
					int colSpan = spans[r][c][1];
					boolean isSource = rowSpan != 0 || colSpan != 0;
					if(isSource) {
						int w = (wComponent + colGap) * colSpan - colGap;
						int h = (hComponent + rowGap) * rowSpan - rowGap;
						comps[comp++].setBounds(x,y,w,h);
					}
					x += wComponent + colGap;
				}
				y += hComponent + rowGap;
			}
		}
	}