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