001package jmri.jmrit.catalog; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004 005import java.util.Set; 006 007import javax.annotation.Nonnull; 008import javax.annotation.CheckForNull; 009 010import jmri.*; 011import jmri.implementation.AbstractInstanceInitializer; 012import jmri.implementation.swing.SwingShutDownTask; 013import jmri.jmrit.catalog.configurexml.DefaultCatalogTreeManagerXml; 014import jmri.jmrix.internal.InternalSystemConnectionMemo; 015import jmri.managers.AbstractManager; 016 017import org.openide.util.lookup.ServiceProvider; 018import org.slf4j.Logger; 019import org.slf4j.LoggerFactory; 020 021/** 022 * Provide the concrete implementation for the Internal CatalogTree Manager. 023 * <p> 024 * Control of the systemName is internal so the more casual approach like that of 025 * SignalHeadManager is used rather than the ProxyManager style. 026 * 027 * @author Pete Cressman Copyright (C) 2009 028 */ 029public class DefaultCatalogTreeManager extends AbstractManager<CatalogTree> implements CatalogTreeManager { 030 031 private boolean _indexChanged = false; 032 private boolean _indexLoaded = false; 033 private ShutDownTask _shutDownTask; 034 035 public DefaultCatalogTreeManager() { 036 super(InstanceManager.getDefault(InternalSystemConnectionMemo.class)); 037 } 038 039 /** 040 * Override parent method to not register this object to be stored 041 * automatically as part of the general storage mechanism. 042 */ 043 @Override 044 @SuppressFBWarnings(value = "OVERRIDING_METHODS_MUST_INVOKE_SUPER", 045 justification = "This method intentionally doesn't register anything") 046 protected void registerSelf() { 047 log.debug("not registering"); 048 } 049 050 @Override 051 public int getXMLOrder() { 052 return 65400; 053 } 054 055 /** 056 * Bogus typeLetter 057 */ 058 @Override 059 public char typeLetter() { 060 return '0'; 061 } 062 063 @CheckForNull 064 @Override 065 public CatalogTree getCatalogTree(@Nonnull String name) { 066 CatalogTree t = getByUserName(name); 067 return (t != null ? t : getBySystemName(name)); 068 } 069 070 @CheckForNull 071 @Override 072 public CatalogTree getBySystemName(@Nonnull String key) { 073 if (log.isDebugEnabled()) { 074 log.debug("getBySystemName: systemName= {}", key); 075 CatalogTree tree = _tsys.get(key); 076 if (tree != null) { 077 CatalogTreeNode root = tree.getRoot(); 078 log.debug("root= {}, has {} children", root,root.getChildCount()); 079 } 080 } 081 return _tsys.get(key); 082 } 083 084 @CheckForNull 085 @Override 086 public CatalogTree getByUserName(@Nonnull String key) { 087 return _tuser.get(key); 088 } 089 090 /** 091 * Provide CatalogTree by UserName, then SystemName, then creates if not found. 092 * {@inheritDoc} 093 */ 094 @Override 095 @Nonnull 096 public CatalogTree newCatalogTree(@Nonnull String systemName, String userName) throws IllegalArgumentException { 097 log.debug("new CatalogTree: systemName= {}, userName= {}", systemName, userName); 098 if (systemName.isEmpty()) { 099 throw new IllegalArgumentException("Empty systemName!"); 100 } 101 // return existing if there is one 102 CatalogTree t; 103 if (userName != null) { 104 t = getByUserName(userName); 105 if (t != null) { 106 if (getBySystemName(systemName) != t) { 107 log.error("inconsistent user ({}) and system name ({}) results; userName related to ({})", 108 userName, systemName, t.getSystemName()); 109 } 110 return t; 111 } 112 } 113 t = getBySystemName(systemName); 114 if (t != null) { 115 if ((t.getUserName() == null) && (userName != null)) { 116 t.setUserName(userName); 117 } else if (userName != null) { 118 log.warn("Found memory via system name ({}) with non-null userName ({})", 119 systemName, userName); 120 } 121 return t; 122 } 123 // doesn't exist, make a new one 124 t = createNewCatalogTree(systemName, userName); 125 // save in the maps 126 register(t); 127 return t; 128 } 129 130 /** 131 * Create a CatalogTree. 132 * <p> 133 * Naming convention is: 134 * <pre> 135 * IF... - filter for image files from the file system 136 * SF... - filter for sound files from the file system 137 * TF... - filter for script files from the file system 138 * NF... - no filter for files from the file system 139 * IX... - index for image files stored in XML config file 140 * SX... - index for sound files stored in XML config file 141 * TX... - index for script files stored in XML config file 142 * NX... - index for files stored in XML config file 143 * </pre> 144 * 145 * @param systemName system name for catalog tree, never null/empty 146 * @param userName user name for catalog tree 147 * @return the new catalog tree or 148 * @throws IllegalArgumentException if unable to create 149 */ 150 @Nonnull 151 protected CatalogTree createNewCatalogTree(@Nonnull String systemName, String userName) throws IllegalArgumentException { 152 if (systemName.isEmpty()) { 153 throw new IllegalArgumentException("Empty systemName!"); 154 } 155 if (userName == null || userName.isEmpty()) { 156 throw new IllegalArgumentException("Null or empty userName!"); 157 } 158 if (systemName.charAt(1) == CatalogTree.XML) { 159 switch (systemName.charAt(0)) { 160 case CatalogTree.IMAGE: 161 case CatalogTree.SOUND: 162 case CatalogTree.SCRIPT: 163 case CatalogTree.NOFILTER: 164 return new CatalogTreeIndex(systemName, userName); 165 default: 166 log.error("Bad systemName: {} (userName= {})", systemName, userName); 167 } 168 } else if (systemName.charAt(1) == CatalogTree.FILESYS) { 169 CatalogTreeFS catTree; 170 switch (systemName.charAt(0)) { 171 case CatalogTree.IMAGE: 172 catTree = new CatalogTreeFS(systemName, userName); 173 catTree.setFilter(IMAGE_FILTER); 174 return catTree; 175 case CatalogTree.SOUND: 176 catTree = new CatalogTreeFS(systemName, userName); 177 catTree.setFilter(SOUND_FILTER); 178 return catTree; 179 case CatalogTree.SCRIPT: 180 catTree = new CatalogTreeFS(systemName, userName); 181 catTree.setFilter(SCRIPT_FILTER); 182 return catTree; 183 case CatalogTree.NOFILTER: 184 return new CatalogTreeFS(systemName, userName); 185 default: 186 log.error("Bad systemName: {} (userName= {})", systemName, userName); 187 } 188 } 189 throw new IllegalArgumentException("systemName.charAt not XML or FILESYS !"); 190 } 191 192 @Override 193 @Nonnull 194 public String getBeanTypeHandled(boolean plural) { 195 return Bundle.getMessage(plural ? "BeanNameCatalogs" : "BeanNameCatalog"); 196 } 197 198 /** 199 * {@inheritDoc} 200 */ 201 @Override 202 public Class<CatalogTree> getNamedBeanClass() { 203 return CatalogTree.class; 204 } 205 206 /** 207 * {@inheritDoc} 208 */ 209 @Override 210 public void storeImageIndex() { 211 jmri.jmrit.display.palette.ItemPalette.storeIcons(); 212 213 log.debug("Start writing CatalogTree info"); 214 try { 215 new DefaultCatalogTreeManagerXml().writeCatalogTrees(); 216 indexChanged(false); 217 } catch (java.io.IOException ioe) { 218 log.error("Exception writing CatalogTrees: ", ioe); 219 } 220 } 221 222 /** 223 * Load the index file, one time per session. 224 */ 225 @Override 226 public void loadImageIndex() { 227 if (!isIndexLoaded()) { 228 new DefaultCatalogTreeManagerXml().readCatalogTrees(); 229 _indexLoaded = true; 230 log.debug("loadImageIndex: catalog file loaded"); 231 } 232 } 233 234 /** 235 * {@inheritDoc} 236 */ 237 @Override 238 public boolean isIndexChanged() { 239 return _indexChanged; 240 } 241 242 /** 243 * {@inheritDoc} 244 */ 245 @Override 246 public boolean isIndexLoaded() { 247 return _indexLoaded; 248 } 249 250 /** 251 * {@inheritDoc} 252 */ 253 @Override 254 public final synchronized void indexChanged(boolean changed) { 255 _indexChanged = changed; 256 ShutDownManager sdm = InstanceManager.getDefault(ShutDownManager.class); 257 if (changed) { 258 if (_shutDownTask == null) { 259 _shutDownTask = new SwingShutDownTask("PanelPro Save default icon check", 260 Bundle.getMessage("IndexChanged"), 261 Bundle.getMessage("SaveAndQuit"), null) { 262 @Override 263 public boolean checkPromptNeeded() { 264 return !_indexChanged; 265 } 266 267 @Override 268 public void didPrompt() { 269 storeImageIndex(); 270 } 271 }; 272 sdm.register(_shutDownTask); 273 } 274 } else if (_shutDownTask != null) { 275 sdm.deregister(_shutDownTask); 276 _shutDownTask = null; 277 } 278 } 279 280 private static final Logger log = LoggerFactory.getLogger(DefaultCatalogTreeManager.class); 281 282 @ServiceProvider(service = InstanceInitializer.class) 283 public static class Initializer extends AbstractInstanceInitializer { 284 285 @Override 286 @Nonnull 287 public <T> Object getDefault(Class<T> type) { 288 if (type.equals(CatalogTreeManager.class)) { 289 return new DefaultCatalogTreeManager(); 290 } 291 return super.getDefault(type); 292 } 293 294 @Override 295 @Nonnull 296 public Set<Class<?>> getInitalizes() { 297 Set<Class<?>> set = super.getInitalizes(); 298 set.add(CatalogTreeManager.class); 299 return set; 300 } 301 302 } 303 304}