1.0.0
authorNiki Roo <niki@nikiroo.be>
Fri, 17 Feb 2017 19:55:28 +0000 (20:55 +0100)
committerNiki Roo <niki@nikiroo.be>
Fri, 17 Feb 2017 19:55:28 +0000 (20:55 +0100)
VERSION
configure.sh
libs/WrapLayout.java [new file with mode: 0644]
src/be/nikiroo/utils/UIUtils.java [new file with mode: 0644]
src/be/nikiroo/utils/WrapLayout.java [new file with mode: 0644]

diff --git a/VERSION b/VERSION
index c81aa44afbfcb4d1955b55e5276991aae023f039..3eefcb9dd5b38e2c1dc061052455dd97bcd51e6c 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.9.7
+1.0.0
index 026db922830dffab71676b498eea2070223c771d..12984bb64caeea9adc816efac2421a540379bb41 100755 (executable)
@@ -45,7 +45,7 @@ fi;
 
 
 echo "MAIN = be/nikiroo/utils/resources/TransBundle" > Makefile
-echo "MORE = be/nikiroo/utils/StringUtils be/nikiroo/utils/IOUtils be/nikiroo/utils/MarkableFileInputStream be/nikiroo/utils/test/TestLauncher" >> Makefile
+echo "MORE = be/nikiroo/utils/StringUtils be/nikiroo/utils/IOUtils be/nikiroo/utils/MarkableFileInputStream be/nikiroo/utils/UIUtils be/nikiroo/utils/WrapLayout be/nikiroo/utils/test/TestLauncher" >> Makefile
 echo "TEST = be/nikiroo/utils/test/Test" >> Makefile
 echo "TEST_PARAMS = $cols $ok $ko" >> Makefile
 echo "NAME = nikiroo-utils" >> Makefile
