Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ private void autoEmulate(CPU cpu) {
}

resultState = CPU.RunState.STATE_RUNNING;
cpu.addCPUListener(new CPU.CPUListener() {
CPU.CPUListener stateListener = new CPU.CPUListener() {
@Override
public void runStateChanged(CPU.RunState state) {
if (state != CPU.RunState.STATE_RUNNING) {
Expand All @@ -177,7 +177,8 @@ public void runStateChanged(CPU.RunState state) {
@Override
public void internalStateChanged() {
}
});
};
cpu.addCPUListener(stateListener);
cpu.execute();

synchronized (resultStateLock) {
Expand All @@ -199,6 +200,7 @@ public void internalStateChanged() {
Thread.currentThread().interrupt();
}
}
cpu.removeCPUListener(stateListener);

switch (resultState) {
case STATE_STOPPED_ADDR_FALLOUT:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public void setValueAt(Object value, int rowIndex, int columnIndex) {
if (location == -1) return;

DebuggerColumn<?> column = columns[columnIndex];
if (value.getClass() == column.getClassType()) {
if (column.getClassType().isInstance(value)) {
try {
column.setValue(location, value);
} catch (CannotSetDebuggerValueException ignored) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ public void mouseClicked(MouseEvent e) {

this.memoryListener = new MemoryContext.MemoryListener() {
@Override
public void memoryContentChanged(int fromLocatiom, int toLocation) {
public void memoryContentChanged(int fromLocation, int toLocation) {
runOnEdt(() -> {
debugTableModel.memoryChanged(fromLocatiom, toLocation + 1);
debugTableModel.memoryChanged(fromLocation, toLocation + 1);
refreshDebugTable();
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

import static net.emustudio.application.gui.framework.EmuStudioGui.*;
import static net.emustudio.application.settings.ConfigFiles.listPluginFiles;
Expand All @@ -38,6 +39,7 @@ public class SchemaEditorDialog extends DialogBase implements KeyListener {
private final GUI gui;

private final DrawingPanel panel;
private final AtomicInteger pluginLoadId = new AtomicInteger();
private boolean buttonSelected = false;
private JToggleButton btnBidirection;
private JToggleButton btnCPU;
Expand Down Expand Up @@ -337,6 +339,7 @@ private void btnSaveActionPerformed(ActionEvent evt) {
} catch (CannotUpdateSettingException e) {
LOGGER.error("Could not save computer schema", e);
dialogs.showError("Could not save computer schema. Please consult log file for details.", "Save schema");
return;
}
dispose();
}
Expand All @@ -353,18 +356,37 @@ private void btnBidirectionActionPerformed(ActionEvent evt) {
}

private void resetComboWithPluginFiles(PLUGIN_TYPE pluginType) {
try {
List<String> pluginFiles = listPluginFiles(pluginType);
cmbPlugin.setModel(new PluginComboModel(pluginFiles));
selectFirstPlugin();
} catch (IOException e) {
LOGGER.error("Could not load CPU plugin files", e);
cmbPlugin.setModel(EMPTY_MODEL);
}
int loadId = pluginLoadId.incrementAndGet();
cmbPlugin.setModel(EMPTY_MODEL);
cmbPlugin.setEnabled(false);

new SwingWorker<List<String>, Void>() {
@Override
protected List<String> doInBackground() throws IOException {
return listPluginFiles(pluginType);
}

@Override
protected void done() {
if (loadId != pluginLoadId.get()) {
return;
}
cmbPlugin.setEnabled(true);
try {
cmbPlugin.setModel(new PluginComboModel(get()));
selectFirstPlugin();
} catch (Exception e) {
LOGGER.error("Could not load plugin files", e);
cmbPlugin.setModel(EMPTY_MODEL);
}
}
}.execute();
}

private boolean checkUnsetDrawingTool() {
if (buttonSelected) {
pluginLoadId.incrementAndGet();
cmbPlugin.setEnabled(true);
cmbPlugin.setModel(EMPTY_MODEL);
groupDraw.clearSelection();
panel.setTool(Tool.TOOL_NOTHING, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;

public class SchemaPreviewPanel extends JPanel {
private final static Logger LOGGER = LoggerFactory.getLogger(SchemaPreviewPanel.class);
Expand All @@ -43,6 +44,7 @@ public class SchemaPreviewPanel extends JPanel {
private int topFactor = 0;

private boolean panelResized = false;
private final AtomicBoolean savingImage = new AtomicBoolean();

public SchemaPreviewPanel(Schema schema, Dialogs dialogs) {
this.dialogs = Objects.requireNonNull(dialogs);
Expand Down Expand Up @@ -103,28 +105,46 @@ public void saveSchemaImage() {
"Save schema image", "Save", currentDirectory, true,
new FileExtensionsFilter("PNG image", "png")
).ifPresent(path -> {
if (!savingImage.compareAndSet(false, true)) {
return;
}
lastImageFile = path.toFile();

// Save the image
BufferedImage bi = new BufferedImage(schemaWidth, schemaHeight, BufferedImage.TYPE_INT_RGB);

Graphics2D graphics = bi.createGraphics();
graphics.setBackground(Color.WHITE);
graphics.fillRect(0, 0, schemaWidth, schemaHeight);
RenderingHints hints = new RenderingHints(Map.of(
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON,
RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY,
RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON
));

graphics.setRenderingHints(hints);
paintComponent(graphics);
try {
ImageIO.write(bi, "png", lastImageFile);
} catch (IOException e) {
LOGGER.error("Could not save schema image.", e);
dialogs.showError("Could not save schema image. Please see log file for details.", "Save schema image");
graphics.setBackground(Color.WHITE);
graphics.fillRect(0, 0, schemaWidth, schemaHeight);
RenderingHints hints = new RenderingHints(Map.of(
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON,
RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY,
RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON
));
graphics.setRenderingHints(hints);
paintComponent(graphics);
} finally {
graphics.dispose();
}

new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws IOException {
ImageIO.write(bi, "png", lastImageFile);
return null;
}

@Override
protected void done() {
savingImage.set(false);
try {
get();
} catch (Exception e) {
LOGGER.error("Could not save schema image.", e);
dialogs.showError("Could not save schema image. Please see log file for details.", "Save schema image");
}
}
}.execute();
});
} else {
dialogs.showError("Could not save schema image: schema is not set.", "Save schema image");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,6 @@ public Element(Color backColor, P schemaPoint, String pluginId, PLUGIN_TYPE plug
this.pluginName = Objects.requireNonNull(pluginName);
this.pluginFileName = Objects.requireNonNull(pluginFileName);
this.pluginSettings = Objects.requireNonNull(pluginSettings);

int x = schemaPoint.ix();
int y = schemaPoint.iy();

this.gradient = new GradientPaint(x, y, Color.WHITE, x, y + height, this.backColor, false);
}

public void draw(Graphics2D g) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ public void saveButtonShowsErrorWhenSchemaSaveFails() throws Exception {
"Could not save computer schema. Please consult log file for details.",
"Save schema"
);
assertFalse(onEdt(dialog::isDisplayable));
assertTrue(onEdt(dialog::isDisplayable));
}

private SchemaEditorDialog createDialog(Schema schema, Dialogs dialogs) {
Expand Down Expand Up @@ -269,6 +269,7 @@ private void assertPluginButtonBehavior(String tooltip, PLUGIN_TYPE pluginType,

triggerButton(button);

waitForPluginLoad(pluginCombo);
assertEquals(1, onEdt(pluginCombo::getItemCount).intValue());
assertEquals(displayName(pluginFile), onEdt(() -> String.valueOf(pluginCombo.getSelectedItem())));
assertEquals(expectedTool, getDrawingModel(dialog).drawTool);
Expand Down Expand Up @@ -298,6 +299,16 @@ private boolean readButtonSelected(SchemaEditorDialog dialog) throws Exception {
return getField(dialog, "buttonSelected", Boolean.class);
}

private void waitForPluginLoad(JComboBox<?> pluginCombo) throws Exception {
for (int i = 0; i < 200; i++) {
if (onEdt(pluginCombo::getItemCount) == 1) {
return;
}
Thread.sleep(10);
}
throw new AssertionError("Plugin list did not load");
}

private void setDrawingTool(SchemaEditorDialog dialog, DrawingPanel.Tool tool, String fileName) throws Exception {
runOnEdt(() -> {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ public void paintComputesPreferredSizeAndSaveWritesImage() throws Exception {

panel.saveSchemaImage();

assertTrue(Files.exists(output));
assertTrue(Files.size(output) > 0);
assertTrue(waitForImage(output));
}
}

Expand All @@ -74,4 +73,14 @@ private CompilerElement findElement(Schema schema) {
}
throw new AssertionError("Missing compiler element");
}

private boolean waitForImage(Path image) throws Exception {
for (int i = 0; i < 200; i++) {
if (Files.size(image) > 0) {
return true;
}
Thread.sleep(10);
}
return false;
}
}
15 changes: 15 additions & 0 deletions docs/adr/0008-shared-compiler-helpers-in-emulib.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# ADR-0008: Shared Compiler Helpers Live in emuLib

## Status
Accepted

## Context
Six bundled compiler plugins each carried identical copies of ANTLR support code (`CharArrayCharStream`, `ParsingUtils`). Bug fixes had to be repeated per copy. emuLib owns reusable utilities shared across emuStudio repositories, so the helpers belong there rather than in an emuStudio-internal module.

## Decision
Move the helpers to emuLib package `net.emustudio.emulib.plugins.compiler.antlr` (a subpackage, because `plugins.compiler` already defines emuStudio's own `Token`). In emuLib, `antlr4-runtime` is a `compileOnly` dependency: only compiler plugins that use these helpers must provide the ANTLR runtime, which they already do.

Plugin-specific code (exception types, error listeners tied to per-plugin grammars) stays in each plugin.

## Consequences
One source of truth for shared parsing code; ~700 lines of duplication removed from this repository. emuLib gains a compile-time-only ANTLR dependency; non-compiler consumers are unaffected. Bundled compiler plugins require emuLib >= 12.1.0.

This file was deleted.

Loading
Loading