001package jmri.jmrix.can.cbus.swing.modules; 002 003import java.util.*; 004 005import javax.annotation.CheckForNull; 006import javax.annotation.Nonnull; 007 008import jmri.jmrix.can.cbus.node.CbusNode; 009import jmri.jmrix.can.cbus.node.CbusNodeNVTableDataModel; 010import jmri.spi.JmriServiceProviderInterface; 011 012import org.slf4j.Logger; 013import org.slf4j.LoggerFactory; 014 015 016/** 017 * Pane for configuring events in a CBUS module 018 * 019 * Definition of objects to handle configuring a CBUS module. 020 * 021 * Implementing classes <em>must</em> be registered as service providers of this 022 * type to be recognized and usable. 023 * <p> 024 * General design documentation is available on the 025 * <a href="http://jmri.org/help/en/html/doc/Technical/SystemStructure.shtml">Structure of External System Connections page</a>. 026 * 027 * @author Andrew Crosland Copyright (C) 2021 028 * @see java.util.ServiceLoader 029 */ 030public abstract class CbusConfigPaneProvider extends jmri.jmrix.can.swing.CanPanel implements JmriServiceProviderInterface { 031 032 protected CbusConfigPaneProvider() { 033 super(); 034 } 035 036 /** 037 * Get the manufacturer name for the class 038 * 039 * @return the manufacturer 040 */ 041 @Nonnull 042 abstract public String getModuleType(); 043 044 /** 045 * Get descriptive name of NV 046 * 047 * @param index of the NV 048 * @return the name as String. May be empty string if NV description is unknown 049 * or null if index is out of range 050 */ 051 abstract public String getNVNameByIndex(int index); 052 053 protected AbstractEditNVPane _nVarEditFrame = null; 054 055 /** 056 * Get the edit frame instance 057 * @return the edit frame 058 */ 059 abstract public AbstractEditNVPane getEditNVFrameInstance(); 060 061 /** 062 * Create a new edit frame 063 * 064 * @param editFrame the containing frame 065 * @param node the node to be edited 066 * @return the edit frame 067 */ 068 abstract public AbstractEditNVPane getEditNVFrame(CbusNodeNVTableDataModel editFrame, CbusNode node); 069 070 /** 071 * Return string representation of the node 072 * 073 * @return name of object 074 */ 075 @Override 076 final public String toString() { 077 return getModuleType(); 078 } 079 080 /** 081 * Get a module provider from a module name 082 * 083 * @param name of the module 084 * @return the module provider, null if not known 085 */ 086 @CheckForNull 087 final static public CbusConfigPaneProvider getProviderByName(String name) { 088 loadInstances(); 089 CbusConfigPaneProvider p = instanceMap.get(name); 090 return p; 091 } 092 093 /** 094 * Get a module provider from a CBUS node 095 * 096 * @param node the node instance 097 * @return the module provider 098 */ 099 final static public CbusConfigPaneProvider getProviderByNode(CbusNode node) { 100 loadInstances(); 101 CbusConfigPaneProvider p = instanceMap.get(node.getName()); 102 if (p != null) { 103 return p; 104 } else if (node.getResyncName() != null) { 105 // Get the saved name during a resync 106 p = instanceMap.get(node.getResyncName()); 107 if (p != null) { 108 return p; 109 } 110 } 111 jmri.util.LoggingUtil.infoOnce(log,"node gets unknown provider: {}", node); 112 return new UnknownPaneProvider(); 113 } 114 115 /** 116 * Get all available instances as an {@link Collections#unmodifiableMap} 117 * between the (localized) name and the pane. Note that this is a SortedMap in 118 * name order. 119 * 120 * @return all instance map sorted in name order. 121 */ 122 final static public Map<String, CbusConfigPaneProvider> getInstancesMap() { 123 loadInstances(); 124 return Collections.unmodifiableMap(instanceMap); 125 } 126 127 /** 128 * Get all available instances as an {@link Collections#unmodifiableCollection} 129 * between the (localized) name and the pane. 130 * 131 * @return unmodifiable collection. 132 */ 133 final static public Collection<CbusConfigPaneProvider> getInstancesCollection() { 134 loadInstances(); 135 return Collections.unmodifiableCollection(instanceMap.values()); 136 } 137 138 /** 139 * Load all the available instances. Note this only runs 140 * once; there's no reloading once the program is running. 141 */ 142 final static public void loadInstances() { 143 if (instanceMap != null) return; 144 145 instanceMap = new TreeMap<>(); // sorted map, in string order on key 146 147 java.util.ServiceLoader.load(CbusConfigPaneProvider.class).forEach((pane) -> { 148 if (!instanceMap.containsKey(pane.getModuleType())) { 149 instanceMap.put(pane.getModuleType(), pane); 150 } 151 }); 152 153 } 154 155 static volatile Map<String, CbusConfigPaneProvider> instanceMap = null; 156 157 private final static Logger log = LoggerFactory.getLogger(CbusConfigPaneProvider.class); 158}