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