001package jmri.jmrit.powerpanel;
002
003import java.awt.Color;
004import java.util.List;
005
006import javax.annotation.Nonnull;
007import javax.swing.*;
008
009import jmri.*;
010import jmri.jmrit.catalog.NamedIcon;
011import jmri.swing.PowerManagerMenu;
012
013/**
014 * Pane for power control
015 *
016 * @author Bob Jacobsen Copyright (C) 2001, 2010
017 */
018public class PowerPane extends jmri.util.swing.JmriPanel {
019
020    final jmri.swing.PowerManagerMenu selectMenu;
021    final JPanel contentP;
022    final List<SinglePowerPane> mgrList = new java.util.ArrayList<>();
023
024    /**
025     * Constructor for PowerPane.
026     */
027    public PowerPane() {
028        this(null);
029    }
030
031    public PowerPane(PowerManager initialMgr){
032        contentP = new JPanel();
033        selectMenu = new PowerManagerMenuImpl(initialMgr);
034        contentP.setLayout(new BoxLayout(contentP, BoxLayout.Y_AXIS));
035        add(contentP);
036        PowerPane.this.managerChanged();
037    }
038
039    /**
040     * Add Connection menu to choose which to turn on/off.
041     * @return List of menu items (all active connections)
042     */
043    @Override
044    public List<JMenu> getMenus() {
045        List<JMenu> list = new java.util.ArrayList<>();
046        list.add(selectMenu);
047        return list;
048    }
049
050    @Override
051    public String getHelpTarget() {
052        return "package.jmri.jmrit.powerpanel.PowerPanelFrame";
053    }
054
055    @Override
056    public String getTitle() {
057        var mgr = selectMenu.getManager();
058        return Bundle.getMessage("TitlePowerPanel") + " : " +
059           ( mgr== null ? Bundle.getMessage("AllConnections") : mgr.getUserName());
060    }
061
062    /**
063     * Reset listener and update status.
064     */
065    void managerChanged() {
066        log.debug("manager changed to {}", selectMenu.getManager() );
067
068        mgrList.forEach( SinglePowerPane::dispose);
069        mgrList.clear();
070        contentP.removeAll();
071        var mgr = selectMenu.getManager();
072        if ( mgr != null ){
073            mgrList.add(new SinglePowerPane(mgr));
074        } else {
075            List<PowerManager> managers = InstanceManager.getList(PowerManager.class);
076            for (PowerManager pm : managers) {
077                mgrList.add(new SinglePowerPane(pm));
078            }
079        }
080        for ( SinglePowerPane spp: mgrList){
081            contentP.add(spp);
082        }
083
084        JFrame f = (JFrame)javax.swing.SwingUtilities.windowForComponent(this);
085        if ( f != null ) {
086            f.pack();
087            f.setTitle(this.getTitle());
088        }
089    }
090
091    @Override
092    public void dispose() {
093        mgrList.forEach( SinglePowerPane::dispose);
094    }
095
096    private static final NamedIcon onIcon = new NamedIcon("resources/icons/throttles/power_green.png", "resources/icons/throttles/power_green.png") ;
097    private static final NamedIcon offIcon = new NamedIcon("resources/icons/throttles/power_red.png", "resources/icons/throttles/power_red.png") ;
098    private static final NamedIcon unknownIcon = new NamedIcon("resources/icons/throttles/power_yellow.png", "resources/icons/throttles/power_yellow.png") ;
099
100    class SinglePowerPane extends javax.swing.JPanel implements java.beans.PropertyChangeListener {
101
102        private final PowerManager powerMgr;
103
104        // GUI member declarations
105        private final JLabel onOffStatus = new JLabel(Bundle.getMessage("LabelUnknown"));
106        private final JLabel connLabel = new JLabel(Bundle.getMessage("LabelLayoutPower"));
107        private final JButton onButton = new JButton(Bundle.getMessage("ButtonOn"));
108        private final JButton offButton = new JButton(Bundle.getMessage("ButtonOff"));
109        private final JButton idleButton = new JButton(Bundle.getMessage("ButtonIdle"));
110
111        SinglePowerPane(@Nonnull PowerManager powerManager){
112        
113            super();
114            powerMgr = powerManager;
115
116            // add listeners to buttons
117            onButton.addActionListener(e -> onButtonPushed());
118            offButton.addActionListener(e -> offButtonPushed());
119            idleButton.addActionListener(e -> idleButtonPushed());
120            idleButton.setToolTipText(Bundle.getMessage("ToolTipIdleButton"));
121
122            // general GUI config
123            setLayout(new java.awt.GridLayout((powerMgr.implementsIdle() ? 3 : 2), 2, 3, 5)); // r, c, hgap , vgap
124            var border = BorderFactory.createLineBorder(Color.BLACK, 1);
125            setBorder(BorderFactory.createTitledBorder(border,
126                PowerManagerMenu.getManagerNameIncludeIfDefault(powerMgr)));
127
128            // set minimum size ( for all 6 cells in the layout ) to prevent twitching
129            onOffStatus.setPreferredSize(new java.awt.Dimension(getLabelMinimumWidth(onOffStatus), onButton.getPreferredSize().height+10 ));
130
131            // install items in GUI
132            add(connLabel);
133            add(onButton);
134            add(onOffStatus); // on row 2
135            add(offButton);
136            
137            if ( powerMgr.implementsIdle()) {
138                add(new JLabel("")); // on row 3
139                add(idleButton);
140            }
141            powerMgr.addPropertyChangeListener(SinglePowerPane.this);
142            setStatus();
143        }
144
145        /**
146         * Respond to Power On button pressed.
147         */
148        private void onButtonPushed() {
149            if (mgrOK()) {
150                try {
151                    powerMgr.setPower(PowerManager.ON);
152                } catch (JmriException e) {
153                    couldNotSetPower("Exception trying to turn power on", e);
154                }
155            }
156        }
157
158        /**
159         * Respond to Power Off button pressed.
160         */
161        private void offButtonPushed() {
162            if (mgrOK()) {
163                try {
164                    powerMgr.setPower(PowerManager.OFF);
165                } catch (JmriException e) {
166                    couldNotSetPower("Exception trying to turn power off", e);
167                }
168            }
169        }
170
171        /**
172         * Respond to Power Idle button pressed.
173         */
174        private void idleButtonPushed() {
175            if ( mgrOK() && powerMgr.implementsIdle() ) {
176                try {
177                    powerMgr.setPower(PowerManager.IDLE);
178                } catch (JmriException e) {
179                    couldNotSetPower("Exception trying to set power to idle", e);
180                }
181            }
182        }
183
184        private void couldNotSetPower( String action, JmriException e){
185            log.error("PowerPane {}", action, e);
186            jmri.util.swing.JmriJOptionPane.showMessageDialog(this,
187                powerMgr.getUserName() + System.lineSeparator() +
188                action + System.lineSeparator() + e.getMessage(),
189                action,
190                jmri.util.swing.JmriJOptionPane.ERROR_MESSAGE);
191        }
192
193        /**
194         * Get Minimum width for the current power status JLabel.
195         * @return minimum width
196         */
197        private int getLabelMinimumWidth (JLabel label){
198            String[] bundleStrings = {"StatusIdle", "StatusOn", "StatusOff", "StatusUnknown"};
199            int a= 10;
200            for ( String bs : bundleStrings ) {
201                java.awt.FontMetrics fm = label.getFontMetrics(label.getFont());
202                int wi = fm.stringWidth(Bundle.getMessage(bs))
203                    + onIcon.getIconWidth() + 5;
204                a = Math.max(a, wi);
205            }
206            return a;
207        }
208
209        /**
210         * Display status changes from PowerManager in PowerPane.
211         */
212        private void setStatus() {
213            // Check to see if the Power Manager has a current status
214            if (mgrOK()) {
215                switch (powerMgr.getPower()) {
216                    case PowerManager.ON:
217                        onOffStatus.setText(Bundle.getMessage("StatusOn"));
218                        onOffStatus.setIcon(onIcon);
219                        break;
220                    case PowerManager.OFF:
221                        onOffStatus.setText(Bundle.getMessage("StatusOff"));
222                        onOffStatus.setIcon(offIcon);
223                        break;
224                    case PowerManager.IDLE:
225                        onOffStatus.setText(Bundle.getMessage("StatusIdle"));
226                        onOffStatus.setIcon(unknownIcon);
227                        break;
228                    case PowerManager.UNKNOWN:
229                        onOffStatus.setText(Bundle.getMessage("StatusUnknown"));
230                        onOffStatus.setIcon(unknownIcon);
231                        break;
232                    default:
233                        onOffStatus.setText(Bundle.getMessage("StatusUnknown"));
234                        onOffStatus.setIcon(unknownIcon);
235                        log.error("Unexpected state value: {}", selectMenu.getManager());
236                        break;
237                }
238            }
239        }
240
241        /**
242         * Check for presence of PowerManager.
243         * @return True if one is available, false if not
244         */
245        private boolean mgrOK() {
246            return InstanceManager.getList(PowerManager.class).contains(powerMgr);
247        }
248    
249        @Override
250        public void propertyChange(java.beans.PropertyChangeEvent ev) {
251            setStatus();
252        }
253
254        void dispose() {
255            powerMgr.removePropertyChangeListener(this);
256        }
257        
258    }
259
260    class PowerManagerMenuImpl extends PowerManagerMenu {
261
262        PowerManagerMenuImpl(PowerManager mgr) {
263            super(true, mgr);
264        }
265
266        @Override
267        protected void choiceChanged() {
268            managerChanged();
269        }
270    }
271
272    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PowerPane.class);
273
274}