001package jmri.jmrit.etcs.dmi.swing; 002 003import java.awt.Font; 004import java.awt.FontMetrics; 005import java.util.ArrayList; 006import java.util.List; 007 008import javax.swing.JFrame; 009import javax.swing.JLabel; 010 011import jmri.jmrit.etcs.CabMessage; 012 013import org.apiguardian.api.API; 014 015/** 016 * Class to represent a CabMessage received by the DMI. 017 * @author Steve Young Copyright (C) 2024 018 */ 019@API(status=API.Status.EXPERIMENTAL) 020public class DmiCabMessage extends CabMessage { 021 022 private final String[] msgArray; 023 024 protected DmiCabMessage(CabMessage msg, Font font){ 025 super(msg.getMessageId(), msg.getMessage(), msg.getGroup(), msg.getAckRequired()); 026 msgArray = msgs(font ); 027 } 028 029 protected String[] getMessageArray(){ 030 return java.util.Arrays.copyOf(msgArray, msgArray.length); 031 } 032 033 private String[] msgs( Font font){ 034 int maxWidth = 170; // Maximum width in pixels 035 String[] result = splitString(getMessage(), maxWidth, font); 036 log.debug("{} lines in message", result.length); 037 return result; 038 } 039 040 private static String[] splitString(String input, int maxWidth, Font font) { 041 List<String> substrings = new ArrayList<>(); 042 StringBuilder currentSubstring = new StringBuilder(); 043 String[] words = input.split(" "); // Split input into words 044 045 for (String word : words) { 046 if (currentSubstring.length() == 0) { 047 currentSubstring.append(word); 048 } else { 049 String potentialSubstring = currentSubstring.toString() + " " + word; 050 051 // Check if adding the word exceeds the maximum width 052 if (getStringWidthInPx(potentialSubstring, font) <= maxWidth) { 053 currentSubstring.append(" ").append(word); 054 } else { 055 // Current substring exceeds the maximum width, start a new substring 056 substrings.add(currentSubstring.toString()); 057 currentSubstring = new StringBuilder(word); 058 } 059 } 060 } 061 062 if (currentSubstring.length() > 0) { 063 substrings.add(currentSubstring.toString()); 064 } 065 return substrings.toArray(String[]::new); 066 } 067 068 // Function to calculate the width of a string (in pixels) 069 // values should be cached as this is not a fast method. 070 private static int getStringWidthInPx(String input, Font font) { 071 072 JFrame frame = new JFrame(); 073 JLabel label = new JLabel(input); 074 label.setFont(font); 075 frame.add(label); 076 077 // Ensure the label is properly sized 078 frame.pack(); 079 frame.setVisible(false); 080 081 FontMetrics fontMetrics = label.getFontMetrics(font); 082 int dd = fontMetrics.stringWidth(input); 083 084 frame.dispose(); // Close the frame 085 086 return dd; 087 } 088 089 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DmiCabMessage.class); 090 091}