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