diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/Application.java b/src/main/java/ovh/alexisdelhaie/endpoint/Application.java index 0f65b7b..42db7e9 100644 --- a/src/main/java/ovh/alexisdelhaie/endpoint/Application.java +++ b/src/main/java/ovh/alexisdelhaie/endpoint/Application.java @@ -1,17 +1,18 @@ package ovh.alexisdelhaie.endpoint; -import com.formdev.flatlaf.FlatIntelliJLaf; +import ovh.alexisdelhaie.endpoint.configuration.ConfigurationProperties; import ovh.alexisdelhaie.endpoint.utils.Tools; import javax.swing.*; -import java.awt.*; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; public class Application { - public static void main(String[] args) throws UnsupportedLookAndFeelException, IOException { - UIManager.setLookAndFeel(new FlatIntelliJLaf()); - MainWindow dialog = new MainWindow(); + public static void main(String[] args) throws UnsupportedLookAndFeelException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + ConfigurationProperties props = new ConfigurationProperties(); + UIManager.setLookAndFeel(Tools.getLookAndFeel(props.getStringProperty("theme", "IntelliJ"))); + MainWindow dialog = new MainWindow(props); dialog.pack(); dialog.setTitle("EndPoint"); dialog.setVisible(true); diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/MainWindow.java b/src/main/java/ovh/alexisdelhaie/endpoint/MainWindow.java index f36a592..e00a207 100644 --- a/src/main/java/ovh/alexisdelhaie/endpoint/MainWindow.java +++ b/src/main/java/ovh/alexisdelhaie/endpoint/MainWindow.java @@ -14,6 +14,7 @@ import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; +import javax.swing.table.DefaultTableModel; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -25,6 +26,8 @@ import java.security.NoSuchAlgorithmException; import java.util.Objects; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class MainWindow extends JFrame { @@ -64,8 +67,8 @@ public class MainWindow extends JFrame { private final ConfigurationProperties props; private final ConcurrentHashMap tabs; - public MainWindow() throws IOException { - props = new ConfigurationProperties(); + public MainWindow(ConfigurationProperties props) throws IOException { + this.props = props; tabs = new ConcurrentHashMap<>(); setIconImage(ImageIO.read(MainWindow.class.getResource("/icon.png"))); setContentPane(contentPane); @@ -77,7 +80,7 @@ public class MainWindow extends JFrame { @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); - ConfigurationDialog.showDialog(props); + ConfigurationDialog.showDialog(props, MainWindow.this); } }); newTabButton.addMouseListener(new MouseAdapter() { @@ -141,6 +144,7 @@ public class MainWindow extends JFrame { URL u = new URL((!urlField.getText().toLowerCase().startsWith("http://") && !urlField.getText().toLowerCase().startsWith("https://")) ? "http://" + urlField.getText() : urlField.getText()); + parseParamsFromUrl(urlField.getText()); if (u.getPath().isBlank()) { title.setText(u.getHost()); } else { @@ -282,4 +286,25 @@ public class MainWindow extends JFrame { return Optional.empty(); } + private void parseParamsFromUrl(String url) { + Optional possibleTab = getSelectedTab(); + if (possibleTab.isPresent()) { + int id = tabbedPane1.indexOfComponent(possibleTab.get()); + JTable table = TabBuilder.getParamsTable(id); + DefaultTableModel m = (DefaultTableModel) table.getModel(); + for (int i = m.getRowCount() - 1; i > -1; i--) { + m.removeRow(i); + } + Pattern pattern = Pattern.compile("[^&?]*?=[^&?]*", Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(url); + while (matcher.find()) { + String param = matcher.group(); + String[] kv = param.split("="); + if (kv.length == 2) { + m.addRow(new Object[]{kv[0], kv[1]}); + } + } + } + } + } diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/builder/ReadOnlyTableModel.java b/src/main/java/ovh/alexisdelhaie/endpoint/builder/ReadOnlyTableModel.java new file mode 100644 index 0000000..ae21da9 --- /dev/null +++ b/src/main/java/ovh/alexisdelhaie/endpoint/builder/ReadOnlyTableModel.java @@ -0,0 +1,16 @@ +package ovh.alexisdelhaie.endpoint.builder; + +import javax.swing.table.DefaultTableModel; + +public class ReadOnlyTableModel extends DefaultTableModel { + + public ReadOnlyTableModel(Object[][] objects, String[] headers) { + super(objects, headers); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + +} diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/builder/TabBuilder.java b/src/main/java/ovh/alexisdelhaie/endpoint/builder/TabBuilder.java index a8d9ed8..6630937 100644 --- a/src/main/java/ovh/alexisdelhaie/endpoint/builder/TabBuilder.java +++ b/src/main/java/ovh/alexisdelhaie/endpoint/builder/TabBuilder.java @@ -2,10 +2,7 @@ package ovh.alexisdelhaie.endpoint.builder; import ovh.alexisdelhaie.endpoint.utils.RequestTab; import ovh.alexisdelhaie.endpoint.utils.Tools; -import ovh.alexisdelhaie.endpoint.utils.adapter.CustomDeleteMouseAdapter; -import ovh.alexisdelhaie.endpoint.utils.adapter.CustomNewMouseAdapter; -import ovh.alexisdelhaie.endpoint.utils.adapter.DeleteParamMouseAdapter; -import ovh.alexisdelhaie.endpoint.utils.adapter.NewParamMouseAdapter; +import ovh.alexisdelhaie.endpoint.utils.adapter.*; import javax.swing.*; import javax.swing.table.DefaultTableModel; @@ -93,7 +90,6 @@ public class TabBuilder { private static JTabbedPane buildParametersTabbedPane(JTextField urlField) { JTabbedPane p = new JTabbedPane(); p.add("Params", buildParamsTab(true, urlField)); - p.add("Authorization", new JPanel()); p.add("Headers", buildParamsTab(false, null)); JTextArea body = new JTextArea(); indexes.put("main[waiting].body", body); @@ -138,6 +134,10 @@ public class TabBuilder { return Tools.tableToHashMap(t); } + public static JTable getParamsTable(int index) { + return (JTable) indexes.get("main[" + index + "].params"); + } + public static HashMap getHeaders(int index) { JTable t = (JTable) indexes.get("main[" + index + "].headers"); return Tools.tableToHashMap(t); @@ -149,7 +149,8 @@ public class TabBuilder { private static JPanel buildParamsTab(boolean isParam, JTextField urlField) { String[] headers = {"Keys", "Values"}; - DefaultTableModel model = new DefaultTableModel(new Object[][]{}, headers); + DefaultTableModel model = (isParam)? new ReadOnlyTableModel(new Object[][]{}, headers) : + new DefaultTableModel(new Object[][]{}, headers); JPanel p = new JPanel(); JTable t = new JTable(model); indexes.put((isParam) ? "main[waiting].params" : "main[waiting].headers", t); @@ -157,17 +158,19 @@ public class TabBuilder { JButton delButton = new JButton("Remove"); delButton.setEnabled(false); t.getSelectionModel().addListSelectionListener(event -> delButton.setEnabled(t.getSelectedRows().length > 0)); + p.add(addButton); + p.add(delButton); if (isParam) { addButton.addMouseListener(new NewParamMouseAdapter(t, urlField)); delButton.addMouseListener(new DeleteParamMouseAdapter(t, urlField)); } else { addButton.addMouseListener(new CustomNewMouseAdapter(t)); delButton.addMouseListener(new CustomDeleteMouseAdapter(t)); + JButton authButton = new JButton("Set authorization"); + authButton.addMouseListener(new AuthorizationAdapter(t)); + p.add(authButton); } - p.add(addButton); - p.add(delButton); p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); - JPanel pp = new JPanel(); pp.add(p); JScrollPane sp = new JScrollPane(t); diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/configuration/AboutDialog.java b/src/main/java/ovh/alexisdelhaie/endpoint/configuration/AboutDialog.java index eaf3a30..689b0f3 100644 --- a/src/main/java/ovh/alexisdelhaie/endpoint/configuration/AboutDialog.java +++ b/src/main/java/ovh/alexisdelhaie/endpoint/configuration/AboutDialog.java @@ -13,7 +13,7 @@ public class AboutDialog extends JDialog { public static final int WIDTH = 740; public static final int HEIGHT = 500; - public static final String VERSION = "0.1.4"; + public static final String VERSION = "0.1.5"; private JPanel contentPane; private JLabel version; diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/configuration/ConfigurationDialog.form b/src/main/java/ovh/alexisdelhaie/endpoint/configuration/ConfigurationDialog.form index f45007c..c3cac52 100644 --- a/src/main/java/ovh/alexisdelhaie/endpoint/configuration/ConfigurationDialog.form +++ b/src/main/java/ovh/alexisdelhaie/endpoint/configuration/ConfigurationDialog.form @@ -49,7 +49,7 @@ - + @@ -73,7 +73,7 @@ - + @@ -168,6 +168,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/configuration/ConfigurationDialog.java b/src/main/java/ovh/alexisdelhaie/endpoint/configuration/ConfigurationDialog.java index 50ad4c1..41f41fc 100644 --- a/src/main/java/ovh/alexisdelhaie/endpoint/configuration/ConfigurationDialog.java +++ b/src/main/java/ovh/alexisdelhaie/endpoint/configuration/ConfigurationDialog.java @@ -1,9 +1,11 @@ package ovh.alexisdelhaie.endpoint.configuration; +import ovh.alexisdelhaie.endpoint.utils.MessageDialog; import ovh.alexisdelhaie.endpoint.utils.Tools; import javax.swing.*; import java.awt.*; +import java.util.Objects; public class ConfigurationDialog extends JDialog { @@ -17,10 +19,11 @@ public class ConfigurationDialog extends JDialog { private JComboBox httpVersion; private JSpinner timeout; private JButton aboutButton; + private JComboBox theme; private final ConfigurationProperties props; - private ConfigurationDialog(ConfigurationProperties props) { + private ConfigurationDialog(ConfigurationProperties props, JFrame frame) { setContentPane(contentPane); setModal(true); getRootPane().setDefaultButton(buttonOK); @@ -32,6 +35,7 @@ public class ConfigurationDialog extends JDialog { allowDowngrade.setSelected(this.props.getBooleanProperty("allowDowngrade", true)); httpVersion.setSelectedItem(this.props.getStringProperty("httpVersion", "HTTP/1.0")); timeout.setValue(this.props.getIntegerProperty("timeout", 10000)); + theme.setSelectedItem(this.props.getStringProperty("theme", "IntelliJ")); allowInvalidSsl.addActionListener((e) -> { this.props.setProperty("allowInvalidSsl", String.valueOf(allowInvalidSsl.isSelected())); @@ -45,15 +49,24 @@ public class ConfigurationDialog extends JDialog { timeout.addChangeListener((e) -> { this.props.setProperty("timeout", String.valueOf(timeout.getValue())); }); - + theme.addActionListener((e) -> { + String value = (String) theme.getSelectedItem(); + this.props.setProperty("theme", value); + try { + UIManager.setLookAndFeel(Tools.getLookAndFeel(Objects.requireNonNull(value))); + SwingUtilities.updateComponentTreeUI(frame); + } catch(UnsupportedLookAndFeelException | InstantiationException | IllegalAccessException | ClassNotFoundException err) { + MessageDialog.error("Error while changing theme", err.getMessage()); + } + }); } private void onOK() { dispose(); } - public static void showDialog(ConfigurationProperties props) { - ConfigurationDialog dialog = new ConfigurationDialog(props); + public static void showDialog(ConfigurationProperties props, JFrame frame) { + ConfigurationDialog dialog = new ConfigurationDialog(props, frame); dialog.setModal(true); dialog.setMinimumSize(new Dimension(WIDTH, HEIGHT)); dialog.setMaximumSize(new Dimension(WIDTH, HEIGHT)); diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/utils/AuthorizationDialog.form b/src/main/java/ovh/alexisdelhaie/endpoint/utils/AuthorizationDialog.form new file mode 100644 index 0000000..f904f96 --- /dev/null +++ b/src/main/java/ovh/alexisdelhaie/endpoint/utils/AuthorizationDialog.form @@ -0,0 +1,167 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/utils/AuthorizationDialog.java b/src/main/java/ovh/alexisdelhaie/endpoint/utils/AuthorizationDialog.java new file mode 100644 index 0000000..d445eaf --- /dev/null +++ b/src/main/java/ovh/alexisdelhaie/endpoint/utils/AuthorizationDialog.java @@ -0,0 +1,100 @@ +package ovh.alexisdelhaie.endpoint.utils; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.Objects; +import java.util.Optional; + +public class AuthorizationDialog extends JDialog { + + public static final int WIDTH = 325; + public static final int HEIGHT = 220; + + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + private JComboBox typeBox; + private JPanel bearerPanel; + private JTextField bearerTokenField; + private JTextField usernameBasicField; + private JTextField passwordBasicField; + private JPanel basicPanel; + + private boolean accepted = false; + private String finalValue = ""; + + public AuthorizationDialog() { + setTitle("Set authorization"); + setContentPane(contentPane); + setModal(true); + getRootPane().setDefaultButton(buttonOK); + + buttonOK.addActionListener(e -> onOK()); + buttonCancel.addActionListener(e -> onCancel()); + + typeBox.addItemListener((e) -> { + String type = (String) typeBox.getSelectedItem(); + switch (Objects.requireNonNull(type)) { + case "Basic" -> { + bearerPanel.setVisible(false); + basicPanel.setVisible(true); + } + case "Bearer" -> { + basicPanel.setVisible(false); + bearerPanel.setVisible(true); + } + } + }); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + } + + private void onOK() { + String type = (String) typeBox.getSelectedItem(); + switch (Objects.requireNonNull(type)) { + case "Basic" -> finalValue = Tools.toBase64( + String.format( + "%s:%s", + usernameBasicField.getText(), + passwordBasicField.getText() + ) + ); + case "Bearer" -> finalValue = String.format("Bearer %s", bearerTokenField.getText()); + } + accepted = true; + dispose(); + } + + private void onCancel() { + dispose(); + } + + public static Optional showDialog() { + AuthorizationDialog dialog = new AuthorizationDialog(); + dialog.setModal(true); + dialog.setMinimumSize(new Dimension(WIDTH, HEIGHT)); + dialog.setMaximumSize(new Dimension(WIDTH, HEIGHT)); + dialog.setResizable(false); + Tools.centerFrame(dialog); + dialog.setVisible(true); + if (dialog.accepted) { + return Optional.of(new KeyValuePair("authorization", dialog.finalValue)); + } + return Optional.empty(); + } + +} diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/utils/Tools.java b/src/main/java/ovh/alexisdelhaie/endpoint/utils/Tools.java index 65d51f1..c61125e 100644 --- a/src/main/java/ovh/alexisdelhaie/endpoint/utils/Tools.java +++ b/src/main/java/ovh/alexisdelhaie/endpoint/utils/Tools.java @@ -1,8 +1,13 @@ package ovh.alexisdelhaie.endpoint.utils; +import com.formdev.flatlaf.FlatDarculaLaf; +import com.formdev.flatlaf.FlatIntelliJLaf; + import javax.swing.*; import javax.swing.table.DefaultTableModel; import java.awt.*; +import java.lang.reflect.InvocationTargetException; +import java.util.Base64; import java.util.HashMap; public class Tools { @@ -32,4 +37,21 @@ public class Tools { return result; } + public static String toBase64(String decoded) { + byte[] encodedBytes = Base64.getEncoder().encode(decoded.getBytes()); + return new String(encodedBytes); + } + + public static String getLookAndFeel(String theme) { + switch (theme) { + case "IntelliJ" -> { + return FlatIntelliJLaf.class.getName(); + } + case "Darcula" -> { + return FlatDarculaLaf.class.getName(); + } + } + return UIManager.getSystemLookAndFeelClassName(); + } + } diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/utils/adapter/AuthorizationAdapter.java b/src/main/java/ovh/alexisdelhaie/endpoint/utils/adapter/AuthorizationAdapter.java new file mode 100644 index 0000000..f283a13 --- /dev/null +++ b/src/main/java/ovh/alexisdelhaie/endpoint/utils/adapter/AuthorizationAdapter.java @@ -0,0 +1,36 @@ +package ovh.alexisdelhaie.endpoint.utils.adapter; + +import ovh.alexisdelhaie.endpoint.utils.AuthorizationDialog; +import ovh.alexisdelhaie.endpoint.utils.KeyValuePair; + +import javax.swing.*; +import javax.swing.table.DefaultTableModel; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Optional; + +public class AuthorizationAdapter extends MouseAdapter { + + protected final JTable table; + + public AuthorizationAdapter(JTable table) { + this.table = table; + } + + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + Optional result = AuthorizationDialog.showDialog(); + if (result.isPresent()) { + DefaultTableModel m = (DefaultTableModel) table.getModel(); + for (int i = m.getRowCount() - 1; i > -1; i--) { + String key = (String) m.getValueAt(i,0); + if (key.toLowerCase().equals(result.get().getKey().toLowerCase())) { + m.removeRow(i); + } + } + m.addRow(new Object[]{result.get().getKey(), result.get().getValue()}); + } + } + +} diff --git a/src/main/java/ovh/alexisdelhaie/endpoint/utils/adapter/CustomNewMouseAdapter.java b/src/main/java/ovh/alexisdelhaie/endpoint/utils/adapter/CustomNewMouseAdapter.java index f2288ab..bc60b71 100644 --- a/src/main/java/ovh/alexisdelhaie/endpoint/utils/adapter/CustomNewMouseAdapter.java +++ b/src/main/java/ovh/alexisdelhaie/endpoint/utils/adapter/CustomNewMouseAdapter.java @@ -28,6 +28,12 @@ public class CustomNewMouseAdapter extends MouseAdapter { Optional result = InsertToTableDialog.showDialog("Enter value"); if (result.isPresent()) { DefaultTableModel m = (DefaultTableModel) table.getModel(); + for (int i = m.getRowCount() - 1; i > -1; i--) { + String key = (String) m.getValueAt(i,0); + if (key.toLowerCase().equals(result.get().getKey().toLowerCase())) { + m.removeRow(i); + } + } m.addRow(new Object[]{result.get().getKey(), result.get().getValue()}); valid = true; }