Version 1.1.0: Add progress reporting, move to ui package nikiroo-utils-1.1.0
authorNiki Roo <niki@nikiroo.be>
Sat, 18 Feb 2017 16:23:48 +0000 (17:23 +0100)
committerNiki Roo <niki@nikiroo.be>
Sat, 18 Feb 2017 16:23:48 +0000 (17:23 +0100)
VERSION
changelog
configure.sh
src/be/nikiroo/utils/package-info.java [deleted file]
src/be/nikiroo/utils/test/ProgressTest.java [new file with mode: 0644]
src/be/nikiroo/utils/test/Test.java
src/be/nikiroo/utils/test/TestCase.java
src/be/nikiroo/utils/test/TestLauncher.java
src/be/nikiroo/utils/ui/Progress.java [new file with mode: 0644]
src/be/nikiroo/utils/ui/UIUtils.java [moved from src/be/nikiroo/utils/UIUtils.java with 96% similarity]
src/be/nikiroo/utils/ui/WrapLayout.java [moved from src/be/nikiroo/utils/WrapLayout.java with 99% similarity]

diff --git a/VERSION b/VERSION
index 3eefcb9dd5b38e2c1dc061052455dd97bcd51e6c..9084fa2f716a7117829f3f32a5f4cef400e02903 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.0
+1.1.0
index e1c2d8f258c9dec8d8d926d31e828d052e663bf2..5bc5c4810643f952f233fdd00f8849e97cd6a6e6 100644 (file)
--- a/changelog
+++ b/changelog
@@ -1,3 +1,18 @@
+Version 1.1.0
+-------------
+
+Add progress reporting, move to ui package
+       A new progress reporting system (and tests) in the new ui package
+       (some other classes have been moved into ui, too: WrapLayout and
+       UIUtils)
+
+Version 1.0.0
+-------------
+
+Add WrapLayout and UIUtils
+       A FlowLayout that automatically wrap to the next line (from existing
+       code found on internet) and a method to set a fake-native look & feel
+
 Version 0.9.7
 -------------
 
