001package jmri.jmrit.progsupport; 002 003import java.awt.event.ActionListener; 004import java.beans.PropertyChangeListener; 005import java.util.*; 006 007import javax.annotation.Nonnull; 008import javax.swing.*; 009 010import org.slf4j.Logger; 011import org.slf4j.LoggerFactory; 012 013import jmri.*; 014 015/** 016 * Provide a JPanel to configure the service mode (Global) programmer. 017 * <p> 018 * The using code should get a configured programmer with getProgrammer. Since 019 * there's only one service mode programmer, maybe this isn't critical, but it's 020 * a good idea for the future. 021 * <p> 022 * A ProgModePane may "share" between one of these and a ProgOpsModePane, which 023 * means that there might be _none_ of these buttons selected. When that 024 * happens, the mode of the underlying programmer is left unchanged and no 025 * message is propagated. 026 * <p> 027 * Note that you should call the dispose() method when you're really done, so 028 * that a ProgModePane object can disconnect its listeners. 029 * <hr> 030 * This file is part of JMRI. 031 * <p> 032 * JMRI is free software; you can redistribute it and/or modify it under the 033 * terms of version 2 of the GNU General Public License as published by the Free 034 * Software Foundation. See the "COPYING" file for a copy of this license. 035 * <p> 036 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 037 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 038 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 039 * 040 * @author Bob Jacobsen Copyright (C) 2001, 2014 041 * @author Daniel Bergqvist Copyright (C) 2021 042 */ 043public class ProgServiceModePane extends ProgModeSelector implements PropertyChangeListener, ActionListener { 044 045 ButtonGroup modeGroup = new ButtonGroup(); 046 HashMap<ProgrammingMode, JRadioButton> buttonMap = new HashMap<>(); 047 JComboBox<GlobalProgrammerManager> progBox; 048 ArrayList<JRadioButton> buttonPool = new ArrayList<>(); 049 050 /** 051 * Get the selected programmer 052 */ 053 @Override 054 public Programmer getProgrammer() { 055 if (progBox.getSelectedItem() == null) { 056 return null; 057 } 058 return ((GlobalProgrammerManager) progBox.getSelectedItem()).getGlobalProgrammer(); 059 } 060 061 /** 062 * Are any of the modes selected? 063 * 064 * @return true is any button is selected 065 */ 066 @Override 067 public boolean isSelected() { 068 for (JRadioButton button : buttonMap.values()) { 069 if (button.isSelected()) { 070 return true; 071 } 072 } 073 return false; 074 } 075 076 /** 077 * @param direction controls layout, either BoxLayout.X_AXIS or 078 * BoxLayout.Y_AXIS 079 */ 080 public ProgServiceModePane(int direction) { 081 this(direction, new javax.swing.ButtonGroup()); 082 } 083 084 /** 085 * Get the list of global managers. 086 * 087 * @return empty list if none 088 */ 089 @Nonnull 090 public List<GlobalProgrammerManager> getMgrList() { 091 return InstanceManager.getList(jmri.GlobalProgrammerManager.class); 092 } 093 094 /** 095 * Create a new Programmer Service Mode Pane. 096 * @param direction controls layout, either BoxLayout.X_AXIS or 097 * BoxLayout.Y_AXIS 098 * @param group mode button group. 099 */ 100 public ProgServiceModePane(int direction, javax.swing.ButtonGroup group) { 101 modeGroup = group; 102 103 // general GUI config 104 setLayout(new BoxLayout(this, direction)); 105 106 // create the programmer display combo box 107 java.util.List<GlobalProgrammerManager> v = new java.util.ArrayList<>(); 108 for (GlobalProgrammerManager pm : getMgrList()) { 109 Programmer progrmr = pm.getGlobalProgrammer(); 110 if (progrmr!=null) { 111 v.add(pm); 112 // listen for changes 113 progrmr.addPropertyChangeListener(this); 114 } 115 } 116 117 add(progBox = new JComboBox<>(v.toArray(new GlobalProgrammerManager[0]))); 118 // if only one, don't show 119 if (progBox.getItemCount() < 2) { 120 // no choice, so don't display, don't monitor for changes 121 progBox.setVisible(false); 122 } else { 123 log.debug("Set combobox box selection to InstanceManager global default: {}", InstanceManager.getDefault(jmri.GlobalProgrammerManager.class)); 124 progBox.setSelectedItem(InstanceManager.getDefault(jmri.GlobalProgrammerManager.class)); // set default 125 progBox.addActionListener((java.awt.event.ActionEvent e) -> { 126 // new programmer selection 127 programmerSelected(); 128 }); 129 } 130 131 // Horizontal glue is needed since the panel is too narrow otherwise 132 add(javax.swing.Box.createHorizontalGlue()); 133 134 // and execute the setup for 1st time 135 programmerSelected(); 136 137 } 138 139 /** 140 * reload the interface with the new programmers 141 */ 142 void programmerSelected() { 143 log.debug("programmerSelected starts with {} buttons", buttonPool.size()); 144 // hide buttons 145 for (JRadioButton button : buttonPool) { 146 button.setVisible(false); 147 } 148 149 // clear map 150 buttonMap.clear(); 151 152 // configure buttons 153 int index = 0; 154 if (getProgrammer() == null) { 155 return; 156 } 157 List<ProgrammingMode> modes = getProgrammer().getSupportedModes(); 158 log.debug(" has {} modes", modes.size()); 159 for (ProgrammingMode mode : modes) { 160 JRadioButton button; 161 // need a new button? 162 if (index >= buttonPool.size()) { 163 log.debug(" add button"); 164 button = new JRadioButton(); 165 buttonPool.add(button); 166 modeGroup.add(button); 167 button.addActionListener(this); 168 add(button); // add to GUI 169 } 170 // configure next button in pool 171 log.debug(" set for {}", mode.toString()); 172 button = buttonPool.get(index++); 173 button.setVisible(true); 174 modeGroup.add(button); 175 button.setText(mode.toString()); 176 buttonMap.put(mode, button); 177 } 178 setGuiFromProgrammer(); 179 } 180 181 /** 182 * Listen to buttons for mode changes 183 */ 184 @Override 185 public void actionPerformed(java.awt.event.ActionEvent e) { 186 // find selected button 187 log.debug("Selected button: {}", e.getActionCommand()); 188 for (ProgrammingMode mode : buttonMap.keySet()) { 189 if (mode.toString().equals(e.getActionCommand())) { 190 log.debug(" set mode {} on {}", mode.toString(), getProgrammer()); 191 getProgrammer().setMode(mode); 192 return; // 1st match 193 } 194 } 195 } 196 197 /** 198 * Listen to programmer for mode changes 199 */ 200 @Override 201 public void propertyChange(java.beans.PropertyChangeEvent e) { 202 if ("Mode".equals(e.getPropertyName()) && getProgrammer().equals(e.getSource())) { 203 // mode changed in programmer, change GUI here if needed 204 log.debug("Mode propertyChange with {}", isSelected()); 205 if (isSelected()) { // only change mode if we have a selected mode, in case some other selector with shared group has the selection 206 setGuiFromProgrammer(); 207 } 208 } 209 } 210 211 void setGuiFromProgrammer() { 212 ProgrammingMode mode = getProgrammer().getMode(); 213 JRadioButton button = buttonMap.get(mode); 214 log.debug(" setting button for mode {}", mode); 215 if (button == null) { 216 log.debug(" didn't find button, returning"); 217 return; 218 } 219 button.setSelected(true); 220 } 221 222 // no longer needed, disconnect if still connected 223 @Override 224 public void dispose() { 225 for (GlobalProgrammerManager pm : getMgrList()) { 226 Programmer gp = pm.getGlobalProgrammer(); 227 if (gp != null) { 228 gp.removePropertyChangeListener(this); 229 } 230 } 231 } 232 233 private final static Logger log = LoggerFactory.getLogger(ProgServiceModePane.class); 234}