001package jmri.jmrit.roster; 002 003import java.awt.Component; 004import java.awt.event.ActionEvent; 005import javax.swing.Icon; 006import javax.swing.JComboBox; 007import javax.swing.JOptionPane; 008import jmri.beans.BeanUtil; 009import jmri.jmrit.roster.rostergroup.RosterGroupSelector; 010import jmri.jmrit.roster.swing.RosterEntryComboBox; 011import jmri.util.FileUtil; 012import jmri.util.swing.JmriAbstractAction; 013import jmri.util.swing.WindowInterface; 014import org.slf4j.Logger; 015import org.slf4j.LoggerFactory; 016 017/** 018 * Remove a locomotive from the roster. 019 * 020 * <p> 021 * In case of error, this moves the definition file to a backup. This action 022 * posts a dialog box to select the loco to be deleted, and then posts an "are 023 * you sure" dialog box before acting. 024 * 025 * @author Bob Jacobsen Copyright (C) 2001, 2002 026 * @see jmri.jmrit.XmlFile 027 */ 028public class DeleteRosterItemAction extends JmriAbstractAction { 029 030 public DeleteRosterItemAction(String s, WindowInterface wi) { 031 super(s, wi); 032 } 033 034 public DeleteRosterItemAction(String s, Icon i, WindowInterface wi) { 035 super(s, i, wi); 036 } 037 038 /** 039 * @param s Name of this action, e.g. in menus 040 * @param who Component that action is associated with, used to ensure 041 * proper position in of dialog boxes 042 */ 043 public DeleteRosterItemAction(String s, Component who) { 044 super(s); 045 _who = who; 046 } 047 Component _who; 048 049 @Override 050 public void actionPerformed(ActionEvent event) { 051 052 Roster roster = Roster.getDefault(); 053 String rosterGroup = Roster.getDefault().getDefaultRosterGroup(); 054 RosterEntry[] entries; 055 // rosterGroup may legitimately be null 056 // but getProperty returns null if the property cannot be found, so 057 // we test that the property exists before attempting to get its value 058 if (BeanUtil.hasProperty(wi, RosterGroupSelector.SELECTED_ROSTER_GROUP)) { 059 rosterGroup = (String) BeanUtil.getProperty(wi, RosterGroupSelector.SELECTED_ROSTER_GROUP); 060 log.debug("selectedRosterGroup was {}", rosterGroup); 061 } 062 if (BeanUtil.hasProperty(wi, "selectedRosterEntries")) { 063 entries = (RosterEntry[]) BeanUtil.getProperty(wi, "selectedRosterEntries"); 064 if (entries != null) { 065 log.debug("selectedRosterEntries found {} entries", entries.length); 066 } else { 067 log.debug("selectedRosterEntries left entries null"); 068 } 069 } else { 070 entries = selectRosterEntry(rosterGroup); 071 if (entries.length > 0 ) { 072 log.debug("selectRosterEntry(rosterGroup) found {} entries", entries.length); 073 } else { 074 log.debug("selectRosterEntry(rosterGroup) found no entries"); 075 } 076 } 077 if (entries == null || entries.length == 0) { 078 return; 079 } 080 // get parent object if there is one 081 //Component parent = null; 082 //if ( event.getSource() instanceof Component) parent = (Component)event.getSource(); 083 084 // find the file for the selected entry 085 for (RosterEntry re : entries) { 086 String filename = roster.fileFromTitle(re.titleString()); 087 String fullFilename = Roster.getDefault().getRosterFilesLocation() + filename; 088 log.debug("resolves to [{}], [{}]", filename, fullFilename); 089 090 // prompt for one last chance 091 log.debug("rosterGroup now {}", rosterGroup); 092 if (rosterGroup == null) { 093 if (!userOK(re.titleString(), filename, fullFilename)) { 094 return; 095 } 096 // delete it from roster 097 roster.removeEntry(re); 098 } else { 099 String group = Roster.getRosterGroupProperty(rosterGroup); 100 log.debug("removing {} group from entry", group); 101 re.deleteAttribute(group); 102 re.updateFile(); 103 } 104 Roster.getDefault().writeRoster(); 105 106 // backup the file & delete it 107 if (rosterGroup == null) { 108 try { 109 // ensure preferences will be found 110 FileUtil.createDirectory(Roster.getDefault().getRosterFilesLocation()); 111 112 // move original file to backup 113 LocoFile df = new LocoFile(); // need a dummy object to do this operation in next line 114 df.makeBackupFile(Roster.getDefault().getRosterFilesLocation() + filename); 115 116 } catch (Exception ex) { 117 log.error("error during locomotive file output", ex); 118 } 119 } 120 } 121 122 } 123 124 protected RosterEntry[] selectRosterEntry(String rosterGroup) { 125 RosterEntry[] entries = new RosterEntry[1]; 126 // create a dialog to select the roster entry 127 JComboBox<?> selections = new RosterEntryComboBox(rosterGroup); 128 int retval = JOptionPane.showOptionDialog(_who, 129 Bundle.getMessage("CopyEntrySelectDialog"), 130 Bundle.getMessage("DeleteEntryTitle roster entry"), 131 JOptionPane.YES_NO_OPTION, 132 JOptionPane.INFORMATION_MESSAGE, 133 null, 134 new Object[] {Bundle.getMessage("ButtonCancel"), Bundle.getMessage("ButtonOK"), selections}, null); 135 log.debug("Dialog value {} selected {}:{}", retval, selections.getSelectedIndex(), selections.getSelectedItem()); // NOI18N 136 if (retval != 1) { 137 return entries; // empty 138 } 139 entries[0] = (RosterEntry) selections.getSelectedItem(); 140 return entries; 141 } 142 143 /** 144 * Can provide some mechanism to prompt for user for one last chance to 145 * change his/her mind. 146 * 147 * @param entry Roster entry being operated on 148 * @param filename Just name of file 149 * @param fullFileName including path 150 * @return true if user says to continue 151 */ 152 boolean userOK(String entry, String filename, String fullFileName) { 153 return (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(_who, 154 Bundle.getMessage("DeletePrompt", entry, fullFileName), 155 Bundle.getMessage("DeleteTitle", entry), 156 JOptionPane.YES_NO_OPTION)); 157 } 158 159 // never invoked, because we overrode actionPerformed above 160 @Override 161 public jmri.util.swing.JmriPanel makePanel() { 162 throw new IllegalArgumentException("Should not be invoked"); 163 } 164 165 // initialize logging 166 private final static Logger log = LoggerFactory.getLogger(DeleteRosterItemAction.class); 167 168}