19 package org.sleuthkit.autopsy.modules.fileextmismatch;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.HashSet;
26 import java.util.logging.Level;
27 import javax.swing.JOptionPane;
28 import javax.swing.ListSelectionModel;
29 import javax.swing.event.ListSelectionEvent;
30 import javax.swing.event.ListSelectionListener;
31 import javax.swing.table.AbstractTableModel;
32 import org.netbeans.spi.options.OptionsPanelController;
33 import org.openide.util.NbBundle;
43 final class FileExtMismatchSettingsPanel
extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
45 private static final Logger logger = Logger.getLogger(FileExtMismatchSettingsPanel.class.getName());
46 private HashMap<String, Set<String>> editableMap =
new HashMap<>();
47 private ArrayList<String> mimeList = null;
48 private ArrayList<String> currentExtensions = null;
49 private MimeTableModel mimeTableModel;
50 private ExtTableModel extTableModel;
51 private final String EXT_HEADER_LABEL = NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
52 "AddFileExtensionAction.extHeaderLbl.text");
53 private String selectedMime =
"";
54 private String selectedExt =
"";
55 ListSelectionModel lsm = null;
56 private FileTypeDetector fileTypeDetector;
58 public FileExtMismatchSettingsPanel() {
59 mimeTableModel =
new MimeTableModel();
60 extTableModel =
new ExtTableModel();
63 fileTypeDetector =
new FileTypeDetector();
64 }
catch (FileTypeDetector.FileTypeDetectorInitException ex) {
65 logger.log(Level.SEVERE,
"Failed to create file type detector", ex);
66 fileTypeDetector = null;
70 customizeComponents();
73 @NbBundle.Messages({
"FileExtMismatchSettingsPanel.Title=Global File Extension Mismatch Identification Settings"})
74 private void customizeComponents() {
75 setName(Bundle.FileExtMismatchSettingsPanel_Title());
78 lsm = mimeTable.getSelectionModel();
79 lsm.addListSelectionListener(
new ListSelectionListener() {
81 public void valueChanged(ListSelectionEvent e) {
82 ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
83 if (!listSelectionModel.isSelectionEmpty()) {
84 int index = listSelectionModel.getMinSelectionIndex();
85 listSelectionModel.setSelectionInterval(index, index);
87 selectedMime = mimeList.get(index);
88 String labelStr = EXT_HEADER_LABEL + selectedMime +
":";
89 if (labelStr.length() > 80) {
90 labelStr = labelStr.substring(0, 80);
92 extHeaderLabel.setText(labelStr);
95 extTableModel.resync();
96 removeTypeButton.setEnabled(
true);
97 newExtButton.setEnabled(
true);
101 currentExtensions = null;
102 removeTypeButton.setEnabled(
false);
103 newExtButton.setEnabled(
false);
104 extTableModel.resync();
110 ListSelectionModel extLsm = extTable.getSelectionModel();
111 extLsm.addListSelectionListener(
new ListSelectionListener() {
113 public void valueChanged(ListSelectionEvent e) {
114 ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
115 if (!listSelectionModel.isSelectionEmpty()) {
116 int index = listSelectionModel.getMinSelectionIndex();
117 listSelectionModel.setSelectionInterval(index, index);
119 selectedExt = currentExtensions.get(index);
120 removeExtButton.setEnabled(
true);
123 removeExtButton.setEnabled(
false);
128 removeExtButton.setEnabled(
false);
129 removeTypeButton.setEnabled(
false);
130 newExtButton.setEnabled(
false);
139 private void initComponents() {
141 jPanel1 =
new javax.swing.JPanel();
142 jScrollPane1 =
new javax.swing.JScrollPane();
143 jSplitPane1 =
new javax.swing.JSplitPane();
144 mimePanel =
new javax.swing.JPanel();
145 jLabel1 =
new javax.swing.JLabel();
146 jScrollPane2 =
new javax.swing.JScrollPane();
147 mimeTable =
new javax.swing.JTable();
148 newTypeButton =
new javax.swing.JButton();
149 removeTypeButton =
new javax.swing.JButton();
150 extensionPanel =
new javax.swing.JPanel();
151 newExtButton =
new javax.swing.JButton();
152 jScrollPane3 =
new javax.swing.JScrollPane();
153 extTable =
new javax.swing.JTable();
154 removeExtButton =
new javax.swing.JButton();
155 extHeaderLabel =
new javax.swing.JLabel();
157 jPanel1.setPreferredSize(
new java.awt.Dimension(687, 450));
159 jSplitPane1.setDividerLocation(430);
160 jSplitPane1.setDividerSize(1);
162 jLabel1.setText(
org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.jLabel1.text"));
164 mimeTable.setModel(mimeTableModel);
165 jScrollPane2.setViewportView(mimeTable);
167 newTypeButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/add16.png")));
168 newTypeButton.setText(
org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newTypeButton.text"));
169 newTypeButton.addActionListener(
new java.awt.event.ActionListener() {
170 public void actionPerformed(java.awt.event.ActionEvent evt) {
171 newTypeButtonActionPerformed(evt);
175 removeTypeButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/delete16.png")));
176 removeTypeButton.setText(
org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.removeTypeButton.text"));
177 removeTypeButton.setToolTipText(
org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.removeTypeButton.toolTipText"));
178 removeTypeButton.addActionListener(
new java.awt.event.ActionListener() {
179 public void actionPerformed(java.awt.event.ActionEvent evt) {
180 removeTypeButtonActionPerformed(evt);
184 javax.swing.GroupLayout mimePanelLayout =
new javax.swing.GroupLayout(mimePanel);
185 mimePanel.setLayout(mimePanelLayout);
186 mimePanelLayout.setHorizontalGroup(
187 mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
188 .addGroup(mimePanelLayout.createSequentialGroup()
190 .addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
191 .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
192 .addGroup(mimePanelLayout.createSequentialGroup()
193 .addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
194 .addComponent(jLabel1)
195 .addGroup(mimePanelLayout.createSequentialGroup()
196 .addComponent(newTypeButton)
197 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
198 .addComponent(removeTypeButton)))
199 .addGap(0, 191, Short.MAX_VALUE)))
202 mimePanelLayout.setVerticalGroup(
203 mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
204 .addGroup(mimePanelLayout.createSequentialGroup()
206 .addComponent(jLabel1)
207 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
208 .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
209 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
210 .addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
211 .addComponent(newTypeButton)
212 .addComponent(removeTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE))
216 jSplitPane1.setLeftComponent(mimePanel);
218 newExtButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/add16.png")));
219 newExtButton.setText(
org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newExtButton.text"));
220 newExtButton.addActionListener(
new java.awt.event.ActionListener() {
221 public void actionPerformed(java.awt.event.ActionEvent evt) {
222 newExtButtonActionPerformed(evt);
226 extTable.setModel(extTableModel);
227 jScrollPane3.setViewportView(extTable);
229 removeExtButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/images/delete16.png")));
230 removeExtButton.setText(
org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.removeExtButton.text"));
231 removeExtButton.addActionListener(
new java.awt.event.ActionListener() {
232 public void actionPerformed(java.awt.event.ActionEvent evt) {
233 removeExtButtonActionPerformed(evt);
237 extHeaderLabel.setText(
org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.extHeaderLabel.text"));
239 javax.swing.GroupLayout extensionPanelLayout =
new javax.swing.GroupLayout(extensionPanel);
240 extensionPanel.setLayout(extensionPanelLayout);
241 extensionPanelLayout.setHorizontalGroup(
242 extensionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
243 .addGroup(extensionPanelLayout.createSequentialGroup()
245 .addGroup(extensionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
246 .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
247 .addGroup(extensionPanelLayout.createSequentialGroup()
248 .addGroup(extensionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
249 .addComponent(extHeaderLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 324, javax.swing.GroupLayout.PREFERRED_SIZE)
250 .addGroup(extensionPanelLayout.createSequentialGroup()
251 .addComponent(newExtButton)
252 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
253 .addComponent(removeExtButton)))
254 .addGap(0, 0, Short.MAX_VALUE)))
257 extensionPanelLayout.setVerticalGroup(
258 extensionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
259 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, extensionPanelLayout.createSequentialGroup()
261 .addComponent(extHeaderLabel)
262 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
263 .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
264 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
265 .addGroup(extensionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
266 .addComponent(newExtButton)
267 .addComponent(removeExtButton))
271 jSplitPane1.setRightComponent(extensionPanel);
273 jScrollPane1.setViewportView(jSplitPane1);
275 javax.swing.GroupLayout jPanel1Layout =
new javax.swing.GroupLayout(jPanel1);
276 jPanel1.setLayout(jPanel1Layout);
277 jPanel1Layout.setHorizontalGroup(
278 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
279 .addGroup(jPanel1Layout.createSequentialGroup()
281 .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 797, Short.MAX_VALUE)
284 jPanel1Layout.setVerticalGroup(
285 jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
286 .addGroup(jPanel1Layout.createSequentialGroup()
288 .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 504, Short.MAX_VALUE)
292 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
293 this.setLayout(layout);
294 layout.setHorizontalGroup(
295 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
296 .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 817, Short.MAX_VALUE)
298 layout.setVerticalGroup(
299 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
300 .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 526, Short.MAX_VALUE)
305 private void newExtButtonActionPerformed(java.awt.event.ActionEvent evt) {
306 String newExt = (String) JOptionPane.showInputDialog(null, NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newExtPrompt.message"),
307 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newExtPrompt.title"), JOptionPane.PLAIN_MESSAGE, null, null,
"");
309 if (newExt == null) {
312 if (newExt.isEmpty()) {
313 JOptionPane.showMessageDialog(null,
314 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newExtPrompt.empty.message"),
315 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newExtPrompt.empty.title"),
316 JOptionPane.ERROR_MESSAGE);
319 if (selectedMime.isEmpty()) {
320 JOptionPane.showMessageDialog(null,
321 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message"),
322 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.title"),
323 JOptionPane.ERROR_MESSAGE);
326 if (currentExtensions.contains(newExt)) {
327 JOptionPane.showMessageDialog(null,
328 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newExtPrompt.extExists.message"),
329 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newExtPrompt.extExists.title"),
330 JOptionPane.ERROR_MESSAGE);
334 Set<String> editedExtensions = editableMap.get(selectedMime);
335 editedExtensions.add(newExt);
338 editableMap.put(selectedMime, editedExtensions);
342 extTableModel.resync();
343 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
346 private void removeExtButtonActionPerformed(java.awt.event.ActionEvent evt) {
347 if (selectedExt.isEmpty()) {
348 JOptionPane.showMessageDialog(null,
349 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message"),
350 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.removeExtButton.noneSelected.title"),
351 JOptionPane.ERROR_MESSAGE);
355 if (selectedMime.isEmpty()) {
356 JOptionPane.showMessageDialog(null,
357 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message"),
358 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.title"),
359 JOptionPane.ERROR_MESSAGE);
363 Set<String> editedExtensions = editableMap.get(selectedMime);
364 editedExtensions.remove(selectedExt);
365 String deadExt = selectedExt;
368 editableMap.put(selectedMime, editedExtensions);
372 extTableModel.resync();
373 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
376 private void removeTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {
377 if (selectedMime.isEmpty()) {
378 JOptionPane.showMessageDialog(null,
379 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message"),
380 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.title"),
381 JOptionPane.ERROR_MESSAGE);
385 editableMap.remove(selectedMime);
389 mimeTableModel.resync();
390 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
393 private void newTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {
394 String newMime = (String) JOptionPane.showInputDialog(null, NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newMimePrompt.message"),
395 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newMimePrompt.title"), JOptionPane.PLAIN_MESSAGE, null, null,
"");
397 if (newMime == null) {
400 if (newMime.isEmpty()) {
401 JOptionPane.showMessageDialog(null,
402 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message"),
403 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.title"),
404 JOptionPane.ERROR_MESSAGE);
407 if (newMime.equals(
"application/octet-stream")) {
408 JOptionPane.showMessageDialog(null,
409 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message"),
410 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.title"),
411 JOptionPane.ERROR_MESSAGE);
414 if (mimeList.contains(newMime)) {
415 JOptionPane.showMessageDialog(null,
416 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message"),
417 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.title"),
418 JOptionPane.ERROR_MESSAGE);
422 FileTypeDetector detector;
424 detector =
new FileTypeDetector();
425 }
catch (FileTypeDetector.FileTypeDetectorInitException ex) {
426 logger.log(Level.WARNING,
"Couldn't create file type detector for file ext mismatch settings.", ex);
429 boolean mimeTypeDetectable = (null != detector) ? detector.isDetectable(newMime) :
false;
430 if (!mimeTypeDetectable) {
431 JOptionPane.showMessageDialog(null,
432 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.message"),
433 NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.title"),
434 JOptionPane.ERROR_MESSAGE);
438 editableMap.put(newMime,
new HashSet<String>());
442 mimeTableModel.resync();
443 firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
446 private void updateMimeList() {
447 mimeList =
new ArrayList<>(editableMap.keySet());
448 if (mimeList.size() > 0) {
449 Collections.sort(mimeList);
453 private void updateExtList() {
454 Set<String> temp = editableMap.get(selectedMime);
456 currentExtensions =
new ArrayList<>(temp);
457 if (temp.size() > 0) {
458 Collections.sort(currentExtensions);
461 currentExtensions = null;
466 public void saveSettings() {
468 FileExtMismatchSettings.writeSettings(
new FileExtMismatchSettings(editableMap));
469 }
catch (FileExtMismatchSettings.FileExtMismatchSettingsException ex) {
471 JOptionPane.showMessageDialog(
this,
472 NbBundle.getMessage(
this.getClass(),
473 "FileExtMismatchConfigPanel.store.msgDlg.msg"),
474 NbBundle.getMessage(
this.getClass(),
475 "FileExtMismatchConfigPanel.save.msgDlg.title"),
476 JOptionPane.ERROR_MESSAGE);
485 editableMap = FileExtMismatchSettings.readSettings().getMimeTypeToExtsMap();
487 }
catch (FileExtMismatchSettings.FileExtMismatchSettingsException ex) {
489 JOptionPane.showMessageDialog(
this,
490 NbBundle.getMessage(
this.getClass(),
491 "AddFileExtensionAction.msgDlg.msg2"),
492 NbBundle.getMessage(
this.getClass(),
493 "FileExtMismatchConfigPanel.save.msgDlg.title"),
494 JOptionPane.ERROR_MESSAGE);
501 public void store() {
505 public void cancel() {
518 private javax.swing.JLabel extHeaderLabel;
519 private javax.swing.JTable extTable;
520 private javax.swing.JPanel extensionPanel;
521 private javax.swing.JLabel jLabel1;
522 private javax.swing.JPanel jPanel1;
523 private javax.swing.JScrollPane jScrollPane1;
524 private javax.swing.JScrollPane jScrollPane2;
525 private javax.swing.JScrollPane jScrollPane3;
526 private javax.swing.JSplitPane jSplitPane1;
527 private javax.swing.JPanel mimePanel;
528 private javax.swing.JTable mimeTable;
529 private javax.swing.JButton newExtButton;
530 private javax.swing.JButton newTypeButton;
531 private javax.swing.JButton removeExtButton;
532 private javax.swing.JButton removeTypeButton;
544 return editableMap == null ? 0 : editableMap.size();
549 String colName = null;
556 if ((mimeList == null) || (rowIndex > mimeList.size())) {
559 String word = mimeList.get(rowIndex);
560 switch (columnIndex) {
565 logger.log(Level.SEVERE,
"Invalid table column index: {0}", columnIndex);
577 public void setValueAt(Object aValue,
int rowIndex,
int columnIndex) {
586 fireTableDataChanged();
599 return currentExtensions == null ? 0 : currentExtensions.size();
604 String colName = null;
612 if ((currentExtensions == null) || (currentExtensions.isEmpty()) || (rowIndex > currentExtensions.size())) {
615 String word = currentExtensions.get(rowIndex);
616 switch (columnIndex) {
621 logger.log(Level.SEVERE,
"Invalid table column index: {0}", columnIndex);
633 public void setValueAt(Object aValue,
int rowIndex,
int columnIndex) {
642 fireTableDataChanged();
String getColumnName(int column)
boolean isCellEditable(int rowIndex, int columnIndex)
Class<?> getColumnClass(int c)
void setValueAt(Object aValue, int rowIndex, int columnIndex)
Class<?> getColumnClass(int c)
void setValueAt(Object aValue, int rowIndex, int columnIndex)
boolean isCellEditable(int rowIndex, int columnIndex)
Object getValueAt(int rowIndex, int columnIndex)
Object getValueAt(int rowIndex, int columnIndex)
String getColumnName(int column)