001package jmri.jmrit.ctc.editor.code;
002
003import jmri.jmrit.ctc.editor.gui.FrmCB;
004import jmri.jmrit.ctc.editor.gui.FrmCO;
005import jmri.jmrit.ctc.editor.gui.FrmIL;
006import jmri.jmrit.ctc.editor.gui.FrmSIDI;
007import jmri.jmrit.ctc.editor.gui.FrmSWDI;
008import jmri.jmrit.ctc.editor.gui.FrmTRL;
009import jmri.jmrit.ctc.editor.gui.FrmTUL;
010import java.awt.Color;
011import java.util.ArrayList;
012import java.util.Enumeration;
013import java.util.TreeSet;
014import javax.swing.DefaultListModel;
015import javax.swing.JButton;
016import javax.swing.JCheckBox;
017import javax.swing.JLabel;
018import jmri.jmrit.ctc.ctcserialdata.CTCSerialData;
019import jmri.jmrit.ctc.ctcserialdata.CodeButtonHandlerData;
020import jmri.jmrit.ctc.ctcserialdata.TrafficLockingData;
021
022/**
023 *
024 * @author Gregory J. Bedlek Copyright (C) 2018, 2019
025
026 This represents all of the codeButtonHandlerData data in a CTC machine relating to the GUI
027 interface.  It maintains the state of the screen for the higher level functions.
028 */
029public class Columns {
030    public final static String REFERENCES_PRESENT_INDICATOR = " (";
031    private final static String ERROR_STRING = " ***ERROR***";
032
033    private final CTCSerialData _mCTCSerialData;
034    private final CheckJMRIObject _mCheckJMRIObject;
035    private final DefaultListModel<String> _mDefaultListModel;
036    private final JButton _mDeleteButton;
037    private final JButton _mChangeNumbersButton;
038    private final JButton _mMoveUpButton;
039    private final JButton _mMoveDownButton;
040    private final JLabel _mEdit_CB_Prompt;
041    private final JLabel _mCB_EditAlwaysEnabled;
042    private final JButton _mEdit_CB;
043    private final JLabel _mEdit_SIDI_Prompt;
044    private final JCheckBox _mSIDI_Enabled;
045    private final JButton _mEdit_SIDI;
046    private final JLabel _mEdit_SIDL_Prompt;
047    private final JCheckBox _mSIDL_Enabled;
048    private final JButton _mEdit_SIDL;
049    private final JLabel _mEdit_SWDI_Prompt;
050    private final JCheckBox _mSWDI_Enabled;
051    private final JButton _mEdit_SWDI;
052    private final JLabel _mEdit_SWDL_Prompt;
053    private final JCheckBox _mSWDL_Enabled;
054    private final JButton _mEdit_SWDL;
055    private final JLabel _mEdit_CO_Prompt;
056    private final JCheckBox _mCO_Enabled;
057    private final JButton _mEdit_CO;
058    private final JLabel _mEdit_TRL_Prompt;
059    private final JCheckBox _mTRL_Enabled;
060    private final JButton _mEdit_TRL;
061    private final JLabel _mEdit_TUL_Prompt;
062    private final JCheckBox _mTUL_Enabled;
063    private final JButton _mEdit_TUL;
064    private final JLabel _mEdit_IL_Prompt;
065    private final JCheckBox _mIL_Enabled;
066    private final JButton _mEdit_IL;
067    private int _mSelectedCodeButtonHandlerDataIndex;
068    private CodeButtonHandlerData _mSelectedCodeButtonHandlerData;
069
070    public Columns( CTCSerialData ctcSerialData, CheckJMRIObject checkJMRIObject, DefaultListModel<String> defaultListModel,
071                    JButton deleteButton, JButton changeNumbersButton,
072                    JButton moveUpButton, JButton moveDownButton,
073                    JLabel edit_CB_Prompt, JLabel cb_EditAlwaysEnabled, JButton edit_CB,
074                    JLabel edit_SIDI_Prompt, JCheckBox sidi_Enabled,  JButton edit_SIDI,
075                    JLabel edit_SIDL_Prompt, JCheckBox sidl_Enabled,  JButton edit_SIDL,
076                    JLabel edit_SWDI_Prompt, JCheckBox swdi_Enabled,  JButton edit_SWDI,
077                    JLabel edit_SWDL_Prompt, JCheckBox swdl_Enabled,  JButton edit_SWDL,
078                    JLabel edit_CO_Prompt, JCheckBox co_Enabled,  JButton edit_CO,
079                    JLabel edit_TRL_Prompt,  JCheckBox trl_Enabled,  JButton edit_TRL,
080                    JLabel edit_TUL_Prompt, JCheckBox tul_Enabled,  JButton edit_TUL,
081                    JLabel edit_IL_Prompt, JCheckBox il_Enabled,  JButton edit_IL) {
082        _mCTCSerialData = ctcSerialData;
083        _mCheckJMRIObject = checkJMRIObject;
084        _mDefaultListModel = defaultListModel;
085        _mDeleteButton = deleteButton;
086        _mChangeNumbersButton = changeNumbersButton;
087        _mMoveUpButton = moveUpButton;
088        _mMoveDownButton = moveDownButton;
089        _mEdit_CB_Prompt = edit_CB_Prompt;
090        _mCB_EditAlwaysEnabled = cb_EditAlwaysEnabled;
091        _mEdit_CB = edit_CB;
092        _mEdit_SIDI_Prompt = edit_SIDI_Prompt;
093        _mSIDI_Enabled = sidi_Enabled;
094        _mEdit_SIDI = edit_SIDI;
095        _mEdit_SIDL_Prompt = edit_SIDL_Prompt;
096        _mSIDL_Enabled = sidl_Enabled;
097        _mEdit_SIDL = edit_SIDL;
098        _mEdit_SWDI_Prompt = edit_SWDI_Prompt;
099        _mSWDI_Enabled = swdi_Enabled;
100        _mEdit_SWDI = edit_SWDI;
101        _mEdit_SWDL_Prompt = edit_SWDL_Prompt;
102        _mSWDL_Enabled = swdl_Enabled;
103        _mEdit_SWDL = edit_SWDL;
104        _mEdit_CO_Prompt = edit_CO_Prompt;
105        _mCO_Enabled = co_Enabled;
106        _mEdit_CO = edit_CO;
107        _mEdit_TRL_Prompt = edit_TRL_Prompt;
108        _mTRL_Enabled = trl_Enabled;
109        _mEdit_TRL = edit_TRL;
110        _mTUL_Enabled = tul_Enabled;
111        _mEdit_TUL_Prompt = edit_TUL_Prompt;
112        _mEdit_TUL = edit_TUL;
113        _mEdit_IL_Prompt = edit_IL_Prompt;
114        _mIL_Enabled = il_Enabled;
115        _mEdit_IL = edit_IL;
116        updateFrame();
117    }
118
119    public CodeButtonHandlerData getSelectedCodeButtonHandlerData() { return _mSelectedCodeButtonHandlerData; }
120
121    public final void updateFrame() {
122        _mDefaultListModel.clear();
123        _mCTCSerialData.getCodeButtonHandlerDataArrayList().forEach((codeButtonHandlerData) -> {
124            _mDefaultListModel.addElement(constructSingleColumnDisplayLine(codeButtonHandlerData));
125        });
126        _mDeleteButton.setEnabled(false);    // None selected.
127        _mChangeNumbersButton.setEnabled(false);
128        _mMoveUpButton.setEnabled(false);
129        _mMoveDownButton.setEnabled(false);
130        _mSIDI_Enabled.setEnabled(false);
131        _mCB_EditAlwaysEnabled.setEnabled(false);
132        _mEdit_CB.setEnabled(false);
133        _mEdit_SIDI.setEnabled(false);
134        _mSIDL_Enabled.setEnabled(false);
135        _mEdit_SIDL.setEnabled(false);
136        _mSWDI_Enabled.setEnabled(false);
137        _mEdit_SWDI.setEnabled(false);
138        _mSWDL_Enabled.setEnabled(false);
139        _mEdit_SWDL.setEnabled(false);
140        _mCO_Enabled.setEnabled(false);
141        _mEdit_CO.setEnabled(false);
142        _mTRL_Enabled.setEnabled(false);
143        _mEdit_TRL.setEnabled(false);
144        _mTUL_Enabled.setEnabled(false);
145        _mEdit_TUL.setEnabled(false);
146        _mIL_Enabled.setEnabled(false);
147        _mEdit_IL.setEnabled(false);
148    }
149
150    public int getEntrySelectedIndex() { return _mSelectedCodeButtonHandlerDataIndex; }
151
152    public void fixAllErrors() {
153        for (CodeButtonHandlerData codeButtonHandlerData : _mCTCSerialData.getCodeButtonHandlerDataArrayList()) {
154            if (!FrmSIDI.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, codeButtonHandlerData)) codeButtonHandlerData._mSIDI_Enabled = false;
155            if (!FrmSWDI.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, codeButtonHandlerData)) codeButtonHandlerData._mSWDI_Enabled = false;
156            if (!FrmCO.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, codeButtonHandlerData)) codeButtonHandlerData._mCO_Enabled = false;
157            if (!FrmTRL.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, codeButtonHandlerData)) codeButtonHandlerData._mTRL_Enabled = false;
158            if (!FrmTUL.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, codeButtonHandlerData)) codeButtonHandlerData._mTUL_Enabled = false;
159            if (!FrmIL.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, codeButtonHandlerData)) codeButtonHandlerData._mIL_Enabled = false;
160        }
161        updateFrame();
162    }
163
164    public boolean anyErrorsPresent() {
165        Enumeration<String> enumerationOfStrings = _mDefaultListModel.elements();
166        while (enumerationOfStrings.hasMoreElements()) {
167            if (enumerationOfStrings.nextElement().contains(ERROR_STRING)) return true;
168        }
169        return false;
170    }
171
172    public void updateCurrentlySelectedColumnErrorStatus() {
173        lazy1(_mEdit_CB_Prompt, FrmCB.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, _mSelectedCodeButtonHandlerData) ? Color.black : Color.red);
174        lazy1(_mEdit_SIDI_Prompt, FrmSIDI.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, _mSelectedCodeButtonHandlerData) ? Color.black : Color.red);
175        lazy1(_mEdit_SWDI_Prompt, FrmSWDI.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, _mSelectedCodeButtonHandlerData) ? Color.black : Color.red);
176        lazy1(_mEdit_CO_Prompt, FrmCO.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, _mSelectedCodeButtonHandlerData) ? Color.black : Color.red);
177        lazy1(_mEdit_TRL_Prompt, FrmTRL.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, _mSelectedCodeButtonHandlerData) ? Color.black : Color.red);
178        lazy1(_mEdit_TUL_Prompt, FrmTUL.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, _mSelectedCodeButtonHandlerData) ? Color.black : Color.red);
179        lazy1(_mEdit_IL_Prompt, FrmIL.dialogCodeButtonHandlerDataValid(_mCheckJMRIObject, _mSelectedCodeButtonHandlerData) ? Color.black : Color.red);
180        _mDefaultListModel.set(_mSelectedCodeButtonHandlerDataIndex, constructSingleColumnDisplayLine(_mSelectedCodeButtonHandlerData));
181    }
182
183    public void clearCurrentlySelectedColumnErrorStatus() {
184        lazy1(_mEdit_CB_Prompt, Color.black);
185        lazy1(_mEdit_SIDI_Prompt, Color.black);
186        lazy1(_mEdit_SIDL_Prompt, Color.black);
187        lazy1(_mEdit_SWDI_Prompt, Color.black);
188        lazy1(_mEdit_SWDL_Prompt, Color.black);
189        lazy1(_mEdit_CO_Prompt, Color.black);
190        lazy1(_mEdit_TRL_Prompt, Color.black);
191        lazy1(_mEdit_TUL_Prompt, Color.black);
192        lazy1(_mEdit_IL_Prompt, Color.black);
193    }
194
195    private static void lazy1(JLabel label, Color foreground) {
196        label.setForeground(foreground);
197    }
198
199    public void setEntrySelected(int selectedIndex) {
200        if (selectedIndex >= 0) {
201            _mDeleteButton.setEnabled(true);
202            _mChangeNumbersButton.setEnabled(true);
203            _mMoveUpButton.setEnabled(selectedIndex > 0);
204            _mMoveDownButton.setEnabled(selectedIndex < _mCTCSerialData.getCodeButtonHandlerDataSize() - 1);
205            _mSelectedCodeButtonHandlerDataIndex = selectedIndex;
206            _mSelectedCodeButtonHandlerData = _mCTCSerialData.getCodeButtonHandlerData(selectedIndex);
207            _mCB_EditAlwaysEnabled.setEnabled(true);
208            updateCurrentlySelectedColumnErrorStatus();
209            _mEdit_CB.setEnabled(true);
210            lazy1(_mSIDI_Enabled, _mEdit_SIDI, true, _mSelectedCodeButtonHandlerData._mSIDI_Enabled);
211            lazy1(_mSIDL_Enabled, _mEdit_SIDL, true, _mSelectedCodeButtonHandlerData._mSIDL_Enabled);
212            lazy1(_mSWDI_Enabled, _mEdit_SWDI, true, _mSelectedCodeButtonHandlerData._mSWDI_Enabled);
213            lazy1(_mSWDL_Enabled, _mEdit_SWDL, true, _mSelectedCodeButtonHandlerData._mSWDL_Enabled);
214            specialUpdateEnableCO_and_TRL();
215            lazy1(_mTUL_Enabled, _mEdit_TUL, true, _mSelectedCodeButtonHandlerData._mTUL_Enabled);
216            lazy1(_mIL_Enabled, _mEdit_IL, true, _mSelectedCodeButtonHandlerData._mIL_Enabled);
217        } else {
218            clearCurrentlySelectedColumnErrorStatus();
219        }
220    }
221
222    private void specialUpdateEnableCO_and_TRL() {
223        boolean signalDirectionLeverEnabled = signalDirectionLeverEnabled();
224        if (!signalDirectionLeverEnabled()) {   // Force these, until user fixes it.
225            _mSelectedCodeButtonHandlerData._mCO_Enabled = false;
226            _mSelectedCodeButtonHandlerData._mTRL_Enabled = false;
227        }
228        lazy1(_mCO_Enabled, _mEdit_CO, signalDirectionLeverEnabled, _mSelectedCodeButtonHandlerData._mCO_Enabled);
229        lazy1(_mTRL_Enabled, _mEdit_TRL, signalDirectionLeverEnabled, _mSelectedCodeButtonHandlerData._mTRL_Enabled);
230    }
231
232    static private void lazy1(JCheckBox jCheckBox, JButton jButton, boolean enabled, boolean value) {
233        jCheckBox.setEnabled(enabled);
234        jCheckBox.setSelected(value);
235        jButton.setEnabled(value);
236    }
237
238    public void sidi_EnabledClicked(boolean newState) {
239        _mSelectedCodeButtonHandlerData._mSIDI_Enabled = newState;
240        lazy2(_mEdit_SIDI, newState);
241    }
242
243    public void sidl_EnabledClicked(boolean newState) {
244        _mSelectedCodeButtonHandlerData._mSIDL_Enabled = newState;
245        lazy2(_mEdit_SIDL, newState);
246        specialUpdateEnableCO_and_TRL();
247    }
248
249    public void swdi_EnabledClicked(boolean newState) {
250        _mSelectedCodeButtonHandlerData._mSWDI_Enabled = newState;
251        lazy2(_mEdit_SWDI, newState);
252    }
253
254    public void swdl_EnabledClicked(boolean newState) {
255        _mSelectedCodeButtonHandlerData._mSWDL_Enabled = newState;
256        lazy2(_mEdit_SWDL, newState);
257    }
258
259    public void co_EnabledClicked(boolean newState) {
260        _mSelectedCodeButtonHandlerData._mCO_Enabled = newState;
261        lazy2(_mEdit_CO, newState);
262    }
263
264    public void trl_EnabledClicked(boolean newState) {
265        _mSelectedCodeButtonHandlerData._mTRL_Enabled = newState;
266        lazy2(_mEdit_TRL, newState);
267    }
268
269    public void tul_EnabledClicked(boolean newState) {
270        _mSelectedCodeButtonHandlerData._mTUL_Enabled = newState;
271        lazy2(_mEdit_TUL, newState);
272    }
273
274    public void il_EnabledClicked(boolean newState) {
275        _mSelectedCodeButtonHandlerData._mIL_Enabled = newState;
276        lazy2(_mEdit_IL, newState);
277    }
278
279    private void lazy2(JButton jButton, boolean value) {
280        jButton.setEnabled(value);
281        _mCTCSerialData.setCodeButtonHandlerData(_mSelectedCodeButtonHandlerDataIndex, _mSelectedCodeButtonHandlerData);
282        updateCurrentlySelectedColumnErrorStatus();
283    }
284
285    public String checkForDups(int newSwitchNumber, int newGUIColumnNumber, boolean isModify, int indexModifying) {
286        ArrayList <CodeButtonHandlerData> codeButtonHandlerDataList = _mCTCSerialData.getCodeButtonHandlerDataArrayList();
287        int codeButtonHandlerDataListSize = codeButtonHandlerDataList.size();
288        for (int index = 0; index < codeButtonHandlerDataListSize; index++) {
289            if (!isModify || index != indexModifying) {  // If add, check all, if modify, check all but indexModifying.
290                CodeButtonHandlerData codeButtonHandlerData = codeButtonHandlerDataList.get(index);
291                if (codeButtonHandlerData._mSwitchNumber == newSwitchNumber) return "Switch #" + newSwitchNumber + " already used";
292                if (newGUIColumnNumber > 0) { // Multiple 0's are allowed here:
293                    if (codeButtonHandlerData._mGUIColumnNumber == newGUIColumnNumber) return "GUI Column #" + newGUIColumnNumber + " already used";
294                }
295            }
296        }
297        return null;
298    }
299
300    private String getListOfTrafficLockingRulesOSSectionsReferenced(CodeButtonHandlerData currentCodeButtonHandlerData,
301                                                                    ArrayList <CodeButtonHandlerData> codeButtonHandlerDataArrayList) {
302        StringBuffer returnStringBuffer = new StringBuffer("");
303        TreeSet<String> temp = new TreeSet<>();
304        int currentUniqueID = currentCodeButtonHandlerData._mUniqueID;
305        for (CodeButtonHandlerData codeButtonHandlerData : codeButtonHandlerDataArrayList) {
306            if (currentCodeButtonHandlerData != codeButtonHandlerData) { // Don't check ourselves
307                int otherUniqueID = codeButtonHandlerData._mUniqueID;
308                checkThisList(currentUniqueID, otherUniqueID, "L", codeButtonHandlerData._mTRL_LeftTrafficLockingRules, temp);    // NOI18N
309                checkThisList(currentUniqueID, otherUniqueID, "R", codeButtonHandlerData._mTRL_RightTrafficLockingRules, temp);   // NOI18N
310            }
311        }
312        for (String result : temp) returnStringBuffer.append(result);
313        if (returnStringBuffer.length() > 0) {
314            return "TrL: " + returnStringBuffer.substring(0, returnStringBuffer.length() - 2);    // NOI18N
315        } else {
316            return "";
317        }
318    }
319
320    private void checkThisList(int ourUniqueID, int otherUniqueID, String lr, ArrayList<TrafficLockingData> trafficLockingRules, TreeSet<String> setOfUniqueIDs) {
321        trafficLockingRules.forEach(rule -> {
322            ArrayList<Integer> idList = rule.getUniqueIDs();
323            lazy3(ourUniqueID, otherUniqueID, lr, idList.get(0), setOfUniqueIDs);
324            lazy3(ourUniqueID, otherUniqueID, lr, idList.get(1), setOfUniqueIDs);
325            lazy3(ourUniqueID, otherUniqueID, lr, idList.get(2), setOfUniqueIDs);
326            lazy3(ourUniqueID, otherUniqueID, lr, idList.get(3), setOfUniqueIDs);
327            lazy3(ourUniqueID, otherUniqueID, lr, idList.get(4), setOfUniqueIDs);
328        });
329    }
330
331    private void lazy3(int ourUniqueID, int otherUniqueID, String lr, int uniqueID, TreeSet<String> setOfUniqueIDs) {
332        if (ourUniqueID == uniqueID) {
333            setOfUniqueIDs.add(_mCTCSerialData.getMyShortStringNoCommaViaUniqueID(otherUniqueID) + lr + ", ");
334        }
335    }
336
337    private String getListOfSwitchSlavedToOSSectionsReferenced( CodeButtonHandlerData currentCodeButtonHandlerData,
338                                                                ArrayList <CodeButtonHandlerData> codeButtonHandlerDataArrayList) {
339        StringBuffer returnStringBuffer = new StringBuffer("");
340        TreeSet<String> temp = new TreeSet<>();
341        int currentUniqueID = currentCodeButtonHandlerData._mUniqueID;
342        for (CodeButtonHandlerData codeButtonHandlerData : codeButtonHandlerDataArrayList) {
343            if (currentCodeButtonHandlerData != codeButtonHandlerData) { // Don't check ourselves
344                if (codeButtonHandlerData._mOSSectionSwitchSlavedToUniqueID != CodeButtonHandlerData.SWITCH_NOT_SLAVED)  { // It's referencing someone else:
345                    if (currentUniqueID == codeButtonHandlerData._mOSSectionSwitchSlavedToUniqueID) {
346                        temp.add(_mCTCSerialData.getMyShortStringNoCommaViaUniqueID(codeButtonHandlerData._mUniqueID) + ", ");
347                    }
348                }
349            }
350        }
351        for (String result : temp)  returnStringBuffer.append(result);
352        if (returnStringBuffer.length() > 0) {
353            return "Sw: " + returnStringBuffer.substring(0, returnStringBuffer.length() - 2);   // NOI18N
354        } else {
355            return "";
356        }
357    }
358
359//  Anything in error, return ERROR_STRING
360    private static String generatePossibleErrorString(CheckJMRIObject checkJMRIObject, CodeButtonHandlerData currentCodeButtonHandlerData) {
361        if (!FrmCB.dialogCodeButtonHandlerDataValid(checkJMRIObject, currentCodeButtonHandlerData)) return ERROR_STRING;
362        if (!FrmSIDI.dialogCodeButtonHandlerDataValid(checkJMRIObject, currentCodeButtonHandlerData)) return ERROR_STRING;
363        if (!FrmSWDI.dialogCodeButtonHandlerDataValid(checkJMRIObject, currentCodeButtonHandlerData)) return ERROR_STRING;
364        if (!FrmCO.dialogCodeButtonHandlerDataValid(checkJMRIObject, currentCodeButtonHandlerData)) return ERROR_STRING;
365        if (!FrmTRL.dialogCodeButtonHandlerDataValid(checkJMRIObject, currentCodeButtonHandlerData)) return ERROR_STRING;
366        if (!FrmTUL.dialogCodeButtonHandlerDataValid(checkJMRIObject, currentCodeButtonHandlerData)) return ERROR_STRING;
367        if (!FrmIL.dialogCodeButtonHandlerDataValid(checkJMRIObject, currentCodeButtonHandlerData)) return ERROR_STRING;
368        return "";                              // No error (string)
369    }
370
371    private String constructSingleColumnDisplayLine(CodeButtonHandlerData codeButtonHandlerData) {
372        String referencesString1 = getListOfTrafficLockingRulesOSSectionsReferenced(codeButtonHandlerData, _mCTCSerialData.getCodeButtonHandlerDataArrayList());
373        String referencesString2 = getListOfSwitchSlavedToOSSectionsReferenced(codeButtonHandlerData, _mCTCSerialData.getCodeButtonHandlerDataArrayList());
374        String displayString = codeButtonHandlerData.myString();
375        if (!referencesString1.isEmpty() || !referencesString2.isEmpty()) {
376            displayString += REFERENCES_PRESENT_INDICATOR + referencesString1 + " " + referencesString2 + ")";
377        }
378        displayString += generatePossibleErrorString(_mCheckJMRIObject, codeButtonHandlerData);
379        return displayString;
380    }
381
382    private boolean signalDirectionLeverEnabled() {
383        return _mSelectedCodeButtonHandlerData._mSIDL_Enabled;
384    }
385
386//     private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Columns.class);
387}