Ticket #13198: patch-fix-flow-layout-wrap.patch
File patch-fix-flow-layout-wrap.patch, 10.2 KB (added by , 8 years ago) |
---|
-
src/org/openstreetmap/josm/gui/io/UploadDialog.java
diff --git a/src/org/openstreetmap/josm/gui/io/UploadDialog.java b/src/org/openstreetmap/josm/gui/io/UploadDialog.java index ed679fa..3312022 100644
a b import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 5 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 6 import static org.openstreetmap.josm.tools.I18n.trn; 7 7 8 import java.awt.BorderLayout;9 8 import java.awt.Component; 10 9 import java.awt.Dimension; 11 10 import java.awt.FlowLayout; … … import org.openstreetmap.josm.tools.ImageProvider.ImageSizes; 59 58 import org.openstreetmap.josm.tools.InputMapUtils; 60 59 import org.openstreetmap.josm.tools.Utils; 61 60 import org.openstreetmap.josm.tools.WindowGeometry; 61 import org.openstreetmap.josm.tools.MultiLineFlowLayout; 62 62 63 63 /** 64 64 * This is a dialog for entering upload options like the parameters for … … public class UploadDialog extends AbstractUploadDialog implements PropertyChange 165 165 tpConfigPanels.setToolTipTextAt(3, tr("Configure advanced settings")); 166 166 167 167 pnl.add(tpConfigPanels, GBC.eol().fill(GBC.HORIZONTAL)); 168 169 pnl.add(buildActionPanel(), GBC.eol().fill(GBC.HORIZONTAL)); 168 170 return pnl; 169 171 } 170 172 … … public class UploadDialog extends AbstractUploadDialog implements PropertyChange 174 176 * @return The panel with the OK and CANCEL buttons 175 177 */ 176 178 protected JPanel buildActionPanel() { 177 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER));179 JPanel pnl = new JPanel(new MultiLineFlowLayout(FlowLayout.CENTER)); 178 180 pnl.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 179 181 180 182 // -- upload button … … public class UploadDialog extends AbstractUploadDialog implements PropertyChange 201 203 */ 202 204 protected void build() { 203 205 setTitle(tr("Upload to ''{0}''", OsmApi.getOsmApi().getBaseUrl())); 204 getContentPane().setLayout(new BorderLayout()); 205 getContentPane().add(buildContentPanel(), BorderLayout.CENTER); 206 getContentPane().add(buildActionPanel(), BorderLayout.SOUTH); 206 setContentPane(buildContentPanel()); 207 207 208 208 addWindowListener(new WindowEventHandler()); 209 209 -
new file src/org/openstreetmap/josm/tools/MultiLineFlowLayout.java
diff --git a/src/org/openstreetmap/josm/tools/MultiLineFlowLayout.java b/src/org/openstreetmap/josm/tools/MultiLineFlowLayout.java new file mode 100644 index 0000000..4892058
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.tools; 3 4 import java.awt.Component; 5 import java.awt.Container; 6 import java.awt.Dimension; 7 import java.awt.FlowLayout; 8 import java.awt.Insets; 9 import java.util.function.Function; 10 11 /** 12 * This is an extension of the flow layout that preferes wraping the text instead of increasing the component width when there is not enough 13 * space. 14 * <p> 15 * This allows for a better preffered size computation. It should be used in all places where a flow layout fills the full width of the parent 16 * container. 17 * <p> 18 * This does not support baseline alignment. 19 * @author Michael Zangl 20 * @since xxx 21 */ 22 public class MultiLineFlowLayout extends FlowLayout { 23 /** 24 * Same as {@link FlowLayout#FlowLayout()} 25 */ 26 public MultiLineFlowLayout() { 27 super(); 28 } 29 30 /** 31 * Same as {@link FlowLayout#FlowLayout(int, int, int)} 32 * @param align Alignment 33 * @param hgap horizontal gap 34 * @param vgap vertical gap 35 */ 36 public MultiLineFlowLayout(int align, int hgap, int vgap) { 37 super(align, hgap, vgap); 38 } 39 40 /** 41 * Same as {@link FlowLayout#FlowLayout(int)} 42 * @param align Alignment 43 */ 44 public MultiLineFlowLayout(int align) { 45 super(align); 46 } 47 48 @Override 49 public Dimension preferredLayoutSize(Container target) { 50 return getLayoutSize(target, c -> c.getPreferredSize()); 51 } 52 53 @Override 54 public Dimension minimumLayoutSize(Container target) { 55 return getLayoutSize(target, c -> c.getMinimumSize()); 56 } 57 58 private Dimension getLayoutSize(Container target, Function<Component, Dimension> baseSize) { 59 synchronized (target.getTreeLock()) { 60 int outerWidth = getWidthOf(target); 61 62 Insets insets = target.getInsets(); 63 int containerWidth = outerWidth - insets.left - insets.right - getHgap() * 2; 64 65 int x = 0; 66 int totalHeight = insets.top + insets.bottom + getVgap() * 2; 67 int rowHeight = 0; 68 for (int i = 0; i < target.getComponentCount(); i++) { 69 Component child = target.getComponent(i); 70 if (!child.isVisible()) { 71 continue; 72 } 73 Dimension size = baseSize.apply(child); 74 if (x != 0) { 75 x += getHgap(); 76 } 77 x += size.getWidth(); 78 if (x > containerWidth) { 79 totalHeight += rowHeight + getVgap(); 80 rowHeight = 0; 81 x = 0; 82 } 83 84 rowHeight = Math.max(rowHeight, size.height); 85 } 86 totalHeight += rowHeight; 87 88 return new Dimension(outerWidth, totalHeight); 89 } 90 } 91 92 private static int getWidthOf(Container target) { 93 Container current = target; 94 while (current.getWidth() == 0 && current.getParent() != null) { 95 current = current.getParent(); 96 } 97 int width = current.getWidth(); 98 if (width == 0) { 99 return Integer.MAX_VALUE; 100 } else { 101 return width; 102 } 103 } 104 105 @Override 106 public String toString() { 107 return "WrapingFlowLayout [align=" + getAlignment() + "]"; 108 } 109 110 } -
new file test/unit/org/openstreetmap/josm/tools/MultiLineFlowLayoutTest.java
diff --git a/test/unit/org/openstreetmap/josm/tools/MultiLineFlowLayoutTest.java b/test/unit/org/openstreetmap/josm/tools/MultiLineFlowLayoutTest.java new file mode 100644 index 0000000..11aa5a0
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.tools; 3 4 import static org.junit.Assert.assertEquals; 5 6 import java.awt.Dimension; 7 import java.awt.FlowLayout; 8 9 import javax.swing.BorderFactory; 10 import javax.swing.JPanel; 11 12 import org.junit.Before; 13 import org.junit.Rule; 14 import org.junit.Test; 15 import org.openstreetmap.josm.testutils.JOSMTestRules; 16 17 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 18 19 /** 20 * Test {@link MultiLineFlowLayout} 21 * @author Michael Zangl 22 * @since xxx 23 */ 24 public class MultiLineFlowLayoutTest { 25 /** 26 * No special rules. 27 */ 28 @Rule 29 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") 30 public JOSMTestRules test = new JOSMTestRules(); 31 32 private static final int TEST_WIDHT = 500; 33 private JPanel container; 34 35 /** 36 * Prepare test container. 37 */ 38 @Before 39 public void setUp() { 40 JPanel parent = new JPanel(); 41 parent.setBounds(0, 0, TEST_WIDHT, 500); 42 43 container = new JPanel(new MultiLineFlowLayout(FlowLayout.CENTER, 0, 0)); 44 parent.add(container); 45 } 46 47 /** 48 * Test that one line is layed out correctly 49 */ 50 @Test 51 public void testOneLine() { 52 fillOneLine(); 53 54 container.invalidate(); 55 Dimension preffered = container.getPreferredSize(); 56 assertEquals(TEST_WIDHT, preffered.width); 57 assertEquals(100, preffered.height); 58 59 Dimension minimum = container.getMinimumSize(); 60 assertEquals(TEST_WIDHT, minimum.width); 61 assertEquals(50, minimum.height); 62 } 63 64 /** 65 * Test that insets are respected 66 */ 67 @Test 68 public void testInsets() { 69 fillOneLine(); 70 71 container.setBorder(BorderFactory.createEmptyBorder(3, 0, 7, 0)); 72 container.invalidate(); 73 Dimension preffered = container.getPreferredSize(); 74 assertEquals(TEST_WIDHT, preffered.width); 75 assertEquals(110, preffered.height); 76 77 // This should force wraping 78 container.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 40)); 79 container.invalidate(); 80 preffered = container.getPreferredSize(); 81 assertEquals(TEST_WIDHT, preffered.width); 82 assertEquals(200, preffered.height); 83 } 84 85 /** 86 * Test that gaps are respected 87 */ 88 @Test 89 public void testGaps() { 90 fillOneLine(); 91 92 container.setLayout(new MultiLineFlowLayout(FlowLayout.LEADING, 20, 10)); 93 container.invalidate(); 94 Dimension preffered = container.getPreferredSize(); 95 assertEquals(TEST_WIDHT, preffered.width); 96 assertEquals(230, preffered.height); 97 } 98 99 /** 100 * Test that it behaves the same as FlowLayout for one line. 101 */ 102 @Test 103 public void testSameAsFlowLayout() { 104 fillOneLine(); 105 JPanel childx = new JPanel(); 106 childx.setPreferredSize(new Dimension(300, 100)); 107 childx.setMinimumSize(new Dimension(200, 50)); 108 childx.setVisible(false); 109 container.add(childx); 110 container.setBorder(BorderFactory.createEmptyBorder(3, 4, 5, 6)); 111 112 container.setLayout(new MultiLineFlowLayout(FlowLayout.LEADING, 2, 1)); 113 container.invalidate(); 114 Dimension is = container.getPreferredSize(); 115 116 container.setLayout(new FlowLayout(FlowLayout.LEADING, 2, 1)); 117 container.invalidate(); 118 Dimension should = container.getPreferredSize(); 119 120 assertEquals(should.height, is.height); 121 } 122 123 private void fillOneLine() { 124 JPanel child1 = new JPanel(); 125 child1.setPreferredSize(new Dimension(300, 100)); 126 child1.setMinimumSize(new Dimension(200, 50)); 127 container.add(child1); 128 JPanel child2 = new JPanel(); 129 child2.setPreferredSize(new Dimension(100, 100)); 130 child1.setMinimumSize(new Dimension(100, 50)); 131 container.add(child2); 132 JPanel child3 = new JPanel(); 133 child3.setPreferredSize(new Dimension(50, 100)); 134 child1.setMinimumSize(new Dimension(50, 50)); 135 container.add(child3); 136 } 137 }