From 093fe4c81cc9cc22b3fc7adf9295b4ebf0b8d5df Mon Sep 17 00:00:00 2001 From: Juan Manuel Gimeno Illa Date: Fri, 7 May 2021 11:33:32 +0200 Subject: [PATCH 1/5] Alternative version of ShowBallistics using Java Beans and property changes due to Observer/Observable deprecation. --- .../observer/ballistics4/BallisticsLabel.java | 53 +++++++ .../observer/ballistics4/BallisticsPanel.java | 73 ++++++++++ .../observer/ballistics4/ShowBallistics4.java | 137 ++++++++++++++++++ src/app/observer/ballistics4/Tpeak.java | 59 ++++++++ 4 files changed, 322 insertions(+) create mode 100644 src/app/observer/ballistics4/BallisticsLabel.java create mode 100644 src/app/observer/ballistics4/BallisticsPanel.java create mode 100644 src/app/observer/ballistics4/ShowBallistics4.java create mode 100644 src/app/observer/ballistics4/Tpeak.java diff --git a/src/app/observer/ballistics4/BallisticsLabel.java b/src/app/observer/ballistics4/BallisticsLabel.java new file mode 100644 index 0000000..8c60840 --- /dev/null +++ b/src/app/observer/ballistics4/BallisticsLabel.java @@ -0,0 +1,53 @@ +package app.observer.ballistics4; + +/* + * Copyright (c) 2001, 2005. Steven J. Metsker. + * + * Steve Metsker makes no representations or warranties about + * the fitness of this software for any particular purpose, + * including the implied warranty of merchantability. + * + * Please use this software as you wish with the sole + * restriction that you may not claim that you wrote it. + */ + +import com.oozinoz.utility.Format; + +import javax.swing.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +/** + * Instances of this class are labels that show the value of a Tpeak model. + * + * @author Steven J. Metsker + */ +public class BallisticsLabel extends JLabel implements PropertyChangeListener { + /** + * Construct a label that will show the value of a Tpeak object. + * + * @param tPeak + * the model to observe + */ + public BallisticsLabel(Tpeak tPeak) { + tPeak.addObserver(this); + showValue(tPeak.getValue()); + } + + /** + * Respond to a change in the observed Tpeak model + * + * @param evt + * change event + */ + + @Override + public void propertyChange(PropertyChangeEvent evt) { + showValue((double) evt.getNewValue()); + } + + private void showValue(double value) { + setText(Format.formatToNPlaces(value, 2)); + repaint(); + } +} diff --git a/src/app/observer/ballistics4/BallisticsPanel.java b/src/app/observer/ballistics4/BallisticsPanel.java new file mode 100644 index 0000000..44eab52 --- /dev/null +++ b/src/app/observer/ballistics4/BallisticsPanel.java @@ -0,0 +1,73 @@ +package app.observer.ballistics4; + +/* + * Copyright (c) 2001, 2005. Steven J. Metsker. + * + * Steve Metsker makes no representations or warranties about + * the fitness of this software for any particular purpose, + * including the implied warranty of merchantability. + * + * Please use this software as you wish with the sole + * restriction that you may not claim that you wrote it. + */ + +import com.oozinoz.ballistics.BallisticsFunction; + +import javax.swing.*; +import java.awt.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +/** + * Plot a ballistics function. This class is refactored from BallisticsPanel_2 + * to rely on a Tpeak object from the business domain. + * + * @author Steven J. Metsker + */ +public class BallisticsPanel extends JPanel implements PropertyChangeListener { + protected BallisticsFunction func; + + protected int nPoint = 101; + + double tPeak = 0; + + protected int[] x = new int[nPoint]; + + protected int[] y = new int[nPoint]; + + /** + * Create a panel that can display the provided function. + * + * @param func + * the ballistics function to plot. Ballistics functions vary + * with time and with the time of peak burn area. + * @param tPeak + * an observable model of the time when burn area peaks + */ + public BallisticsPanel(BallisticsFunction func, Tpeak tPeak) { + this.func = func; + tPeak.addObserver(this); + } + + protected void paintComponent(Graphics g) { + super.paintComponent(g); // paint the background + for (int i = 0; i < nPoint; i++) { + double t = ((double) i) / (nPoint - 1); + x[i] = (int) (t * getWidth()); + y[i] = (int) (getHeight() * (1 - func.function(t, tPeak))); + } + g.drawPolyline(x, y, nPoint); + } + + /** + * Respond to a change in the observed Tpeak model + * + * @param evt + * change event from Tpeak + */ + @Override + public void propertyChange(PropertyChangeEvent evt) { + tPeak = (double) evt.getNewValue(); + repaint(); + } +} diff --git a/src/app/observer/ballistics4/ShowBallistics4.java b/src/app/observer/ballistics4/ShowBallistics4.java new file mode 100644 index 0000000..c86b191 --- /dev/null +++ b/src/app/observer/ballistics4/ShowBallistics4.java @@ -0,0 +1,137 @@ +package app.observer.ballistics4; + +/* + * Copyright (c) 2001, 2005. Steven J. Metsker. + * + * Steve Metsker makes no representations or warranties about + * the fitness of this software for any particular purpose, + * including the implied warranty of merchantability. + * + * Please use this software as you wish with the sole + * restriction that you may not claim that you wrote it. + */ + +import com.oozinoz.ballistics.Ballistics; +import com.oozinoz.ui.SwingFacade; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +/** + * Show the standard burn rate and thrust equations. This class is refactored + * from ShowBallistics2. The changes involve pushing the value of tPeak down + * into a business layer and using a BallisticsLabel that knows about tPeak. + * + * @author Steven J. Metsker + */ +public class ShowBallistics4 { + /** + * Show the standard burn rate and thrust equations. + */ + public static void main(String[] args) { + SwingFacade.launch(new ShowBallistics4().mainPanel(), + "Effects of tPeak"); + } + + protected BallisticsPanel burnPanel; + + protected JSlider slider; + + protected double sliderMax; + + protected double sliderMin; + + protected BallisticsPanel thrustPanel; + + protected JLabel valueLabel; + + protected Tpeak tPeak = new Tpeak(0); + + protected BallisticsPanel burnPanel() { + if (burnPanel == null) { + burnPanel = new BallisticsPanel(Ballistics.rate(), tPeak); + burnPanel.setPreferredSize(new Dimension(300, 200)); + } + return burnPanel; + } + + /* + * A panel to contain the two plots. + */ + protected JPanel curvePanel() { + JPanel p = new JPanel(); + p.setLayout(new GridLayout(1, 2)); + p.add(SwingFacade.createTitledPanel("Burn Rate", burnPanel())); + p.add(SwingFacade.createTitledPanel("Thrust", thrustPanel())); + return p; + } + + /* + * The main panel -- the one that actually gets displayed. + */ + protected JPanel mainPanel() { + JPanel p = new JPanel(); + p.setLayout(new BorderLayout()); + p.add(curvePanel(), "Center"); + p.add(sliderBox(), "South"); + return p; + } + + /* + * Now the slider just tells the business domain tPeak object that the + * slider moved. + */ + protected JSlider slider() { + if (slider == null) { + slider = new JSlider(); + sliderMax = slider.getMaximum(); + sliderMin = slider.getMinimum(); + slider.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + if (sliderMax == sliderMin) return; + + tPeak.setValue((slider.getValue() - sliderMin) + / (sliderMax - sliderMin)); + } + }); + slider.setValue(slider.getMinimum()); + } + return slider; + } + + /* + * The box that holds the slider plus a textual label and a changing label + * that shows the value of the slider. + */ + protected Box sliderBox() { + Box b = Box.createHorizontalBox(); + JLabel label = new JLabel("tPeak"); + label.setFont(SwingFacade.getStandardFont()); + label.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + label.setForeground(java.awt.Color.black); + b.add(label); + b.add(valueLabel()); + b.add(slider()); + return b; + } + + protected BallisticsPanel thrustPanel() { + if (thrustPanel == null) { + thrustPanel = new BallisticsPanel(Ballistics.thrust(), tPeak); + thrustPanel.setPreferredSize(new Dimension(300, 200)); + } + return thrustPanel; + } + + protected JLabel valueLabel() { + if (valueLabel == null) { + valueLabel = new BallisticsLabel(tPeak); + valueLabel.setFont(SwingFacade.getStandardFont()); + valueLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + valueLabel.setForeground(java.awt.Color.black); + } + return valueLabel; + } +} diff --git a/src/app/observer/ballistics4/Tpeak.java b/src/app/observer/ballistics4/Tpeak.java new file mode 100644 index 0000000..0277002 --- /dev/null +++ b/src/app/observer/ballistics4/Tpeak.java @@ -0,0 +1,59 @@ +package app.observer.ballistics4; + +/* + * Copyright (c) 2001, 2005. Steven J. Metsker. + * + * Steve Metsker makes no representations or warranties about + * the fitness of this software for any particular purpose, + * including the implied warranty of merchantability. + * + * Please use this software as you wish with the sole + * restriction that you may not claim that you wrote it. + */ + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +/** + * Instances of this class provide an observably changeable model of the time at + * which a fuel's burn area peaks. + * + * @author Steven J. Metsker + */ +public class Tpeak { + protected double value; + private PropertyChangeSupport support; + + /** + * Create a model of the time at which a fuel's burn area peaks. + * + * @param value + * the initial peak time + */ + public Tpeak(double value) { + this.value = value; + this.support = new PropertyChangeSupport(this); + } + + /** + * @return the current value of the peak time + */ + public double getValue() { + return value; + } + + /** + * @param newValue + * the new value for the peak time + */ + public void setValue(double newValue) { + double oldValue = this.value; + this.value = newValue; + support.firePropertyChange("value", oldValue, newValue); + + } + + public void addObserver(PropertyChangeListener listener) { + support.addPropertyChangeListener(listener); + } +} From 3c5c6c15f4c603ae6f7bd6d210b78f7a1a6ba062 Mon Sep 17 00:00:00 2001 From: Juan Manuel Gimeno Illa Date: Thu, 12 May 2022 12:32:28 +0200 Subject: [PATCH 2/5] Obey contract of Iterator next() should throw NoSuchElementException instead of returning null when there are no more elements --- src/com/oozinoz/iterator/CompositeIterator.java | 13 +++++++++---- src/com/oozinoz/iterator/LeafIterator.java | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/com/oozinoz/iterator/CompositeIterator.java b/src/com/oozinoz/iterator/CompositeIterator.java index b23c59b..7d87dd3 100644 --- a/src/com/oozinoz/iterator/CompositeIterator.java +++ b/src/com/oozinoz/iterator/CompositeIterator.java @@ -13,6 +13,7 @@ import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; import java.util.Set; public class CompositeIterator> extends ComponentIterator { @@ -32,9 +33,13 @@ public int getDepth() { } public boolean hasNext() { - if (peek == null) - peek = next(); - return peek != null; + try { + if (peek == null) + peek = next(); + return true; + } catch (NoSuchElementException ex) { + return false; + } } public E next() { @@ -65,7 +70,7 @@ protected E nextDescendant() { if (subiterator.hasNext()) return subiterator.next(); } - if (!children.hasNext()) return null; + if (!children.hasNext()) throw new NoSuchElementException("No next element"); E pc = children.next(); if (!visited.contains(pc)) { diff --git a/src/com/oozinoz/iterator/LeafIterator.java b/src/com/oozinoz/iterator/LeafIterator.java index 2e6ec98..18c86f2 100644 --- a/src/com/oozinoz/iterator/LeafIterator.java +++ b/src/com/oozinoz/iterator/LeafIterator.java @@ -11,6 +11,7 @@ * restriction that you may not claim that you wrote it. */ +import java.util.NoSuchElementException; import java.util.Set; public class LeafIterator extends ComponentIterator { @@ -27,7 +28,7 @@ public boolean hasNext() { } public E next() { - if (visited.contains(head)) return null; + if (visited.contains(head)) throw new NoSuchElementException("No next element"); visited.add(head); return head; From 4635e4ec74b5590f4fd38148792ff64014d0d378 Mon Sep 17 00:00:00 2001 From: Juan Manuel Gimeno Illa Date: Mon, 13 May 2024 07:49:59 +0200 Subject: [PATCH 3/5] Made find in FindVisitor static. --- src/app/visitor/FindVisitor.java | 15 +++++++++------ src/app/visitor/ShowFindVisitor.java | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/app/visitor/FindVisitor.java b/src/app/visitor/FindVisitor.java index d8fdcd6..774968b 100644 --- a/src/app/visitor/FindVisitor.java +++ b/src/app/visitor/FindVisitor.java @@ -26,16 +26,19 @@ public class FindVisitor implements MachineVisitor { private MachineComponent found; + public FindVisitor(int soughtId) { + this.soughtId = soughtId; + } + /** * @param mc the composite to look within * @param id the id of the machine to find * @return a machine with the given id, within the given machine composite */ - public MachineComponent find(MachineComponent mc, int id) { - found = null; - soughtId = id; - mc.accept(this); - return found; + public static MachineComponent find(MachineComponent mc, int id) { + FindVisitor visitor = new FindVisitor(id); + mc.accept(visitor); + return visitor.found; } /** @@ -59,4 +62,4 @@ public void visit(MachineComposite mc) { while (found == null && iter.hasNext()) iter.next().accept(this); } -} \ No newline at end of file +} diff --git a/src/app/visitor/ShowFindVisitor.java b/src/app/visitor/ShowFindVisitor.java index ff7294e..79fba7a 100644 --- a/src/app/visitor/ShowFindVisitor.java +++ b/src/app/visitor/ShowFindVisitor.java @@ -23,7 +23,7 @@ public class ShowFindVisitor { public static void main(String[] args) { MachineComponent factory = OozinozFactory.dublin(); - MachineComponent machine = new FindVisitor().find(factory, 3404); + MachineComponent machine = FindVisitor.find(factory, 3404); System.out.println(machine != null ? machine.toString() : "Not found"); } -} \ No newline at end of file +} From 76e7a80889a33344d63d91844b7fc648281e62f0 Mon Sep 17 00:00:00 2001 From: Juan Manuel Gimeno Illa Date: Mon, 20 May 2024 08:06:25 +0200 Subject: [PATCH 4/5] Migrated AcyclicIterable to a modern java interface using default method --- src/com/oozinoz/iterator/AcycliclyIterable.java | 5 +++++ src/com/oozinoz/process/ProcessComponent.java | 15 ++++----------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/com/oozinoz/iterator/AcycliclyIterable.java b/src/com/oozinoz/iterator/AcycliclyIterable.java index 887c3f4..bc0ec41 100644 --- a/src/com/oozinoz/iterator/AcycliclyIterable.java +++ b/src/com/oozinoz/iterator/AcycliclyIterable.java @@ -1,7 +1,12 @@ package com.oozinoz.iterator; +import java.util.HashSet; import java.util.Set; public interface AcycliclyIterable extends Iterable { + default ComponentIterator iterator() { + return iterator(new HashSet<>()); + } + ComponentIterator iterator(Set visited); } diff --git a/src/com/oozinoz/process/ProcessComponent.java b/src/com/oozinoz/process/ProcessComponent.java index c7a5cb6..f48aa2d 100644 --- a/src/com/oozinoz/process/ProcessComponent.java +++ b/src/com/oozinoz/process/ProcessComponent.java @@ -11,12 +11,11 @@ * restriction that you may not claim that you wrote it. */ +import com.oozinoz.iterator.AcycliclyIterable; + import java.util.HashSet; import java.util.Set; -import com.oozinoz.iterator.AcycliclyIterable; -import com.oozinoz.iterator.ComponentIterator; - /** * Objects of this class represent either individual process steps or * compositions of process steps. A process is essentially a recipe for @@ -50,17 +49,11 @@ public String getName() { return name; } - public ComponentIterator iterator() { - return iterator(new HashSet()); - } - - public abstract ComponentIterator iterator(Set visited); - /** * @return the number of leaf node steps in this composite. */ public int getStepCount() { - return getStepCount(new HashSet()); + return getStepCount(new HashSet<>()); } /** @@ -76,4 +69,4 @@ public int getStepCount() { public String toString() { return name; } -} \ No newline at end of file +} From 1994fdcd417ece14246a4ea7858a0c37dea8221c Mon Sep 17 00:00:00 2001 From: Juan Manuel Gimeno Illa Date: Mon, 20 May 2024 10:08:20 +0200 Subject: [PATCH 5/5] removed non needed implementation of Iterator::remove --- src/com/oozinoz/iterator/ComponentIterator.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/com/oozinoz/iterator/ComponentIterator.java b/src/com/oozinoz/iterator/ComponentIterator.java index 6b02952..645bef6 100644 --- a/src/com/oozinoz/iterator/ComponentIterator.java +++ b/src/com/oozinoz/iterator/ComponentIterator.java @@ -48,7 +48,4 @@ public void setShowInterior(boolean value) { */ public abstract int getDepth(); - public void remove() { - throw new UnsupportedOperationException("ComponentIterator.Remove"); - } -} \ No newline at end of file +}