001package jmri.jmrix.rps.aligntable; 002 003import java.awt.Dimension; 004import java.awt.FlowLayout; 005import java.awt.event.ActionEvent; 006import java.awt.event.ActionListener; 007import java.beans.PropertyChangeListener; 008import java.util.ResourceBundle; 009import javax.swing.BoxLayout; 010import javax.swing.JButton; 011import javax.swing.JComboBox; 012import javax.swing.JLabel; 013import javax.swing.JPanel; 014import javax.swing.JScrollPane; 015import javax.swing.JTable; 016import javax.swing.JTextField; 017import javax.swing.SortOrder; 018import javax.swing.table.AbstractTableModel; 019import javax.swing.table.TableCellEditor; 020import javax.swing.table.TableRowSorter; 021import javax.vecmath.Point3d; 022import jmri.jmrix.rps.Algorithms; 023import jmri.jmrix.rps.Engine; 024import jmri.jmrix.rps.Receiver; 025import jmri.swing.RowSorterUtil; 026import jmri.util.table.ButtonEditor; 027import jmri.util.table.ButtonRenderer; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031/** 032 * Pane for user management of RPS alignment. 033 * 034 * @author Bob Jacobsen Copyright (C) 2008 035 */ 036public class AlignTablePane extends javax.swing.JPanel { 037 038 static ResourceBundle rb = ResourceBundle.getBundle("jmri.jmrix.rps.aligntable.AlignTableBundle"); 039 040 /** 041 * Constructor method. 042 * @param flag the ModifiedFlag tag. 043 */ 044 public AlignTablePane(jmri.ModifiedFlag flag) { 045 super(); 046 this.flag = flag; 047 } 048 049 AlignModel alignModel = null; 050 jmri.ModifiedFlag flag; 051 052 /** 053 * Initialize the window 054 */ 055 public void initComponents() { 056 057 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 058 059 alignModel = new AlignModel(); 060 061 JTable alignTable = new JTable(alignModel); 062 063 // install a button renderer & editor 064 ButtonRenderer buttonRenderer = new ButtonRenderer(); 065 alignTable.setDefaultRenderer(JButton.class, buttonRenderer); 066 TableCellEditor buttonEditor = new ButtonEditor(new JButton()); 067 alignTable.setDefaultEditor(JButton.class, buttonEditor); 068 069 TableRowSorter<AlignModel> sorter = new TableRowSorter<>(alignModel); 070 RowSorterUtil.setSortOrder(sorter, AlignModel.NUMCOL, SortOrder.ASCENDING); 071 alignTable.setRowSelectionAllowed(false); 072 alignTable.setPreferredScrollableViewportSize(new java.awt.Dimension(580, 80)); 073 074 JScrollPane scrollPane = new JScrollPane(alignTable); 075 add(scrollPane); 076 077 // status info on bottom 078 JPanel p = new JPanel() { 079 080 @Override 081 public Dimension getMaximumSize() { 082 int height = getPreferredSize().height; 083 int width = super.getMaximumSize().width; 084 return new Dimension(width, height); 085 } 086 }; 087 p.setLayout(new FlowLayout()); 088 089 p.add(new JLabel(rb.getString("LabelNumCol"))); 090 num.setText("" + Engine.instance().getMaxReceiverNumber()); 091 p.add(num); 092 093 JButton b = new JButton(rb.getString("ButtonSet")); 094 b.addActionListener(new ActionListener() { 095 @Override 096 public void actionPerformed(ActionEvent event) { 097 // set number of columns 098 Engine.instance().setMaxReceiverNumber( 099 Integer.parseInt(num.getText())); 100 // mark modification 101 flag.setModifiedFlag(true); 102 // resize table 103 alignModel.fireTableStructureChanged(); 104 105 } 106 }); 107 p.add(b); 108 add(p); 109 110 p = new JPanel() { 111 112 @Override 113 public Dimension getMaximumSize() { 114 int height = getPreferredSize().height; 115 int width = super.getMaximumSize().width; 116 return new Dimension(width, height); 117 } 118 }; 119 p.setLayout(new FlowLayout()); 120 121 p.add(new JLabel(rb.getString("LabelVSound"))); 122 vsound.setText("" + Engine.instance().getVSound()); 123 p.add(vsound); 124 125 p.add(new JLabel(rb.getString("LabelOffset"))); 126 offset.setText("" + Engine.instance().getOffset()); 127 p.add(offset); 128 129 p.add(new JLabel(rb.getString("LabelAlgorithm"))); 130 p.add(algorithmBox); 131 132 b = new JButton(rb.getString("ButtonSet")); 133 b.addActionListener(new ActionListener() { 134 @Override 135 public void actionPerformed(ActionEvent event) { 136 // set number of vsound, offset 137 Engine.instance().setOffset( 138 Integer.parseInt(offset.getText())); 139 Engine.instance().setVSound( 140 Double.parseDouble(vsound.getText())); 141 Engine.instance().setAlgorithm( 142 (String) algorithmBox.getSelectedItem()); 143 // mark modification 144 flag.setModifiedFlag(true); 145 } 146 }); 147 p.add(b); 148 add(p); 149 150 // 151 add(loadStore = new jmri.jmrix.rps.swing.LoadStorePanel() { 152 // make sure we redisplay if changed 153 @Override 154 public void load() { 155 super.load(); 156 alignModel.fireTableStructureChanged(); 157 // modified (to force store of default after load new values) 158 flag.setModifiedFlag(true); 159 } 160 161 @Override 162 public void storeDefault() { 163 super.storeDefault(); 164 // no longer modified after storeDefault 165 flag.setModifiedFlag(false); 166 } 167 }); 168 169 // add sound listener 170 Engine.instance().addPropertyChangeListener(new PropertyChangeListener() { 171 @Override 172 public void propertyChange(java.beans.PropertyChangeEvent e) { 173 if (e.getPropertyName().equals("vSound")) { 174 // update sound display 175 vsound.setText("" + e.getNewValue()); 176 } 177 } 178 }); 179 } 180 181 jmri.jmrix.rps.swing.LoadStorePanel loadStore; 182 183 void storeDefault() { 184 loadStore.storeDefault(); 185 // no longer modified after storeDefault 186 flag.setModifiedFlag(false); 187 } 188 189 JTextField num = new JTextField(4); 190 JTextField vsound = new JTextField(8); 191 JTextField offset = new JTextField(4); 192 JComboBox<String> algorithmBox = Algorithms.algorithmBox(); 193 194 /** 195 * Set up table for showing individual receivers 196 * <ol> 197 * <li>Address 198 * <li>Present Y/N 199 * <li>Edit button 200 * </ol> 201 */ 202 public class AlignModel extends AbstractTableModel { 203 204 static private final int NUMCOL = 0; 205 static private final int XCOL = 1; 206 static private final int YCOL = 2; 207 static private final int ZCOL = 3; 208 209 static private final int LASTTIMECOL = 4; 210 211 static private final int ACTIVECOL = 5; 212 213 static private final int MINTIMECOL = 6; 214 static private final int MAXTIMECOL = 7; 215 216 static private final int LAST = MAXTIMECOL; 217 218 @Override 219 public int getColumnCount() { 220 return LAST + 1; 221 } 222 223 @Override 224 public int getRowCount() { 225 return Engine.instance().getMaxReceiverNumber(); 226 } 227 228 @Override 229 public String getColumnName(int c) { 230 switch (c) { 231 case NUMCOL: 232 return rb.getString("TitleColNum"); 233 case XCOL: 234 return rb.getString("TitleColX"); 235 case YCOL: 236 return rb.getString("TitleColY"); 237 case ZCOL: 238 return rb.getString("TitleColZ"); 239 case LASTTIMECOL: 240 return rb.getString("TitleColLast"); 241 case ACTIVECOL: 242 return rb.getString("TitleColActive"); 243 case MINTIMECOL: 244 return rb.getString("TitleColMin"); 245 case MAXTIMECOL: 246 return rb.getString("TitleColMax"); 247 default: 248 return ""; 249 } 250 } 251 252 @Override 253 public Class<?> getColumnClass(int c) { 254 if (c == XCOL || c == YCOL || c == ZCOL) { 255 return Double.class; 256 } else if (c == NUMCOL) { 257 return Integer.class; 258 } else if (c == ACTIVECOL) { 259 return Boolean.class; 260 } 261 if (c == MINTIMECOL || c == MAXTIMECOL || c == LASTTIMECOL) { 262 return Integer.class; 263 } else { 264 return String.class; 265 } 266 } 267 268 @Override 269 public boolean isCellEditable(int r, int c) { 270 if (c == XCOL || c == YCOL || c == ZCOL || c == ACTIVECOL 271 || c == MINTIMECOL || c == MAXTIMECOL) { 272 return true; 273 } else { 274 return false; 275 } 276 } 277 278 @Override 279 public Object getValueAt(int r, int c) { 280 // r is row number, from 0; receiver addresses start at 1 281 Receiver rc; 282 switch (c) { 283 case NUMCOL: 284 return Integer.valueOf(r + 1); 285 case XCOL: 286 rc = Engine.instance().getReceiver(r + 1); 287 if (rc == null) { 288 return null; 289 } 290 return Double.valueOf(rc.getPosition().x); 291 case YCOL: 292 rc = Engine.instance().getReceiver(r + 1); 293 if (rc == null) { 294 return null; 295 } 296 return Double.valueOf(rc.getPosition().y); 297 case ZCOL: 298 rc = Engine.instance().getReceiver(r + 1); 299 if (rc == null) { 300 return null; 301 } 302 return Double.valueOf(rc.getPosition().z); 303 case ACTIVECOL: 304 rc = Engine.instance().getReceiver(r + 1); 305 if (rc == null) { 306 return null; 307 } 308 return Boolean.valueOf(rc.isActive()); 309 case LASTTIMECOL: 310 rc = Engine.instance().getReceiver(r + 1); 311 if (rc == null) { 312 return null; 313 } 314 return Integer.valueOf(rc.getLastTime()); 315 case MINTIMECOL: 316 rc = Engine.instance().getReceiver(r + 1); 317 if (rc == null) { 318 return null; 319 } 320 return Integer.valueOf(rc.getMinTime()); 321 case MAXTIMECOL: 322 rc = Engine.instance().getReceiver(r + 1); 323 if (rc == null) { 324 return null; 325 } 326 return Integer.valueOf(rc.getMaxTime()); 327 default: 328 return null; 329 } 330 } 331 332 @Override 333 public void setValueAt(Object val, int r, int c) { 334 // r is row number, from 0 335 Receiver rc; 336 Point3d p; 337 switch (c) { 338 case XCOL: 339 rc = Engine.instance().getReceiver(r + 1); 340 if (rc == null) { 341 rc = new Receiver(new Point3d(0., 0., 0.)); 342 Engine.instance().setReceiver(r + 1, rc); 343 } 344 p = rc.getPosition(); 345 p.x = ((Double) val).doubleValue(); 346 Engine.instance().setReceiverPosition(r + 1, p); 347 flag.setModifiedFlag(true); 348 break; 349 case YCOL: 350 rc = Engine.instance().getReceiver(r + 1); 351 if (rc == null) { 352 rc = new Receiver(new Point3d(0., 0., 0.)); 353 Engine.instance().setReceiver(r + 1, rc); 354 } 355 p = rc.getPosition(); 356 p.y = ((Double) val).doubleValue(); 357 Engine.instance().setReceiverPosition(r + 1, p); 358 flag.setModifiedFlag(true); 359 break; 360 case ZCOL: 361 rc = Engine.instance().getReceiver(r + 1); 362 if (rc == null) { 363 rc = new Receiver(new Point3d(0., 0., 0.)); 364 Engine.instance().setReceiver(r + 1, rc); 365 } 366 p = rc.getPosition(); 367 p.z = ((Double) val).doubleValue(); 368 Engine.instance().setReceiverPosition(r + 1, p); 369 flag.setModifiedFlag(true); 370 break; 371 case ACTIVECOL: 372 rc = Engine.instance().getReceiver(r + 1); 373 if (rc == null) { 374 rc = new Receiver(new Point3d(0., 0., 0.)); 375 Engine.instance().setReceiver(r + 1, rc); 376 } 377 rc.setActive(((Boolean) val).equals(Boolean.TRUE)); 378 flag.setModifiedFlag(true); 379 break; 380 case MINTIMECOL: 381 rc = Engine.instance().getReceiver(r + 1); 382 if (rc == null) { 383 rc = new Receiver(new Point3d(0., 0., 0.)); 384 Engine.instance().setReceiver(r + 1, rc); 385 } 386 int min = ((Integer) val).intValue(); 387 Engine.instance().getReceiver(r + 1).setMinTime(min); 388 flag.setModifiedFlag(true); 389 break; 390 case MAXTIMECOL: 391 rc = Engine.instance().getReceiver(r + 1); 392 if (rc == null) { 393 rc = new Receiver(new Point3d(0., 0., 0.)); 394 Engine.instance().setReceiver(r + 1, rc); 395 } 396 int max = ((Integer) val).intValue(); 397 Engine.instance().getReceiver(r + 1).setMaxTime(max); 398 flag.setModifiedFlag(true); 399 break; 400 default: 401 log.error("setValueAt of column {}", c); 402 } 403 } 404 } 405 406 private final static Logger log = LoggerFactory.getLogger(AlignTablePane.class); 407 408}