index 12984bb64caeea9adc816efac2421a540379bb41..7d8a70d8ee2b7d010106fb41a54499bd9c1d0549 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/UIUtils be/nikiroo/utils/WrapLayout be/nikiroo/utils/test/TestLauncher" >> Makefile
+echo "MORE = be/nikiroo/utils/StringUtils be/nikiroo/utils/IOUtils be/nikiroo/utils/MarkableFileInputStream be/nikiroo/utils/ui/UIUtils be/nikiroo/utils/ui/WrapLayout be/nikiroo/utils/ui/Progress 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/src/be/nikiroo/utils/package-info.java b/src/be/nikiroo/utils/package-info.java
deleted file mode 100644 (file)
index 4951378..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * Some small utilities used through the pogram.
- * 
- * @author niki
- */
-package be.nikiroo.utils;
\ No newline at end of file
diff --git a/src/be/nikiroo/utils/test/ProgressTest.java b/src/be/nikiroo/utils/test/ProgressTest.java
new file mode 100644 (file)
index 0000000..2509735
--- /dev/null
@@ -0,0 +1,187 @@
+package be.nikiroo.utils.test;
+
+import be.nikiroo.utils.ui.Progress;
+
+public class ProgressTest extends TestLauncher {
+       public ProgressTest(String[] args) {
+               super("Progress reporting", args);
+
+               addSeries(new TestLauncher("Simple progress", args) {
+                       {
+                               addTest(new TestCase("Relative values and direct values") {
+                                       @Override
+                                       public void test() throws Exception {
+                                               Progress p = new Progress();
+                                               assertEquals(0, p.getProgress());
+                                               assertEquals(0, p.getRelativeProgress());
+                                               p.setProgress(33);
+                                               assertEquals(33, p.getProgress());
+                                               assertEquals(0.33, p.getRelativeProgress());
+                                               p.setMax(3);
+                                               p.setProgress(1);
+                                               assertEquals(1, p.getProgress());
+                                               assertEquals(
+                                                               generateAssertMessage("0.33..",
+                                                                               p.getRelativeProgress()), true,
+                                                               p.getRelativeProgress() >= 0.332);
+                                               assertEquals(
+                                                               generateAssertMessage("0.33..",
+                                                                               p.getRelativeProgress()), true,
+                                                               p.getRelativeProgress() <= 0.334);
+                                       }
+                               });
+
+                               addTest(new TestCase("Listeners at first level") {
+                                       int pg;
+
+                                       @Override
+                                       public void test() throws Exception {
+                                               Progress p = new Progress();
+                                               p.addProgressListener(new Progress.ProgressListener() {
+                                                       public void progress(Progress progress, String name) {
+                                                               pg = progress.getProgress();
+                                                       }
+                                               });
+
+                                               p.setProgress(42);
+                                               assertEquals(42, pg);
+                                               p.setProgress(0);
+                                               assertEquals(0, pg);
+                                       }
+                               });
+                       }
+               });
+
+               addSeries(new TestLauncher("Progress with children", args) {
+                       {
+                               addTest(new TestCase("One child") {
+                                       @Override
+                                       public void test() throws Exception {
+                                               Progress p = new Progress();
+                                               Progress child = new Progress();
+
+                                               p.addProgress(child, 100);
+
+                                               child.setProgress(42);
+                                               assertEquals(42, p.getProgress());
+                                       }
+                               });
+
+                               addTest(new TestCase("Multiple children") {
+                                       @Override
+                                       public void test() throws Exception {
+                                               Progress p = new Progress();
+                                               Progress child1 = new Progress();
+                                               Progress child2 = new Progress();
+                                               Progress child3 = new Progress();
+
+                                               p.addProgress(child1, 20);
+                                               p.addProgress(child2, 60);
+                                               p.addProgress(child3, 20);
+
+                                               child1.setProgress(50);
+                                               assertEquals(10, p.getProgress());
+                                               child2.setProgress(100);
+                                               assertEquals(70, p.getProgress());
+                                               child3.setProgress(100);
+                                               assertEquals(90, p.getProgress());
+                                               child1.setProgress(100);
+                                               assertEquals(100, p.getProgress());
+                                       }
+                               });
+
+                               addTest(new TestCase("Listeners with children") {
+                                       int pg;
+
+                                       @Override
+                                       public void test() throws Exception {
+                                               Progress p = new Progress();
+                                               Progress child1 = new Progress();
+                                               Progress child2 = new Progress();
+                                               p.addProgress(child1, 50);
+                                               p.addProgress(child2, 50);
+
+                                               p.addProgressListener(new Progress.ProgressListener() {
+                                                       public void progress(Progress progress, String name) {
+                                                               pg = progress.getProgress();
+                                                       }
+                                               });
+
+                                               child1.setProgress(50);
+                                               assertEquals(25, pg);
+                                               child2.setProgress(100);
+                                               assertEquals(75, pg);
+                                               child1.setProgress(100);
+                                               assertEquals(100, pg);
+                                       }
+                               });
+
+                               addTest(new TestCase("Listeners with children, not 1-100") {
+                                       int pg;
+
+                                       @Override
+                                       public void test() throws Exception {
+                                               Progress p = new Progress();
+                                               p.setMax(1000);
+
+                                               Progress child1 = new Progress();
+                                               child1.setMax(2);
+
+                                               Progress child2 = new Progress();
+                                               p.addProgress(child1, 500);
+                                               p.addProgress(child2, 500);
+
+                                               p.addProgressListener(new Progress.ProgressListener() {
+                                                       public void progress(Progress progress, String name) {
+                                                               pg = progress.getProgress();
+                                                       }
+                                               });
+
+                                               child1.setProgress(1);
+                                               assertEquals(250, pg);
+                                               child2.setProgress(100);
+                                               assertEquals(750, pg);
+                                               child1.setProgress(2);
+                                               assertEquals(1000, pg);
+                                       }
+                               });
+
+                               addTest(new TestCase(
+                                               "Listeners with children, not 1-100, local progress") {
+                                       int pg;
+
+                                       @Override
+                                       public void test() throws Exception {
+                                               Progress p = new Progress();
+                                               p.setMax(1000);
+
+                                               Progress child1 = new Progress();
+                                               child1.setMax(2);
+
+                                               Progress child2 = new Progress();
+                                               p.addProgress(child1, 400);
+                                               p.addProgress(child2, 400);
+                                               // 200 = local progress
+
+                                               p.addProgressListener(new Progress.ProgressListener() {
+                                                       public void progress(Progress progress, String name) {
+                                                               pg = progress.getProgress();
+                                                       }
+                                               });
+
+                                               child1.setProgress(1);
+                                               assertEquals(200, pg);
+                                               child2.setProgress(100);
+                                               assertEquals(600, pg);
+                                               p.setProgress(100);
+                                               assertEquals(700, pg);
+                                               child1.setProgress(2);
+                                               assertEquals(900, pg);
+                                               p.setProgress(200);
+                                               assertEquals(1000, pg);
+                                       }
+                               });
+                       }
+               });
+       }
+}
index 0804039e1b410389c34385a3735e94082017d5ca..4340f5f8ac18db11d08a7425a043d7aa4436c571 100644 (file)
@@ -9,6 +9,7 @@ public class Test extends TestLauncher {
        public Test(String[] args) {
                super("Nikiroo-utils", args);
 
+               addSeries(new ProgressTest(args));
                addSeries(new BundleTest(args));
        }
 
index 0349bc07c5cdcb3df3b6e90e92dd10d9febaba6f..e4860fa11f51e0f5e4cda5d366fffa8db0eef285 100644 (file)
@@ -123,10 +123,7 @@ abstract public class TestCase {
                        throws AssertException {
 
                if (errorMessage == null) {
-                       errorMessage = String.format("" //
-                                       + "Assertion failed!\n" //
-                                       + "Expected value: [%s]\n" //
-                                       + "Actual value: [%s]", expected, actual);
+                       errorMessage = generateAssertMessage(expected, actual);
                }
 
                if ((expected == null && actual != null)
@@ -235,4 +232,22 @@ abstract public class TestCase {
                        throws AssertException {
                assertEquals(errorMessage, new Double(expected), new Double(actual));
        }
+
+       /**
+        * Generate the default assert message for 2 different values that were
+        * supposed to be equals.
+        * 
+        * @param expected
+        *            the expected value
+        * @param actual
+        *            the actual value
+        * 
+        * @return the message
+        */
+       public static String generateAssertMessage(Object expected, Object actual) {
+               return String.format("" //
+                               + "Assertion failed!\n" //
+                               + "Expected value: [%s]\n" //
+                               + "Actual value: [%s]", expected, actual);
+       }
 }
index ba4e81de22262f23a8e9161c2b2b81fec4413c15..b6118df103ee68711273e30b0ae33d3517883855 100644 (file)
@@ -1,8 +1,12 @@
 package be.nikiroo.utils.test;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
 
+import be.nikiroo.utils.test.TestCase.AssertException;
+
 /**
  * A {@link TestLauncher} starts a series of {@link TestCase}s and displays the
  * result to the user.
@@ -47,6 +51,8 @@ public class TestLauncher {
        protected int executed;
        protected int total;
 
+       private int currentSeries = 0;
+
        /**
         * Create a new {@link TestLauncher} with default parameters.
         * 
@@ -144,10 +150,12 @@ public class TestLauncher {
                                System.out.println("");
                        }
 
+                       currentSeries = 0;
                        for (TestLauncher serie : series) {
                                errors += serie.launch(depth + 1);
                                executed += serie.executed;
                                total += serie.total;
+                               currentSeries++;
                        }
                } catch (Exception e) {
                        print(depth, "__start");
@@ -263,7 +271,7 @@ public class TestLauncher {
                        System.out.println("[ Test suite: " + name + " ]");
                        System.out.println("");
                } else {
-                       System.out.println(prefix(depth) + name + ":");
+                       System.out.println(prefix(depth, false) + name + ":");
                }
        }
 
@@ -276,7 +284,8 @@ public class TestLauncher {
         *            the {@link TestCase}
         */
        protected void print(int depth, String name) {
-               name = prefix(depth) + (name == null ? "" : name).replace("\t", "    ");
+               name = prefix(depth, false)
+                               + (name == null ? "" : name).replace("\t", "    ");
 
                while (name.length() < columns - 11) {
                        name += ".";
@@ -296,8 +305,15 @@ public class TestLauncher {
        private void print(int depth, Exception error) {
                if (error != null) {
                        System.out.println(" " + koString);
-                       for (String line : (error.getMessage() + "").split("\n")) {
-                               System.out.println(prefix(depth) + "\t\t" + line);
+                       String lines = error.getMessage() + "";
+                       if (!(error instanceof AssertException)) {
+                               StringWriter sw = new StringWriter();
+                               PrintWriter pw = new PrintWriter(sw);
+                               error.printStackTrace(pw);
+                               lines = sw.toString();
+                       }
+                       for (String line : lines.split("\n")) {
+                               System.out.println(prefix(depth, false) + "\t\t" + line);
                        }
                } else {
                        System.out.println(" " + okString);
@@ -332,11 +348,10 @@ public class TestLauncher {
                if (depth == 0) {
                        System.out.println(resume);
                } else {
-                       String arrow = "┗▶";
-                       if (series.isEmpty()) {
-                               arrow = "━▶";
-                       }
-                       System.out.println(prefix(depth) + arrow + resume);
+                       String arrow = "┗▶ ";
+                       System.out.println(prefix(depth, currentSeries == 0) + arrow
+                                       + resume);
+                       System.out.println(prefix(depth, currentSeries == 0));
                }
        }
 
@@ -347,22 +362,25 @@ public class TestLauncher {
         * 
         * @param depth
         *            the current depth
+        * @param first
+        *            this line is the first of its tabulation level
         * 
         * @return the prefix
         */
-       private String prefix(int depth) {
+       private String prefix(int depth, boolean first) {
                String space = tabs(depth - 1);
 
                String line = "";
                if (depth > 0) {
                        if (depth > 1) {
-                               if (depth != last) {
+                               if (depth != last && first) {
                                        line = "╻"; // first line
                                } else {
                                        line = "┃"; // continuation
                                }
                        }
-                       space = space + line + tabs(1);
+
+                       space += line + tabs(1);
                }
 
                last = depth;
@@ -378,7 +396,6 @@ public class TestLauncher {
         * @return the string
         */
        private String tabs(int depth) {
-
                StringBuilder builder = new StringBuilder();
                for (int i = 0; i < depth; i++) {
                        builder.append("    ");
diff --git a/src/be/nikiroo/utils/ui/Progress.java b/src/be/nikiroo/utils/ui/Progress.java
new file mode 100644 (file)
index 0000000..2785180
--- /dev/null
@@ -0,0 +1,279 @@
+package be.nikiroo.utils.ui;
+
+import java.util.ArrayList;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Progress reporting system, possibly nested.
+ * 
+ * @author niki
+ */
+public class Progress {
+       public interface ProgressListener extends EventListener {
+               /**
+                * A progression event.
+                * 
+                * @param progress
+                *            the {@link Progress} object that generated it, or a parent
+                * @param name
+                *            the first non-null name of the {@link Progress} step that
+                *            generated this event
+                */
+               public void progress(Progress progress, String name);
+       }
+
+       private String name;
+       private Map<Progress, Double> children;
+       private List<ProgressListener> listeners;
+       private int min;
+       private int max;
+       private int localProgress;
+       private int progress; // children included
+
+       /**
+        * Create a new default unnamed {@link Progress}, from 0 to 100.
+        */
+       public Progress() {
+               this(null);
+       }
+
+       /**
+        * Create a new default {@link Progress}, from 0 to 100.
+        * 
+        * @param name
+        *            the name of this {@link Progress} step
+        */
+       public Progress(String name) {
+               this(name, 0, 100);
+       }
+
+       /**
+        * Create a new unnamed {@link Progress}, from min to max.
+        * 
+        * @param min
+        *            the minimum progress value (and starting value) -- must be
+        *            non-negative
+        * @param max
+        *            the maximum progress value
+        */
+       public Progress(int min, int max) {
+               this(null, min, max);
+       }
+
+       /**
+        * Create a new {@link Progress}, from min to max.
+        * 
+        * @param name
+        *            the name of this {@link Progress} step
+        * @param min
+        *            the minimum progress value (and starting value) -- must be
+        *            non-negative
+        * @param max
+        *            the maximum progress value
+        */
+       public Progress(String name, int min, int max) {
+               this.name = name;
+               this.children = new HashMap<Progress, Double>();
+               this.listeners = new ArrayList<Progress.ProgressListener>();
+               setMinMax(min, max);
+               setProgress(min);
+       }
+
+       /**
+        * The name of this {@link Progress} step.
+        * 
+        * @return the name
+        */
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * The minimum progress value.
+        * 
+        * @return the min
+        */
+       public int getMin() {
+               return min;
+       }
+
+       /**
+        * The minimum progress value.
+        * 
+        * @param min
+        *            the min to set
+        */
+       public void setMin(int min) {
+               if (min < 0) {
+                       throw new Error("negative values not supported");
+               }
+
+               if (min > max) {
+                       throw new Error(
+                                       "The minimum progress value must be <= the maximum progress value");
+               }
+
+               this.min = min;
+       }
+
+       /**
+        * The maximum progress value.
+        * 
+        * @return the max
+        */
+       public int getMax() {
+               return max;
+       }
+
+       /**
+        * The maximum progress value (must be >= the minimum progress value).
+        * 
+        * @param max
+        *            the max to set
+        */
+       public void setMax(int max) {
+               if (max < min) {
+                       throw new Error(
+                                       "The maximum progress value must be >= the minimum progress value");
+               }
+
+               this.max = max;
+       }
+
+       /**
+        * Set both the minimum and maximum progress values.
+        * 
+        * @param min
+        *            the min
+        * @param max
+        *            the max
+        */
+       public void setMinMax(int min, int max) {
+               if (min < 0) {
+                       throw new Error("negative values not supported");
+               }
+
+               if (min > max) {
+                       throw new Error(
+                                       "The minimum progress value must be <= the maximum progress value");
+               }
+
+               this.min = min;
+               this.max = max;
+       }
+
+       /**
+        * Get the total progress value (including the optional children
+        * {@link Progress}) on a {@link Progress#getMin()} to
+        * {@link Progress#getMax()} scale.
+        * 
+        * @return the progress the value
+        */
+       public int getProgress() {
+               return progress;
+       }
+
+       /**
+        * Set the local progress value (not including the optional children
+        * {@link Progress}), on a {@link Progress#getMin()} to
+        * {@link Progress#getMax()} scale.
+        * 
+        * @param progress
+        *            the progress to set
+        */
+       public void setProgress(int progress) {
+               int diff = this.progress - this.localProgress;
+               this.localProgress = progress;
+               setTotalProgress(name, progress + diff);
+       }
+
+       /**
+        * Check if the action corresponding to this {@link Progress} is done (i.e.,
+        * if its progress value is >= its max value).
+        * 
+        * @return TRUE if it is
+        */
+       public boolean isDone() {
+               return progress >= max;
+       }
+
+       /**
+        * Get the total progress value (including the optional children
+        * {@link Progress}) on a 0.0 to 1.0 scale.
+        * 
+        * @return the progress
+        */
+       public double getRelativeProgress() {
+               return (((double) progress) / (max - min));
+       }
+
+       /**
+        * Set the total progress value (including the optional children
+        * {@link Progress}), on a {@link Progress#getMin()} to
+        * {@link Progress#getMax()} scale.
+        * 
+        * @param name
+        *            the current name (if it is NULL, the first non-null name in
+        *            the hierarchy will overwrite it)
+        * @param progress
+        *            the progress to set
+        */
+       private void setTotalProgress(String name, int progress) {
+               this.progress = progress;
+
+               for (ProgressListener l : listeners) {
+                       l.progress(this, name);
+               }
+       }
+
+       /**
+        * Add a {@link ProgressListener} that will trigger on progress changes.
+        * 
+        * @param l
+        *            the listener
+        */
+       public void addProgressListener(ProgressListener l) {
+               this.listeners.add(l);
+       }
+
+       /**
+        * Add a child {@link Progress} of the given weight.
+        * 
+        * @param progress
+        *            the child {@link Progress} to add
+        * @param weight
+        *            the weight (on a {@link Progress#getMin()} to
+        *            {@link Progress#getMax()} scale) of this child
+        *            {@link Progress} in relation to its parent
+        */
+       public void addProgress(Progress progress, double weight) {
+               if (weight < min || weight > max) {
+                       throw new Error(
+                                       "A Progress object cannot have a weight outside its parent range");
+               }
+
+               // Note: this is quite inefficient, especially with many children
+               // TODO: improve it?
+               progress.addProgressListener(new ProgressListener() {
+                       public void progress(Progress progress, String name) {
+                               double total = ((double) localProgress) / (max - min);
+                               for (Entry<Progress, Double> entry : children.entrySet()) {
+                                       total += (entry.getValue() / (max - min))
+                                                       * entry.getKey().getRelativeProgress();
+                               }
+
+                               if (name == null) {
+                                       name = Progress.this.name;
+                               }
+
+                               setTotalProgress(name, (int) (total * (max - min)));
+                       }
+               });
+
+               this.children.put(progress, weight);
+       }
+}
similarity index 96%
rename from src/be/nikiroo/utils/UIUtils.java
rename to src/be/nikiroo/utils/ui/UIUtils.java
index abdfcadbf0779bd2b76aebd93b14ba56201e1dc9..547ff6c3d40fb42e14f45c42d1b65ae02578898e 100644 (file)
@@ -1,4 +1,4 @@
-package be.nikiroo.utils;
+package be.nikiroo.utils.ui;
 
 import javax.swing.UIManager;
 import javax.swing.UnsupportedLookAndFeelException;
similarity index 99%
rename from src/be/nikiroo/utils/WrapLayout.java
rename to src/be/nikiroo/utils/ui/WrapLayout.java
index da03c2f1385f40a2747240cfa02ce85dcc961d83..7f34d7974c4adba5a8fd6d4d534a10a7adea1360 100644 (file)
@@ -1,4 +1,4 @@
-package be.nikiroo.utils;
+package be.nikiroo.utils.ui;
 
 import java.awt.Component;
 import java.awt.Container;