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}