001package jmri.jmrix.can.cbus.swing.nodeconfig;
002
003import java.awt.BorderLayout;
004import java.awt.event.ActionListener;
005
006import javax.swing.*;
007import javax.swing.event.TableModelEvent;
008import javax.swing.event.TableModelListener;
009
010import jmri.jmrix.can.cbus.node.CbusNode;
011import jmri.jmrix.can.cbus.node.CbusNodeNVTableDataModel;
012import jmri.jmrix.can.cbus.swing.modules.CbusConfigPaneProvider;
013import jmri.jmrix.can.cbus.swing.modules.UnknownPaneProvider;
014import jmri.util.swing.JmriJOptionPane;
015
016/**
017 *
018 * @author Steve Young Copyright (C) 2019
019 */
020public class CbusNodeEditNVarPane extends CbusNodeConfigTab implements TableModelListener {
021
022    private JTabbedPane tabbedPane;
023    private JPanel infoPane;
024    private CbusNodeNVTableDataModel nodeNVModel;
025    private JButton saveNvButton;
026    private JToggleButton liveUpdateNvButton;
027    private JButton resetNvButton;
028    private JPanel buttonPane;
029    private CbusNodeNVEditTablePane genericNVTable;
030    private CbusNodeNVEditGuiPane editNVGui;
031    private CbusConfigPaneProvider provider;
032
033    private static final int GENERIC = 0;
034    private static final int EDIT = 1;
035
036    /**
037     * Create a new instance of CbusNodeEditNVarPane.
038     * @param main the NodeConfigToolPane this is a component of
039     */
040    protected CbusNodeEditNVarPane( NodeConfigToolPane main ) {
041        super(main);
042        buildPane();
043    }
044
045    /**
046     * {@inheritDoc}
047     */
048    @Override
049    public String getTitle(){
050        return "Node Variables";
051    }
052
053    private void buildPane() {
054        
055        nodeNVModel = new CbusNodeNVTableDataModel(memo, 5,
056        CbusNodeNVTableDataModel.MAX_COLUMN); // controller, row, column
057        nodeNVModel.addTableModelListener(this);
058        
059        infoPane = new JPanel();
060        infoPane.setLayout(new BorderLayout() );
061        
062        saveNvButton = new JButton(Bundle.getMessage("ButtonSave"));
063        saveNvButton.setToolTipText(Bundle.getMessage("SaveNvButtonTt"));
064        
065        liveUpdateNvButton = new JToggleButton(Bundle.getMessage("LiveUpdateNode"));
066        liveUpdateNvButton.setToolTipText(Bundle.getMessage("LiveUpdateNodeTt"));
067        
068        resetNvButton = new JButton(Bundle.getMessage("Reset"));
069        resetNvButton.setToolTipText(Bundle.getMessage("ResetTt"));
070        
071        ActionListener reset = ae -> {
072            cancelOption();
073        };
074        resetNvButton.addActionListener(reset);
075        
076        ActionListener save = ae -> {
077            saveOption();
078        };
079        saveNvButton.addActionListener(save);
080        
081        ActionListener liveUpdate = ae -> {
082            liveUpdateOption();
083        };
084        liveUpdateNvButton.addActionListener(liveUpdate);
085        
086        buttonPane = new JPanel();
087        buttonPane.add(liveUpdateNvButton );
088        buttonPane.add(saveNvButton );
089        buttonPane.add(resetNvButton ); 
090        
091        
092        infoPane.setLayout(new BorderLayout() );
093
094        JPanel nvMenuPane = new JPanel();
095
096        nvMenuPane.add(buttonPane);
097        nvMenuPane.add( new JSeparator(SwingConstants.HORIZONTAL) );
098        
099        genericNVTable = new CbusNodeNVEditTablePane(nodeNVModel);
100        genericNVTable.initComponents(memo);
101        
102        editNVGui = new CbusNodeNVEditGuiPane(nodeNVModel);
103        editNVGui.initComponents(memo);
104        
105        tabbedPane = new JTabbedPane();
106        
107        tabbedPane.addTab(("Generic"), genericNVTable);
108        tabbedPane.addTab(("Edit"), editNVGui);
109        
110        tabbedPane.setEnabledAt(EDIT,false);
111        tabbedPane.setSelectedIndex(GENERIC);
112        
113        infoPane.add(nvMenuPane, BorderLayout.PAGE_START);
114        infoPane.add(tabbedPane, BorderLayout.CENTER);
115        
116        this.add(infoPane);
117        
118    }
119
120    /**
121     * Put the Node into Live Update Mode.
122     * For templates that support this, NV writes are performed immediately.
123     * e.g., for live update of servo position NVs.
124     * Checks if NVs are changed before entering this mode.
125     */
126    protected void liveUpdateOption() {
127        if ( liveUpdateNvButton.isSelected() && areNvsDirty() ) {
128            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("LiveUpdateVeto"),
129                    nodeOfInterest.toString(), JmriJOptionPane.ERROR_MESSAGE);
130            liveUpdateNvButton.setSelected(false);
131            return;
132        }
133        nodeOfInterest.setliveUpdate(liveUpdateNvButton.isSelected());
134    }
135
136    /**
137     * {@inheritDoc}
138     * 
139     * Save button ( only enabled if changed NVs ) clicked.
140     * Show dialogue to save NVs to module.
141     */
142    @Override
143    protected void saveOption(){
144        getMainPane().showConfirmThenSave(nodeNVModel.getChangedNode(),nodeOfInterest,
145            true,false,false, null ); // from, to, nvs, clear events, events, null uses mainpane frame
146    }
147
148    /**
149     * Set the Node and update panes
150     * 
151     * Show the edit GUI if available.
152     * 
153     * @param node the CbusNode of Interest, can be null
154     */
155    @Override
156    public void changedNode( CbusNode node ) {
157        log.debug("setnode {}",nodeOfInterest);
158        
159        nodeNVModel.setNode(nodeOfInterest);
160        setSaveCancelButtonsActive ( false );
161        if (nodeOfInterest.getnvWriteInLearnOnly()) { // perhaps in future change to flag in Config Pane Provider?
162            liveUpdateNvButton.setVisible(true);
163            liveUpdateNvButton.setEnabled(true);
164        } else {
165            liveUpdateNvButton.setVisible(false);
166            liveUpdateNvButton.setEnabled(false);
167        }
168        genericNVTable.setNode( nodeOfInterest );
169
170        provider = CbusConfigPaneProvider.getProviderByNode(nodeOfInterest);
171        editNVGui.setNode(nodeOfInterest, provider);
172
173        if (!(provider instanceof UnknownPaneProvider)) {
174            tabbedPane.setEnabledAt(EDIT, true);
175            tabbedPane.setSelectedIndex(EDIT);
176        } else {
177            tabbedPane.setEnabledAt(EDIT, false);
178            tabbedPane.setSelectedIndex(GENERIC);
179        }
180        
181        validate();
182        repaint();
183        setVisible(true);
184    }
185
186    /**
187     * Get if any NVs are dirty
188     * @return true if NVs have been edited, else false
189     */
190    public boolean areNvsDirty(){
191        log.debug("Table Dirty {}",nodeNVModel.isTableDirty());
192        return nodeNVModel.isTableDirty();
193    }
194
195    /**
196     * Reset edited NVs to original value ( or reset edited NV values if mid-load )
197     * Inform the provider of a the reset
198     */
199    @Override
200    protected void cancelOption(){
201        nodeNVModel.resetNewNvs();
202        editNVGui.setNode(nodeOfInterest);
203    }
204
205    /**
206     * Set the Save / Reset NV button status
207     * 
208     * Save button is always enabled when in live update
209     * 
210     * @param newstate true if buttons should be enabled, else false
211     */
212    public void setSaveCancelButtonsActive ( boolean newstate ) {
213        saveNvButton.setEnabled(newstate);
214        resetNvButton.setEnabled(newstate);
215    }
216
217    /**
218     * Sets save / reset buttons active / inactive depending on table status.
219     * Informs the module provider of a table change
220     * {@inheritDoc}
221     */
222    @Override
223    public void tableChanged(TableModelEvent e) {
224        setSaveCancelButtonsActive( nodeNVModel.isTableDirty() );
225        editNVGui.tableChanged(e);
226    }
227
228    /**
229     * {@inheritDoc}
230     */
231    @Override
232    protected boolean getVetoBeingChanged(){
233        if (areNvsDirty()) {
234            return getCancelSaveEditDialog( Bundle.getMessage("NvsEditUnsaved",nodeOfInterest) );
235        }
236        return false;
237    }
238
239    /**
240     * Removes the NV Model listener from the Node.
241     * 
242     * Also dispose of the edit gui cleanly, take node out of live update mode
243     */
244    @Override
245    public void dispose(){
246        if ( nodeNVModel !=null ) {
247            nodeNVModel.removeTableModelListener(this);
248            nodeNVModel.dispose(); // which does a node setliveUpdate(false)
249        }
250        editNVGui.dispose();
251    }
252
253    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CbusNodeEditNVarPane.class);
254
255}