diff --git a/src/main/java/de/neemann/digital/draw/gif/GifExporter.java b/src/main/java/de/neemann/digital/draw/gif/GifExporter.java
index 802220d55..b98284f3a 100644
--- a/src/main/java/de/neemann/digital/draw/gif/GifExporter.java
+++ b/src/main/java/de/neemann/digital/draw/gif/GifExporter.java
@@ -1,18 +1,29 @@
package de.neemann.digital.draw.gif;
import de.neemann.digital.core.Model;
+import de.neemann.digital.core.ModelEvent;
+import de.neemann.digital.core.ModelStateObserver;
import de.neemann.digital.core.NodeException;
-import de.neemann.digital.core.ObservableValue;
-import de.neemann.digital.core.wiring.Clock;
import de.neemann.digital.draw.elements.Circuit;
import de.neemann.digital.draw.graphics.GraphicMinMax;
import de.neemann.digital.draw.graphics.GraphicsImage;
import de.neemann.digital.draw.graphics.linemerger.GraphicLineCollector;
import de.neemann.digital.draw.graphics.linemerger.GraphicSkipLines;
+import de.neemann.digital.gui.ModelModifier;
+import de.neemann.digital.lang.Lang;
+import de.neemann.gui.ErrorMessage;
+import de.neemann.gui.Screen;
+import de.neemann.gui.ToolTipAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.imageio.stream.FileImageOutputStream;
-import javax.imageio.stream.ImageOutputStream;
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
@@ -21,52 +32,109 @@ import java.io.IOException;
* Exporter which creates an animated GIF file.
* Created by hneemann on 17.05.17.
*/
-public class GifExporter {
- private final Model model;
+public class GifExporter extends JDialog implements ModelStateObserver, ModelModifier {
+ private static final Logger LOGGER = LoggerFactory.getLogger(GifExporter.class);
private final Circuit circuit;
- private final int frames;
private final int delayMs;
private final GraphicMinMax minMax;
+ private final JLabel frameLabel;
+ private int frames;
+ private FileImageOutputStream output;
+ private GifSequenceWriter writer;
+ private boolean closed = false;
/**
* Creates a new instance
*
- * @param model the mode to use
+ * @param parent the parent frame
* @param circuit the circuit to export
- * @param frames then number of frames to write to the file
* @param delayMs the delay between frames im milliseconds
*/
- public GifExporter(Model model, Circuit circuit, int frames, int delayMs) {
- this.model = model;
+ public GifExporter(JFrame parent, Circuit circuit, int delayMs) {
+ super(parent, "GIF-Export", false);
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+ frameLabel = new JLabel(Lang.get("msg_framesWritten_N", frames));
+ frameLabel.setFont(Screen.getInstance().getFont(1.5f));
+ frameLabel.setBorder(new EmptyBorder(5, 5, 5, 5));
+ getContentPane().add(frameLabel);
+
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosed(WindowEvent windowEvent) {
+ close();
+ }
+ });
+
+ getContentPane().add(new ToolTipAction(Lang.get("btn_gifComplete")) {
+ @Override
+ public void actionPerformed(ActionEvent actionEvent) {
+ close();
+ }
+ }.setToolTip(Lang.get("btn_gifComplete_tt")).createJButton(), BorderLayout.SOUTH);
+
this.circuit = circuit;
- this.frames = frames;
this.delayMs = delayMs;
minMax = new GraphicMinMax();
circuit.drawTo(minMax);
+
+ pack();
+ setLocation(parent.getLocation());
}
/**
* Exports the file
*
* @param file the file to write
+ * @return this for chained calls
* @throws IOException IOException
* @throws NodeException NodeException
*/
- public void export(File file) throws IOException, NodeException {
- try (ImageOutputStream output = new FileImageOutputStream(file)) {
- try (GifSequenceWriter writer = new GifSequenceWriter(output, BufferedImage.TYPE_INT_ARGB, delayMs, true)) {
- for (int i = 0; i < frames; i++) {
- writer.writeToSequence(createBufferedImage());
+ public GifExporter export(File file) throws IOException, NodeException {
+ output = new FileImageOutputStream(file);
+ writer = new GifSequenceWriter(output, BufferedImage.TYPE_INT_ARGB, delayMs, true);
+ LOGGER.debug("open GIF file");
+ return this;
+ }
- Clock clock = model.getClocks().get(0);
- ObservableValue o = clock.getClockOutput();
- o.setBool(!o.getBool());
- model.doStep();
- }
+ private void close() {
+ if (!closed) {
+ try {
+ writer.close();
+ output.close();
+ LOGGER.debug("closed GIF file");
+ closed = true;
+ } catch (IOException e) {
+ SwingUtilities.invokeLater(new ErrorMessage(Lang.get("msg_errorWritingGif")).addCause(e));
}
}
+ dispose();
+ }
+
+ @Override
+ public void preInit(Model model) throws NodeException {
+ SwingUtilities.invokeLater(() -> setVisible(true));
+ model.addObserver(this);
+ }
+
+ @Override
+ public void handleEvent(ModelEvent event) {
+ if (event.equals(ModelEvent.STEP)) {
+ writeImage();
+ }
}
+ private void writeImage() {
+ if (!closed) {
+ try {
+ writer.writeToSequence(createBufferedImage());
+ } catch (IOException e) {
+ SwingUtilities.invokeLater(new ErrorMessage(Lang.get("msg_errorWritingGif")).addCause(e));
+ }
+ frames++;
+ frameLabel.setText(Lang.get("msg_framesWritten_N", frames));
+ LOGGER.debug("frame written to GIF file");
+ }
+ }
private BufferedImage createBufferedImage() throws IOException {
GraphicsImage gri = GraphicsImage.create(null, minMax.getMin(), minMax.getMax(), "gif", 1);
diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java
index cfc53fbb3..724e03e20 100644
--- a/src/main/java/de/neemann/digital/gui/Main.java
+++ b/src/main/java/de/neemann/digital/gui/Main.java
@@ -1151,44 +1151,28 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
@Override
public void actionPerformed(ActionEvent e) {
+ JFileChooser fc = new MyFileChooser();
+ if (filename != null)
+ fc.setSelectedFile(SaveAsHelper.checkSuffix(filename, "gif"));
- if (model == null)
- new ErrorMessage(Lang.get("msg_modelNeedsToBeStarted")).show(Main.this);
- else {
+ if (lastExportDirectory != null)
+ fc.setCurrentDirectory(lastExportDirectory);
- String numStr = JOptionPane.showInputDialog(Lang.get("msg_numberOfFrames"));
- if (numStr != null) {
-
- int f = 0;
- try {
- f = Integer.parseInt(numStr);
- } catch (NumberFormatException e1) {
- new ErrorMessage().addCause(e1).show(Main.this);
+ fc.addChoosableFileFilter(new FileNameExtensionFilter(name, "gif"));
+ new SaveAsHelper(Main.this, fc, "gif").checkOverwrite(
+ file -> {
+ lastExportDirectory = file.getParentFile();
+ try {
+ GifExporter ge = new GifExporter(Main.this, circuitComponent.getCircuit(), 500).export(file);
+ setDebug(false);
+ windowPosManager.closeAll();
+ runModelState.enter(false, ge);
+ circuitComponent.hasChanged();
+ } catch (NodeException e1) {
+ new ErrorMessage().addCause(e1).show(Main.this);
+ }
}
- final int frames = f;
- if (frames > 0) {
-
- JFileChooser fc = new MyFileChooser();
- if (filename != null)
- fc.setSelectedFile(SaveAsHelper.checkSuffix(filename, "gif"));
-
- if (lastExportDirectory != null)
- fc.setCurrentDirectory(lastExportDirectory);
-
- fc.addChoosableFileFilter(new FileNameExtensionFilter(name, "gif"));
- new SaveAsHelper(Main.this, fc, "gif").checkOverwrite(
- file -> {
- lastExportDirectory = file.getParentFile();
- try {
- new GifExporter(model, circuitComponent.getCircuit(), frames, 500).export(file);
- } catch (NodeException e1) {
- new ErrorMessage().addCause(e1).show(Main.this);
- }
- }
- );
- }
- }
- }
+ );
}
}
diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml
index f773f3a39..13f1e7daf 100644
--- a/src/main/resources/lang/lang_de.xml
+++ b/src/main/resources/lang/lang_de.xml
@@ -858,8 +858,10 @@ Die Icons stammen aus dem Tango Desktop Project.
Pin {0}
Nummerierungshilfe
Wählen Sie Pin {0}:
- Die Schaltung muss gestartet sein.
- Anzahl der Einzelbilder:
+ Geschriebene Bilder: {0}
+ Fehler beim Schreiben der GIF Datei!
+ Fertig
+ Die GIF-Datei wird abgeschlossen.
Ok
0°
diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml
index 9c79bdc80..a74d6480c 100644
--- a/src/main/resources/lang/lang_en.xml
+++ b/src/main/resources/lang/lang_en.xml
@@ -847,8 +847,10 @@ The icons are taken from the Tango Desktop Project.
Error during speed test!
Pin {0}
Numbering Wizard
- The circuit needs to be started.
- Number of frames:
+ Written frames: {0}
+ Error writing to GIF file!
+ Ready
+ The GIF file is finalized and closed.
Ok
0°