001package jmri.jmrix.bidib.netbidib; 002 003import java.awt.event.WindowAdapter; 004import java.awt.event.WindowEvent; 005import java.awt.event.ActionListener; 006import java.awt.event.ActionEvent; 007 008import javax.swing.JOptionPane; 009import javax.swing.JDialog; 010//import javax.swing.Timer; 011import java.beans.PropertyChangeListener; 012import java.beans.PropertyChangeEvent; 013import jmri.jmrix.bidib.BiDiBPortController; 014 015import org.bidib.jbidibc.messages.helpers.Context; 016import org.bidib.jbidibc.messages.utils.ByteUtils; 017import org.bidib.jbidibc.netbidib.NetBidibContextKeys; 018import org.slf4j.Logger; 019import org.slf4j.LoggerFactory; 020 021/** 022 * This dialog is presented to the user if netBiDiB pairing is required. 023 * It informs the user about the remote device and waits until the pairing is 024 * accepted on the remote side. In this case, the dialog should be removed by the 025 * calling program. If the request timed out, is is closed an the calling program 026 * is informed by an ActionListener. 027 * 028 * @author Eckart Meyer Copyright (C) 2024 029 */ 030 031public class NetBiDiBPairingRequestDialog { 032 033 //private final java.util.ResourceBundle rb = java.util.ResourceBundle.getBundle("jmri.jmrix.bidib.BiDiBBundle"); // NOI18N 034 035 private final Context context; 036 private final BiDiBPortController portController; 037 private final Long uniqueId; 038 private Integer remainingTimeout; 039 private JOptionPane optionPane; 040 private final JDialog dialog = new JDialog(); 041 private final ActionListener actionListener; 042 043 private final javax.swing.Timer updateTimer = new javax.swing.Timer(1000, e -> updateDialog()); 044 045 /** 046 * Constructor. 047 * 048 * @param context to transfer several parameters to show on the dialog 049 * @param portController to transfer the port hostname and port number 050 * @param listener listing to the cancel event 051 */ 052 public NetBiDiBPairingRequestDialog(Context context, BiDiBPortController portController, ActionListener listener) { 053 this.context = context; 054 this.portController = portController; 055 actionListener = listener; 056 uniqueId = context.get(NetBidibContextKeys.KEY_DESCRIPTOR_UID, Long.class, null); 057 remainingTimeout = context.get(NetBidibContextKeys.KEY_PAIRING_TIMEOUT, Integer.class, Integer.valueOf(30)); 058 } 059 060 061 /** 062 * Show the dialog, setup listeners for the button and for the window close event. 063 * Immediately return, this is not a modal dialog. 064 */ 065 public void show() { 066 067 068 String[] options = new String[1]; 069 options[0] = Bundle.getMessage("netBiDiBPairingDialogCancel"); // NOI18N 070 String title = Bundle.getMessage("netBiDiBPairingDialogTitle") ; // NOI18N 071 072 optionPane = new JOptionPane(makeMessageText(), JOptionPane.DEFAULT_OPTION,JOptionPane.INFORMATION_MESSAGE, null, options, null); 073 074 optionPane.addPropertyChangeListener(new PropertyChangeListener() { 075 076 @Override 077 public void propertyChange(PropertyChangeEvent e) { 078 String prop = e.getPropertyName(); 079 //log.trace("property change event: {}", e); 080 //log.trace("propertychange: name: {}, old value: {}, new value: {}", prop, e.getOldValue(), e.getNewValue()); 081 082 if (dialog.isVisible() 083 && (e.getSource() == optionPane) 084 && (prop.equals(JOptionPane.VALUE_PROPERTY))) { 085 log.trace("propertychange new value: {}", e.getNewValue()); 086 onCancel(); 087 } 088 } 089 }); 090 091 092 093 dialog.setTitle(title); 094 dialog.setModal(false); //true: setVisible() would not return until dispose() 095 dialog.setContentPane(optionPane); 096 dialog.setLocationRelativeTo(null); // Centers on the screen 097 dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); //would inhibit closing the window from the user 098 dialog.addWindowListener(new WindowAdapter() { 099 100 @Override 101 public void windowClosing(WindowEvent we) { 102 log.debug("user closes window."); 103 onCancel(); 104 } 105 }); 106 107 updateTimer.setRepeats(true); // 1s tick 108 109 // timer removes dialog after iDelayInSeconds 110 updateTimer.start(); 111 112 113 dialog.pack(); 114 dialog.setVisible(true); 115 } 116 117 /** 118 * Stop timer and remove dialog 119 */ 120 public void dispose() { 121 updateTimer.stop(); 122 dialog.dispose(); 123 } 124 125 /** 126 * Stop timer and hide dialog 127 */ 128 public void hide() { 129 updateTimer.stop(); 130 dialog.setVisible(false); 131 } 132 133 /** 134 * Call the listener on the cancel event 135 */ 136 private void onCancel() { 137 log.info("User cancelled netBiDiB pairing"); 138 dispose(); 139 if (actionListener != null) { 140 actionListener.actionPerformed(new ActionEvent(this, 0, "Cancel")); 141 } 142 } 143 144 /** 145 * Update the dialog message. 146 * The text changes every second to display the remaining time. 147 */ 148 private void updateDialog() { 149 remainingTimeout -= 1; 150 if (remainingTimeout > 0) { 151 optionPane.setMessage(makeMessageText()); 152 } 153 else { 154 dispose(); 155 } 156 } 157 158 /** 159 * Setup the text to be presented to the user. 160 * The data is taken from the Context given by the calling program. 161 * 162 * @return the complete string 163 */ 164 private String makeMessageText() { 165 String remoteLinkData = Bundle.getMessage("netBiDiBPairingDialogText") + "\n"; 166 remoteLinkData += "\n" + Bundle.getMessage("netBiDiBPairingDialogTime") + ": " + remainingTimeout.toString() + Bundle.getMessage("netBiDiBPairingDialogSecondsShort"); 167 remoteLinkData += "\n" + Bundle.getMessage("netBiDiBPairingDialogProdName") + ": " + context.get(NetBidibContextKeys.KEY_DESCRIPTOR_PROD_STRING, String.class, ""); 168 remoteLinkData += "\n" + Bundle.getMessage("netBiDiBPairingDialogUserName") + ": " + context.get(NetBidibContextKeys.KEY_DESCRIPTOR_USER_STRING, String.class, ""); 169 remoteLinkData += "\n" + Bundle.getMessage("netBiDiBPairingDialogPortName") + ": " + portController.getRealPortName(); 170 remoteLinkData += "\n" + Bundle.getMessage("netBiDiBPairingDialogUniqueID") + ": " + ByteUtils.getUniqueIdAsString(uniqueId); 171 172 return remoteLinkData; 173 } 174 175 private final static Logger log = LoggerFactory.getLogger(NetBiDiBPairingRequestDialog.class); 176 177}