001package jmri.jmrit.whereused; 002 003import java.awt.*; 004import java.awt.event.*; 005import java.io.File; 006import java.io.IOException; 007import javax.swing.*; 008 009import jmri.*; 010import jmri.jmrit.entryexit.DestinationPoints; 011import jmri.jmrit.entryexit.EntryExitPairs; 012import jmri.jmrit.logix.OBlock; 013import jmri.jmrit.logix.OBlockManager; 014import jmri.jmrit.logix.Warrant; 015import jmri.jmrit.logix.WarrantManager; 016import jmri.swing.NamedBeanComboBox; 017import jmri.util.FileUtil; 018import jmri.util.swing.JComboBoxUtil; 019import jmri.util.swing.JmriJOptionPane; 020 021/** 022 * Create a where used report based on the selected bean. The selection combo box is 023 * based on the selected type. 024 025 * @author Dave Sand Copyright (C) 2020 026 */ 027public class WhereUsedFrame extends jmri.util.JmriJFrame { 028 ItemType _itemType = ItemType.NONE; 029 JComboBox<ItemType> _itemTypeBox; 030 031 NamedBean _itemBean; 032 NamedBeanComboBox<?> _itemNameBox = new NamedBeanComboBox<>( 033 InstanceManager.getDefault(SensorManager.class)); 034 035 JPanel _topPanel; 036 JPanel _bottomPanel; 037 JPanel _scrolltext = new JPanel(); 038 JTextArea _textArea; 039 JButton _createButton; 040 JLabel itemNameLabel; 041 042 public WhereUsedFrame() { 043 super(true, true); 044 setTitle(Bundle.getMessage("TitleWhereUsed")); // NOI18N 045 createFrame(); 046 addHelpMenu("package.jmri.jmrit.whereused.WhereUsed", true); // NOI18N 047 } 048 049 /** 050 * Create the window frame. The top part contains the item type, the item name 051 * combo box, and a Create button. The middle contains the scrollable "where used" text area and the 052 * bottom part has a button for saving the content to a file. 053 */ 054 void createFrame() { 055 Container contentPane = getContentPane(); 056 contentPane.setLayout(new BorderLayout()); 057 058 // Build the top panel 059 buildTopPanel(); 060 contentPane.add(_topPanel, BorderLayout.NORTH); 061 062 // Build an empty where used listing 063 JScrollPane scrollPane; 064 buildWhereUsedListing(ItemType.NONE, null); 065 scrollPane = new JScrollPane(_scrolltext); 066 contentPane.add(scrollPane); 067 068 // Build the bottom panel 069 buildBottomPanel(); 070 contentPane.add(_bottomPanel, BorderLayout.SOUTH); 071 072 pack(); 073 } 074 075 void buildTopPanel() { 076 _topPanel = new JPanel(); 077 JLabel itemTypeLabel = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("LabelItemType"))); // NOI18N 078 _topPanel.add(itemTypeLabel); 079 _itemTypeBox = new JComboBox<>(); 080 itemTypeLabel.setLabelFor(_itemTypeBox); 081 for (ItemType itemType : ItemType.values()) { 082 _itemTypeBox.addItem(itemType); 083 } 084 JComboBoxUtil.setupComboBoxMaxRows(_itemTypeBox); 085 _topPanel.add(_itemTypeBox); 086 087 itemNameLabel = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("LabelItemName"))); // NOI18N 088 _topPanel.add(itemNameLabel); 089 itemNameLabel.setLabelFor(_itemNameBox); 090 _topPanel.add(_itemNameBox); 091 _itemTypeBox.addActionListener((e) -> { 092 _itemType = _itemTypeBox.getItemAt(_itemTypeBox.getSelectedIndex()); 093 setItemNameBox(_itemType); 094 }); 095 096 _createButton = new JButton(Bundle.getMessage("ButtonCreate")); // NOI18N 097 _createButton.addActionListener((e) -> buildWhereUsedListing(_itemType, _itemBean)); 098 099 _topPanel.add(_createButton); 100 _itemNameBox.setEnabled(false); 101 _createButton.setEnabled(false); 102 } 103 104 void buildBottomPanel() { 105 _bottomPanel = new JPanel(); 106 _bottomPanel.setLayout(new BorderLayout()); 107 108 JButton saveButton = new JButton(Bundle.getMessage("SaveButton")); // NOI18N 109 saveButton.setToolTipText(Bundle.getMessage("SaveButtonHint")); // NOI18N 110 _bottomPanel.add(saveButton, BorderLayout.EAST); 111 saveButton.addActionListener((ActionEvent e) -> saveWhereUsedPressed()); 112 } 113 114 /** 115 * Create a new NamedBeanComboBox based on the item type and refresh the panel. 116 * A selection listener saves the selection and enables the Create button. 117 * @param itemType The enum for the selected item type. 118 */ 119 void setItemNameBox(ItemType itemType) { 120 _createButton.setEnabled(false); 121 buildWhereUsedListing(ItemType.NONE, null); 122 NamedBeanComboBox<?> newNameBox = createNameBox(itemType); 123 if (newNameBox == null) { 124 _itemNameBox.setSelectedIndex(-1); 125 _itemNameBox.setEnabled(false); 126 return; 127 } 128 _itemNameBox = newNameBox; 129 itemNameLabel.setLabelFor(newNameBox); 130 _itemNameBox.setSelectedIndex(-1); 131 _topPanel.remove(3); 132 _topPanel.add(_itemNameBox, 3); 133 134 _itemNameBox.setEnabled(true); 135 _itemNameBox.addItemListener((e) -> { 136 if (e.getStateChange() == ItemEvent.SELECTED) { 137 _itemBean = (NamedBean) e.getItem(); 138 _createButton.setEnabled(true); 139 } 140 }); 141 pack(); 142 repaint(); 143 } 144 145 /** 146 * Build the where used content and update the JScrollPane. 147 * <p> 148 * The selected object is passed to the appropriate detail class which returns a populated textarea. 149 * The textarea is formatted and inserted into a scrollable panel. 150 * @param type Indicated type of item being examined 151 * @param bean The bean being examined 152 */ 153 void buildWhereUsedListing(ItemType type, NamedBean bean) { 154 switch (type) { 155 case TURNOUT: 156 _textArea = TurnoutWhereUsed.getWhereUsed(bean); 157 break; 158 case SENSOR: 159 _textArea = SensorWhereUsed.getWhereUsed(bean); 160 break; 161 case LIGHT: 162 _textArea = LightWhereUsed.getWhereUsed(bean); 163 break; 164 case SIGNALHEAD: 165 _textArea = SignalHeadWhereUsed.getWhereUsed(bean); 166 break; 167 case SIGNALMAST: 168 _textArea = SignalMastWhereUsed.getWhereUsed(bean); 169 break; 170 case REPORTER: 171 _textArea = ReporterWhereUsed.getWhereUsed(bean); 172 break; 173 case MEMORY: 174 _textArea = MemoryWhereUsed.getWhereUsed(bean); 175 break; 176 case ROUTE: 177 _textArea = RouteWhereUsed.getWhereUsed(bean); 178 break; 179 case OBLOCK: 180 _textArea = OBlockWhereUsed.getWhereUsed(bean); 181 break; 182 case BLOCK: 183 _textArea = BlockWhereUsed.getWhereUsed(bean); 184 break; 185 case SECTION: 186 _textArea = SectionWhereUsed.getWhereUsed(bean); 187 break; 188 case WARRANT: 189 _textArea = WarrantWhereUsed.getWhereUsed(bean); 190 break; 191 case ENTRYEXIT: 192 _textArea = EntryExitWhereUsed.getWhereUsed(bean); 193 break; 194 case AUDIO: 195 _textArea = AudioWhereUsed.getWhereUsed(bean); 196 break; 197 default: 198 _textArea = new JTextArea(Bundle.getMessage("TypePrompt", Bundle.getMessage("ButtonCreate"))); 199 break; 200 } 201 202 _textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12)); 203 _textArea.setTabSize(4); 204 _textArea.setEditable(false); 205 _textArea.setCaretPosition(0); 206 if (_scrolltext.getComponentCount() > 0) { 207 _scrolltext.remove(0); 208 } 209 _scrolltext.add(_textArea); 210 pack(); 211 repaint(); 212 } 213 214 JFileChooser userFileChooser = new jmri.util.swing.JmriJFileChooser(FileUtil.getUserFilesPath()); 215 216 /** 217 * Save the where used textarea content to a text file. 218 */ 219 void saveWhereUsedPressed() { 220 userFileChooser.setApproveButtonText(Bundle.getMessage("SaveDialogApprove")); // NOI18N 221 userFileChooser.setDialogTitle(Bundle.getMessage("SaveDialogTitle")); // NOI18N 222 userFileChooser.rescanCurrentDirectory(); 223 224 String itemName = _itemNameBox.getSelectedItemDisplayName(); 225 String fileName = Bundle.getMessage("SaveFileName", (itemName == null) ? "Unknown" : itemName); // NOI18N 226 userFileChooser.setSelectedFile(new File(fileName)); 227 int retVal = userFileChooser.showSaveDialog(null); 228 if (retVal != JFileChooser.APPROVE_OPTION) { 229 log.debug("Save where used content stopped, no file selected"); // NOI18N 230 return; // give up if no file selected or cancel pressed 231 } 232 File file = userFileChooser.getSelectedFile(); 233 log.debug("Save where used content to '{}'", file); // NOI18N 234 235 if (file.exists()) { 236 Object[] options = {Bundle.getMessage("SaveDuplicateReplace"), // NOI18N 237 Bundle.getMessage("SaveDuplicateAppend"), // NOI18N 238 Bundle.getMessage("ButtonCancel")}; // NOI18N 239 int selectedOption = JmriJOptionPane.showOptionDialog(null, 240 Bundle.getMessage("SaveDuplicatePrompt", file.getName(), 241 Bundle.getMessage("SaveDuplicateAppend"), 242 Bundle.getMessage("SaveDuplicateReplace")), // NOI18N 243 Bundle.getMessage("SaveDuplicateTitle"), // NOI18N 244 JmriJOptionPane.DEFAULT_OPTION, 245 JmriJOptionPane.WARNING_MESSAGE, 246 null, options, options[0]); 247 if (selectedOption == 2 || selectedOption == -1) { 248 log.debug("Save where used content stopped, file replace/append cancelled"); // NOI18N 249 return; // Cancel selected or dialog box closed 250 } 251 if (selectedOption == 0) { 252 FileUtil.delete(file); // Replace selected 253 } 254 } 255 256 // Create the file content 257 try { 258 FileUtil.appendTextToFile(file, _textArea.getText()); 259 } catch (IOException e) { 260 log.error("Unable to write where used content to '{}', exception", file, e); // NOI18N 261 } 262 } 263 264 /** 265 * Create a combo name box for name selection. 266 * 267 * @param itemType The selected bean type 268 * @return a combo box based on the item type or null if no match 269 */ 270 NamedBeanComboBox<?> createNameBox(ItemType itemType) { 271 NamedBeanComboBox<?> nameBox; 272 switch (itemType) { 273 case TURNOUT: 274 nameBox = new NamedBeanComboBox<Turnout>(InstanceManager.getDefault(TurnoutManager.class)); 275 break; 276 case SENSOR: 277 nameBox = new NamedBeanComboBox<Sensor>(InstanceManager.getDefault(SensorManager.class)); 278 break; 279 case LIGHT: 280 nameBox = new NamedBeanComboBox<Light>(InstanceManager.getDefault(LightManager.class)); 281 break; 282 case SIGNALHEAD: 283 nameBox = new NamedBeanComboBox<SignalHead>(InstanceManager.getDefault(SignalHeadManager.class)); 284 break; 285 case SIGNALMAST: 286 nameBox = new NamedBeanComboBox<SignalMast>(InstanceManager.getDefault(SignalMastManager.class)); 287 break; 288 case REPORTER: 289 nameBox = new NamedBeanComboBox<Reporter>(InstanceManager.getDefault(ReporterManager.class)); 290 break; 291 case MEMORY: 292 nameBox = new NamedBeanComboBox<Memory>(InstanceManager.getDefault(MemoryManager.class)); 293 break; 294 case ROUTE: 295 nameBox = new NamedBeanComboBox<Route>(InstanceManager.getDefault(RouteManager.class)); 296 break; 297 case OBLOCK: 298 nameBox = new NamedBeanComboBox<OBlock>(InstanceManager.getDefault(OBlockManager.class)); 299 break; 300 case BLOCK: 301 nameBox = new NamedBeanComboBox<Block>(InstanceManager.getDefault(BlockManager.class)); 302 break; 303 case SECTION: 304 nameBox = new NamedBeanComboBox<Section>(InstanceManager.getDefault(SectionManager.class)); 305 break; 306 case WARRANT: 307 nameBox = new NamedBeanComboBox<Warrant>(InstanceManager.getDefault(WarrantManager.class)); 308 break; 309 case ENTRYEXIT: 310 nameBox = new NamedBeanComboBox<DestinationPoints>(InstanceManager.getDefault(EntryExitPairs.class)); 311 break; 312 case AUDIO: 313 nameBox = new NamedBeanComboBox<Audio>(InstanceManager.getDefault(AudioManager.class)); 314 break; 315 default: 316 return null; // Skip any other items. 317 } 318 nameBox.setEditable(false); 319 nameBox.setValidatingInput(false); 320 JComboBoxUtil.setupComboBoxMaxRows(nameBox); 321 return nameBox; 322 } 323 324 /** 325 * The item types. A bundle key for each type is stored with the type to 326 * create a language dependent toString result. 327 */ 328 enum ItemType { 329 NONE("ItemTypeNone"), 330 TURNOUT("BeanNameTurnout"), 331 SENSOR("BeanNameSensor"), 332 LIGHT("BeanNameLight"), 333 SIGNALHEAD("BeanNameSignalHead"), 334 SIGNALMAST("BeanNameSignalMast"), 335 REPORTER("BeanNameReporter"), 336 MEMORY("BeanNameMemory"), 337 ROUTE("BeanNameRoute"), 338 OBLOCK("BeanNameOBlock"), 339 BLOCK("BeanNameBlock"), 340 SECTION("BeanNameSection"), 341 WARRANT("BeanNameWarrant"), 342 ENTRYEXIT("BeanNameEntryExit"), 343 AUDIO("BeanNameAudio"); 344 345 private final String _bundleKey; 346 347 ItemType(String bundleKey) { 348 _bundleKey = bundleKey; 349 } 350 351 @Override 352 public String toString() { 353 return Bundle.getMessage(_bundleKey); 354 } 355 } 356 357 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WhereUsedFrame.class); 358 359}