001package jmri.jmrit.vsdecoder.swing; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004 005import java.awt.Dimension; 006import java.awt.GridBagLayout; 007import java.awt.event.ActionEvent; 008import java.awt.event.ActionListener; 009import java.awt.event.KeyEvent; 010import java.util.ArrayList; 011import java.util.HashMap; 012import java.util.List; 013import java.util.Map; 014 015import javax.swing.BoxLayout; 016import javax.swing.JButton; 017import javax.swing.JMenu; 018import javax.swing.JMenuBar; 019import javax.swing.JPanel; 020import javax.swing.JScrollPane; 021import javax.swing.JTabbedPane; 022import javax.swing.JTable; 023 024import jmri.Block; 025import jmri.BlockManager; 026import jmri.Reporter; 027import jmri.ReporterManager; 028import jmri.jmrit.operations.OperationsXml; 029import jmri.jmrit.operations.locations.Location; 030import jmri.jmrit.operations.locations.LocationManager; 031import jmri.jmrit.operations.setup.Setup; 032import jmri.jmrit.vsdecoder.VSDecoderManager; 033import jmri.jmrit.vsdecoder.listener.ListeningSpot; 034import jmri.util.PhysicalLocation; 035import jmri.util.swing.JmriJOptionPane; 036 037/** 038 * GUI to manage Reporters, Blocks, Locations and Listener attributes. 039 * 040 * <hr> 041 * This file is part of JMRI. 042 * <p> 043 * JMRI is free software; you can redistribute it and/or modify it under 044 * the terms of version 2 of the GNU General Public License as published 045 * by the Free Software Foundation. See the "COPYING" file for a copy 046 * of this license. 047 * <p> 048 * JMRI is distributed in the hope that it will be useful, but WITHOUT 049 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 050 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 051 * for more details. 052 * 053 * @author Mark Underwood Copyright (C) 2011 054 */ 055public class ManageLocationsFrame extends jmri.util.JmriJFrame { 056 057 // Map of Mnemonic KeyEvent values to GUI Components 058 private static final Map<String, Integer> Mnemonics = new HashMap<>(); 059 060 static { 061 Mnemonics.put("ReporterTab", KeyEvent.VK_E); // NOI18N 062 Mnemonics.put("OpsTab", KeyEvent.VK_P); // NOI18N 063 Mnemonics.put("ListenerTab", KeyEvent.VK_L); // NOI18N 064 Mnemonics.put("BlockTab", KeyEvent.VK_B); // NOI18N 065 Mnemonics.put("CloseButton", KeyEvent.VK_O); // NOI18N 066 Mnemonics.put("SaveButton", KeyEvent.VK_S); // NOI18N 067 } 068 069 private JTabbedPane tabbedPane; 070 private JPanel listenerPanel; 071 private JPanel reporterPanel; 072 private JPanel opsPanel; 073 private JPanel blockPanel; 074 075 private Object[][] reporterData; // positions of Reporters 076 private Object[][] opsData; // positions of Operations Locations 077 private Object[][] locData; // positions of Listener Locations 078 private Object[][] blockData; // positions of Blocks 079 private ManageLocationsTableModel.ReporterBlockTableModel reporterModel; 080 private ManageLocationsTableModel.LocationTableModel opsModel; 081 private ManageLocationsTableModel.ListenerTableModel locModel; 082 private ManageLocationsTableModel.ReporterBlockTableModel blockModel; 083 private ListeningSpot listenerLoc; 084 085 private HashMap<String, PhysicalLocation> data; 086 087 private List<JMenu> menuList; 088 089 @SuppressFBWarnings(value = "EI_EXPOSE_REP2", 090 justification = "2D array of different types passed as complex parameter. " 091 + "Better to switch to passing use-specific objects rather than " 092 + "papering this over with a deep copy of the arguments. " 093 + "In any case, there's no risk of exposure here.") 094 public ManageLocationsFrame(ListeningSpot listener, 095 Object[][] reporters, 096 Object[][] ops, 097 Object[][] blocks) { 098 super(true, true); 099 reporterData = reporters; 100 opsData = ops; 101 listenerLoc = listener; 102 blockData = blocks; 103 initGui(); 104 } 105 106 private void initGui() { 107 108 this.setTitle(Bundle.getMessage("FieldManageLocationsFrameTitle")); 109 this.buildMenu(); 110 // Panel for managing listeners 111 listenerPanel = new JPanel(); 112 listenerPanel.setLayout(new BoxLayout(listenerPanel, BoxLayout.Y_AXIS)); 113 114 // Build Listener Locations Table 115 locData = new Object[1][7]; 116 locData[0][ManageLocationsTableModel.NAMECOL] = listenerLoc.getName(); 117 locData[0][ManageLocationsTableModel.USECOL] = true; 118 locData[0][ManageLocationsTableModel.XCOL] = listenerLoc.getLocation().x; 119 locData[0][ManageLocationsTableModel.YCOL] = listenerLoc.getLocation().y; 120 locData[0][ManageLocationsTableModel.ZCOL] = listenerLoc.getLocation().z; 121 locData[0][ManageLocationsTableModel.BEARINGCOL] = listenerLoc.getBearing(); 122 locData[0][ManageLocationsTableModel.AZIMUTHCOL] = listenerLoc.getAzimuth(); 123 124 log.debug("Listener: {}", listenerLoc.toString()); 125 log.debug(" locData:"); 126 for (int i = 0; i < 7; i++) { 127 log.debug(" item {}", locData[0][i]); 128 } 129 130 JPanel locPanel = new JPanel(); 131 locPanel.setLayout(new BoxLayout(locPanel, BoxLayout.LINE_AXIS)); 132 JScrollPane locScrollPanel = new JScrollPane(); 133 locModel = new ManageLocationsTableModel.ListenerTableModel(locData); 134 JTable locTable = new JTable(locModel); 135 locTable.setFillsViewportHeight(true); 136 locTable.setPreferredScrollableViewportSize(new Dimension(520, 200)); 137 locScrollPanel.getViewport().add(locTable); 138 139 listenerPanel.add(locScrollPanel); 140 141 reporterPanel = new JPanel(); 142 reporterPanel.setLayout(new GridBagLayout()); 143 JScrollPane reporterScrollPanel = new JScrollPane(); 144 reporterModel = new ManageLocationsTableModel.ReporterBlockTableModel(reporterData); 145 JTable reporterTable = new JTable(reporterModel); 146 reporterTable.setFillsViewportHeight(true); 147 reporterTable.setPreferredScrollableViewportSize(new Dimension(540, 200)); 148 reporterScrollPanel.getViewport().add(reporterTable); 149 150 blockPanel = new JPanel(); 151 blockPanel.setLayout(new GridBagLayout()); 152 JScrollPane blockScrollPanel = new JScrollPane(); 153 blockModel = new ManageLocationsTableModel.ReporterBlockTableModel(blockData); 154 JTable blockTable = new JTable(blockModel); 155 blockTable.setFillsViewportHeight(true); 156 blockTable.setPreferredScrollableViewportSize(new Dimension(540, 200)); 157 blockScrollPanel.getViewport().add(blockTable); 158 159 opsPanel = new JPanel(); 160 opsPanel.setLayout(new GridBagLayout()); 161 opsPanel.revalidate(); 162 JScrollPane opsScrollPanel = new JScrollPane(); 163 opsModel = new ManageLocationsTableModel.LocationTableModel(opsData); 164 JTable opsTable = new JTable(opsModel); 165 opsTable.setFillsViewportHeight(true); 166 opsTable.setPreferredScrollableViewportSize(new Dimension(520, 200)); 167 opsScrollPanel.getViewport().add(opsTable); 168 169 tabbedPane = new JTabbedPane(); 170 tabbedPane.addTab(Bundle.getMessage("Reporters"), reporterScrollPanel); // Reporters Tab Title 171 tabbedPane.setToolTipTextAt(0, Bundle.getMessage("ToolTipReporterTab")); 172 tabbedPane.setMnemonicAt(0, Mnemonics.get("ReporterTab")); // NOI18N 173 tabbedPane.addTab(Bundle.getMessage("Blocks"), blockScrollPanel); 174 tabbedPane.setToolTipTextAt(1, Bundle.getMessage("ToolTipBlockTab")); 175 tabbedPane.setMnemonicAt(1, Mnemonics.get("BlockTab")); // NOI18N 176 tabbedPane.addTab(Bundle.getMessage("FieldOpsTabTitle"), opsScrollPanel); 177 tabbedPane.setToolTipTextAt(2, Bundle.getMessage("ToolTipOpsTab")); 178 tabbedPane.setMnemonicAt(2, Mnemonics.get("OpsTab")); // NOI18N 179 tabbedPane.addTab(Bundle.getMessage("FieldListenersTabTitle"), listenerPanel); 180 tabbedPane.setToolTipTextAt(3, Bundle.getMessage("ToolTipListenerTab")); 181 tabbedPane.setMnemonicAt(3, Mnemonics.get("ListenerTab")); // NOI18N 182 183 JPanel buttonPane = new JPanel(); 184 buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS)); 185 JButton closeButton = new JButton(Bundle.getMessage("ButtonCancel")); 186 closeButton.setToolTipText(Bundle.getMessage("ToolTipButtonMLFClose")); 187 closeButton.setMnemonic(Mnemonics.get("CloseButton")); // NOI18N 188 closeButton.addActionListener(new ActionListener() { 189 @Override 190 public void actionPerformed(ActionEvent e) { 191 closeButtonPressed(e); 192 } 193 }); 194 JButton saveButton = new JButton(Bundle.getMessage("ButtonSave")); 195 saveButton.setToolTipText(Bundle.getMessage("ToolTipButtonMLFSave")); 196 saveButton.setMnemonic(Mnemonics.get("SaveButton")); // NOI18N 197 saveButton.addActionListener(new ActionListener() { 198 @Override 199 public void actionPerformed(ActionEvent e) { 200 saveButtonPressed(e); 201 } 202 }); 203 buttonPane.add(closeButton); 204 buttonPane.add(saveButton); 205 206 this.getContentPane().setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS)); 207 this.getContentPane().add(tabbedPane); 208 this.getContentPane().add(buttonPane); 209 this.pack(); 210 this.setVisible(true); 211 } 212 213 private void buildMenu() { 214 JMenu editMenu = new JMenu(Bundle.getMessage("MenuEdit")); 215 editMenu.add(new VSDPreferencesAction(Bundle.getMessage("VSDecoderFileMenuPreferences"))); 216 217 menuList = new ArrayList<>(1); 218 219 menuList.add(editMenu); 220 221 this.setJMenuBar(new JMenuBar()); 222 this.getJMenuBar().add(editMenu); 223 this.addHelpMenu("package.jmri.jmrit.vsdecoder.swing.ManageLocationsFrame", true); // NOI18N 224 } 225 226 private void saveButtonPressed(ActionEvent e) { 227 int value = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("FieldMLFSaveDialogConfirmMessage"), 228 Bundle.getMessage("FieldMLFSaveDialogTitle"), 229 JmriJOptionPane.YES_NO_OPTION); 230 if (value == JmriJOptionPane.YES_OPTION) { 231 saveTableValues(); 232 OperationsXml.save(); 233 } 234 if (Setup.isCloseWindowOnSaveEnabled()) { 235 dispose(); 236 } 237 } 238 239 @SuppressFBWarnings(value = "WMI_WRONG_MAP_ITERATOR", justification = "only in slow debug") 240 private void saveTableValues() { 241 if ((Boolean) locModel.getValueAt(0, ManageLocationsTableModel.USECOL)) { 242 // Don't accept Azimuth value 90 or -90 (they are not in the domain of definition) 243 if ((Double) locModel.getValueAt(0, ManageLocationsTableModel.AZIMUTHCOL) != null 244 && ((Double) locModel.getValueAt(0, ManageLocationsTableModel.AZIMUTHCOL) == 90.0d 245 || (Double) locModel.getValueAt(0, ManageLocationsTableModel.AZIMUTHCOL) == -90.0d)) { 246 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("FieldTableAzimuthInvalidValue")); 247 } else { 248 listenerLoc.setLocation((Double) locModel.getValueAt(0, ManageLocationsTableModel.XCOL), 249 (Double) locModel.getValueAt(0, ManageLocationsTableModel.YCOL), 250 (Double) locModel.getValueAt(0, ManageLocationsTableModel.ZCOL)); 251 listenerLoc.setOrientation((Double) locModel.getValueAt(0, ManageLocationsTableModel.BEARINGCOL), 252 (Double) locModel.getValueAt(0, ManageLocationsTableModel.AZIMUTHCOL)); 253 VSDecoderManager.instance().getVSDecoderPreferences().save(); 254 VSDecoderManager.instance().getVSDecoderPreferences().setListenerPosition(listenerLoc); 255 } 256 } 257 258 data = reporterModel.getDataMap(); 259 ReporterManager mgr = jmri.InstanceManager.getDefault(ReporterManager.class); 260 for (String s : data.keySet()) { 261 log.debug("Reporter: {}, Location: {}", s, data.get(s)); 262 Reporter r = mgr.getByDisplayName(s); 263 if (r != null) { 264 PhysicalLocation.setBeanPhysicalLocation(data.get(s), r); 265 } 266 } 267 268 data = blockModel.getDataMap(); 269 BlockManager bmgr = jmri.InstanceManager.getDefault(BlockManager.class); 270 for (String s : data.keySet()) { 271 log.debug("Block: {}, Location: {}", s, data.get(s)); 272 Block b = bmgr.getByDisplayName(s); 273 if (b != null) { 274 PhysicalLocation.setBeanPhysicalLocation(data.get(s), b); 275 } 276 } 277 278 data = opsModel.getDataMap(); 279 LocationManager lmgr = jmri.InstanceManager.getDefault(LocationManager.class); 280 for (String s : data.keySet()) { 281 log.debug("OpsLocation: {}, Location: {}", s, data.get(s)); 282 Location l = lmgr.getLocationByName(s); 283 l.setPhysicalLocation(data.get(s)); 284 } 285 } 286 287 private void closeButtonPressed(ActionEvent e) { 288 dispose(); 289 } 290 291 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ManageLocationsFrame.class); 292 293}