diff --git a/convex-core/src/main/java/convex/core/util/FileUtils.java b/convex-core/src/main/java/convex/core/util/FileUtils.java index 727796943..d99b20278 100644 --- a/convex-core/src/main/java/convex/core/util/FileUtils.java +++ b/convex-core/src/main/java/convex/core/util/FileUtils.java @@ -107,4 +107,6 @@ public static File getFile(String path) { + + } diff --git a/convex-core/src/main/java/convex/core/util/Utils.java b/convex-core/src/main/java/convex/core/util/Utils.java index 5c9ee7f33..0199132e7 100644 --- a/convex-core/src/main/java/convex/core/util/Utils.java +++ b/convex-core/src/main/java/convex/core/util/Utils.java @@ -12,6 +12,9 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -1362,6 +1365,15 @@ public static String getVersion() { return v; } + public static String timeString() { + return timeString(Instant.now()); + } + + private static String timeString(Instant timeStamp) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss").withZone(ZoneId.from(ZoneOffset.UTC)); + return formatter.format(timeStamp); + } + diff --git a/convex-core/src/main/java/module-info.java b/convex-core/src/main/java/module-info.java index 62594eeee..40d55d934 100644 --- a/convex-core/src/main/java/module-info.java +++ b/convex-core/src/main/java/module-info.java @@ -28,4 +28,5 @@ requires org.bouncycastle.util; requires org.slf4j; requires java.base; + requires java.desktop; } \ No newline at end of file diff --git a/convex-gui/src/main/java/convex/gui/peer/PeerComponent.java b/convex-gui/src/main/java/convex/gui/peer/PeerComponent.java index 479623ae0..d36349447 100644 --- a/convex-gui/src/main/java/convex/gui/peer/PeerComponent.java +++ b/convex-gui/src/main/java/convex/gui/peer/PeerComponent.java @@ -1,9 +1,13 @@ package convex.gui.peer; +import java.io.IOException; +import java.nio.file.Path; import java.util.Objects; import javax.swing.JButton; +import javax.swing.JFileChooser; import javax.swing.JMenuItem; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; @@ -20,8 +24,12 @@ import convex.core.cvm.PeerStatus; import convex.core.cvm.State; import convex.core.data.ACell; +import convex.core.data.AMap; import convex.core.data.AccountKey; +import convex.core.data.Keyword; import convex.core.text.Text; +import convex.core.util.FileUtils; +import convex.core.util.Utils; import convex.etch.EtchStore; import convex.gui.components.BaseImageButton; import convex.gui.components.BaseListComponent; @@ -166,6 +174,15 @@ public PeerComponent(ConvexLocal value) { new WalletApp(connectLocalControllerWallet(server)).run(); }); popupMenu.add(walletButton); + + JMenuItem saveButton = new JMenuItem("Save Peer Data...",Toolkit.menuIcon(0xe161)); + saveButton.addActionListener(e -> savePeerData(this.convex)); + popupMenu.add(saveButton); + + JMenuItem loadButton = new JMenuItem("Load Peer Data...",Toolkit.menuIcon(0xeaf3)); + loadButton.addActionListener(e -> loadPeerData(this.convex)); + popupMenu.add(loadButton); + DropdownMenu dm = new DropdownMenu(popupMenu); @@ -193,6 +210,32 @@ public PeerComponent(ConvexLocal value) { updateDescription(); } + private void loadPeerData(ConvexLocal convex) { + JFileChooser chooser=Toolkit.createCAD3Chooser(null); + int result=chooser.showOpenDialog(this); + if (result==JFileChooser.APPROVE_OPTION) { + System.out.println("Loading: "+chooser.getSelectedFile()); + } + } + + private void savePeerData(ConvexLocal convex) { + Peer p=convex.getLocalServer().getPeer(); + AMap data = p.toData(); + + String fileName="peer-data-"+p.getPeerKey().toHexString(8)+"-"+Utils.timeString()+".cad3"; + JFileChooser chooser=Toolkit.createCAD3Chooser(fileName); + + int result=chooser.showSaveDialog(this); + if (result==JFileChooser.APPROVE_OPTION) { + Path path =chooser.getSelectedFile().toPath(); + try { + FileUtils.writeCAD3(path, data); + } catch (IOException e) { + JOptionPane.showMessageDialog(this, "Peer data save failed:\n "+e,"Save Error",JOptionPane.ERROR_MESSAGE); + } + } + } + protected void updateDescription() { String current=description.getText(); String updated=getPeerDescription(); diff --git a/convex-gui/src/main/java/convex/gui/utils/Toolkit.java b/convex-gui/src/main/java/convex/gui/utils/Toolkit.java index 7d66c6d05..1dd656f58 100644 --- a/convex-gui/src/main/java/convex/gui/utils/Toolkit.java +++ b/convex-gui/src/main/java/convex/gui/utils/Toolkit.java @@ -16,11 +16,13 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Path; import javax.swing.AbstractAction; import javax.swing.BorderFactory; @@ -28,6 +30,7 @@ import javax.swing.ImageIcon; import javax.swing.InputMap; import javax.swing.JComponent; +import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenuItem; @@ -44,6 +47,7 @@ import javax.swing.border.Border; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; +import javax.swing.filechooser.FileFilter; import javax.swing.text.DefaultEditorKit; import org.slf4j.Logger; @@ -58,34 +62,34 @@ @SuppressWarnings("serial") public class Toolkit { - + private static Logger log = LoggerFactory.getLogger(Toolkit.class.getName()); - public static final double BASE_SCALE=1.25; - public static final float SCALE=getUIScale(); - - public static final int ICON_SIZE = (int) (32*SCALE); - public static final int IDENTICON_SIZE = (int) (14*SCALE); - public static final int IDENTICON_SIZE_LARGE = 2*IDENTICON_SIZE; - public static final int SMALL_ICON_SIZE = (int) (16*SCALE); - public static final int MAIN_ICON_SIZE = (int) (72*SCALE); - - public static final float DEFAULT_FONT_SIZE=12*SCALE; - - public static Font DEFAULT_FONT = new Font(Font.SANS_SERIF,Font.PLAIN,(int)DEFAULT_FONT_SIZE); - public static Font BIG_FONT = new Font(Font.SANS_SERIF, Font.BOLD, (int)(DEFAULT_FONT_SIZE*1.8)); - public static Font MONO_FONT = new Font(Font.MONOSPACED, Font.PLAIN, (int)(DEFAULT_FONT_SIZE)); - public static Font BIG_MONO_FONT = new Font(Font.MONOSPACED, Font.BOLD, (int)(DEFAULT_FONT_SIZE*1.5)); - public static Font SMALL_MONO_FONT = new Font(Font.MONOSPACED, Font.PLAIN, (int)(DEFAULT_FONT_SIZE*0.8)); - public static Font BUTTON_FONT = new Font(Font.SANS_SERIF, Font.PLAIN, (int)(DEFAULT_FONT_SIZE*1.2)); - - public static final float SYMBOL_FONT_SIZE= DEFAULT_FONT_SIZE; - - public static Font SYMBOL_FONT = new Font(Font.MONOSPACED, Font.PLAIN, (int)SYMBOL_FONT_SIZE); - - public static final Color SYMBOL_COLOUR = new Color(100,170,200); + public static final double BASE_SCALE = 1.25; + public static final float SCALE = getUIScale(); + + public static final int ICON_SIZE = (int) (32 * SCALE); + public static final int IDENTICON_SIZE = (int) (14 * SCALE); + public static final int IDENTICON_SIZE_LARGE = 2 * IDENTICON_SIZE; + public static final int SMALL_ICON_SIZE = (int) (16 * SCALE); + public static final int MAIN_ICON_SIZE = (int) (72 * SCALE); + + public static final float DEFAULT_FONT_SIZE = 12 * SCALE; + + public static Font DEFAULT_FONT = new Font(Font.SANS_SERIF, Font.PLAIN, (int) DEFAULT_FONT_SIZE); + public static Font BIG_FONT = new Font(Font.SANS_SERIF, Font.BOLD, (int) (DEFAULT_FONT_SIZE * 1.8)); + public static Font MONO_FONT = new Font(Font.MONOSPACED, Font.PLAIN, (int) (DEFAULT_FONT_SIZE)); + public static Font BIG_MONO_FONT = new Font(Font.MONOSPACED, Font.BOLD, (int) (DEFAULT_FONT_SIZE * 1.5)); + public static Font SMALL_MONO_FONT = new Font(Font.MONOSPACED, Font.PLAIN, (int) (DEFAULT_FONT_SIZE * 0.8)); + public static Font BUTTON_FONT = new Font(Font.SANS_SERIF, Font.PLAIN, (int) (DEFAULT_FONT_SIZE * 1.2)); + + public static final float SYMBOL_FONT_SIZE = DEFAULT_FONT_SIZE; + + public static Font SYMBOL_FONT = new Font(Font.MONOSPACED, Font.PLAIN, (int) SYMBOL_FONT_SIZE); + + public static final Color SYMBOL_COLOUR = new Color(100, 170, 200); public static final Color WARNING_COLOUR = Color.ORANGE; - public static final Color BUTTON_FG = new Color(176,190,197); + public static final Color BUTTON_FG = new Color(176, 190, 197); static { try { @@ -95,26 +99,25 @@ public class Toolkit { } loadFonts(); UIManager.getLookAndFeelDefaults().put("defaultFont", DEFAULT_FONT); - //LookAndFeel laf = installMDLaf(); - LookAndFeel laf=installFlatLaf(); - - + // LookAndFeel laf = installMDLaf(); + LookAndFeel laf = installFlatLaf(); + if (System.getProperty("os.name").toLowerCase().startsWith("mac")) { InputMap im = (InputMap) UIManager.get("TextField.focusInputMap"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.META_DOWN_MASK), DefaultEditorKit.copyAction); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.META_DOWN_MASK), DefaultEditorKit.pasteAction); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.META_DOWN_MASK), DefaultEditorKit.cutAction); } - - + UIManager.setLookAndFeel(laf); FlatMaterialOceanicIJTheme.setup(); - + // Override button foreground, too dark by default - UIManager.put( "Button.foreground", UIManager.get("Label.foreground") ); + UIManager.put("Button.foreground", UIManager.get("Label.foreground")); // System.out.println(UIManager.get("Label.foreground")); } catch (HeadlessException e) { - // We need this to stop things like tests failing in headless mode (e.g. in CI builds) + // We need this to stop things like tests failing in headless mode (e.g. in CI + // builds) log.warn("Unable to initialise GUI Toolkit due to headless execution mode."); } catch (Exception e) { e.printStackTrace(); @@ -124,26 +127,27 @@ public class Toolkit { protected static void setupForApple() { // For Mac, use Convex as the application name - System.setProperty( "apple.awt.application.name", "Convex" ); - System.setProperty( "apple.awt.application.appearance", "system" ); - System.setProperty( "apple.laf.useScreenMenuBar", "true" ); + System.setProperty("apple.awt.application.name", "Convex"); + System.setProperty("apple.awt.application.appearance", "system"); + System.setProperty("apple.laf.useScreenMenuBar", "true"); } protected static LookAndFeel installFlatLaf() { - FlatDarculaLaf laf=new FlatDarculaLaf(); + FlatDarculaLaf laf = new FlatDarculaLaf(); return laf; } private static float getUIScale() { try { - //GraphicsDevice screen = GraphicsEnvironment - // .getLocalGraphicsEnvironment() - // .getDefaultScreenDevice(); - //Double scale=screen.getDefaultConfiguration().getDefaultTransform().getScaleX(); - Double scale=BASE_SCALE; - System.setProperty( "flatlaf.uiScale", ""+scale ); - log.info("UI Scale: "+scale); - return (float)(scale.doubleValue()); + // GraphicsDevice screen = GraphicsEnvironment + // .getLocalGraphicsEnvironment() + // .getDefaultScreenDevice(); + // Double + // scale=screen.getDefaultConfiguration().getDefaultTransform().getScaleX(); + Double scale = BASE_SCALE; + System.setProperty("flatlaf.uiScale", "" + scale); + log.info("UI Scale: " + scale); + return (float) (scale.doubleValue()); } catch (HeadlessException e) { return 1.0f; } @@ -153,11 +157,13 @@ private static float getUIScale() { // scaledIcon(36,"/images/ic_lock_outline_black_36dp.png"); // public static final ImageIcon UNLOCKED_ICON = // scaledIcon(36,"/images/ic_lock_open_black_36dp.png"); - //public static final ImageIcon LOCKED_ICON = scaledIcon(ICON_SIZE, "/images/padlock.png"); - //public static final ImageIcon UNLOCKED_ICON = scaledIcon(ICON_SIZE, "/images/padlock-open.png"); - - public static final ImageIcon LOCKED_ICON = SymbolIcon.get(0xe897,ICON_SIZE,Toolkit.SYMBOL_COLOUR.getRGB()); - public static final ImageIcon UNLOCKED_ICON = SymbolIcon.get(0xe898,ICON_SIZE,Toolkit.WARNING_COLOUR.getRGB()); + // public static final ImageIcon LOCKED_ICON = scaledIcon(ICON_SIZE, + // "/images/padlock.png"); + // public static final ImageIcon UNLOCKED_ICON = scaledIcon(ICON_SIZE, + // "/images/padlock-open.png"); + + public static final ImageIcon LOCKED_ICON = SymbolIcon.get(0xe897, ICON_SIZE, Toolkit.SYMBOL_COLOUR.getRGB()); + public static final ImageIcon UNLOCKED_ICON = SymbolIcon.get(0xe898, ICON_SIZE, Toolkit.WARNING_COLOUR.getRGB()); public static final ImageIcon WARNING = scaledIcon(ICON_SIZE, "/images/ic_priority_high_black_36dp.png"); public static final ImageIcon CAKE = scaledIcon(ICON_SIZE, "/images/ic_cake_black_36dp.png"); public static final ImageIcon CONVEX = scaledIcon(ICON_SIZE, "/images/Convex.png"); @@ -172,11 +178,10 @@ private static float getUIScale() { public static final ImageIcon WALLET_ICON = scaledIcon(MAIN_ICON_SIZE, "/images/wallet.png"); public static final ImageIcon DLFS_ICON = scaledIcon(MAIN_ICON_SIZE, "/images/filesystem.png"); - - public static ImageIcon scaledIcon(int size, String resourcePath) { java.net.URL imgURL = Toolkit.class.getResource(resourcePath); - if (imgURL == null) throw new Error("No image: " + resourcePath); + if (imgURL == null) + throw new Error("No image: " + resourcePath); ImageIcon imageIcon = new ImageIcon(imgURL); Image image = imageIcon.getImage(); image = image.getScaledInstance(size, size, Image.SCALE_SMOOTH); @@ -190,12 +195,12 @@ private static void loadFonts() { InputStream is = Utils.getResourceAsStream("/fonts/SourceCodePro-Regular.ttf"); MONO_FONT = Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(DEFAULT_FONT_SIZE); } - + { // Material Symbols InputStream is = Utils.getResourceAsStream("/fonts/MaterialSymbolsSharp.ttf"); SYMBOL_FONT = Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(SYMBOL_FONT_SIZE); } - DEFAULT_FONT=DEFAULT_FONT.deriveFont(DEFAULT_FONT_SIZE).deriveFont(Font.PLAIN); + DEFAULT_FONT = DEFAULT_FONT.deriveFont(DEFAULT_FONT_SIZE).deriveFont(Font.PLAIN); } catch (Exception e) { System.err.println("PROBLEM LOADING FONTS:"); @@ -208,8 +213,8 @@ private static void loadFonts() { * Scale an image with interpolation / AA for nicer effects * * @param src Source image - * @param w Width of new image - * @param h Height of new image + * @param w Width of new image + * @param h Height of new image * @return A new, resized image */ public static BufferedImage smoothResize(BufferedImage src, int w, int h) { @@ -224,7 +229,7 @@ public static BufferedImage smoothResize(BufferedImage src, int w, int h) { graphics.drawImage(src, 0, 0, w, h, null); return newImage; } - + public static BufferedImage pixelResize(BufferedImage src, int w, int h) { BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = (Graphics2D) newImage.getGraphics(); @@ -270,20 +275,21 @@ public static void launchBrowser(String url) { Desktop.getDesktop().browse(new URI(url)); } } catch (IOException | URISyntaxException ex) { - log.warn("IO Failure launching browser: "+ex); + log.warn("IO Failure launching browser: " + ex); } } public static void showMainFrame(JComponent comp) { - JFrame frame = new JFrame("Test Frame"); - frame.getContentPane().add(comp); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.pack(); - frame.setVisible(true); + JFrame frame = new JFrame("Test Frame"); + frame.getContentPane().add(comp); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.pack(); + frame.setVisible(true); } /** * Relinquish focus from a component + * * @param c Component to remove focus from */ public static void relinquishFocus(Component c) { @@ -293,13 +299,13 @@ public static void relinquishFocus(Component c) { } } - public static JMenuItem makeMenu(String name,Runnable op) { - AbstractAction action=makeAction(name,op); - JMenuItem mi= new JMenuItem(action); + public static JMenuItem makeMenu(String name, Runnable op) { + AbstractAction action = makeAction(name, op); + JMenuItem mi = new JMenuItem(action); return mi; } - - public static AbstractAction makeAction(String name,Runnable op) { + + public static AbstractAction makeAction(String name, Runnable op) { return new AbstractAction(name) { @Override public void actionPerformed(ActionEvent e) { @@ -310,24 +316,26 @@ public void actionPerformed(ActionEvent e) { /** * Adds a popup menu to a component, including necessary mouse listeners + * * @param popupMenu Op up menu component */ - public static void addPopupMenu(JComponent comp,javax.swing.JPopupMenu popupMenu) { - comp.addMouseListener(new MouseAdapter () { - public void mousePressed(MouseEvent e) { - maybeDisplayPopupMenu(e); - } - - public void mouseReleased(MouseEvent e) { - maybeDisplayPopupMenu(e); - } - - private void maybeDisplayPopupMenu(MouseEvent e) { - // This is because different platforms have different mouse events for popup triggers. Ugly..... - if (e.isPopupTrigger()) { - popupMenu.show(e.getComponent(),e.getX(), e.getY()); - } - } + public static void addPopupMenu(JComponent comp, javax.swing.JPopupMenu popupMenu) { + comp.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + maybeDisplayPopupMenu(e); + } + + public void mouseReleased(MouseEvent e) { + maybeDisplayPopupMenu(e); + } + + private void maybeDisplayPopupMenu(MouseEvent e) { + // This is because different platforms have different mouse events for popup + // triggers. Ugly..... + if (e.isPopupTrigger()) { + popupMenu.show(e.getComponent(), e.getX(), e.getY()); + } + } }); } @@ -338,56 +346,58 @@ public static Border createDialogBorder() { public static Border createEmptyBorder(int x) { return BorderFactory.createEmptyBorder(x, x, x, x); } - + public static JComponent makeHelp(String helpText) { - JLabel help=new JLabel(SymbolIcon.get(0xe887,Toolkit.SMALL_ICON_SIZE)); + JLabel help = new JLabel(SymbolIcon.get(0xe887, Toolkit.SMALL_ICON_SIZE)); help.setToolTipText(helpText); help.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { - JOptionPane.showMessageDialog(help, helpText,"Help Tips",JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(help, helpText, "Help Tips", JOptionPane.INFORMATION_MESSAGE); } }); return help; } - + public static JComponent makeNote(String title, String note) { - // JLabel ta = new JLabel(""+note+""); // Alternative, but doesn't scale component height? + // JLabel ta = new JLabel(""+note+""); // Alternative, but doesn't + // scale component height? JTextArea ta = new JTextArea(note); - + // This allows the text area to shrink, for some odd reason.... - ta.setMinimumSize(new Dimension(50,50)); - + ta.setMinimumSize(new Dimension(50, 50)); + ta.setEditable(false); // Can't edit notes ta.setFocusable(false); // informational only, shouldn't focus // ta.setFont(Toolkit.DEFAULT_FONT); ta.setLineWrap(true); // for wrapping ta.setWrapStyleWord(true); // for nice text when it wraps - return withTitledBorder(title,ta); + return withTitledBorder(title, ta); } - + public static JComponent makeNote(String note) { - return makeNote("NOTE",note); + return makeNote("NOTE", note); } public static void copyToClipboard(String string) { - if (string==null) return; - Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard(); - StringSelection text = new StringSelection(string); - c.setContents(text,text); + if (string == null) + return; + Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard(); + StringSelection text = new StringSelection(string); + c.setContents(text, text); } public static JComponent withTitledBorder(String title, JComponent comp) { - Border existingBorder=comp.getBorder(); - Border border=BorderFactory.createTitledBorder(title); - if (existingBorder!=null) { - border=BorderFactory.createCompoundBorder(border, existingBorder); + Border existingBorder = comp.getBorder(); + Border border = BorderFactory.createTitledBorder(title); + if (existingBorder != null) { + border = BorderFactory.createCompoundBorder(border, existingBorder); } comp.setBorder(border); return comp; } public static Icon menuIcon(int codePoint) { - return SymbolIcon.get(codePoint,Toolkit.BUTTON_FONT.getSize()); + return SymbolIcon.get(codePoint, Toolkit.BUTTON_FONT.getSize()); } public static void scrollToBottom(JScrollPane scrollPane) { @@ -399,31 +409,64 @@ public static void showMessge(Component parent, Object message) { JOptionPane.showMessageDialog(parent, message); } - public static void showErrorMessage(Component parent, String attemptFailure,Exception e) { - JOptionPane.showMessageDialog(parent, attemptFailure+ "\n"+e.getMessage()); + public static void showErrorMessage(Component parent, String attemptFailure, Exception e) { + JOptionPane.showMessageDialog(parent, attemptFailure + "\n" + e.getMessage()); } public static Component wrapPasswordField(JPasswordField passArea) { - char ec=passArea.getEchoChar(); - JPanel panel=new JPanel(); - JLabel eye=new JLabel(SymbolIcon.get(0xe8f4)); + char ec = passArea.getEchoChar(); + JPanel panel = new JPanel(); + JLabel eye = new JLabel(SymbolIcon.get(0xe8f4)); eye.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { - char c=passArea.getEchoChar(); - if (c==0) { + char c = passArea.getEchoChar(); + if (c == 0) { eye.setIcon(SymbolIcon.get(0xe8f4)); passArea.setEchoChar(ec); } else { eye.setIcon(SymbolIcon.get(0xe8f5)); - passArea.setEchoChar((char)0); + passArea.setEchoChar((char) 0); } } }); panel.setBorder(null); panel.setLayout(new MigLayout()); - panel.add(passArea,"dock center"); - panel.add(eye,"dock east"); + panel.add(passArea, "dock center"); + panel.add(eye, "dock east"); return panel; } + public static JFileChooser createCAD3Chooser(String fileName) { + JFileChooser chooser = new JFileChooser(); + chooser.setFileFilter(getCAD3Filter()); + if (fileName != null) { + Path p = Path.of(fileName); + Path dir = chooser.getCurrentDirectory().toPath(); + Path defaultFile = dir.resolve(p); + chooser.setSelectedFile(defaultFile.toFile()); + } + return chooser; + } + + public static FileFilter getCAD3Filter() { + return new FileFilter() { + + @Override + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } else { + String filename = f.getName().toLowerCase(); + return filename.endsWith(".cad3") || filename.endsWith(".cad"); + } + } + + @Override + public String getDescription() { + return "CAD3 file (*.cad3, *.cad)"; + } + + }; + } + }