Added better load and save preferences, non-modal help.

This commit is contained in:
Andrew Lalis 2021-02-23 09:10:23 +01:00
parent 7a49772540
commit f37df5defc
5 changed files with 59 additions and 25 deletions

View File

@ -18,11 +18,12 @@ import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.prefs.Preferences;
public class ExportToImageAction extends AbstractAction { public class ExportToImageAction extends AbstractAction {
private static ExportToImageAction instance; private static final String LAST_EXPORT_LOCATION_KEY = "lastExportLocation";
private static ExportToImageAction instance;
public static ExportToImageAction getInstance() { public static ExportToImageAction getInstance() {
if (instance == null) { if (instance == null) {
instance = new ExportToImageAction(); instance = new ExportToImageAction();
@ -30,8 +31,6 @@ public class ExportToImageAction extends AbstractAction {
return instance; return instance;
} }
private File lastSelectedFile;
@Setter @Setter
private MappingModel model; private MappingModel model;
@ -52,12 +51,14 @@ public class ExportToImageAction extends AbstractAction {
); );
return; return;
} }
JFileChooser fileChooser = new JFileChooser(this.lastSelectedFile); JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileFilter(new FileNameExtensionFilter( fileChooser.setFileFilter(new FileNameExtensionFilter(
"Image files", ImageIO.getReaderFileSuffixes() "Image files", ImageIO.getReaderFileSuffixes()
)); ));
if (this.lastSelectedFile != null) { Preferences prefs = Preferences.userNodeForPackage(ExportToImageAction.class);
fileChooser.setSelectedFile(this.lastSelectedFile); String path = prefs.get(LAST_EXPORT_LOCATION_KEY, null);
if (path != null) {
fileChooser.setSelectedFile(new File(path));
} }
int choice = fileChooser.showSaveDialog((Component) e.getSource()); int choice = fileChooser.showSaveDialog((Component) e.getSource());
if (choice == JFileChooser.APPROVE_OPTION) { if (choice == JFileChooser.APPROVE_OPTION) {
@ -74,7 +75,18 @@ public class ExportToImageAction extends AbstractAction {
chosenFile = new File(chosenFile.getParent(), chosenFile.getName() + '.' + extension); chosenFile = new File(chosenFile.getParent(), chosenFile.getName() + '.' + extension);
} }
try { try {
ImageIO.write(this.renderModel(), extension, chosenFile); long start = System.currentTimeMillis();
BufferedImage render = this.renderModel();
double durationSeconds = (System.currentTimeMillis() - start) / 1000.0;
ImageIO.write(render, extension, chosenFile);
prefs.put(LAST_EXPORT_LOCATION_KEY, chosenFile.getAbsolutePath());
JOptionPane.showMessageDialog(
fileChooser,
"Image export completed in " + String.format("%.4f", durationSeconds) + " seconds.\n" +
"Resolution: " + render.getWidth() + "x" + render.getHeight(),
"Image Export Complete",
JOptionPane.INFORMATION_MESSAGE
);
} catch (IOException ex) { } catch (IOException ex) {
ex.printStackTrace(); ex.printStackTrace();
JOptionPane.showMessageDialog(fileChooser, "An error occurred and the file could not be saved:\n" + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); JOptionPane.showMessageDialog(fileChooser, "An error occurred and the file could not be saved:\n" + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
@ -83,23 +95,30 @@ public class ExportToImageAction extends AbstractAction {
} }
private BufferedImage renderModel() { private BufferedImage renderModel() {
// Prepare a tiny sample image that we can use to determine the bounds of the model in a graphics context.
BufferedImage bufferedImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); BufferedImage bufferedImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bufferedImage.createGraphics(); Graphics2D g2d = bufferedImage.createGraphics();
DiagramPanel.prepareGraphics(g2d); DiagramPanel.prepareGraphics(g2d);
final Rectangle bounds = this.model.getViewModel().getBounds(g2d); final Rectangle bounds = this.model.getViewModel().getBounds(g2d);
// Prepare the output image.
BufferedImage outputImage = new BufferedImage(bounds.width, bounds.height + 20, BufferedImage.TYPE_INT_RGB); BufferedImage outputImage = new BufferedImage(bounds.width, bounds.height + 20, BufferedImage.TYPE_INT_RGB);
g2d = outputImage.createGraphics(); g2d = outputImage.createGraphics();
g2d.setColor(Color.WHITE); g2d.setColor(Color.WHITE);
g2d.fillRect(outputImage.getMinX(), outputImage.getMinY(), outputImage.getWidth(), outputImage.getHeight()); g2d.fillRect(outputImage.getMinX(), outputImage.getMinY(), outputImage.getWidth(), outputImage.getHeight());
// Transform the graphics space to account for the model's offset from origin.
AffineTransform originalTransform = g2d.getTransform(); AffineTransform originalTransform = g2d.getTransform();
g2d.setTransform(AffineTransform.getTranslateInstance(-bounds.x, -bounds.y)); g2d.setTransform(AffineTransform.getTranslateInstance(-bounds.x, -bounds.y));
DiagramPanel.prepareGraphics(g2d); DiagramPanel.prepareGraphics(g2d);
// Render the model.
List<Relation> selectedRelations = this.model.getSelectedRelations(); List<Relation> selectedRelations = this.model.getSelectedRelations();
this.model.getSelectedRelations().forEach(r -> r.setSelected(false)); this.model.getSelectedRelations().forEach(r -> r.setSelected(false));
new MappingModelViewModel(this.model).draw(g2d); new MappingModelViewModel(this.model).draw(g2d);
this.model.getRelations().forEach(r -> r.setSelected(selectedRelations.contains(r))); this.model.getRelations().forEach(r -> r.setSelected(selectedRelations.contains(r)));
// Revert back to the normal image space, and render a watermark.
g2d.setTransform(originalTransform); g2d.setTransform(originalTransform);
g2d.setColor(Color.LIGHT_GRAY); g2d.setColor(Color.LIGHT_GRAY);
g2d.setFont(g2d.getFont().deriveFont(10.0f)); g2d.setFont(g2d.getFont().deriveFont(10.0f));

View File

@ -12,10 +12,16 @@ import java.net.URISyntaxException;
public abstract class HtmlDocumentViewerAction extends AbstractAction { public abstract class HtmlDocumentViewerAction extends AbstractAction {
private final String resourceFileName; private final String resourceFileName;
private final Dialog.ModalityType modalityType;
public HtmlDocumentViewerAction(String name, String resourceFileName) { public HtmlDocumentViewerAction(String name, String resourceFileName) {
this(name, resourceFileName, Dialog.ModalityType.APPLICATION_MODAL);
}
public HtmlDocumentViewerAction(String name, String resourceFileName, Dialog.ModalityType modalityType) {
super(name); super(name);
this.resourceFileName = resourceFileName; this.resourceFileName = resourceFileName;
this.modalityType = modalityType;
} }
@Override @Override
@ -23,7 +29,7 @@ public abstract class HtmlDocumentViewerAction extends AbstractAction {
JDialog dialog = new JDialog( JDialog dialog = new JDialog(
SwingUtilities.getWindowAncestor((Component) e.getSource()), SwingUtilities.getWindowAncestor((Component) e.getSource()),
(String) this.getValue(NAME), (String) this.getValue(NAME),
Dialog.ModalityType.APPLICATION_MODAL this.modalityType
); );
JTextPane textPane = new JTextPane(); JTextPane textPane = new JTextPane();
textPane.setEditable(false); textPane.setEditable(false);

View File

@ -14,10 +14,12 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.util.prefs.Preferences;
public class LoadAction extends AbstractAction { public class LoadAction extends AbstractAction {
private static LoadAction instance; private static final String LAST_LOAD_LOCATION_KEY = "lastLoadLocation";
private static LoadAction instance;
public static LoadAction getInstance() { public static LoadAction getInstance() {
if (instance == null) { if (instance == null) {
instance = new LoadAction(); instance = new LoadAction();
@ -25,8 +27,6 @@ public class LoadAction extends AbstractAction {
return instance; return instance;
} }
private File lastSelectedFile;
@Setter @Setter
private DiagramPanel diagramPanel; private DiagramPanel diagramPanel;
@ -38,14 +38,16 @@ public class LoadAction extends AbstractAction {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser(this.lastSelectedFile); JFileChooser fileChooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter( FileNameExtensionFilter filter = new FileNameExtensionFilter(
"ERME Serialized Files", "ERME Serialized Files",
"erme" "erme"
); );
fileChooser.setFileFilter(filter); fileChooser.setFileFilter(filter);
if (this.lastSelectedFile != null) { Preferences prefs = Preferences.userNodeForPackage(LoadAction.class);
fileChooser.setSelectedFile(this.lastSelectedFile); String path = prefs.get(LAST_LOAD_LOCATION_KEY, null);
if (path != null) {
fileChooser.setSelectedFile(new File(path));
} }
int choice = fileChooser.showOpenDialog((Component) e.getSource()); int choice = fileChooser.showOpenDialog((Component) e.getSource());
if (choice == JFileChooser.APPROVE_OPTION) { if (choice == JFileChooser.APPROVE_OPTION) {
@ -56,8 +58,8 @@ public class LoadAction extends AbstractAction {
} }
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(chosenFile))) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(chosenFile))) {
MappingModel loadedModel = (MappingModel) ois.readObject(); MappingModel loadedModel = (MappingModel) ois.readObject();
this.lastSelectedFile = chosenFile;
this.diagramPanel.setModel(loadedModel); this.diagramPanel.setModel(loadedModel);
prefs.put(LAST_LOAD_LOCATION_KEY, chosenFile.getAbsolutePath());
} catch (IOException | ClassNotFoundException | ClassCastException ex) { } catch (IOException | ClassNotFoundException | ClassCastException ex) {
ex.printStackTrace(); ex.printStackTrace();
JOptionPane.showMessageDialog(fileChooser, "An error occurred and the file could not be read:\n" + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); JOptionPane.showMessageDialog(fileChooser, "An error occurred and the file could not be read:\n" + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);

View File

@ -1,5 +1,7 @@
package nl.andrewlalis.erme.control.actions; package nl.andrewlalis.erme.control.actions;
import java.awt.*;
public class MappingAlgorithmHelpAction extends HtmlDocumentViewerAction { public class MappingAlgorithmHelpAction extends HtmlDocumentViewerAction {
private static MappingAlgorithmHelpAction instance; private static MappingAlgorithmHelpAction instance;
@ -11,7 +13,7 @@ public class MappingAlgorithmHelpAction extends HtmlDocumentViewerAction {
} }
public MappingAlgorithmHelpAction() { public MappingAlgorithmHelpAction() {
super("Mapping Algorithm Help", "html/er_mapping_algorithm.html"); super("Mapping Algorithm Help", "html/er_mapping_algorithm.html", Dialog.ModalityType.DOCUMENT_MODAL);
this.putValue(SHORT_DESCRIPTION, "Shows a quick guide on how to map from an ER model to a schema."); this.putValue(SHORT_DESCRIPTION, "Shows a quick guide on how to map from an ER model to a schema.");
} }
} }

View File

@ -9,11 +9,16 @@ import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.InputEvent; import java.awt.event.InputEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.io.*; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.prefs.Preferences;
public class SaveAction extends AbstractAction { public class SaveAction extends AbstractAction {
private static SaveAction instance; private static final String LAST_SAVE_LOCATION_KEY = "lastSaveLocation";
private static SaveAction instance;
public static SaveAction getInstance() { public static SaveAction getInstance() {
if (instance == null) { if (instance == null) {
instance = new SaveAction(); instance = new SaveAction();
@ -21,8 +26,6 @@ public class SaveAction extends AbstractAction {
return instance; return instance;
} }
private File lastSelectedFile;
@Setter @Setter
private MappingModel model; private MappingModel model;
@ -34,14 +37,16 @@ public class SaveAction extends AbstractAction {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser(this.lastSelectedFile); JFileChooser fileChooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter( FileNameExtensionFilter filter = new FileNameExtensionFilter(
"ERME Serialized Files", "ERME Serialized Files",
"erme" "erme"
); );
fileChooser.setFileFilter(filter); fileChooser.setFileFilter(filter);
if (this.lastSelectedFile != null) { Preferences prefs = Preferences.userNodeForPackage(SaveAction.class);
fileChooser.setSelectedFile(this.lastSelectedFile); String path = prefs.get(LAST_SAVE_LOCATION_KEY, null);
if (path != null) {
fileChooser.setSelectedFile(new File(path));
} }
int choice = fileChooser.showSaveDialog((Component) e.getSource()); int choice = fileChooser.showSaveDialog((Component) e.getSource());
if (choice == JFileChooser.APPROVE_OPTION) { if (choice == JFileChooser.APPROVE_OPTION) {
@ -56,7 +61,7 @@ public class SaveAction extends AbstractAction {
// TODO: Check for confirm before overwriting. // TODO: Check for confirm before overwriting.
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(chosenFile))) { try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(chosenFile))) {
oos.writeObject(this.model); oos.writeObject(this.model);
this.lastSelectedFile = chosenFile; prefs.put(LAST_SAVE_LOCATION_KEY, chosenFile.getAbsolutePath());
JOptionPane.showMessageDialog(fileChooser, "File saved successfully.", "Success", JOptionPane.INFORMATION_MESSAGE); JOptionPane.showMessageDialog(fileChooser, "File saved successfully.", "Success", JOptionPane.INFORMATION_MESSAGE);
} catch (IOException ex) { } catch (IOException ex) {
ex.printStackTrace(); ex.printStackTrace();