/* Author: Maple * Feb. 2 2026 * */ package org.openautonomousconnection.oacswing.component; import lombok.NonNull; import org.openautonomousconnection.oacswing.component.design.DesignManager; import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.concurrent.atomic.AtomicInteger; public class OACOptionPane extends JOptionPane implements OACComponent { public OACOptionPane() { super(); } public OACOptionPane(Object message) { super(message); } public OACOptionPane(Object message, int messageType) { super(message, messageType); } public OACOptionPane(Object message, int messageType, int optionType) { super(message, messageType, optionType); } public OACOptionPane(Object message, int messageType, int optionType, Icon icon) { super(message, messageType, optionType, icon); } public OACOptionPane(Object message, int messageType, int optionType, Icon icon, Object[] options) { super(message, messageType, optionType, icon, options); } public OACOptionPane(Object message, int messageType, int optionType, Icon icon, Object[] options, Object initialValue) { super(message, messageType, optionType, icon, options, initialValue); } @Override public void init() { setOpaque(true); setBackground(DesignManager.resolveBackground(OACOptionPane.class, getBackground())); setForeground(DesignManager.resolveForeground(OACOptionPane.class, getForeground())); } public static int showOptionDialog(Component parentComponent, Object message, String title, int optionType, int messageType, Icon icon, Object[] options, Object initialValue) throws HeadlessException { AtomicInteger result = new AtomicInteger(CLOSED_OPTION); OACDialog dialog = new OACDialog(JOptionPane.getFrameForComponent(parentComponent), null, true); dialog.setUndecorated(true); dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); dialog.setContentPane(buildDialogContent(title, message, icon, optionType, options, result, dialog)); dialog.setResizable(false); dialog.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { result.set(CLOSED_OPTION); } }); dialog.pack(); dialog.setMinimumSize(new Dimension(420, dialog.getHeight())); dialog.setLocationRelativeTo(parentComponent); dialog.setVisible(true); dialog.dispose(); return result.get(); } public static int showConfirmDialog(Component parentComponent, Object message) throws HeadlessException { return showConfirmDialog(parentComponent, message, "Select an Option", YES_NO_CANCEL_OPTION); } public static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType) throws HeadlessException { return showConfirmDialog(parentComponent, message, title, optionType, QUESTION_MESSAGE); } public static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType) throws HeadlessException { return showConfirmDialog(parentComponent, message, title, optionType, messageType, null); } public static int showConfirmDialog(Component parentComponent, Object message, String title, int optionType, int messageType, Icon icon) throws HeadlessException { return showOptionDialog( parentComponent, message, title, optionType, messageType, icon != null ? icon : resolveDefaultIcon(messageType), null, null ); } public static void showMessageDialog(Component parentComponent, Object message) throws HeadlessException { showMessageDialog(parentComponent, message, "Message", INFORMATION_MESSAGE); } public static void showMessageDialog(Component parentComponent, Object message, String title, int messageType) throws HeadlessException { showMessageDialog(parentComponent, message, title, messageType, null); } public static void showMessageDialog(Component parentComponent, Object message, String title, int messageType, Icon icon) throws HeadlessException { showOptionDialog( parentComponent, message, title, DEFAULT_OPTION, messageType, icon != null ? icon : resolveDefaultIcon(messageType), new Object[]{"OK"}, "OK" ); } private static Container buildDialogContent(String title, Object message, Icon icon, int optionType, Object[] options, AtomicInteger result, OACDialog dialog) { OACPanel root = new OACPanel(new BorderLayout()); Color background = DesignManager.resolveBackground(OACOptionPane.class, root.getBackground()); Color foreground = DesignManager.resolveForeground(OACOptionPane.class, Color.LIGHT_GRAY); Color borderColor = DesignManager.resolveBorderColor(foreground.darker()); root.setBackground(background); root.setBorder(BorderFactory.createLineBorder(borderColor, 1)); OACPanel header = new OACPanel(new BorderLayout()); header.setBorder(new EmptyBorder(0, 12, 8, 12)); header.setBackground(background); OACLabel titleLabel = new OACLabel(title == null ? "" : title); titleLabel.setForeground(foreground); header.add(titleLabel, BorderLayout.WEST); OACPanel center = new OACPanel(new BorderLayout(10, 0)); center.setBackground(background); center.setBorder(new EmptyBorder(14, 12, 12, 12)); if (icon != null) { OACLabel iconLabel = new OACLabel(icon); iconLabel.setForeground(foreground); center.add(iconLabel, BorderLayout.WEST); } if (message instanceof Component messageComponent) { if (messageComponent instanceof OACComponent oacComponent) { oacComponent.initDesign(); } else { messageComponent.setBackground(background); messageComponent.setForeground(foreground); } center.add(messageComponent, BorderLayout.CENTER); } else { JTextArea messageArea = new JTextArea(String.valueOf(message)); messageArea.setEditable(false); messageArea.setLineWrap(true); messageArea.setWrapStyleWord(true); messageArea.setOpaque(false); messageArea.setForeground(foreground); messageArea.setBorder(null); center.add(messageArea, BorderLayout.CENTER); } OACPanel buttons = new OACPanel(new FlowLayout(FlowLayout.RIGHT, 8, 8)); buttons.setBackground(background); Object[] displayOptions = resolveOptions(optionType, options); for (int i = 0; i < displayOptions.length; i++) { final int index = i; OACButton button = new OACButton(String.valueOf(displayOptions[i])); button.initDesign(); button.setBackground(DesignManager.resolveBackground(OACButton.class, button.getBackground())); button.setForeground(DesignManager.resolveForeground(OACButton.class, button.getForeground())); button.setHoveredColor(DesignManager.resolveHovered(OACButton.class, button.getBackground().brighter())); button.setPressedColor(DesignManager.resolvePressed(OACButton.class, button.getBackground().darker())); button.setBorder(BorderFactory.createLineBorder(borderColor, 1, true)); button.setPreferredSize(new Dimension(100, 32)); button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); button.addActionListener(e -> { result.set(mapResult(optionType, options, index)); dialog.dispose(); }); buttons.add(button); } root.add(header, BorderLayout.NORTH); root.add(center, BorderLayout.CENTER); root.add(buttons, BorderLayout.SOUTH); return root; } private static Object[] resolveOptions(int optionType, Object[] options) { if (options != null && options.length > 0) { return options; } return switch (optionType) { case YES_NO_OPTION -> new Object[]{"Yes", "No"}; case YES_NO_CANCEL_OPTION -> new Object[]{"Yes", "No", "Cancel"}; case OK_CANCEL_OPTION -> new Object[]{"OK", "Cancel"}; default -> new Object[]{"OK"}; }; } private static int mapResult(int optionType, Object[] providedOptions, int clickedIndex) { if (providedOptions != null && providedOptions.length > 0) { return clickedIndex; } return switch (optionType) { case YES_NO_OPTION -> clickedIndex == 0 ? YES_OPTION : NO_OPTION; case YES_NO_CANCEL_OPTION -> clickedIndex == 0 ? YES_OPTION : (clickedIndex == 1 ? NO_OPTION : CANCEL_OPTION); case OK_CANCEL_OPTION -> clickedIndex == 0 ? OK_OPTION : CANCEL_OPTION; default -> OK_OPTION; }; } private static Icon resolveDefaultIcon(int messageType) { return switch (messageType) { case ERROR_MESSAGE -> UIManager.getIcon("OptionPane.errorIcon"); case WARNING_MESSAGE -> UIManager.getIcon("OptionPane.warningIcon"); case QUESTION_MESSAGE -> UIManager.getIcon("OptionPane.questionIcon"); default -> UIManager.getIcon("OptionPane.informationIcon"); }; } @Override public Component add(Component comp) { this.initOther(comp); return super.add(comp); } @Override public Component add(Component comp, int index) { this.initOther(comp); return super.add(comp, index); } @Override public void add(@NonNull Component comp, Object constraints) { this.initOther(comp); super.add(comp, constraints); } @Override public Component add(String name, Component comp) { this.initOther(comp); return super.add(name, comp); } @Override public void add(Component comp, Object constraints, int index) { this.initOther(comp); super.add(comp, constraints, index); } }