001package jmri.jmrit.throttle;
002
003import java.awt.*;
004import java.awt.event.ActionEvent;
005import java.awt.event.ActionListener;
006import java.io.File;
007import java.io.IOException;
008
009import javax.swing.*;
010
011import jmri.InstanceManager;
012import jmri.util.swing.JmriJOptionPane;
013
014import org.jdom2.Element;
015import org.jdom2.JDOMException;
016
017/**
018 * A preferences panel to display and edit JMRI throttle preferences
019 * 
020 * @author Lionel Jeanson - 2009 - 2021
021 * 
022 */
023public class ThrottlesPreferencesUISettingsPane extends JPanel {
024
025    private JCheckBox cbUseToolBar;
026    private JCheckBox cbUseFunctionIcon;
027    private JCheckBox cbUseLargeSpeedSlider;
028    private JCheckBox cbResizeWinImg;
029    private JCheckBox cbUseExThrottle;
030    private JCheckBox cbUseRosterImage;
031    private JCheckBox cbEnableRosterSearch;
032    private JCheckBox cbEnableAutoLoad;
033    private JCheckBox cbHideUndefinedButtons;
034    private JCheckBox cbHideSpeedSelector;
035    private JCheckBox cbIgnoreThrottlePosition;
036    private JCheckBox cbSaveThrottleOnLayoutSave;
037    private JCheckBox cbSilentSteal;
038    private JCheckBox cbSilentShare;
039    private JTextField tfDefaultThrottleLocation;
040    private boolean isDirty = false;
041
042    /**
043     * Creates new form ThrottlesPreferencesPane
044     * @param tp the throttle preferences to init the component
045     */
046    public ThrottlesPreferencesUISettingsPane(ThrottlesPreferences tp) {
047        initComponents();
048        resetComponents(tp);
049        checkConsistancy();
050    }
051
052    private void initComponents() {
053
054        cbUseExThrottle = new JCheckBox();
055        cbUseToolBar = new JCheckBox();
056        cbUseFunctionIcon = new JCheckBox();
057        cbUseLargeSpeedSlider = new JCheckBox();
058        cbUseRosterImage = new JCheckBox();
059        cbResizeWinImg = new JCheckBox();
060        cbEnableRosterSearch = new JCheckBox();
061        cbEnableAutoLoad = new JCheckBox();
062        cbHideUndefinedButtons = new JCheckBox();
063        cbHideSpeedSelector = new JCheckBox();
064        cbIgnoreThrottlePosition = new JCheckBox();
065        cbSaveThrottleOnLayoutSave = new JCheckBox();
066        cbSilentSteal = new JCheckBox();
067        cbSilentShare = new JCheckBox();
068        tfDefaultThrottleLocation = new JTextField();
069
070        cbUseExThrottle.setText(Bundle.getMessage("UseExThrottle"));
071        cbResizeWinImg.setText(Bundle.getMessage("ExThrottleForceResize"));
072        cbUseToolBar.setText(Bundle.getMessage("ExThrottleUseToolBar"));
073        cbUseFunctionIcon.setText(Bundle.getMessage("ExThrottleUseFunctionIcons"));
074        cbUseLargeSpeedSlider.setText(Bundle.getMessage("ExThrottleUseLargeSpeedSlider"));
075        cbUseRosterImage.setText(Bundle.getMessage("ExThrottleUseRosterImageBkg"));
076        cbEnableRosterSearch.setText(Bundle.getMessage("ExThrottleEnableRosterSearch"));
077        cbEnableAutoLoad.setText(Bundle.getMessage("ExThrottleEnableAutoSave"));
078        cbHideUndefinedButtons.setText(Bundle.getMessage("ExThrottleHideUndefinedFunctionButtons"));
079        cbHideSpeedSelector.setText(Bundle.getMessage("ExThrottleCheckBoxHideSpeedStepSelector"));
080        cbIgnoreThrottlePosition.setText(Bundle.getMessage("ExThrottleIgnoreThrottlePosition"));
081        cbSaveThrottleOnLayoutSave.setText(Bundle.getMessage("ExThrottleSaveThrottleOnLayoutSave"));
082        cbSilentSteal.setText(Bundle.getMessage("ExThrottleSilentSteal"));
083        cbSilentShare.setText(Bundle.getMessage("ExThrottleSilentShare"));
084
085        ActionListener dirtyAL = (ActionEvent evt) -> {        
086            isDirty = true;
087        };
088        cbUseExThrottle.addActionListener(dirtyAL);
089        cbResizeWinImg.addActionListener(dirtyAL);
090        cbUseToolBar.addActionListener(dirtyAL);
091        cbUseFunctionIcon.addActionListener(dirtyAL);
092        cbUseLargeSpeedSlider.addActionListener(dirtyAL);
093        cbUseRosterImage.addActionListener(dirtyAL);
094        cbEnableRosterSearch.addActionListener(dirtyAL);
095        cbEnableAutoLoad.addActionListener(dirtyAL);
096        cbHideUndefinedButtons.addActionListener(dirtyAL);
097        cbHideSpeedSelector.addActionListener(dirtyAL);
098        cbIgnoreThrottlePosition.addActionListener(dirtyAL);     
099        cbSaveThrottleOnLayoutSave.addActionListener(dirtyAL);     
100        cbSilentSteal.addActionListener(dirtyAL);     
101        cbSilentShare.addActionListener(dirtyAL);
102        
103        ActionListener al = (ActionEvent evt) -> {
104            checkConsistancy();
105        };
106        cbUseExThrottle.addActionListener(al);
107        cbUseToolBar.addActionListener(al);
108        cbUseRosterImage.addActionListener(al);
109        cbEnableAutoLoad.addActionListener(al);
110        
111        // only the steal checkbox OR the share checkbox should be selected
112        ActionListener stealCheck = (ActionEvent evt) -> {
113            checkStealButtonOk();
114        };
115        ActionListener shareCheck = (ActionEvent evt) -> {
116            checkShareButtonOk();
117        };
118        cbSilentSteal.addActionListener(stealCheck);
119        cbSilentShare.addActionListener(shareCheck);
120
121        ActionListener tal = (ActionEvent evt) -> {
122            checkDefaultThrottleFile();
123        };
124        tfDefaultThrottleLocation.addActionListener(tal);
125        
126        setLayout(new GridBagLayout());
127        
128        GridBagConstraints constraints = new GridBagConstraints();
129        constraints.anchor = GridBagConstraints.WEST;
130        constraints.fill = GridBagConstraints.HORIZONTAL;
131        constraints.gridheight = 1;
132        constraints.gridwidth = 1;
133        constraints.ipadx = 5;
134        constraints.ipady = 5;
135        Insets x0 = new Insets(2, 2, 2, 2);
136        Insets x1 = new Insets(2, 18, 2, 2);
137        Insets x2 = new Insets(2, 32, 2, 2);        
138        constraints.insets = x0;
139        constraints.weightx = 1;
140        constraints.weighty = 1;
141        
142        constraints.gridx = 0;
143        constraints.gridy = 0;
144        this.add(cbUseExThrottle, constraints);
145
146        constraints.gridy++;
147        constraints.insets = x1;
148        this.add(cbSaveThrottleOnLayoutSave, constraints);
149        
150        constraints.gridy++;
151        this.add(cbUseRosterImage, constraints);
152        
153        constraints.gridy++;
154        constraints.insets = x2;
155        this.add(cbResizeWinImg, constraints);
156        
157        constraints.gridy++;
158        constraints.insets = x1;
159        this.add(cbEnableRosterSearch, constraints);
160        
161        constraints.gridy++;
162        this.add(cbEnableAutoLoad, constraints);
163
164        constraints.gridy++;
165        constraints.insets = x2;
166        this.add(cbIgnoreThrottlePosition, constraints);
167        
168        constraints.gridy++;
169        constraints.insets = x1;
170        this.add(cbHideUndefinedButtons, constraints);
171
172        constraints.gridy++;
173        this.add(cbUseToolBar, constraints);
174        
175        constraints.gridy++;
176        this.add(cbHideSpeedSelector, constraints);
177
178        constraints.gridy++;
179        this.add(cbUseFunctionIcon, constraints);
180
181        constraints.gridy++;
182        this.add(cbUseLargeSpeedSlider, constraints);
183
184        constraints.gridy++;
185        constraints.insets = x0;
186        this.add(new JSeparator(),constraints );
187        constraints.gridy++;
188        this.add(cbSilentSteal,constraints );
189        
190        constraints.gridy++;
191        this.add(cbSilentShare,constraints );
192        
193        constraints.gridy++;
194        this.add(new JSeparator(),constraints );
195        
196        constraints.gridy++;
197        this.add(defaultThrottleLocationPanel(), constraints);
198                                
199        if (InstanceManager.getNullableDefault(jmri.ThrottleManager.class) != null) {
200            cbSilentSteal.setEnabled(InstanceManager.throttleManagerInstance().enablePrefSilentStealOption());
201            cbSilentShare.setEnabled(InstanceManager.throttleManagerInstance().enablePrefSilentShareOption());
202        }
203        
204    }
205
206    public final void resetComponents(ThrottlesPreferences tp) {
207        if (tp == null) {
208            return;
209        }
210        cbSaveThrottleOnLayoutSave.setSelected(tp.isSavingThrottleOnLayoutSave());
211        cbResizeWinImg.setSelected(tp.isResizingWindow());
212        cbUseToolBar.setSelected(tp.isUsingToolBar());
213        cbUseFunctionIcon.setSelected(tp.isUsingFunctionIcon());
214        cbUseRosterImage.setSelected(tp.isUsingRosterImage());
215        cbUseExThrottle.setSelected(tp.isUsingExThrottle());
216        cbEnableRosterSearch.setSelected(tp.isEnablingRosterSearch());
217        cbEnableAutoLoad.setSelected(tp.isAutoLoading());
218        cbHideUndefinedButtons.setSelected(tp.isHidingUndefinedFuncButt());
219        cbHideSpeedSelector.setSelected(tp.isHidingSpeedStepSelector());
220        cbIgnoreThrottlePosition.setSelected(tp.isIgnoringThrottlePosition());
221        cbUseLargeSpeedSlider.setSelected(tp.isUsingLargeSpeedSlider());
222        cbSilentSteal.setSelected(tp.isSilentSteal());
223        cbSilentShare.setSelected(tp.isSilentShare());
224        tfDefaultThrottleLocation.setText(tp.getDefaultThrottleFilePath());
225        checkConsistancy();
226        isDirty = false;
227    }
228
229    public ThrottlesPreferences updateThrottlesPreferences(ThrottlesPreferences tp) {
230        tp.setUseExThrottle(cbUseExThrottle.isSelected());
231        tp.setUsingToolBar(cbUseToolBar.isSelected());
232        tp.setUsingFunctionIcon(cbUseFunctionIcon.isSelected());
233        tp.setResizeWindow(cbResizeWinImg.isSelected());
234        tp.setUseRosterImage(cbUseRosterImage.isSelected());
235        tp.setSaveThrottleOnLayoutSave(cbSaveThrottleOnLayoutSave.isSelected());
236        tp.setSilentSteal(cbSilentSteal.isSelected());
237        tp.setSilentShare(cbSilentShare.isSelected());
238        tp.setEnableRosterSearch(cbEnableRosterSearch.isSelected());
239        tp.setAutoLoad(cbEnableAutoLoad.isSelected());
240        tp.setHideUndefinedFuncButt(cbHideUndefinedButtons.isSelected());
241        tp.setHideSpeedStepSelector(cbHideSpeedSelector.isSelected());
242        tp.setIgnoreThrottlePosition(cbIgnoreThrottlePosition.isSelected());        
243        tp.setUseLargeSpeedSlider(cbUseLargeSpeedSlider.isSelected());
244        tp.setDefaultThrottleFilePath(tfDefaultThrottleLocation.getText());
245        return tp;
246    }
247
248    private void checkConsistancy() {
249        cbSaveThrottleOnLayoutSave.setEnabled(cbUseExThrottle.isSelected());
250        cbUseToolBar.setEnabled(cbUseExThrottle.isSelected());
251        cbUseFunctionIcon.setEnabled(cbUseExThrottle.isSelected());
252        cbEnableRosterSearch.setEnabled(cbUseExThrottle.isSelected());
253        cbEnableAutoLoad.setEnabled(cbUseExThrottle.isSelected());
254        cbUseRosterImage.setEnabled(cbUseExThrottle.isSelected());
255        cbResizeWinImg.setEnabled(cbUseExThrottle.isSelected() && cbUseRosterImage.isSelected());
256        cbHideUndefinedButtons.setEnabled(cbUseExThrottle.isSelected());
257        cbHideSpeedSelector.setEnabled(cbUseExThrottle.isSelected());
258        cbIgnoreThrottlePosition.setEnabled(cbUseExThrottle.isSelected() && cbEnableAutoLoad.isSelected());
259        cbUseLargeSpeedSlider.setEnabled(cbUseExThrottle.isSelected());
260        if (cbUseExThrottle.isSelected()) {
261            if (cbUseToolBar.isSelected()) {
262                cbIgnoreThrottlePosition.setSelected(true);
263                cbIgnoreThrottlePosition.setEnabled(false);
264            }
265        }
266    }
267    
268    private void checkStealButtonOk() {
269        if (cbSilentShare.isSelected()){
270            cbSilentShare.setSelected(false);
271        }
272    }
273    
274    private void checkShareButtonOk() {
275        if (cbSilentSteal.isSelected()){
276            cbSilentSteal.setSelected(false);
277        }
278    }
279    
280    private void checkDefaultThrottleFile() {
281        boolean isBad = false;
282        try {
283            LoadXmlThrottlesLayoutAction.ThrottlePrefs prefs = new LoadXmlThrottlesLayoutAction.ThrottlePrefs();
284            Element root = prefs.rootFromFile(new File (tfDefaultThrottleLocation.getText()));
285            // simply test for root element
286            
287            if (root == null || (root.getChildren("ThrottleFrame").size() != 1)) {
288                isBad = true;
289            }
290        } catch (IOException | JDOMException ex) {            
291            isBad = true;
292        } 
293        if (isBad) {
294            tfDefaultThrottleLocation.setText(null);
295            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("DefaultThrottleFileNotValid"),
296                Bundle.getMessage("DefaultThrottleFile"), JmriJOptionPane.ERROR_MESSAGE);
297        }
298    }
299    
300    private JPanel defaultThrottleLocationPanel() {        
301        final JFileChooser fileChooser = jmri.jmrit.XmlFile.userFileChooser(Bundle.getMessage("PromptXmlFileTypes"), "xml");
302        fileChooser.setDialogType(JFileChooser.OPEN_DIALOG);
303        fileChooser.setDialogTitle(Bundle.getMessage("MessageSelectDefaultThrottleFile"));
304        
305        JButton bScript = new JButton(Bundle.getMessage("ButtonSetDots"));
306        bScript.addActionListener(new ThrottlesPreferencesUISettingsPane.OpenAction(fileChooser, tfDefaultThrottleLocation));        
307        JPanel p = new JPanel(new BorderLayout());        
308        p.add(new JLabel(Bundle.getMessage("DefaultThrottleFile")), BorderLayout.LINE_START);
309        p.add(tfDefaultThrottleLocation, BorderLayout.CENTER);
310        p.add(bScript, BorderLayout.LINE_END);        
311        
312        return p;
313    }
314
315    boolean isDirty() {
316        return isDirty;        
317    }
318    
319    private class OpenAction extends AbstractAction {
320
321        JFileChooser chooser;
322        JTextField field;
323        private boolean firstOpen = true;
324
325        OpenAction(JFileChooser chooser, JTextField field) {
326            this.chooser = chooser;
327            this.field = field;
328        }
329
330        @Override
331        public void actionPerformed(ActionEvent e) {
332            if ( firstOpen ) {
333                chooser.setCurrentDirectory(new File(ThrottleFrame.getDefaultThrottleFolder()));
334                firstOpen = false;
335            }
336            // get the file
337            int retVal = chooser.showOpenDialog(field);
338            if ( (retVal != JFileChooser.APPROVE_OPTION) || (chooser.getSelectedFile() == null) ) {
339                return; // cancelled
340            }
341            field.setText(chooser.getSelectedFile().toString());
342            checkDefaultThrottleFile();
343        }
344    }
345
346    // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ThrottlesPreferencesUISettingsPane.class);
347
348}