first mostly working attempt of new modify logic

This commit is contained in:
hneemann 2021-04-30 20:04:37 +02:00
parent 9eb1b23073
commit b84a921f86
13 changed files with 98 additions and 82 deletions

View File

@ -8,6 +8,10 @@
{{de 4-Bit Ripple-Carry addierer bestehend aus vier
Volladdierern.}}</string>
</entry>
<entry>
<string>showDataGraphMicro</string>
<boolean>true</boolean>
</entry>
</attributes>
<visualElements>
<visualElement>
@ -692,4 +696,20 @@ end loop</dataString>
<p2 x="140" y="0"/>
</wire>
</wires>
<measurementOrdering>
<string>C_-1</string>
<string>A_0</string>
<string>A_1</string>
<string>A_2</string>
<string>A_3</string>
<string>B_0</string>
<string>B_1</string>
<string>B_2</string>
<string>B_3</string>
<string>S_0</string>
<string>S_1</string>
<string>S_2</string>
<string>S_3</string>
<string>C_3</string>
</measurementOrdering>
</circuit>

View File

@ -209,7 +209,7 @@ public class Model implements Iterable<Node>, SyncAccess {
* Closes the model.
* A STOPPED event is fired.
*/
public void close() {
public synchronized void close() {
if (state != State.CLOSED) {
state = State.CLOSED;
int obs = observers.size();
@ -463,7 +463,7 @@ public class Model implements Iterable<Node>, SyncAccess {
* @param event the mandatory event
* @param events more optional events
*/
public void addObserver(ModelStateObserver observer, ModelEventType event, ModelEventType... events) {
public synchronized void addObserver(ModelStateObserver observer, ModelEventType event, ModelEventType... events) {
addObserverForEvent(observer, event);
for (ModelEventType ev : events)
addObserverForEvent(observer, ev);
@ -474,13 +474,12 @@ public class Model implements Iterable<Node>, SyncAccess {
*
* @param observer the observer to add
*/
public void addObserver(ModelStateObserverTyped observer) {
public synchronized void addObserver(ModelStateObserverTyped observer) {
for (ModelEventType ev : observer.getEvents())
addObserverForEvent(observer, ev);
}
private void addObserverForEvent(ModelStateObserver observer, ModelEventType event) {
private synchronized void addObserverForEvent(ModelStateObserver observer, ModelEventType event) {
ArrayList<ModelStateObserver> obs = observers;
if (event == ModelEventType.STEP || event == ModelEventType.CHECKBURN) {
if (observersStep == null)
@ -501,7 +500,7 @@ public class Model implements Iterable<Node>, SyncAccess {
*
* @param observer the observer to remove
*/
public void removeObserver(ModelStateObserver observer) {
public synchronized void removeObserver(ModelStateObserver observer) {
observers.remove(observer);
if (observersStep != null)
observersStep.remove(observer);
@ -516,7 +515,7 @@ public class Model implements Iterable<Node>, SyncAccess {
* @param <T> the type of the observer
* @return the found observer or null if not present
*/
public <T extends ModelStateObserver> T getObserver(Class<T> observerClass) {
public synchronized <T extends ModelStateObserver> T getObserver(Class<T> observerClass) {
for (ModelStateObserver mso : observers)
if (mso.getClass() == observerClass)
return (T) mso;
@ -908,10 +907,40 @@ public class Model implements Iterable<Node>, SyncAccess {
synchronized (this) {
run.run();
}
fireEvent(ModelEvent.EXTERNALCHANGE);
fireEvent(ModelEvent.MICROSTEP); // record the external modification as a micro step!
doStep();
return run;
}
/**
* Creates a {@link SyncAccess} instance to access the model.
* If microStep is true, there is no foll step performed, in case of a user interaction.
*
* @param microStep if true no full step is calculated at a user interaction
* @return the instance
*/
public SyncAccess createSync(boolean microStep) {
if (microStep) {
return new SyncAccess() {
@Override
public <A extends Runnable> A modify(A run) {
synchronized (this) {
run.run();
}
fireEvent(ModelEvent.MICROSTEP); // record the external modification as a micro step!
return run;
}
@Override
public <A extends Runnable> A read(A run) {
return Model.this.read(run);
}
};
} else
return this;
}
@Override
public <A extends Runnable> A read(A run) {
synchronized (this) {

View File

@ -43,10 +43,6 @@ public class ModelEvent {
* Shorthand for a ModelEventType.BREAK event
*/
public static final ModelEvent BREAK = new ModelEvent(ModelEventType.BREAK);
/**
* Shorthand for a ModelEventType.EXTERNALCHANGE event
*/
public static final ModelEvent EXTERNALCHANGE = new ModelEvent(ModelEventType.EXTERNALCHANGE);
private final ModelEventType type;
private Exception cause;

View File

@ -42,11 +42,6 @@ public enum ModelEventType {
*/
BREAK,
/**
* Here was a manual change to the model by the user.
*/
EXTERNALCHANGE,
/**
* Is fired if a micro step is calculated.
* This means the aktual nodes are calculated, but not the effected nodes.

View File

@ -57,7 +57,7 @@ public class DataPlotter implements Drawable {
* Fits the data in the visible area
*/
public void fitInside() {
modelSync.modify(() -> size = ((double) (width - textWidth)) / dataOriginal.getRows());
modelSync.read(() -> size = ((double) (width - textWidth)) / dataOriginal.getRows());
offset = 0;
manualScaling = false;
}

View File

@ -97,7 +97,6 @@ public class RealTimeClock implements ModelStateObserverTyped {
frequencyCalculator = null;
timer = executor.scheduleAtFixedRate(() -> {
model.modify(() -> output.setValue(1 - output.getValue()));
model.doStep();
if (frequencyCalculator != null)
frequencyCalculator.calc();
}, delay, delay, TimeUnit.MICROSECONDS);
@ -123,7 +122,6 @@ public class RealTimeClock implements ModelStateObserverTyped {
FrequencyCalculator frequencyCalculator = new FrequencyCalculator(status, frequency);
while (!Thread.interrupted()) {
model.modify(() -> output.setValue(1 - output.getValue()));
model.doStep();
frequencyCalculator.calc();
}
});

View File

@ -1382,7 +1382,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
private void clearModelDescription() {
if (model != null)
model.modify(() -> model.close());
model.close();
modelCreator = null;
model = null;
@ -1397,11 +1397,9 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
modelCreator = new ModelCreator(circuitComponent.getCircuit(), library);
if (model != null) {
model.modify(() -> {
ModelClosedObserver mco = model.getObserver(ModelClosedObserver.class);
if (mco != null) mco.setClosedByRestart(true);
model.close();
});
ModelClosedObserver mco = model.getObserver(ModelClosedObserver.class);
if (mco != null) mco.setClosedByRestart(true);
model.close();
circuitComponent.getCircuit().clearState();
model = null;
}
@ -1448,7 +1446,8 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
}
}
circuitComponent.setModeAndReset(true, model);
circuitComponent.setModeAndReset(true,
model.createSync(updateEvent == ModelEventType.MICROSTEP));
if (circuitComponent.getCircuit().getAttributes().get(Keys.IS_GENERIC))
circuitComponent.setCopy(modelCreator.getCircuit());
@ -1456,12 +1455,12 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
CircuitModifierPostClosed cmpc = new CircuitModifierPostClosed(
modification -> SwingUtilities.invokeLater(() -> circuitComponent.modify(modification)));
modelCreator.connectToGui(cmpc);
model.addObserver(cmpc);
this.model.addObserver(cmpc);
handleKeyboardComponents();
doMicroStep.setEnabled(false);
if (!realTimeClockRunning && model.isRunToBreakAllowed()) {
if (!realTimeClockRunning && this.model.isRunToBreakAllowed()) {
if (updateEvent == ModelEventType.MICROSTEP)
runToBreakMicroAction.setEnabled(true);
else
@ -1478,30 +1477,30 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
showMeasurementGraph(ModelEventType.MICROSTEP);
if (modelModifier != null)
modelModifier.preInit(model);
modelModifier.preInit(this.model);
else {
if (settings.get(Keys.PRELOAD_PROGRAM)) {
File romHex = new FileLocator(settings.get(Keys.PROGRAM_TO_PRELOAD))
.setupWithMain(this)
.locate();
new ProgramMemoryLoader(romHex)
.preInit(model);
.preInit(this.model);
}
}
if (updateEvent == ModelEventType.MICROSTEP) {
checkMicroStepActions(model);
model.addObserver(new MicroStepObserver(model, modelCreator));
checkMicroStepActions(this.model);
this.model.addObserver(new UpdateViewMicroStepObserver(this.model, modelCreator));
} else if (updateEvent == ModelEventType.STEP) {
if (maxFrequency <= 50)
model.addObserver(new FullStepObserver(model));
this.model.addObserver(new UpdateViewAtEventObserver());
else
model.addObserver(new FastObserver());
this.model.addObserver(new UpdateViewPeriodicObserver());
}
model.addObserver(new ModelClosedObserver());
this.model.addObserver(new ModelClosedObserver());
model.init();
this.model.init();
} catch (NodeException | PinException | RuntimeException | ElementNotFoundException e) {
if (model != null)
@ -1736,20 +1735,15 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
/**
* Updates the graphic at every modification.
*/
private class FullStepObserver implements ModelStateObserverTyped {
private final Model model;
FullStepObserver(Model model) {
this.model = model;
private class UpdateViewAtEventObserver implements ModelStateObserverTyped {
UpdateViewAtEventObserver() {
}
@Override
public void handleEvent(ModelEvent event) {
switch (event.getType()) {
case EXTERNALCHANGE:
model.doStep();
circuitComponent.graphicHasChanged();
break;
case CHECKBURN:
case STEP:
case BREAK:
circuitComponent.graphicHasChanged();
break;
@ -1758,17 +1752,17 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
@Override
public ModelEventType[] getEvents() {
return new ModelEventType[]{ModelEventType.EXTERNALCHANGE, ModelEventType.BREAK};
return new ModelEventType[]{ModelEventType.CHECKBURN, ModelEventType.STEP, ModelEventType.BREAK};
}
}
/**
* Updates the graphic at every 100ms
*/
private final class FastObserver implements ModelStateObserverTyped {
private final class UpdateViewPeriodicObserver implements ModelStateObserverTyped {
private final Timer timer;
private FastObserver() {
private UpdateViewPeriodicObserver() {
timer = new Timer(100, actionEvent -> circuitComponent.graphicHasChanged());
}
@ -1795,11 +1789,11 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
/**
* Updates the graphic at every micro step
*/
private final class MicroStepObserver implements ModelStateObserverTyped {
private final class UpdateViewMicroStepObserver implements ModelStateObserverTyped {
private final Model model;
private final ModelCreator modelCreator;
private MicroStepObserver(Model model, ModelCreator modelCreator) {
private UpdateViewMicroStepObserver(Model model, ModelCreator modelCreator) {
this.model = model;
this.modelCreator = modelCreator;
}
@ -1807,7 +1801,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
@Override
public void handleEvent(ModelEvent event) {
switch (event.getType()) {
case EXTERNALCHANGE:
case CHECKBURN:
case MICROSTEP:
case BREAK:
if (!realTimeClockRunning) {
@ -1823,7 +1817,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
@Override
public ModelEventType[] getEvents() {
return new ModelEventType[]{ModelEventType.EXTERNALCHANGE, ModelEventType.MICROSTEP, ModelEventType.BREAK};
return new ModelEventType[]{ModelEventType.CHECKBURN, ModelEventType.MICROSTEP, ModelEventType.BREAK};
}
}
@ -1961,12 +1955,9 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
if (cl.size() == 1) {
ObservableValue clkVal = cl.get(0).getClockOutput();
model.modify(() -> clkVal.setBool(!clkVal.getBool()));
model.doStep();
if (model != null) {
if (clkVal.getBool() && model.isRunning()) {
if (clkVal.getBool() && model.isRunning())
model.modify(() -> clkVal.setBool(!clkVal.getBool()));
model.doStep();
}
addressPicker.getProgramROMAddress(model);
}
}

View File

@ -60,12 +60,12 @@ public class ProbeDialog extends JDialog implements ModelStateObserverTyped {
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
model.modify(() -> model.addObserver(ProbeDialog.this));
model.addObserver(ProbeDialog.this);
}
@Override
public void windowClosed(WindowEvent e) {
model.modify(() -> model.removeObserver(ProbeDialog.this));
model.removeObserver(ProbeDialog.this);
}
});
@ -109,7 +109,7 @@ public class ProbeDialog extends JDialog implements ModelStateObserverTyped {
@Override
public void handleEvent(ModelEvent event) {
if (event.getType() == type || event == ModelEvent.EXTERNALCHANGE) {
if (event.getType() == type || event == ModelEvent.CHECKBURN) {
if (tableUpdateEnable) {
if (paintPending.compareAndSet(false, true)) {
SwingUtilities.invokeLater(() -> {
@ -133,7 +133,7 @@ public class ProbeDialog extends JDialog implements ModelStateObserverTyped {
@Override
public ModelEventType[] getEvents() {
return new ModelEventType[]{type, ModelEventType.EXTERNALCHANGE, ModelEventType.FASTRUN, ModelEventType.BREAK, ModelEventType.CLOSED};
return new ModelEventType[]{type, ModelEventType.CHECKBURN, ModelEventType.FASTRUN, ModelEventType.BREAK, ModelEventType.CLOSED};
}
private static class SignalTableModel implements TableModel {

View File

@ -109,11 +109,11 @@ public final class SingleValueDialog extends JDialog implements ModelStateObserv
JPanel checkBoxPanel = createCheckBoxPanel(editValue);
model.modify(() -> model.addObserver(this));
model.addObserver(this);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent windowEvent) {
model.modify(() -> model.removeObserver(SingleValueDialog.this));
model.removeObserver(SingleValueDialog.this);
}
});

View File

@ -78,12 +78,12 @@ public class GraphDialog extends JDialog implements Observer {
graphDialog.addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
model.modify(() -> model.addObserver(valueTableObserver));
model.addObserver(valueTableObserver);
}
@Override
public void windowClosed(WindowEvent e) {
model.modify(() -> model.removeObserver(valueTableObserver));
model.removeObserver(valueTableObserver);
}
});

View File

@ -167,7 +167,7 @@ public class ScopeTrigger extends Node implements Element {
graphDialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
model.modify(() -> model.removeObserver(scopeModelStateObserver));
model.removeObserver(scopeModelStateObserver);
}
});
graphDialog.setVisible(true);

View File

@ -24,8 +24,6 @@ public class ValueTableObserver implements ModelStateObserverTyped {
private final ModelEventType type;
private final ArrayList<Signal> signals;
private Value[] manualSample;
/**
* Creates a new instance
*
@ -51,18 +49,7 @@ public class ValueTableObserver implements ModelStateObserverTyped {
if (event == ModelEvent.STARTED)
logData.clear();
if (event == ModelEvent.EXTERNALCHANGE && type == ModelEventType.MICROSTEP) {
if (manualSample == null)
manualSample = new Value[logData.getColumns()];
for (int i = 0; i < logData.getColumns(); i++)
manualSample[i] = new Value(signals.get(i).getValue());
}
if (event.getType() == type) {
if (manualSample != null) {
logData.add(new TestRow(manualSample));
manualSample = null;
}
Value[] row = new Value[logData.getColumns()];
for (int i = 0; i < logData.getColumns(); i++)
row[i] = new Value(signals.get(i).getValue());
@ -72,7 +59,7 @@ public class ValueTableObserver implements ModelStateObserverTyped {
@Override
public ModelEventType[] getEvents() {
return new ModelEventType[]{type, ModelEventType.STARTED, ModelEventType.EXTERNALCHANGE};
return new ModelEventType[]{type, ModelEventType.STARTED};
}
/**

View File

@ -228,12 +228,12 @@ public class InitialTutorial extends JDialog implements CircuitComponent.Tutoria
@Override
public ModelEventType[] getEvents() {
return new ModelEventType[]{ModelEventType.EXTERNALCHANGE};
return new ModelEventType[]{ModelEventType.STEP};
}
@Override
public void handleEvent(ModelEvent event) {
if (event == ModelEvent.EXTERNALCHANGE)
if (event == ModelEvent.STEP)
modified(null);
}