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