ProportionalLayout implements LayoutManager2 { public static ProportionalLayout fromString(@NotNull String columnDefinitions) throws IllegalArgumentException { List<String> splits = Lists.newArrayList(Splitter.on(',').split(columnDefinitions)); int numColumns = splits.size(); ColumnDefinition[] definitions = new ColumnDefinition[numColumns]; try { for (int i = 0; i < splits.size(); i++) { String s = splits.get(i); if (s.equals("Fit")) { definitions[i] = new ColumnDefinition(Type.Fit); } else if (s.endsWith("px")) { int value = Integer.parseInt(s.substring(0, s.length() - 2)); definitions[i] = new ColumnDefinition(Type.Fixed, value); } else if (s.equals("*")) { definitions[i] = new ColumnDefinition(Type.Proportional, 1); } else if (s.endsWith("*")) { int value = Integer.parseInt(s.substring(0, s.length() - 1)); definitions[i] = new ColumnDefinition(Type.Proportional, value); } else { throw new IllegalArgumentException(String.format("Bad column definition: \"%1$s\" in \"%2$s\"", s, columnDefinitions)); } } } catch (NumberFormatException ex) { throw new IllegalArgumentException(String.format("Bad column definition: \"%s\"", columnDefinitions)); } return new ProportionalLayout(definitions); } ProportionalLayout(ColumnDefinition... definitions); static ProportionalLayout fromString(@NotNull String columnDefinitions); int getNumColumns(); @Override void addLayoutComponent(Component comp, Object constraint); @Override Dimension maximumLayoutSize(Container target); @Override float getLayoutAlignmentX(Container target); @Override float getLayoutAlignmentY(Container target); @Override void invalidateLayout(Container target); @Override void addLayoutComponent(String name, Component comp); @Override void removeLayoutComponent(Component comp); @Override Dimension preferredLayoutSize(Container parent); @Override Dimension minimumLayoutSize(Container parent); @Override void layoutContainer(Container parent);  }
@Test public void minimumWidthCalculationUsesFitValues() throws Exception { final JPanel panel = new JPanel(ProportionalLayout.fromString("Fit,Fit")); Component col0 = Box.createHorizontalStrut(80); Component col1 = Box.createHorizontalStrut(20); panel.add(col0, new ProportionalLayout.Constraint(0, 0)); panel.add(col1, new ProportionalLayout.Constraint(0, 1)); mockPackPanel(panel); assertThat(panel.getWidth()).isEqualTo(100); }
@Test public void minimumWidthCalculationFixedValuesOverrideComponentSizes() throws Exception { final JPanel panel = new JPanel(ProportionalLayout.fromString("100px,50px")); Component col0 = Box.createHorizontalStrut(90); Component col1 = Box.createHorizontalStrut(90); panel.add(col0, new ProportionalLayout.Constraint(0, 0)); panel.add(col1, new ProportionalLayout.Constraint(0, 1)); mockPackPanel(panel); assertThat(panel.getWidth()).isEqualTo(150); }
@Test public void fitWidthChoosesLargestValueAcrossMultipleRows() throws Exception { final JPanel panel = new JPanel(ProportionalLayout.fromString("Fit,Fit")); final Component row0col0 = Box.createHorizontalStrut(100); final Component row1col0 = Box.createHorizontalStrut(300); final Component row3col0 = Box.createHorizontalStrut(200); final Component row0col1 = Box.createHorizontalStrut(500); final Component row2col1 = Box.createHorizontalStrut(400); final Component row4col1 = Box.createHorizontalStrut(100); panel.add(row0col0, new ProportionalLayout.Constraint(0, 0)); panel.add(row1col0, new ProportionalLayout.Constraint(1, 0)); panel.add(row3col0, new ProportionalLayout.Constraint(3, 0)); panel.add(row0col1, new ProportionalLayout.Constraint(0, 1)); panel.add(row2col1, new ProportionalLayout.Constraint(2, 1)); panel.add(row4col1, new ProportionalLayout.Constraint(4, 1)); mockPackPanel(panel); assertThat(panel.getWidth()).isEqualTo(800); assertThat(row0col0.getWidth()).isEqualTo(300); assertThat(row1col0.getWidth()).isEqualTo(300); assertThat(row3col0.getWidth()).isEqualTo(300); assertThat(row0col1.getWidth()).isEqualTo(500); assertThat(row2col1.getWidth()).isEqualTo(500); assertThat(row4col1.getWidth()).isEqualTo(500); }
@Test public void proportionalColumnsTakeRemainingSpace() throws Exception { final JPanel panel = new JPanel(ProportionalLayout.fromString("100px,Fit,3*,*,50px")); panel.setPreferredSize(new Dimension(300, 20)); final Component col0 = new JPanel(); final Component col1 = Box.createHorizontalStrut(50); final Component col2 = new JPanel(); final Component col3 = new JPanel(); final Component col4 = new JPanel(); panel.add(col0, new ProportionalLayout.Constraint(0, 0)); panel.add(col1, new ProportionalLayout.Constraint(0, 1)); panel.add(col2, new ProportionalLayout.Constraint(0, 2)); panel.add(col3, new ProportionalLayout.Constraint(0, 3)); panel.add(col4, new ProportionalLayout.Constraint(0, 4)); mockPackPanel(panel); assertThat(panel.getWidth()).isEqualTo(300); assertThat(col0.getWidth()).isEqualTo(100); assertThat(col1.getWidth()).isEqualTo(50); assertThat(col2.getWidth()).isEqualTo(75); assertThat(col3.getWidth()).isEqualTo(25); assertThat(col4.getWidth()).isEqualTo(50); }
@Test public void preferredSizeCalculationMakesRoomForProportionalColumns() throws Exception { final JPanel panel = new JPanel(ProportionalLayout.fromString("*,2*,3*,4*")); final Component col0 = Box.createHorizontalStrut(40); final Component col1 = Box.createHorizontalStrut(50); final Component col2 = Box.createHorizontalStrut(30); final Component col3 = Box.createHorizontalStrut(80); panel.add(col0, new ProportionalLayout.Constraint(0, 0)); panel.add(col1, new ProportionalLayout.Constraint(0, 1)); panel.add(col2, new ProportionalLayout.Constraint(0, 2)); panel.add(col3, new ProportionalLayout.Constraint(0, 3)); mockPackPanel(panel); assertThat(panel.getWidth()).isEqualTo(400); assertThat(col0.getWidth()).isEqualTo(40); assertThat(col1.getWidth()).isEqualTo(80); assertThat(col2.getWidth()).isEqualTo(120); assertThat(col3.getWidth()).isEqualTo(160); }
@Test public void minimumSizeCalculationCollapsesProportionalColumns() throws Exception { final JPanel panel = new JPanel(ProportionalLayout.fromString("10px,990*,*,20px,3*")); mockPackPanel(panel); assertThat(panel.getMinimumSize().getWidth()).isEqualTo(30); }
@Test public void heightCalculationSkipsEmptyRows() throws Exception { final JPanel panel = new JPanel(ProportionalLayout.fromString("100px")); final Component row0 = Box.createVerticalStrut(20); final Component row2 = Box.createVerticalStrut(50); panel.add(row0, new ProportionalLayout.Constraint(0, 0)); panel.add(row2, new ProportionalLayout.Constraint(2, 0)); mockPackPanel(panel); assertThat(panel.getHeight()).isEqualTo(70); assertThat(row0.getHeight()).isEqualTo(20); assertThat(row2.getY()).isEqualTo(20); assertThat(row2.getHeight()).isEqualTo(50); }
@Test public void layoutTakesInsetsIntoAccount() throws Exception { final JPanel panel = new JPanel(ProportionalLayout.fromString("*")); panel.setPreferredSize(new Dimension(300, 30)); final Component cell = new JPanel(); panel.add(cell, new ProportionalLayout.Constraint(0, 0)); final int top = 1; final int left = 2; final int bottom = 3; final int right = 4; panel.setBorder(BorderFactory.createEmptyBorder(top, left, bottom, right)); mockPackPanel(panel); assertThat(panel.getWidth()).isEqualTo(300); assertThat(panel.getHeight()).isEqualTo(30); assertThat(cell.getWidth()).isEqualTo(300 - left - right); }