001package apps; 002 003import java.text.MessageFormat; 004import java.util.ArrayList; 005import java.util.HashMap; 006import java.util.List; 007import java.util.Map; 008import java.util.ResourceBundle; 009import javax.swing.JLabel; 010import jmri.Application; 011import jmri.ConfigureManager; 012import jmri.InstanceManager; 013import jmri.ShutDownManager; 014import jmri.UserPreferencesManager; 015import jmri.jmrix.ConnectionConfig; 016import jmri.jmrix.ConnectionConfigManager; 017import jmri.jmrix.JmrixConfigPane; 018import jmri.swing.ManagingPreferencesPanel; 019import jmri.swing.PreferencesPanel; 020import jmri.util.swing.JmriPanel; 021import jmri.util.swing.JmriJOptionPane; 022 023/** 024 * Basic configuration infrastructure, to be used by specific GUI 025 * implementations 026 * 027 * @author Bob Jacobsen Copyright (C) 2003, 2008, 2010 028 * @author Matthew Harris copyright (c) 2009 029 * @author Ken Cameron Copyright (C) 2011 030 */ 031public class AppConfigBase extends JmriPanel { 032 033 /** 034 * All preferences panels handled, whether persisted or not. 035 */ 036 protected HashMap<String, PreferencesPanel> preferencesPanels = new HashMap<>(); 037 038 protected static final ResourceBundle rb = ResourceBundle.getBundle("apps.AppsConfigBundle"); 039 040 /** 041 * Construct a configuration panel for inclusion in a preferences or 042 * configuration dialog with default number of connections. 043 */ 044 public AppConfigBase() { 045 } 046 047 /** 048 * Detect duplicate connection types It depends on all connections have the 049 * first word be the same if they share the same type. So LocoNet ... is a 050 * fine example. 051 * <p> 052 * This also was broken when the names for systems were updated before JMRI 053 * 2.9.4, so it should be revisited. 054 * 055 * @return true if OK, false if duplicates present. 056 */ 057 private boolean checkDups() { 058 Map<String, List<ConnectionConfig>> ports = new HashMap<>(); 059 ConnectionConfig[] connections = InstanceManager.getDefault(ConnectionConfigManager.class).getConnections(); 060 for (ConnectionConfig connection : connections) { 061 if (!connection.getDisabled()) { 062 String port = connection.getInfo(); 063 if (!port.equals(JmrixConfigPane.NONE)) { 064 if (!ports.containsKey(port)) { 065 List<ConnectionConfig> arg1 = new ArrayList<>(); 066 arg1.add(connection); 067 ports.put(port, arg1); 068 } else { 069 ports.get(port).add(connection); 070 } 071 } 072 } 073 } 074 boolean ret = true; 075 /* one or more dups or NONE, lets see if it is dups */ 076 for (Map.Entry<String, List<ConnectionConfig>> e : ports.entrySet()) { 077 if (e.getValue().size() > 1) { 078 /* dup port found */ 079 ret = false; 080 StringBuilder nameB = new StringBuilder(); 081 for (int n = 0; n < e.getValue().size(); n++) { 082 nameB.append(e.getValue().get(n).getManufacturer()); 083 nameB.append("|"); 084 } 085 String instanceNames = new String(nameB); 086 instanceNames = instanceNames.substring(0, instanceNames.lastIndexOf("|")); 087 instanceNames = instanceNames.replaceAll("[|]", ", "); 088 log.error("Duplicate ports found on: {} for port: {}", instanceNames, e.getKey()); 089 } 090 } 091 return ret; 092 } 093 094 /** 095 * Checks to see if user selected a valid serial port 096 * 097 * @return true if okay 098 */ 099 private boolean checkPortNames() { 100 for (ConnectionConfig connection : InstanceManager.getDefault(ConnectionConfigManager.class).getConnections()) { 101 String port = connection.getInfo(); 102 if (port.equals(JmrixConfigPane.NONE_SELECTED) || port.equals(JmrixConfigPane.NO_PORTS_FOUND)) { 103 if (JmriJOptionPane.YES_OPTION != JmriJOptionPane.showConfirmDialog( 104 null, 105 MessageFormat.format(rb.getString("MessageSerialPortWarning"), new Object[]{port, connection.getConnectionName()}), 106 rb.getString("MessageSerialPortNotValid"), 107 JmriJOptionPane.YES_NO_OPTION, 108 JmriJOptionPane.ERROR_MESSAGE)) { 109 return false; 110 } 111 } 112 } 113 return true; 114 } 115 116 @Override 117 public void dispose() { 118 this.preferencesPanels.clear(); 119 } 120 121 public void saveContents() { 122 // remove old prefs that are registered in ConfigManager 123 ConfigureManager cm = InstanceManager.getNullableDefault(jmri.ConfigureManager.class); 124 if (cm != null) { 125 cm.removePrefItems(); 126 } 127 // put the new GUI managedPreferences on the persistance list 128 this.getPreferencesPanels().values().stream().forEach((panel) -> { 129 this.registerWithConfigureManager(panel); 130 }); 131 if (cm != null) { 132 cm.storePrefs(); 133 } 134 } 135 136 private void registerWithConfigureManager(PreferencesPanel panel) { 137 if (panel.isPersistant()) { 138 ConfigureManager cm = InstanceManager.getNullableDefault(jmri.ConfigureManager.class); 139 if (cm != null) { 140 cm.registerPref(panel); 141 } 142 } 143 if (panel instanceof ManagingPreferencesPanel) { 144 log.debug("Iterating over managed panels within {}/{}", panel.getPreferencesItemText(), panel.getTabbedPreferencesTitle()); 145 ((ManagingPreferencesPanel) panel).getPreferencesPanels().stream().forEach((managed) -> { 146 log.debug("Registering {} with the ConfigureManager", managed.getClass().getName()); 147 this.registerWithConfigureManager(managed); 148 }); 149 } 150 } 151 152 /** 153 * Handle the Save button: Backup the file, write a new one, prompt for what 154 * to do next. To do that, the last step is to present a dialog box 155 * prompting the user to end the program, if required. 156 * 157 * @param restartRequired true if JMRI should prompt user to restart 158 */ 159 public void savePressed(boolean restartRequired) { 160 // true if port name OK 161 if (!checkPortNames()) { 162 return; 163 } 164 // true if there arn't any duplicates 165 if (!checkDups()) { 166 if (!(JmriJOptionPane.showConfirmDialog(null, rb.getString("MessageLongDupsWarning"), 167 rb.getString("MessageShortDupsWarning"), JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION)) { 168 return; 169 } 170 } 171 saveContents(); 172 final UserPreferencesManager p; 173 p = InstanceManager.getDefault(UserPreferencesManager.class); 174 p.resetChangeMade(); 175 if (restartRequired && !InstanceManager.getDefault(ShutDownManager.class).isShuttingDown()) { 176 JLabel question = new JLabel(MessageFormat.format(rb.getString("MessageLongQuitWarning"), Application.getApplicationName())); 177 Object[] options = {rb.getString("RestartNow"), rb.getString("RestartLater")}; 178 int retVal = JmriJOptionPane.showOptionDialog(this, 179 question, 180 MessageFormat.format(rb.getString("MessageShortQuitWarning"), Application.getApplicationName()), 181 JmriJOptionPane.DEFAULT_OPTION, 182 JmriJOptionPane.QUESTION_MESSAGE, 183 null, 184 options, 185 null); 186 switch (retVal) { 187 case 0: // array position 0, restart Now 188 dispose(); 189 Apps.handleRestart(); 190 break; 191 default: 192 break; 193 } 194 } 195 // don't restart the program, just close the window 196 if (getTopLevelAncestor() != null) { 197 getTopLevelAncestor().setVisible(false); 198 } 199 } 200 201 public String getClassDescription() { 202 return rb.getString("Application"); 203 } 204 205 public String getClassName() { 206 return AppConfigBase.class.getName(); 207 } 208 209 /** 210 * @return the preferencesPanels 211 */ 212 public HashMap<String, PreferencesPanel> getPreferencesPanels() { 213 return preferencesPanels; 214 } 215 216 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AppConfigBase.class); 217 218}