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