001package jmri.jmrit.roster; 002 003import java.awt.Component; 004import java.awt.event.ActionEvent; 005import java.io.File; 006import java.util.Objects; 007import javax.swing.Icon; 008import javax.swing.JComboBox; 009import javax.swing.JFileChooser; 010 011import jmri.beans.BeanUtil; 012import jmri.jmrit.roster.rostergroup.RosterGroupSelector; 013import jmri.jmrit.roster.swing.RosterEntryComboBox; 014import jmri.util.swing.JmriJOptionPane; 015import jmri.util.swing.WindowInterface; 016 017/** 018 * Base class for Actions to copy, export and import RosterEntry objects. 019 * <p> 020 * Note that {@link DeleteRosterItemAction} is sufficiently different that it 021 * doesn't use this base class. 022 * 023 * @author Bob Jacobsen Copyright (C) 2001, 2002, 2007, 2008 024 * @see jmri.jmrit.XmlFile 025 */ 026abstract public class AbstractRosterItemAction extends jmri.util.swing.JmriAbstractAction { 027 028 public AbstractRosterItemAction(String pName, Component pWho) { 029 super(pName); 030 mParent = pWho; 031 } 032 033 public AbstractRosterItemAction(String s, WindowInterface wi) { 034 super(s, wi); 035 } 036 037 public AbstractRosterItemAction(String s, Icon i, WindowInterface wi) { 038 super(s, i, wi); 039 } 040 041 Component mParent; 042 043 @Override 044 public void actionPerformed(ActionEvent event) { 045 046 // select the "from" entry/file 047 if (!selectFrom()) { 048 return; 049 } 050 // select the "to" entry/file 051 if (!selectTo()) { 052 return; 053 } 054 // transfer "from" to "to" as needed 055 if (!doTransfer()) { 056 return; 057 } 058 // update roster 059 updateRoster(); 060 } 061 062 protected abstract boolean selectFrom(); 063 064 abstract boolean selectTo(); 065 066 abstract boolean doTransfer(); 067 068 /** 069 * Common, but not unique implementation to add the "To" entry to the Roster 070 * and rewrite the roster file. 071 */ 072 void updateRoster() { 073 addToEntryToRoster(); 074 } 075 076 // variables to communicate the "from" entry, file, etc 077 String mFromID = null; 078 RosterEntry mFromEntry = null; 079 File mFromFile = null; 080 String mFromFilename = null; 081 String mFullFromFilename = null; // includes path to preferences 082 083 // variables to communicate the "to" entry, file, etc. 084 String mToID = null; 085 RosterEntry mToEntry = null; 086 File mToFile = null; 087 String mToFilename = null; 088 String mFullToFilename = null; // includes path to preferences 089 090 boolean selectExistingFromEntry() { 091 // create a dialog to select the roster entry to copy 092 String group = null; 093 if (BeanUtil.hasProperty(wi, RosterGroupSelector.SELECTED_ROSTER_GROUP)) { 094 group = (String) BeanUtil.getProperty(wi, RosterGroupSelector.SELECTED_ROSTER_GROUP); 095 } 096 JComboBox<?> selections = new RosterEntryComboBox(group); 097 int retval = JmriJOptionPane.showOptionDialog(mParent, 098 Bundle.getMessage("CopyEntrySelectDialog"), Bundle.getMessage("CopyEntrySelectDialogTitle"), 099 JmriJOptionPane.DEFAULT_OPTION, JmriJOptionPane.INFORMATION_MESSAGE, null, 100 new Object[]{Bundle.getMessage("ButtonCancel"), Bundle.getMessage("ButtonOK"), selections}, null); 101 log.debug("Dialog value {} selected {}:\"{}\"", retval, selections.getSelectedIndex(), selections.getSelectedItem()); 102 if (retval != 1) { // if not array position 1, ButtonOK 103 return false; // user didn't select 104 } 105 // find the file for the selected entry to copy 106 setExistingEntry((RosterEntry) Objects.requireNonNull(selections.getSelectedItem())); 107 108 return true; 109 } 110 111 /** 112 * Set the roster entry this action acts upon. 113 * 114 * @param mFromEntry the roster entry to act upon 115 */ 116 public void setExistingEntry(RosterEntry mFromEntry) { 117 this.mFromEntry = mFromEntry; 118 mFromFilename = mFromEntry.getFileName(); 119 mFullFromFilename = Roster.getDefault().getRosterFilesLocation() + mFromFilename; 120 log.debug(" from resolves to \"{}\", \"{}\"", mFromFilename, mFullFromFilename); 121 } 122 123 boolean selectNewToEntryID() { 124 do { 125 // prompt for the new ID 126 mToID = JmriJOptionPane.showInputDialog(mParent, Bundle.getMessage("NewEntryDialog"),""); 127 if (mToID == null) { 128 return false; 129 } 130 131 // check for empty 132 if (mToID.isEmpty()) { 133 JmriJOptionPane.showMessageDialog(mParent, Bundle.getMessage("NewEntryEmptyWarn")); 134 // ask again 135 continue; 136 } 137 138 // check for duplicate 139 if (0 == Roster.getDefault().matchingList(null, null, null, null, 140 null, null, mToID).size()) { 141 break; 142 } 143 144 // here it is a duplicate, reprompt 145 JmriJOptionPane.showMessageDialog(mParent, Bundle.getMessage("NewEntryDuplicateWarn")); 146 147 } while (true); 148 return true; 149 } 150 151 javax.swing.JFileChooser fileChooser; 152 153 boolean selectNewFromFile() { 154 if (fileChooser == null) { 155 fileChooser = jmri.jmrit.XmlFile.userFileChooser(); 156 } 157 // refresh fileChooser view of directory, in case it changed 158 fileChooser.rescanCurrentDirectory(); 159 int retVal = fileChooser.showOpenDialog(mParent); 160 161 // handle selection or cancel 162 if (retVal != JFileChooser.APPROVE_OPTION) { 163 return false; // give up if no file selected 164 } 165 // call load to process the file 166 mFromFile = fileChooser.getSelectedFile(); 167 mFromFilename = mFromFile.getName(); 168 mFullFromFilename = mFromFile.getAbsolutePath(); 169 log.debug("New from file: {} at {}", mFromFilename, mFullFromFilename); // NOI18N 170 return true; 171 } 172 173 boolean selectNewToFile() { 174 if (fileChooser == null) { 175 fileChooser = jmri.jmrit.XmlFile.userFileChooser(); 176 } 177 fileChooser.setSelectedFile(new File(mFromFilename)); 178 int retVal = fileChooser.showSaveDialog(mParent); 179 180 // handle selection or cancel 181 if (retVal != JFileChooser.APPROVE_OPTION) { 182 return false; // give up if no file selected 183 } 184 // call load to process the file 185 mToFile = fileChooser.getSelectedFile(); 186 mToFilename = mToFile.getName(); 187 mFullToFilename = mToFile.getAbsolutePath(); 188 log.debug("New to file: {} at {}", mToFilename, mFullToFilename); // NOI18N 189 return true; 190 } 191 192 void addToEntryToRoster() { 193 // add the new entry to the roster & write it out 194 Roster.getDefault().addEntry(mToEntry); 195 Roster.getDefault().writeRoster(); 196 } 197 198 // never invoked, because we overrode actionPerformed above 199 @Override 200 public jmri.util.swing.JmriPanel makePanel() { 201 throw new IllegalArgumentException("Should not be invoked"); 202 } 203 204 // initialize logging 205 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractRosterItemAction.class); 206 207}