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