From 1073af21305360bd33903c533cdac57e9f936294 Mon Sep 17 00:00:00 2001 From: Yuuta Liang Date: Tue, 28 Nov 2023 18:19:39 -0800 Subject: Move TUI and GUI into separate packages Signed-off-by: Yuuta Liang --- src/main/ui/gui/widgets/UIUtils.java | 168 +++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 src/main/ui/gui/widgets/UIUtils.java (limited to 'src/main/ui/gui/widgets/UIUtils.java') diff --git a/src/main/ui/gui/widgets/UIUtils.java b/src/main/ui/gui/widgets/UIUtils.java new file mode 100644 index 0000000..bb09a72 --- /dev/null +++ b/src/main/ui/gui/widgets/UIUtils.java @@ -0,0 +1,168 @@ +package ui.gui.widgets; + +import model.asn1.exceptions.ParseException; +import ui.Utils; + +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.awt.*; +import java.awt.event.ActionListener; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.stream.IntStream; + +import static java.awt.GridBagConstraints.BOTH; +import static java.awt.GridBagConstraints.HORIZONTAL; +import static javax.swing.JOptionPane.*; + +/** + * Useful utilities for building GUI. + */ +public class UIUtils { + /** + * EFFECTS: Create a horizontal actions pane: + * ----------------------------------------------------------- + * | | Button1 | Button2 | Button3 | ButtonN | + * ----------------------------------------------------------- + * REQUIRES: buttons != null + */ + public static JPanel createActionsPane(JButton... buttons) { + final JPanel panelAct = new JPanel(); + panelAct.setLayout(new GridBagLayout()); + IntStream.range(0, buttons.length) + .forEach(i -> panelAct.add(buttons[i], + new GCBuilder().gridXY(i + 1, 1).fill(HORIZONTAL).build())); + panelAct.add(new JPanel(), new GCBuilder().expandXY().fill(BOTH).build()); + return panelAct; + } + + /** + * EFFECTS: Show / hide default text for a card layout container. + * MODIFIES: cardLayoutPanel + * REQUIRES: cardLayoutPanel must have a card layout; it must have CardContent and CardDefault cards. + */ + public static void setContentVisible(Container cardLayoutPanel, boolean showContent) { + switchTo(cardLayoutPanel, showContent ? "CardContent" : "CardDefault"); + } + + /** + * EFFECTS: Switch to the card for a card layout panel. + * MODIFIES: cardLayoutPanel + * REQUIRES: cardLayoutPanel must have a card layout; it must have "card" card. + */ + public static void switchTo(Container cardLayoutPanel, String card) { + ((CardLayout) cardLayoutPanel.getLayout()).show(cardLayoutPanel, card); + } + + /** + * EFFECTS: Show an error message based on {@link Throwable#getMessage()} + * REQUIRES: component must have a frame. + */ + public static void alert(Component component, String title, Throwable e) { + alert(component, title, e.getMessage()); + } + + /** + * EFFECTS: Show an error message. + * REQUIRES: component must have a frame. + */ + public static void alert(Component component, String title, String message) { + showMessageDialog(getFrameForComponent(component), + message, + title, + ERROR_MESSAGE); + } + + /** + * EFFECTS: Show a file chooser with the given filter title and list of extensions. Starting from cwd. + * Return null if cancelled. + */ + public static Path chooseFile(Component component, String filterTitle, String... extensions) { + final JFileChooser fc = new JFileChooser(); + fc.setFileFilter(new FileNameExtensionFilter(filterTitle, extensions)); + fc.setCurrentDirectory(Paths.get("").toAbsolutePath().toFile()); + if (fc.showOpenDialog(getFrameForComponent(component)) == JFileChooser.APPROVE_OPTION) { + return fc.getSelectedFile().toPath(); + } + return null; + } + + /** + * EFFECTS: Create a JPanel with CardLayout that has CardDefault set to component and CardContent set to a JLabel + * with the default text. + */ + public static JPanel defView(Component component, String defaultText) { + final JPanel panel = new JPanel(); + panel.setLayout(new CardLayout(0, 0)); + + JLabel labelDefault = new JLabel(defaultText); + labelDefault.setHorizontalAlignment(0); + panel.add(labelDefault, "CardDefault"); + panel.add(component, "CardContent"); + + return panel; + } + + /** + * EFFECTS: Create a JScrollPane-wrapped JTable. + * MODIFIES: table + */ + public static JScrollPane scrTbl(JTable table) { + final JScrollPane scrollPane = new JScrollPane(); + table.setFillsViewportHeight(true); + scrollPane.setViewportView(table); + return scrollPane; + } + + /** + * EFFECTS: Parse the given path and automatically determine if it is a DER binary or a PEM. Automatically decode + * PEM. + * Throws {@link IOException} if it cannot be read. + * Throws {@link ParseException} if the PEM is invalid. + */ + public static Byte[] openDERorPEM(Path path, String tag) throws IOException, ParseException { + final InputStream fd = Files.newInputStream(path, StandardOpenOption.READ); + Byte[] bs = Utils.byteToByte(fd.readAllBytes()); + fd.close(); + if (bs.length < 1) { + throw new ParseException("Invalid file: too short"); + } + if (bs[0] == '-') { + bs = Utils.parsePEM(bs, tag); + } + return bs; + } + + /** + * EFFECTS: Create a button with the given label and click listener. + */ + public static JButton btn(String string, ActionListener onClick) { + final JButton btn = new JButton(string); + btn.addActionListener(onClick); + return btn; + } + + /** + * EFFECTS: Create a button with the given label, mnemonic, and click listener. + */ + public static JButton btn(String string, char m, ActionListener onClick) { + final JButton btn = new JButton(string); + btn.setMnemonic(m); + btn.setDisplayedMnemonicIndex(0); + btn.addActionListener(onClick); + return btn; + } + + /** + * EFFECTS: Create a button with the given label, mnemonic, icon, and click listener. + */ + public static JButton btn(String string, String icon, ActionListener onClick) { + final JButton btn = new JButton(string, new ImageIcon(UIUtils.class.getResource("/" + icon))); + btn.addActionListener(onClick); + return btn; + } +} -- cgit v1.2.3