001package jmri.jmrit.logix; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004import java.awt.Dimension; 005import java.awt.event.ActionEvent; 006import java.awt.event.ActionListener; 007import java.awt.event.ItemEvent; 008import java.awt.event.ItemListener; 009import java.text.NumberFormat; 010import java.util.ArrayList; 011import java.util.Iterator; 012import java.util.Map.Entry; 013 014import javax.swing.BorderFactory; 015import javax.swing.Box; 016import javax.swing.BoxLayout; 017import javax.swing.ButtonGroup; 018import javax.swing.JButton; 019import javax.swing.JComboBox; 020import javax.swing.JComponent; 021import javax.swing.JLabel; 022import javax.swing.JPanel; 023import javax.swing.JRadioButton; 024import javax.swing.JScrollPane; 025import javax.swing.JSpinner; 026import javax.swing.JTable; 027import javax.swing.JTextField; 028import javax.swing.SpinnerNumberModel; 029import javax.swing.SwingConstants; 030import javax.swing.table.AbstractTableModel; 031 032import jmri.implementation.SignalSpeedMap; 033import jmri.swing.PreferencesPanel; 034import jmri.util.swing.JComboBoxUtil; 035import jmri.util.swing.JmriJOptionPane; 036 037import org.openide.util.lookup.ServiceProvider; 038 039/** 040 * @author Pete Cressman Copyright (C) 2015 041 */ 042@ServiceProvider(service = PreferencesPanel.class) 043public class WarrantPreferencesPanel extends JPanel implements PreferencesPanel, ItemListener { 044 045 static int STRUT_SIZE = 10; 046 047 private boolean _isDirty = false; 048 049 private JComboBox<ScaleData> _layoutScales; 050 private JSpinner _searchDepth; 051 private JSpinner _timeIncre; 052 private JTextField _rampIncre; 053 private JTextField _throttleScale; 054 private JTextField _speedAssistance; 055 private int _interpretation = SignalSpeedMap.PERCENT_NORMAL; 056 private ArrayList<DataPair<String, Float>> _speedNameMap; 057 private SpeedNameTableModel _speedNameModel; 058 private JTable _speedNameTable; 059 private ArrayList<DataPair<String, String>> _appearanceMap; 060 private AppearanceTableModel _appearanceModel; 061 private JTable _appearanceTable; 062 private ArrayList<DataPair<String, Integer>> _stepIncrementMap; 063 private WarrantPreferences.Shutdown _shutdown; 064 private boolean _traceWarrants; 065 066 public WarrantPreferencesPanel() { 067 initGUI(); 068 } 069 070 private void initGUI() { 071 this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); 072 JPanel leftPanel = new JPanel(); 073 leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS)); 074 JPanel rightPanel = new JPanel(); 075 rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.PAGE_AXIS)); 076 leftPanel.add(layoutScalePanel()); 077 leftPanel.add(searchDepthPanel(true)); 078 _timeIncre = new JSpinner(new SpinnerNumberModel(750, 200, 10000, 1)); 079 leftPanel.add(timeIncrementPanel(true, _timeIncre)); 080 _rampIncre = new JTextField(6); 081 leftPanel.add(throttleIncrementPanel(true, _rampIncre)); 082 leftPanel.add(throttleScalePanel(true)); 083 leftPanel.add(speedRosterPanel(true)); 084 leftPanel.add(tracePanel(true)); 085 leftPanel.add(speedAssistancePanel(true)); 086 rightPanel.add(speedNamesPanel()); 087 rightPanel.add(Box.createGlue()); 088// rightPanel.add(interpretationPanel()); 089// rightPanel.add(Box.createGlue()); 090 rightPanel.add(appearancePanel()); 091 _rampIncre.addActionListener(new ActionListener() { 092 @Override 093 public void actionPerformed(ActionEvent e) { 094 String text = _rampIncre.getText(); 095 boolean showdialog = false; 096 try { 097 float incr = NumberFormat.getNumberInstance().parse(text).floatValue(); 098 showdialog = (incr < 0.5f || incr > 25f); 099 } catch (java.text.ParseException pe) { 100 showdialog = true; 101 } 102 if (showdialog) { 103 JmriJOptionPane.showMessageDialog(leftPanel, Bundle.getMessage("rampIncrWarning", text), 104 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 105 } 106 } 107 }); 108 JPanel panel = new JPanel(); 109 panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS)); 110 panel.add(leftPanel); 111 panel.add(rightPanel); 112 add(panel); 113 } 114 115 private JPanel layoutScalePanel() { 116 JPanel panel = new JPanel(); 117 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 118 _layoutScales = new JComboBox<>(); 119 _layoutScales.addItem(new ScaleData("G", 22.5f)); 120 _layoutScales.addItem(new ScaleData("L", 38f)); 121 _layoutScales.addItem(new ScaleData("O", 48f)); 122 _layoutScales.addItem(new ScaleData("O'", 43f)); 123 _layoutScales.addItem(new ScaleData("S", 64f)); 124 _layoutScales.addItem(new ScaleData("OO", 76.2f)); 125 _layoutScales.addItem(new ScaleData("HO", 87.1f)); 126 _layoutScales.addItem(new ScaleData("TT", 120f)); 127 _layoutScales.addItem(new ScaleData("N", 160f)); 128 _layoutScales.addItem(new ScaleData("Z", 220f)); 129 _layoutScales.addItem(new ScaleData("T", 480f)); 130 JComboBoxUtil.setupComboBoxMaxRows(_layoutScales); 131 ScaleData sc = makeCustomItem(WarrantPreferences.getDefault().getLayoutScale()); 132 _layoutScales.addItem(sc); 133 if (_layoutScales.getSelectedIndex() < 0) { 134 _layoutScales.setSelectedItem(sc); 135 } 136 Dimension dim = _layoutScales.getPreferredSize(); 137 dim.width = 3 * dim.width / 2; 138 _layoutScales.setPreferredSize(dim); 139 _layoutScales.addItemListener(this); 140 _layoutScales.setToolTipText(Bundle.getMessage("ToolTipLayoutScale")); 141 JLabel label = new JLabel(Bundle.getMessage("LabelLayoutScale")); // shared key in jmrit.Bundle.properties 142 label.setToolTipText(Bundle.getMessage("ToolTipLayoutScale")); 143 panel.add(label); 144 JPanel p = new JPanel(); 145 p.add(_layoutScales); 146 panel.add(p); 147 return panel; 148 } 149 150 @SuppressFBWarnings(value = "FE_FLOATING_POINT_EQUALITY", justification = "fixed number of possible values") 151 private ScaleData makeCustomItem(float scale) { 152 int cnt = 0; 153 while (cnt < _layoutScales.getItemCount()) { 154 if (_layoutScales.getItemAt(cnt).scale == scale) { 155 _layoutScales.setSelectedItem(_layoutScales.getItemAt(cnt)); 156 return new CustomDialog("custom", 0.0f); 157 } 158 cnt++; 159 } 160 _layoutScales.setSelectedIndex(-1); 161 return new CustomDialog(Bundle.getMessage("custom"), scale); 162 } 163 164 @Override 165 public void itemStateChanged(ItemEvent e) { 166 WarrantPreferences preferences = WarrantPreferences.getDefault(); 167 if (e.getStateChange() == ItemEvent.SELECTED) { 168 ScaleData sd = (ScaleData) e.getItem(); 169 if (sd instanceof CustomDialog) { 170 boolean ok = false; 171 while (!ok) { 172 float scale = 0.0f; 173 String str = JmriJOptionPane.showInputDialog(this, Bundle.getMessage("customInput"), 174 Bundle.getMessage("customTitle"), JmriJOptionPane.QUESTION_MESSAGE); 175 try { 176 if (str == null) { 177 sd.scale = 0.0f; 178 makeCustomItem(preferences.getLayoutScale()); 179 ok = true; 180 } else { 181 scale = Float.parseFloat(str); 182 if (scale <= 1.0f) { 183 throw new NumberFormatException(); 184 } 185 sd.scale = scale; 186 preferences.setLayoutScale(scale); 187 _isDirty = true; 188 ok = true; 189 } 190 } catch (NumberFormatException nfe) { 191 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("customError", str), 192 Bundle.getMessage("customTitle"), JmriJOptionPane.ERROR_MESSAGE); 193 } 194 } 195 } else { 196 preferences.setLayoutScale(sd.scale); 197 _isDirty = true; 198 } 199 } 200 } 201 202 // Preferences left column items 203 204 class ScaleData { 205 206 float scale; 207 String scaleName; 208 209 ScaleData(String scaleName, float scale) { 210 this.scale = scale; 211 this.scaleName = scaleName; 212 } 213 214 @Override 215 public String toString() { 216 return Bundle.getMessage("scaleItem", scaleName, Float.toString(scale)); 217 } 218 } 219 220 class CustomDialog extends ScaleData { 221 222 CustomDialog(String scaleName, float scale) { 223 super(scaleName, scale); 224 } 225 226 @Override 227 public String toString() { 228 if (scale < 1.0f) { 229 return Bundle.getMessage("custom"); 230 } 231 return super.toString(); 232 } 233 } 234 235 private JPanel searchDepthPanel(boolean vertical) { 236 _searchDepth = new JSpinner(new SpinnerNumberModel(20, 1, 50, 1)); 237 int searchDepthPref = WarrantPreferences.getDefault().getSearchDepth(); 238 if (searchDepthPref >= 1 && searchDepthPref <= 50) { 239 _searchDepth.setValue(searchDepthPref); 240 } 241 JPanel p = new JPanel(); 242 p.add(WarrantRoute.makeTextBoxPanel(vertical, _searchDepth, "SearchDepth", "ToolTipSearchDepth")); 243 p.setToolTipText(Bundle.getMessage("ToolTipSearchDepth")); 244 return p; 245 } 246 247 private JPanel throttleScalePanel(boolean vertical) { 248 _throttleScale = new JTextField(5); 249 _throttleScale.setText(NumberFormat.getNumberInstance().format(WarrantPreferences.getDefault().getThrottleScale())); 250 JPanel p = new JPanel(); 251 p.add(WarrantRoute.makeTextBoxPanel(vertical, _throttleScale, "ThrottleScale", "ToolTipThrottleScale")); 252 _throttleScale.setColumns(8); 253 p.setToolTipText(Bundle.getMessage("ToolTipThrottleScale")); 254 return p; 255 } 256 257 static protected JPanel timeIncrementPanel(boolean vertical, JSpinner timeIncre) { 258 int timeIncrePrefs = WarrantPreferences.getDefault().getTimeIncrement(); 259 if (timeIncrePrefs >= 200 && timeIncrePrefs <= 10000) { 260 timeIncre.setValue(timeIncrePrefs); 261 } 262 JPanel incrPanel = new JPanel(); 263 incrPanel.add(timeIncre); 264 incrPanel.add(new JLabel(Bundle.getMessage("milliseconds"))); 265 JPanel p = new JPanel(); 266 p.add(WarrantFrame.makeTextBoxPanel(vertical, incrPanel, "TimeIncrement", "ToolTipTimeIncrement")); 267 p.setToolTipText(Bundle.getMessage("ToolTipTimeIncrement")); 268 return p; 269 } 270 271 static protected JPanel throttleIncrementPanel(boolean vertical, JTextField rampIncre) { 272 rampIncre.setText(NumberFormat.getNumberInstance().format(WarrantPreferences.getDefault().getThrottleIncrement()*100)); 273 JPanel incrPanel = new JPanel(); 274 incrPanel.add(rampIncre); 275 incrPanel.add(new JLabel(Bundle.getMessage("percent"))); 276 JPanel p = new JPanel(); 277 p.add(WarrantFrame.makeTextBoxPanel(vertical, incrPanel, "RampIncrement", "ToolTipRampIncrement")); 278 p.setToolTipText(Bundle.getMessage("ToolTipRampIncrement")); 279 return p; 280 } 281 282 private JPanel tracePanel(boolean vertical) { 283 _traceWarrants = WarrantPreferences.getDefault().getTrace(); 284 String text = (_traceWarrants ? "ColumnHeadEnabled" : "Disabled"); 285 JButton button = new JButton(Bundle.getMessage(text)); 286 button.addActionListener(new ActionListener() { 287 @Override 288 public void actionPerformed(ActionEvent e) { 289 _traceWarrants = !_traceWarrants; 290 String text = (_traceWarrants ? "ColumnHeadEnabled" : "Disabled"); 291 button.setText(Bundle.getMessage(text)); 292 button.setSelected(false); 293 } 294 }); 295 JPanel p = new JPanel(); 296 p.add(WarrantFrame.makeTextBoxPanel(vertical, button, "warrantTrace", "ToolTipTraceWarrant")); 297 p.setToolTipText(Bundle.getMessage("ToolTipTimeIncrement")); 298 return p; 299 } 300 301 private JPanel speedAssistancePanel(boolean vertical) { 302 _speedAssistance = new JTextField(6); 303 _speedAssistance.setText(NumberFormat.getNumberInstance().format(WarrantPreferences.getDefault().getSpeedAssistance()*100)); 304 JPanel incrPanel = new JPanel(); 305 incrPanel.add(_speedAssistance); 306 incrPanel.add(new JLabel(Bundle.getMessage("percent"))); 307 JPanel p = new JPanel(); 308 p.add(WarrantFrame.makeTextBoxPanel(vertical, incrPanel, "SpeedAssistance", "ToolTipSpeedAssistance")); 309 p.setToolTipText(Bundle.getMessage("ToolTipRampIncrement")); 310 return p; 311 } 312 313 private JPanel speedRosterPanel(boolean vertical) { 314 ButtonGroup bg = new ButtonGroup(); 315 JPanel p = new JPanel(); 316 p.setLayout(new BoxLayout(p, BoxLayout.LINE_AXIS)); 317 JRadioButton b1 = new JRadioButton(Bundle.getMessage("NeverMerge")); 318 b1.addActionListener((ActionEvent e) -> { 319 if (b1.isSelected()) { 320 _shutdown = WarrantPreferences.Shutdown.NO_MERGE; 321 } 322 }); 323 bg.add(b1); 324 p.add(b1); 325 JRadioButton b2 = new JRadioButton(Bundle.getMessage("PromptMerges")); 326 b2.addActionListener((ActionEvent e) -> { 327 if (b2.isSelected()) { 328 _shutdown = WarrantPreferences.Shutdown.PROMPT; 329 } 330 }); 331 bg.add(b2); 332 p.add(b2); 333 JRadioButton b3 = new JRadioButton(Bundle.getMessage("AlwaysMerge")); 334 b3.addActionListener((ActionEvent e) -> { 335 if (b3.isSelected()) { 336 _shutdown = WarrantPreferences.Shutdown.MERGE_ALL; 337 } 338 }); 339 bg.add(b3); 340 p.add(b3); 341 _shutdown = WarrantPreferences.getDefault().getShutdown(); 342 switch (_shutdown) { 343 case NO_MERGE: 344 b1.setSelected(true); 345 break; 346 case PROMPT: 347 b2.setSelected(true); 348 break; 349 case MERGE_ALL: 350 b3.setSelected(true); 351 break; 352 default: 353 // fall out 354 break; 355 } 356 JPanel panel = new JPanel(); 357 panel.add(WarrantRoute.makeTextBoxPanel(vertical, p, "MergeRoster", "ToolTipMergeRoster")); 358 return panel; 359 } 360 361 private JPanel speedNamesPanel() { 362 JPanel panel = new JPanel(); 363 panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(java.awt.Color.BLACK), 364 Bundle.getMessage("LabelSpeedNameTable"), 365 javax.swing.border.TitledBorder.CENTER, 366 javax.swing.border.TitledBorder.TOP)); 367 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 368 369 _speedNameMap = new ArrayList<>(); 370 Iterator<Entry<String, Float>> it = WarrantPreferences.getDefault().getSpeedNameEntryIterator(); 371 while (it.hasNext()) { 372 Entry<String, Float> ent = it.next(); 373 _speedNameMap.add(new DataPair<>(ent.getKey(), ent.getValue())); 374 } 375 _speedNameModel = new SpeedNameTableModel(); 376 _speedNameTable = new JTable(_speedNameModel); 377 for (int i = 0; i < _speedNameModel.getColumnCount(); i++) { 378 int width = _speedNameModel.getPreferredWidth(i); 379 _speedNameTable.getColumnModel().getColumn(i).setPreferredWidth(width); 380 } 381 ActionListener insertAction = new ActionListener() { 382 @Override 383 public void actionPerformed(ActionEvent e) { 384 insertSpeedNameRow(); 385 } 386 }; 387 ActionListener deleteAction = new ActionListener() { 388 @Override 389 public void actionPerformed(ActionEvent e) { 390 deleteSpeedNameRow(); 391 } 392 }; 393 panel.add(tablePanel(_speedNameTable, "ToolTipSpeedNameTable", insertAction, deleteAction)); 394 panel.add(interpretationPanel()); 395 return panel; 396 } 397 398 private JPanel appearancePanel() { 399 JPanel panel = new JPanel(); 400 panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(java.awt.Color.BLACK), 401 Bundle.getMessage("LabelAppearanceTable"), 402 javax.swing.border.TitledBorder.CENTER, 403 javax.swing.border.TitledBorder.TOP)); 404 panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS)); 405 406 _appearanceMap = new ArrayList<>(); 407 Iterator<Entry<String, String>> it = WarrantPreferences.getDefault().getAppearanceEntryIterator(); 408 while (it.hasNext()) { 409 Entry<String, String> ent = it.next(); 410 _appearanceMap.add(new DataPair<>(ent.getKey(), ent.getValue())); 411 } 412 _appearanceModel = new AppearanceTableModel(); 413 _appearanceTable = new JTable(_appearanceModel); 414 for (int i = 0; i < _appearanceModel.getColumnCount(); i++) { 415 int width = _appearanceModel.getPreferredWidth(i); 416 _appearanceTable.getColumnModel().getColumn(i).setPreferredWidth(width); 417 } 418 panel.add(Box.createGlue()); 419 panel.add(tablePanel(_appearanceTable, "ToolTipAppearanceTable", null, null)); 420 panel.add(Box.createGlue()); 421 return panel; 422 } 423 424 static private JPanel tablePanel(JTable table, String toolTip, ActionListener insertAction, ActionListener removeAction) { 425 JPanel tablePanel = new JPanel(); 426 tablePanel.setLayout(new BoxLayout(tablePanel, BoxLayout.LINE_AXIS)); 427 JScrollPane scrollPane = new JScrollPane(table); 428 int height = table.getRowHeight(); 429 Dimension dim = table.getPreferredSize(); 430 dim.height = height * 5; 431 scrollPane.getViewport().setPreferredSize(dim); 432 table.setToolTipText(Bundle.getMessage(toolTip)); 433 scrollPane.setToolTipText(Bundle.getMessage(toolTip)); 434 tablePanel.add(scrollPane); 435 tablePanel.add(Box.createVerticalStrut(STRUT_SIZE)); 436 437 JPanel buttonPanel = new JPanel(); 438 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.PAGE_AXIS)); 439 440 if (insertAction != null) { 441 JButton insertButton = new JButton(Bundle.getMessage("buttonInsertRow")); 442 insertButton.addActionListener(insertAction); 443 buttonPanel.add(insertButton); 444 buttonPanel.add(Box.createVerticalStrut(2 * STRUT_SIZE)); 445 } 446 447 if (removeAction != null) { 448 JButton deleteButton = new JButton(Bundle.getMessage("buttonDeleteRow")); 449 deleteButton.addActionListener(removeAction); 450 buttonPanel.add(deleteButton); 451 } 452 tablePanel.add(buttonPanel); 453 return tablePanel; 454 } 455 456 private void insertSpeedNameRow() { 457 int row = _speedNameTable.getSelectedRow(); 458 if (row < 0) { 459 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("selectRow"), 460 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 461 return; 462 } 463 _speedNameMap.add(row, new DataPair<>("", 0f)); 464 _speedNameModel.fireTableDataChanged(); 465 } 466 467 private void deleteSpeedNameRow() { 468 int row = _speedNameTable.getSelectedRow(); 469 if (row < 0) { 470 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("selectRow"), 471 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 472 return; 473 } 474 _speedNameMap.remove(row); 475 _speedNameModel.fireTableDataChanged(); 476 } 477 478 private JPanel interpretationPanel() { 479 _interpretation = WarrantPreferences.getDefault().getInterpretation(); 480 JPanel buttonPanel = new JPanel(); 481 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS)); 482 ButtonGroup group = new ButtonGroup(); 483 makeButton(buttonPanel, group, "percentNormal", "ToolTipPercentNormal", SignalSpeedMap.PERCENT_NORMAL); 484 makeButton(buttonPanel, group, "percentThrottle", "ToolTipPercentThrottle", SignalSpeedMap.PERCENT_THROTTLE); 485 makeButton(buttonPanel, group, "speedMph", "ToolTipSpeedMph", SignalSpeedMap.SPEED_MPH); 486 makeButton(buttonPanel, group, "speedKmph", "ToolTipSpeedKmph", SignalSpeedMap.SPEED_KMPH); 487 JPanel panel = new JPanel(); 488 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 489 JPanel p = new JPanel(); 490 p.setLayout(new BoxLayout(p, BoxLayout.LINE_AXIS)); 491 p.add(Box.createGlue()); 492 JLabel label = new JLabel(Bundle.getMessage("LabelInterpretation", SwingConstants.CENTER)); 493 label.setToolTipText(Bundle.getMessage("ToolTipInterpretation")); 494 p.setToolTipText(Bundle.getMessage("ToolTipInterpretation")); 495 p.add(label); 496 p.add(Box.createGlue()); 497 panel.add(p, SwingConstants.CENTER); 498 panel.add(buttonPanel, Box.CENTER_ALIGNMENT); 499 return panel; 500 } 501 502 private void makeButton(JPanel panel, ButtonGroup group, String name, String tooltip, int interp) { 503 JRadioButton button = new JRadioButton(Bundle.getMessage(name)); 504 group.add(button); 505 panel.add(button); 506 button.setToolTipText(Bundle.getMessage(tooltip)); 507 button.addActionListener(new ActionListener() { 508 int value; 509 JRadioButton but; 510 511 @Override 512 public void actionPerformed(ActionEvent e) { 513 if (but.isSelected()) { 514 _interpretation = value; 515 } 516 } 517 518 ActionListener init(JRadioButton b, int num) { 519 but = b; 520 value = num; 521 return this; 522 } 523 }.init(button, interp)); 524 if (_interpretation == interp) { 525 button.setSelected(true); 526 } 527 } 528 529 /** 530 * Compare GUI values with Preferences. When different, update Preferences 531 * and set _isDirty flag. 532 */ 533 @SuppressFBWarnings(value = "FE_FLOATING_POINT_EQUALITY", justification = "fixed number of possible values") 534 private void setValues() { 535 WarrantPreferences preferences = WarrantPreferences.getDefault(); 536 537 int depth = (Integer) _searchDepth.getValue(); 538 if (preferences.getSearchDepth() != depth) { 539 preferences.setSearchDepth(depth); 540 _isDirty = true; 541 } 542 543 if (preferences.getInterpretation() != _interpretation) { 544 preferences.setInterpretation(_interpretation); 545 _isDirty = true; 546 } 547 548 int time = (Integer) _timeIncre.getValue(); 549 if (preferences.getTimeIncrement() != time) { 550 preferences.setTimeIncrement(time); 551 _isDirty = true; 552 } 553 554 if (preferences.getTrace() != _traceWarrants) { 555 preferences.setTrace(_traceWarrants); 556 _isDirty = true; 557 } 558 559 float scale = preferences.getThrottleIncrement(); 560 try { 561 scale = NumberFormat.getNumberInstance().parse(_rampIncre.getText()).floatValue(); 562 } catch (java.text.ParseException pe) { 563 _rampIncre.setText(NumberFormat.getNumberInstance().format(preferences.getThrottleIncrement()*100)); 564 } 565 if (scale < 0.5f || scale > 25f) { 566 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("rampIncrWarning", _rampIncre.getText()), 567 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 568 _rampIncre.setText(NumberFormat.getNumberInstance().format(WarrantPreferences.getDefault().getThrottleIncrement()*100)); 569 } else { 570 scale /= 100; 571 if (preferences.getThrottleIncrement() != scale) { 572 preferences.setThrottleIncrement(scale); 573 _isDirty = true; 574 } 575 } 576 577 scale = preferences.getThrottleScale(); 578 try { 579 scale = NumberFormat.getNumberInstance().parse(_throttleScale.getText()).floatValue(); 580 } catch (java.text.ParseException pe) { 581 _throttleScale.setText(NumberFormat.getNumberInstance().format(preferences.getThrottleScale())); 582 } 583 if (preferences.getThrottleScale() != scale) { 584 preferences.setThrottleScale(scale); 585 _isDirty = true; 586 } 587 588 scale = preferences.getSpeedAssistance(); 589 try { 590 scale = NumberFormat.getNumberInstance().parse(_speedAssistance.getText()).floatValue(); 591 } catch (java.text.ParseException pe) { 592 _rampIncre.setText(NumberFormat.getNumberInstance().format(preferences.getSpeedAssistance()*100)); 593 } 594 scale /= 100; 595 if (preferences.getSpeedAssistance() != scale) { 596 preferences.setSpeedAssistance(scale); 597 _isDirty = true; 598 } 599 600 WarrantPreferences.Shutdown shutDown = preferences.getShutdown(); 601 if (shutDown != _shutdown) { 602 preferences.setShutdown(_shutdown); 603 _isDirty = true; 604 } 605 606 boolean different = false; 607 javax.swing.table.TableCellEditor tce = _speedNameTable.getCellEditor(); 608 if (tce != null) { 609 tce.stopCellEditing(); 610 } 611 if (preferences.getSpeedNames().size() != _speedNameMap.size()) { 612 different = true; 613 } else { 614 for (int i = 0; i < _speedNameMap.size(); i++) { 615 DataPair<String, Float> dp = _speedNameMap.get(i); 616 String name = dp.getKey(); 617 if (preferences.getSpeedNameValue(name) == null 618 || preferences.getSpeedNameValue(name).floatValue() != dp.getValue().floatValue()) { 619 different = true; 620 break; 621 } 622 } 623 } 624 if (different) { 625 preferences.setSpeedNames(_speedNameMap); 626 _isDirty = true; 627 } 628 629 different = false; 630 tce = _appearanceTable.getCellEditor(); 631 if (tce != null) { 632 tce.stopCellEditing(); 633 } 634 if (preferences.getAppearances().size() != _appearanceMap.size()) { 635 different = true; 636 } else { 637 for (int i = 0; i < _appearanceMap.size(); i++) { 638 DataPair<String, String> dp = _appearanceMap.get(i); 639 String name = dp.getKey(); 640 if (preferences.getAppearanceValue(name) == null || !preferences.getAppearanceValue(name).equals(dp.getValue())) { 641 different = true; 642 break; 643 } 644 } 645 } 646 if (different) { 647 preferences.setAppearances(_appearanceMap); 648 _isDirty = true; 649 } 650 } 651 652 @Override 653 public String getPreferencesItem() { 654 return "WARRANTS"; // NOI18N 655 } 656 657 @Override 658 public String getPreferencesItemText() { 659 return Bundle.getMessage("TitleWarrantPreferences"); 660 } 661 662 @Override 663 public String getTabbedPreferencesTitle() { 664 return null; 665 } 666 667 @Override 668 public String getLabelKey() { 669 return null; 670 } 671 672 @Override 673 public JComponent getPreferencesComponent() { 674 return this; 675 } 676 677 @Override 678 public boolean isPersistant() { 679 return false; 680 } 681 682 @Override 683 public String getPreferencesTooltip() { 684 return Bundle.getMessage("ToolTipLayoutScale"); 685 } 686 687 @Override 688 public void savePreferences() { 689 setValues(); 690 if (_isDirty) { 691 WarrantPreferences.getDefault().save(); 692 _isDirty = false; 693 } 694 } 695 696 @Override 697 public boolean isDirty() { 698 return this._isDirty; 699 } 700 701 @Override 702 public boolean isRestartRequired() { 703 return false; 704 } 705 706 @Override 707 public boolean isPreferencesValid() { 708 return true; // no validity checking performed 709 } 710 711 /** 712 * Retain the key/value pair of a Map or Dictionary as a pair. 713 * 714 * @param <K> key class 715 * @param <V> value class 716 */ 717 // Can uses of DataPair be replaced with used of Map.Entry or AbstractMap.SimpleEntry? 718 static class DataPair<K, V> implements Entry<K, V> { 719 720 K key; 721 V value; 722 723 DataPair(K k, V v) { 724 key = k; 725 value = v; 726 } 727 728 DataPair(Entry<K, V> entry) { 729 this.key = entry.getKey(); 730 this.value = entry.getValue(); 731 } 732 733 @Override 734 public K getKey() { 735 return key; 736 } 737 738 void setKey(K k) { 739 key = k; 740 } 741 742 @Override 743 public V getValue() { 744 return value; 745 } 746 747 @Override 748 public V setValue(V v) { 749 value = v; 750 return value; 751 } 752 753 } 754 755 /* *********************** SpeedName Table ******************************/ 756 class SpeedNameTableModel extends AbstractTableModel { 757 758 public SpeedNameTableModel() { 759 super(); 760 } 761 762 @Override 763 public int getColumnCount() { 764 return 2; 765 } 766 767 @Override 768 public int getRowCount() { 769 return _speedNameMap.size(); 770 } 771 772 @Override 773 public String getColumnName(int col) { 774 if (col == 0) { 775 return Bundle.getMessage("speedName"); 776 } 777 return Bundle.getMessage("speedValue"); 778 } 779 780 @Override 781 public boolean isCellEditable(int row, int col) { 782 return true; 783 } 784 785 @Override 786 public Class<?> getColumnClass(int col) { 787 return String.class; 788 } 789 790 public int getPreferredWidth(int col) { 791 if (col == 0) { 792 return new JTextField(15).getPreferredSize().width; 793 } 794 return new JTextField(8).getPreferredSize().width; 795 } 796 797 @Override 798 public Object getValueAt(int row, int col) { 799 // some error checking 800 if (row >= _speedNameMap.size()) { 801 log.error("row is greater than aspect speedNames size"); 802 return ""; 803 } 804 DataPair<String, Float> data = _speedNameMap.get(row); 805 if (data == null) { 806 log.error("Aspect speedName data is null!"); 807 return ""; 808 } 809 if (col == 0) { 810 return data.getKey(); 811 } 812 return data.getValue(); 813 } 814 815 @Override 816 public void setValueAt(Object value, int row, int col) { 817 DataPair<String, Float> data = _speedNameMap.get(row); 818 String str = (String) value; 819 String msg = null; 820 if (str == null || data == null) { 821 msg = Bundle.getMessage("NoData"); 822 } 823 if (data != null) { 824 if (col == 0) { 825 data.setKey((String) value); 826 } else { 827 try { 828 float f = Float.parseFloat((String) value); 829 if (f < 0) { 830 msg = Bundle.getMessage("InvalidNumber", (String) value); 831 } else { 832 data.setValue(f); 833 } 834 } catch (NumberFormatException nfe) { 835 msg = Bundle.getMessage("MustBeFloat", (String) value); 836 } 837 } 838 if (msg != null) { 839 JmriJOptionPane.showMessageDialog(null, msg, 840 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 841 } else { 842 fireTableRowsUpdated(row, row); 843 } 844 } 845 } 846 } 847 848 /* *********************** Appearance Table ******************************/ 849 class AppearanceTableModel extends AbstractTableModel { 850 851 public AppearanceTableModel() { 852 super(); 853 } 854 855 @Override 856 public int getColumnCount() { 857 return 2; 858 } 859 860 @Override 861 public int getRowCount() { 862 return _appearanceMap.size(); 863 } 864 865 @Override 866 public String getColumnName(int col) { 867 if (col == 0) { 868 return Bundle.getMessage("appearance"); 869 } 870 return Bundle.getMessage("speedName"); 871 } 872 873 @Override 874 public boolean isCellEditable(int row, int col) { 875 return (col != 0); 876 } 877 878 @Override 879 public Class<?> getColumnClass(int col) { 880 return String.class; 881 } 882 883 public int getPreferredWidth(int col) { 884 if (col == 0) { 885 return new JTextField(15).getPreferredSize().width; 886 } 887 return new JTextField(15).getPreferredSize().width; 888 } 889 890 @Override 891 public Object getValueAt(int row, int col) { 892 // some error checking 893 if (row >= _appearanceMap.size()) { 894 log.error("row is greater than appearance names size"); 895 return ""; 896 } 897 DataPair<String, String> data = _appearanceMap.get(row); 898 if (data == null) { 899 log.error("Appearance name data is null!"); 900 return ""; 901 } 902 if (col == 0) { 903 return data.getKey(); 904 } 905 return data.getValue(); 906 } 907 908 @Override 909 public void setValueAt(Object value, int row, int col) { 910 DataPair<String, String> data = _appearanceMap.get(row); 911 String str = (String) value; 912 String msg = null; 913 if (str == null || data == null) { 914 msg = Bundle.getMessage("NoData"); 915 } 916 if (data != null) { 917 if (col == 0) { 918 data.setKey((String) value); 919 } else { 920 data.setValue((String) value); 921 } 922 if (msg != null) { 923 JmriJOptionPane.showMessageDialog(null, msg, 924 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 925 } else { 926 fireTableRowsUpdated(row, row); 927 } 928 } 929 } 930 } 931 932 /* *********************** Throttle Step Increment Table *****************************/ 933 class StepIncrementTableModel extends AbstractTableModel { 934 935 public StepIncrementTableModel() { 936 super(); 937 } 938 939 @Override 940 public int getColumnCount() { 941 return 2; 942 } 943 944 @Override 945 public int getRowCount() { 946 return _stepIncrementMap.size(); 947 } 948 949 @Override 950 public String getColumnName(int col) { 951 if (col == 0) { 952 return Bundle.getMessage("throttleStepMode"); 953 } 954 return Bundle.getMessage("rampIncrement"); 955 } 956 957 @Override 958 public boolean isCellEditable(int row, int col) { 959 return (col != 0); 960 } 961 962 @Override 963 public Class<?> getColumnClass(int col) { 964 return String.class; 965 } 966 967 public int getPreferredWidth(int col) { 968 if (col == 0) { 969 return new JTextField(15).getPreferredSize().width; 970 } 971 return new JTextField(5).getPreferredSize().width; 972 } 973 974 @Override 975 public Object getValueAt(int row, int col) { 976 // some error checking 977 if (row >= _stepIncrementMap.size()) { 978 log.error("row is greater than throttle step modes size"); 979 return ""; 980 } 981 DataPair<String, Integer> data = _stepIncrementMap.get(row); 982 if (data == null) { 983 log.error("Throttle step data is null!"); 984 return ""; 985 } 986 if (col == 0) { 987 return data.getKey(); 988 } 989 return data.getValue(); 990 } 991 992 @Override 993 public void setValueAt(Object value, int row, int col) { 994 DataPair<String, Integer> data = _stepIncrementMap.get(row); 995 String str = (String) value; 996 String msg = null; 997 if (str == null || data == null) { 998 msg = Bundle.getMessage("NoData"); 999 } 1000 if (data != null) { 1001 if (col == 0) { 1002 data.setKey((String) value); 1003 } else { 1004 try { 1005 Integer f = Integer.parseInt((String) value); 1006 if (f < 1) { 1007 msg = Bundle.getMessage("InvalidNumber", (String) value); 1008 } else { 1009 data.setValue(f); 1010 } 1011 } catch (NumberFormatException nfe) { 1012 msg = Bundle.getMessage("InvalidNumber", (String) value); 1013 } 1014 } 1015 if (msg != null) { 1016 JmriJOptionPane.showMessageDialog(null, msg, 1017 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 1018 } else { 1019 fireTableRowsUpdated(row, row); 1020 } 1021 } 1022 } 1023 } 1024 1025 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WarrantPreferencesPanel.class); 1026 1027}