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