diff --git a/libs/WrapLayout.java b/libs/WrapLayout.java
new file mode 100644 (file)
index 0000000..da03c2f
--- /dev/null
@@ -0,0 +1,205 @@
+package be.nikiroo.utils;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Insets;
+
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+
+/**
+ * FlowLayout subclass that fully supports wrapping of components.
+ * 
+ * @author https://tips4java.wordpress.com/2008/11/06/wrap-layout/
+ */
+public class WrapLayout extends FlowLayout {
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * Constructs a new <code>WrapLayout</code> with a left alignment and a
+        * default 5-unit horizontal and vertical gap.
+        */
+       public WrapLayout() {
+               super();
+       }
+
+       /**
+        * Constructs a new <code>FlowLayout</code> with the specified alignment and
+        * a default 5-unit horizontal and vertical gap. The value of the alignment
+        * argument must be one of <code>WrapLayout</code>, <code>WrapLayout</code>,
+        * or <code>WrapLayout</code>.
+        * 
+        * @param align
+        *            the alignment value
+        */
+       public WrapLayout(int align) {
+               super(align);
+       }
+
+       /**
+        * Creates a new flow layout manager with the indicated alignment and the
+        * indicated horizontal and vertical gaps.
+        * <p>
+        * The value of the alignment argument must be one of
+        * <code>WrapLayout</code>, <code>WrapLayout</code>, or
+        * <code>WrapLayout</code>.
+        * 
+        * @param align
+        *            the alignment value
+        * @param hgap
+        *            the horizontal gap between components
+        * @param vgap
+        *            the vertical gap between components
+        */
+       public WrapLayout(int align, int hgap, int vgap) {
+               super(align, hgap, vgap);
+       }
+
+       /**
+        * Returns the preferred dimensions for this layout given the <i>visible</i>
+        * components in the specified target container.
+        * 
+        * @param target
+        *            the component which needs to be laid out
+        * @return the preferred dimensions to lay out the subcomponents of the
+        *         specified container
+        */
+       @Override
+       public Dimension preferredLayoutSize(Container target) {
+               return layoutSize(target, true);
+       }
+
+       /**
+        * Returns the minimum dimensions needed to layout the <i>visible</i>
+        * components contained in the specified target container.
+        * 
+        * @param target
+        *            the component which needs to be laid out
+        * @return the minimum dimensions to lay out the subcomponents of the
+        *         specified container
+        */
+       @Override
+       public Dimension minimumLayoutSize(Container target) {
+               Dimension minimum = layoutSize(target, false);
+               minimum.width -= (getHgap() + 1);
+               return minimum;
+       }
+
+       /**
+        * Returns the minimum or preferred dimension needed to layout the target
+        * container.
+        *
+        * @param target
+        *            target to get layout size for
+        * @param preferred
+        *            should preferred size be calculated
+        * @return the dimension to layout the target container
+        */
+       private Dimension layoutSize(Container target, boolean preferred) {
+               synchronized (target.getTreeLock()) {
+                       // Each row must fit with the width allocated to the containter.
+                       // When the container width = 0, the preferred width of the
+                       // container
+                       // has not yet been calculated so lets ask for the maximum.
+
+                       int targetWidth = target.getSize().width;
+                       Container container = target;
+
+                       while (container.getSize().width == 0
+                                       && container.getParent() != null) {
+                               container = container.getParent();
+                       }
+
+                       targetWidth = container.getSize().width;
+
+                       if (targetWidth == 0)
+                               targetWidth = Integer.MAX_VALUE;
+
+                       int hgap = getHgap();
+                       int vgap = getVgap();
+                       Insets insets = target.getInsets();
+                       int horizontalInsetsAndGap = insets.left + insets.right
+                                       + (hgap * 2);
+                       int maxWidth = targetWidth - horizontalInsetsAndGap;
+
+                       // Fit components into the allowed width
+
+                       Dimension dim = new Dimension(0, 0);
+                       int rowWidth = 0;
+                       int rowHeight = 0;
+
+                       int nmembers = target.getComponentCount();
+
+                       for (int i = 0; i < nmembers; i++) {
+                               Component m = target.getComponent(i);
+
+                               if (m.isVisible()) {
+                                       Dimension d = preferred ? m.getPreferredSize() : m
+                                                       .getMinimumSize();
+
+                                       // Can't add the component to current row. Start a new
+                                       // row.
+
+                                       if (rowWidth + d.width > maxWidth) {
+                                               addRow(dim, rowWidth, rowHeight);
+                                               rowWidth = 0;
+                                               rowHeight = 0;
+                                       }
+
+                                       // Add a horizontal gap for all components after the
+                                       // first
+
+                                       if (rowWidth != 0) {
+                                               rowWidth += hgap;
+                                       }
+
+                                       rowWidth += d.width;
+                                       rowHeight = Math.max(rowHeight, d.height);
+                               }
+                       }
+
+                       addRow(dim, rowWidth, rowHeight);
+
+                       dim.width += horizontalInsetsAndGap;
+                       dim.height += insets.top + insets.bottom + vgap * 2;
+
+                       // When using a scroll pane or the DecoratedLookAndFeel we need
+                       // to
+                       // make sure the preferred size is less than the size of the
+                       // target containter so shrinking the container size works
+                       // correctly. Removing the horizontal gap is an easy way to do
+                       // this.
+
+                       Container scrollPane = SwingUtilities.getAncestorOfClass(
+                                       JScrollPane.class, target);
+
+                       if (scrollPane != null && target.isValid()) {
+                               dim.width -= (hgap + 1);
+                       }
+
+                       return dim;
+               }
+       }
+
+       /*
+        * A new row has been completed. Use the dimensions of this row to update
+        * the preferred size for the container.
+        * 
+        * @param dim update the width and height when appropriate
+        * 
+        * @param rowWidth the width of the row to add
+        * 
+        * @param rowHeight the height of the row to add
+        */
+       private void addRow(Dimension dim, int rowWidth, int rowHeight) {
+               dim.width = Math.max(dim.width, rowWidth);
+
+               if (dim.height > 0) {
+                       dim.height += getVgap();
+               }
+
+               dim.height += rowHeight;
+       }
+}
\ No newline at end of file
diff --git a/src/be/nikiroo/utils/UIUtils.java b/src/be/nikiroo/utils/UIUtils.java
new file mode 100644 (file)
index 0000000..abdfcad
--- /dev/null
@@ -0,0 +1,32 @@
+package be.nikiroo.utils;
+
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+
+/**
+ * Some Java Swing utilities.
+ * 
+ * @author niki
+ */
+public class UIUtils {
+       /**
+        * Set a fake "native look &amp; feel" for the application if possible
+        * (check for the one currently in use, then try GTK).
+        * <p>
+        * <b>Must</b> be called prior to any GUI work.
+        */
+       static public void setLookAndFeel() {
+               // native look & feel
+               try {
+                       String noLF = "javax.swing.plaf.metal.MetalLookAndFeel";
+                       String lf = UIManager.getSystemLookAndFeelClassName();
+                       if (lf.equals(noLF))
+                               lf = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
+                       UIManager.setLookAndFeel(lf);
+               } catch (InstantiationException e) {
+               } catch (ClassNotFoundException e) {
+               } catch (UnsupportedLookAndFeelException e) {
+               } catch (IllegalAccessException e) {
+               }
+       }
+}
diff --git a/src/be/nikiroo/utils/WrapLayout.java b/src/be/nikiroo/utils/WrapLayout.java
new file mode 100644 (file)
index 0000000..da03c2f
--- /dev/null
@@ -0,0 +1,205 @@
+package be.nikiroo.utils;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Insets;
+
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+
+/**
+ * FlowLayout subclass that fully supports wrapping of components.
+ * 
+ * @author https://tips4java.wordpress.com/2008/11/06/wrap-layout/
+ */
+public class WrapLayout extends FlowLayout {
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * Constructs a new <code>WrapLayout</code> with a left alignment and a
+        * default 5-unit horizontal and vertical gap.
+        */
+       public WrapLayout() {
+               super();
+       }
+
+       /**
+        * Constructs a new <code>FlowLayout</code> with the specified alignment and
+        * a default 5-unit horizontal and vertical gap. The value of the alignment
+        * argument must be one of <code>WrapLayout</code>, <code>WrapLayout</code>,
+        * or <code>WrapLayout</code>.
+        * 
+        * @param align
+        *            the alignment value
+        */
+       public WrapLayout(int align) {
+               super(align);
+       }
+
+       /**
+        * Creates a new flow layout manager with the indicated alignment and the
+        * indicated horizontal and vertical gaps.
+        * <p>
+        * The value of the alignment argument must be one of
+        * <code>WrapLayout</code>, <code>WrapLayout</code>, or
+        * <code>WrapLayout</code>.
+        * 
+        * @param align
+        *            the alignment value
+        * @param hgap
+        *            the horizontal gap between components
+        * @param vgap
+        *            the vertical gap between components
+        */
+       public WrapLayout(int align, int hgap, int vgap) {
+               super(align, hgap, vgap);
+       }
+
+       /**
+        * Returns the preferred dimensions for this layout given the <i>visible</i>
+        * components in the specified target container.
+        * 
+        * @param target
+        *            the component which needs to be laid out
+        * @return the preferred dimensions to lay out the subcomponents of the
+        *         specified container
+        */
+       @Override
+       public Dimension preferredLayoutSize(Container target) {
+               return layoutSize(target, true);
+       }
+
+       /**
+        * Returns the minimum dimensions needed to layout the <i>visible</i>
+        * components contained in the specified target container.
+        * 
+        * @param target
+        *            the component which needs to be laid out
+        * @return the minimum dimensions to lay out the subcomponents of the
+        *         specified container
+        */
+       @Override
+       public Dimension minimumLayoutSize(Container target) {
+               Dimension minimum = layoutSize(target, false);
+               minimum.width -= (getHgap() + 1);
+               return minimum;
+       }
+
+       /**
+        * Returns the minimum or preferred dimension needed to layout the target
+        * container.
+        *
+        * @param target
+        *            target to get layout size for
+        * @param preferred
+        *            should preferred size be calculated
+        * @return the dimension to layout the target container
+        */
+       private Dimension layoutSize(Container target, boolean preferred) {
+               synchronized (target.getTreeLock()) {
+                       // Each row must fit with the width allocated to the containter.
+                       // When the container width = 0, the preferred width of the
+                       // container
+                       // has not yet been calculated so lets ask for the maximum.
+
+                       int targetWidth = target.getSize().width;
+                       Container container = target;
+
+                       while (container.getSize().width == 0
+                                       && container.getParent() != null) {
+                               container = container.getParent();
+                       }
+
+                       targetWidth = container.getSize().width;
+
+                       if (targetWidth == 0)
+                               targetWidth = Integer.MAX_VALUE;
+
+                       int hgap = getHgap();
+                       int vgap = getVgap();
+                       Insets insets = target.getInsets();
+                       int horizontalInsetsAndGap = insets.left + insets.right
+                                       + (hgap * 2);
+                       int maxWidth = targetWidth - horizontalInsetsAndGap;
+
+                       // Fit components into the allowed width
+
+                       Dimension dim = new Dimension(0, 0);
+                       int rowWidth = 0;
+                       int rowHeight = 0;
+
+                       int nmembers = target.getComponentCount();
+
+                       for (int i = 0; i < nmembers; i++) {
+                               Component m = target.getComponent(i);
+
+                               if (m.isVisible()) {
+                                       Dimension d = preferred ? m.getPreferredSize() : m
+                                                       .getMinimumSize();
+
+                                       // Can't add the component to current row. Start a new
+                                       // row.
+
+                                       if (rowWidth + d.width > maxWidth) {
+                                               addRow(dim, rowWidth, rowHeight);
+                                               rowWidth = 0;
+                                               rowHeight = 0;
+                                       }
+
+                                       // Add a horizontal gap for all components after the
+                                       // first
+
+                                       if (rowWidth != 0) {
+                                               rowWidth += hgap;
+                                       }
+
+                                       rowWidth += d.width;
+                                       rowHeight = Math.max(rowHeight, d.height);
+                               }
+                       }
+
+                       addRow(dim, rowWidth, rowHeight);
+
+                       dim.width += horizontalInsetsAndGap;
+                       dim.height += insets.top + insets.bottom + vgap * 2;
+
+                       // When using a scroll pane or the DecoratedLookAndFeel we need
+                       // to
+                       // make sure the preferred size is less than the size of the
+                       // target containter so shrinking the container size works
+                       // correctly. Removing the horizontal gap is an easy way to do
+                       // this.
+
+                       Container scrollPane = SwingUtilities.getAncestorOfClass(
+                                       JScrollPane.class, target);
+
+                       if (scrollPane != null && target.isValid()) {
+                               dim.width -= (hgap + 1);
+                       }
+
+                       return dim;
+               }
+       }
+
+       /*
+        * A new row has been completed. Use the dimensions of this row to update
+        * the preferred size for the container.
+        * 
+        * @param dim update the width and height when appropriate
+        * 
+        * @param rowWidth the width of the row to add
+        * 
+        * @param rowHeight the height of the row to add
+        */
+       private void addRow(Dimension dim, int rowWidth, int rowHeight) {
+               dim.width = Math.max(dim.width, rowWidth);
+
+               if (dim.height > 0) {
+                       dim.height += getVgap();
+               }
+
+               dim.height += rowHeight;
+       }
+}
\ No newline at end of file