001package jmri.jmrit.beantable.usermessagepreferences;
002
003import java.awt.BorderLayout;
004import java.awt.Dimension;
005import java.beans.PropertyChangeEvent;
006import java.util.ArrayList;
007import java.util.HashMap;
008import java.util.Map.Entry;
009import javax.swing.BorderFactory;
010import javax.swing.BoxLayout;
011import javax.swing.JCheckBox;
012import javax.swing.JComboBox;
013import javax.swing.JComponent;
014import javax.swing.JLabel;
015import javax.swing.JPanel;
016import javax.swing.JScrollPane;
017import javax.swing.JTabbedPane;
018import jmri.UserPreferencesManager;
019import jmri.jmrit.beantable.AudioTableAction;
020import jmri.jmrit.beantable.BlockTableAction;
021import jmri.jmrit.beantable.LRouteTableAction;
022import jmri.jmrit.beantable.LightTableAction;
023import jmri.jmrit.beantable.LogixTableAction;
024import jmri.jmrit.beantable.MemoryTableAction;
025import jmri.jmrit.beantable.ReporterTableAction;
026import jmri.jmrit.beantable.RouteTableAction;
027import jmri.jmrit.beantable.SensorTableAction;
028import jmri.jmrit.beantable.SignalGroupTableAction;
029import jmri.jmrit.beantable.SignalHeadTableAction;
030import jmri.jmrit.beantable.SignalMastTableAction;
031import jmri.jmrit.beantable.TransitTableAction;
032import jmri.jmrit.beantable.TurnoutTableAction;
033import jmri.swing.PreferencesPanel;
034import jmri.util.swing.JmriPanel;
035import org.openide.util.lookup.ServiceProvider;
036
037/**
038 * Pane to show User Message Preferences.
039 *
040 * @author Kevin Dickerson Copyright (C) 2009
041 */
042@ServiceProvider(service = PreferencesPanel.class)
043public class UserMessagePreferencesPane extends JmriPanel implements PreferencesPanel {
044
045    UserPreferencesManager p;
046
047    public UserMessagePreferencesPane() {
048        super();
049        p = jmri.InstanceManager.getDefault(UserPreferencesManager.class);
050        p.addPropertyChangeListener((PropertyChangeEvent e) -> {
051            if (e.getPropertyName().equals(UserPreferencesManager.PREFERENCES_UPDATED)) {
052                refreshOptions();
053            }
054        });
055        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
056
057        setMinimumMessagePref();
058        add(tab);
059    }
060
061    private synchronized void setMinimumMessagePref() {
062        //This ensures that as a minimum that the following items are at least initialised and appear in the preference panel
063        p.setClassDescription(AudioTableAction.class.getName());
064        p.setClassDescription(BlockTableAction.class.getName());
065
066        p.setClassDescription(LightTableAction.class.getName());
067        p.setClassDescription(LogixTableAction.class.getName());
068        p.setClassDescription(LRouteTableAction.class.getName());
069        p.setClassDescription(MemoryTableAction.class.getName());
070
071        p.setClassDescription(ReporterTableAction.class.getName());
072        p.setClassDescription(RouteTableAction.class.getName());
073
074        p.setClassDescription(SensorTableAction.class.getName());
075        p.setClassDescription(SignalGroupTableAction.class.getName());
076        p.setClassDescription(SignalHeadTableAction.class.getName());
077        p.setClassDescription(SignalMastTableAction.class.getName());
078
079        p.setClassDescription(TransitTableAction.class.getName());
080        p.setClassDescription(TurnoutTableAction.class.getName());
081
082        newMessageTab();
083    }
084
085    JTabbedPane tab = new JTabbedPane();
086
087    private HashMap<JComboBox<Object>, ListItems> _comboBoxes = new HashMap<>();
088    private HashMap<JCheckBox, ListItems> _checkBoxes = new HashMap<>();
089
090    private synchronized void newMessageTab() {
091        remove(tab);
092        tab = new JTabbedPane();
093
094        //might need to redo this so that it doesn't recreate everything all the time.
095        _comboBoxes = new HashMap<>();
096        _checkBoxes = new HashMap<>();
097
098        ArrayList<String> preferenceClassList = p.getPreferencesClasses();
099        for (String strClass : preferenceClassList) {
100            JPanel classholder = new JPanel();
101            classholder.setLayout(new BorderLayout());
102
103            HashMap<Integer, String> options;
104            boolean add = false;
105            boolean addtoindependant = false;
106            if (p.getPreferencesSize(strClass) > 1) {
107                addtoindependant = true;
108            }
109            JPanel classPanel = new JPanel();
110            classPanel.setLayout(new BoxLayout(classPanel, BoxLayout.Y_AXIS));
111            classPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
112            for (int j = 0; j < p.getMultipleChoiceSize(strClass); j++) {
113                String itemName = p.getChoiceName(strClass, j);
114                options = p.getChoiceOptions(strClass, itemName);
115                if (options != null) {
116                    JComboBox<Object> optionBox = new JComboBox<>();
117                    ListItems li = new ListItems(strClass, itemName);
118                    _comboBoxes.put(optionBox, li);
119                    li.isIncluded(addtoindependant);
120                    optionBox.removeAllItems();
121                    for (Object value : options.values()) {
122                        optionBox.addItem(value);
123                    }
124                    int current = p.getMultipleChoiceOption(strClass, itemName);
125
126                    if (options.containsKey(current)) {
127                        optionBox.setSelectedItem(options.get(current));
128                    }
129                    if (addtoindependant) {
130                        JPanel optionPanel = new JPanel();
131                        JLabel _comboLabel = new JLabel(p.getChoiceDescription(strClass, itemName), JLabel.LEFT);
132                        _comboLabel.setAlignmentX(0.5f);
133                        optionPanel.add(_comboLabel);
134                        optionPanel.add(optionBox);
135                        add = true;
136                        classPanel.add(optionPanel);
137                    }
138                }
139            }
140            ArrayList<String> singleList = p.getPreferenceList(strClass);
141            if (!singleList.isEmpty()) {
142                for (int i = 0; i < singleList.size(); i++) {
143                    String itemName = p.getPreferenceItemName(strClass, i);
144                    String description = p.getPreferenceItemDescription(strClass, itemName);
145                    if ((description != null) && (!description.isEmpty())) {
146                        JCheckBox check = new JCheckBox(description);
147                        check.setSelected(p.getPreferenceState(strClass, itemName));
148                        ListItems li = new ListItems(strClass, itemName);
149                        _checkBoxes.put(check, li);
150                        li.isIncluded(addtoindependant);
151
152                        if (addtoindependant) {
153                            classPanel.add(check);
154                            add = true;
155                        }
156                    }
157                }
158            }
159            if (add) {
160                classholder.add(classPanel, BorderLayout.NORTH);
161                if (p.getPreferencesSize(strClass) > 1) {
162                    JScrollPane scrollPane = new JScrollPane(classholder);
163                    scrollPane.setPreferredSize(new Dimension(300, 300));
164                    scrollPane.setBorder(BorderFactory.createEmptyBorder());
165                    tab.add(scrollPane, p.getClassDescription(strClass));
166                }
167            }
168        }
169        HashMap<String, ArrayList<ListItems>> countOfItems = new HashMap<>();
170        HashMap<String, ArrayList<JCheckBox>> countOfItemsCheck = new HashMap<>();
171        HashMap<String, ArrayList<JComboBox<Object>>> countOfItemsCombo = new HashMap<>();
172
173        for (Entry<JComboBox<Object>, ListItems> entry : _comboBoxes.entrySet()) {
174            if (!entry.getValue().isIncluded()) {
175                String strItem = entry.getValue().getItem();
176                if (!countOfItems.containsKey(strItem)) {
177                    countOfItems.put(strItem, new ArrayList<>());
178                    countOfItemsCombo.put(strItem, new ArrayList<>());
179                }
180                ArrayList<ListItems> a = countOfItems.get(strItem);
181                a.add(entry.getValue());
182
183                ArrayList<JComboBox<Object>> acb = countOfItemsCombo.get(strItem);
184                acb.add(entry.getKey());
185            }
186        }
187
188        for (Entry<JCheckBox, ListItems> entry : _checkBoxes.entrySet()) {
189            if (!entry.getValue().isIncluded()) {
190                String strItem = entry.getValue().getItem();
191                if (!countOfItems.containsKey(strItem)) {
192                    countOfItems.put(strItem, new ArrayList<>());
193                    countOfItemsCheck.put(strItem, new ArrayList<>());
194                }
195                ArrayList<ListItems> a = countOfItems.get(strItem);
196                a.add(entry.getValue());
197
198                ArrayList<JCheckBox> acb = countOfItemsCheck.get(strItem);
199                acb.add(entry.getKey());
200            }
201        }
202
203        JPanel miscPanel = new JPanel();
204        miscPanel.setLayout(new BoxLayout(miscPanel, BoxLayout.Y_AXIS));
205
206        JPanel mischolder = new JPanel();
207        mischolder.setLayout(new BorderLayout());
208        mischolder.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
209        for (Entry<String, ArrayList<ListItems>> entry : countOfItems.entrySet()) {
210            ArrayList<ListItems> a = entry.getValue();
211            ArrayList<JCheckBox> chb = countOfItemsCheck.get(entry.getKey());
212            ArrayList<JComboBox<Object>> cob = countOfItemsCombo.get(entry.getKey());
213            if (a.size() > 1) {
214                JPanel tableDeleteTabPanel = new JPanel();
215                tableDeleteTabPanel.setLayout(new BoxLayout(tableDeleteTabPanel, BoxLayout.Y_AXIS));
216                JLabel tableDeleteInfoLabel = new JLabel(p.getChoiceDescription(a.get(0).getClassName(), a.get(0).getItem()), JLabel.CENTER);
217                tableDeleteInfoLabel.setAlignmentX(0.5f);
218                tableDeleteTabPanel.add(tableDeleteInfoLabel);
219                JPanel inside = new JPanel();
220                if (cob != null) {
221                    JPanel insideCombo = new JPanel();
222                    int gridsize = (int) (Math.ceil((cob.size() / 2.0)));
223                    insideCombo.setLayout(new jmri.util.javaworld.GridLayout2(gridsize, 2 * 2, 10, 2));
224                    for (JComboBox<Object> combo : cob) {
225                        JLabel _comboLabel = new JLabel(p.getClassDescription(_comboBoxes.get(combo).getClassName()), JLabel.RIGHT);
226                        _comboBoxes.get(combo).isIncluded(true);
227                        insideCombo.add(_comboLabel);
228                        insideCombo.add(combo);
229                    }
230                    inside.add(insideCombo);
231                }
232                if (chb != null) {
233                    JPanel insideCheck = new JPanel();
234                    insideCheck.setLayout(new jmri.util.javaworld.GridLayout2(chb.size(), 1));
235                    for (JCheckBox check : chb) {
236                        JLabel _checkLabel = new JLabel(p.getClassDescription(_checkBoxes.get(check).getClassName()), JLabel.RIGHT);
237                        _checkBoxes.get(check).isIncluded(true);
238                        insideCheck.add(_checkLabel);
239                        insideCheck.add(check);
240                    }
241                    inside.add(insideCheck);
242                }
243                tableDeleteTabPanel.add(inside);
244                JScrollPane scrollPane = new JScrollPane(tableDeleteTabPanel);
245                scrollPane.setPreferredSize(new Dimension(300, 300));
246                tab.add(scrollPane, entry.getKey());
247            } else {
248                JPanel itemPanel = new JPanel();
249                JPanel subItem = new JPanel();
250                subItem.setLayout(new BoxLayout(subItem, BoxLayout.Y_AXIS));
251                subItem.add(new JLabel(p.getClassDescription(a.get(0).getClassName()), JLabel.CENTER));
252
253                if (countOfItemsCheck.containsKey(entry.getKey())) {
254                    subItem.add(countOfItemsCheck.get(entry.getKey()).get(0));
255                    itemPanel.add(subItem);
256                    miscPanel.add(itemPanel);
257                }
258            }
259        }
260
261        add(tab);
262        mischolder.add(miscPanel, BorderLayout.NORTH);
263        JScrollPane miscScrollPane = new JScrollPane(mischolder);
264        miscScrollPane.setPreferredSize(new Dimension(300, 300));
265
266        tab.add(miscScrollPane, "Misc items");
267        revalidate();
268    }
269
270    @Override
271    public String getPreferencesItem() {
272        return "MESSAGES"; // NOI18N
273    }
274
275    @Override
276    public String getPreferencesItemText() {
277        return Bundle.getMessage("MenuMessages"); // NOI18N
278    }
279
280    @Override
281    public String getTabbedPreferencesTitle() {
282        return null;
283    }
284
285    @Override
286    public String getLabelKey() {
287        return null;
288    }
289
290    @Override
291    public JComponent getPreferencesComponent() {
292        return this;
293    }
294
295    @Override
296    public boolean isPersistant() {
297        return false;
298    }
299
300    @Override
301    public String getPreferencesTooltip() {
302        return null;
303    }
304
305    @Override
306    public void savePreferences() {
307        this.updateManager();
308    }
309
310    @Override
311    public synchronized  boolean isDirty() {
312        for (Entry<JComboBox<Object>, ListItems> entry : _comboBoxes.entrySet()) {
313            String strClass = entry.getValue().getClassName();
314            String strItem = entry.getValue().getItem();
315            if (!p.getChoiceOptions(strClass, strItem).get(p.getMultipleChoiceOption(strClass, strItem)).equals(entry.getKey().getSelectedItem())) {
316                return true;
317            }
318        }
319        for (Entry<JCheckBox, ListItems> entry : _checkBoxes.entrySet()) {
320            String strClass = entry.getValue().getClassName();
321            String strItem = entry.getValue().getItem();
322            if (p.getPreferenceState(strClass, strItem) != entry.getKey().isSelected()) {
323                return true;
324            }
325        }
326        return false;
327    }
328
329    @Override
330    public boolean isRestartRequired() {
331        return false;
332    }
333
334    @Override
335    public boolean isPreferencesValid() {
336        return true; // no validity checking performed
337    }
338
339    static class ListItems {
340
341        String strClass;
342        String item;
343        boolean included = false;
344
345        ListItems(String strClass, String item) {
346            this.strClass = strClass;
347            this.item = item;
348        }
349
350        String getClassName() {
351            return strClass;
352        }
353
354        String getItem() {
355            return item;
356        }
357
358        boolean isIncluded() {
359            return included;
360        }
361
362        void isIncluded(boolean boo) {
363            included = boo;
364        }
365    }
366
367    boolean updating = false;
368
369    public synchronized void updateManager() {
370        updating = true;
371        p.setLoading();
372
373        for (Entry<JComboBox<Object>, ListItems> entry : _comboBoxes.entrySet()) {
374            String strClass = entry.getValue().getClassName();
375            String strItem = entry.getValue().getItem();
376            String strSelection = (String) entry.getKey().getSelectedItem();
377            p.setMultipleChoiceOption(strClass, strItem, strSelection);
378        }
379
380        for (Entry<JCheckBox, ListItems> entry : _checkBoxes.entrySet()) {
381            String strClass = entry.getValue().getClassName();
382            String strItem = entry.getValue().getItem();
383            p.setPreferenceState(strClass, strItem, entry.getKey().isSelected());
384        }
385
386        updating = false;
387        p.finishLoading();
388        refreshOptions();
389    }
390
391    private void refreshOptions() {
392        if (updating) {
393            return;
394        }
395        newMessageTab();
396    }
397
398}