View Javadoc
1   package nom.tam.fits;
2   
3   import nom.tam.fits.header.GenericKey;
4   import nom.tam.fits.header.IFitsHeader;
5   
6   import static nom.tam.fits.header.Standard.NAXISn;
7   import static nom.tam.fits.header.Standard.TFIELDS;
8   import static nom.tam.fits.header.Standard.TFORMn;
9   import static nom.tam.fits.header.Standard.TTYPEn;
10  
11  /*
12   * #%L
13   * nom.tam FITS library
14   * %%
15   * Copyright (C) 2004 - 2024 nom-tam-fits
16   * %%
17   * This is free and unencumbered software released into the public domain.
18   *
19   * Anyone is free to copy, modify, publish, use, compile, sell, or
20   * distribute this software, either in source code form or as a compiled
21   * binary, for any purpose, commercial or non-commercial, and by any
22   * means.
23   *
24   * In jurisdictions that recognize copyright laws, the author or authors
25   * of this software dedicate any and all copyright interest in the
26   * software to the public domain. We make this dedication for the benefit
27   * of the public at large and to the detriment of our heirs and
28   * successors. We intend this dedication to be an overt act of
29   * relinquishment in perpetuity of all present and future rights to this
30   * software under copyright law.
31   *
32   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
35   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
36   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
37   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
38   * OTHER DEALINGS IN THE SOFTWARE.
39   * #L%
40   */
41  
42  /**
43   * Base class for binary and ASCII table implementations.
44   *
45   * @param <T> the generic type of table data contained in this HDU instance.
46   */
47  @SuppressWarnings("deprecation")
48  public abstract class TableHDU<T extends AbstractTableData> extends BasicHDU<T> {
49  
50      /**
51       * Returns the default name for a columns with the specified index, to use if no column name was explicitly defined
52       * 
53       * @param  col The zero-based Java index of the column
54       * 
55       * @return     The default column name to use if no other name was defined.
56       * 
57       * @since      1.20
58       * 
59       * @author     Attila Kovacs
60       * 
61       * @see        #setColumnName(int, String, String)
62       */
63      public static String getDefaultColumnName(int col) {
64          return "Column " + (col + 1);
65      }
66  
67      /**
68       * Create the TableHDU. Note that this will normally only be invoked by subclasses in the FITS package.
69       *
70       * @deprecated     intended for internal use. Its visibility should be reduced to package level in the future.
71       * 
72       * @param      hdr the header
73       * @param      td  The data for the table.
74       */
75      protected TableHDU(Header hdr, T td) {
76          super(hdr, td);
77      }
78  
79      /**
80       * Add a column to the table without any associated header information.
81       *
82       * @param  newCol        the new column information. the newCol should be an Object[] where type of all of the
83       *                           constituents is identical. The length of data should match the other columns. <b>
84       *                           Note:</b> It is valid for data to be a 2 or higher dimensionality primitive array. In
85       *                           this case the column index is the first (in Java speak) index of the array. E.g., if
86       *                           called with int[30][20][10], the number of rows in the table should be 30 and this
87       *                           column will have elements which are 2-d integer arrays with TDIM = (10,20).
88       *
89       * @return               the number of columns in the adapted table
90       *
91       * @throws FitsException if the operation failed
92       */
93      public int addColumn(Object newCol) throws FitsException {
94          int nCols = getNCols();
95          myHeader.findCard(TFIELDS).setValue(nCols);
96          return nCols;
97      }
98  
99      /**
100      * Add a row to the end of the table. If this is the first row, then this will add appropriate columns for each of
101      * the entries. The rows to add must be supplied as column based array of arrays.
102      *
103      * @return               the number of rows in the adapted table
104      *
105      * @param  newRows       rows to add to the table
106      *
107      * @throws FitsException if the operation failed
108      */
109     public int addRow(Object[] newRows) throws FitsException {
110         int row = myData.addRow(newRows);
111         myHeader.findCard(NAXISn.n(2)).setValue(getNRows());
112         return row;
113     }
114 
115     /**
116      * Returns the list of column description keyword stems that descrive this column in the FITS header.
117      * 
118      * @return the stems of the keywords that are associated with table columns. Users can supplement this with their
119      *             own and call the appropriate deleteColumns fields.
120      */
121     protected abstract IFitsHeader[] columnKeyStems();
122 
123     /**
124      * Delete a set of columns from a table.
125      *
126      * @param      column        The one-indexed start column.
127      * @param      len           The number of columns to delete.
128      *
129      * @throws     FitsException if the operation failed
130      * 
131      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
132      *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
133      *                               HDU and editing the header as necessary to incorporate custom entries. May be
134      *                               removed from the API in the future.
135      */
136     public void deleteColumnsIndexOne(int column, int len) throws FitsException {
137         deleteColumnsIndexZero(column - 1, len);
138     }
139 
140     /**
141      * Delete a set of columns from a table.
142      *
143      * @param      column        The one-indexed start column.
144      * @param      len           The number of columns to delete.
145      * @param      fields        Stems for the header fields to be removed for the table.
146      *
147      * @throws     FitsException if the operation failed
148      * 
149      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
150      *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
151      *                               HDU and editing the header as necessary to incorporate custom entries. May be
152      *                               removed from the API in the future.
153      */
154     public void deleteColumnsIndexOne(int column, int len, String[] fields) throws FitsException {
155         deleteColumnsIndexZero(column - 1, len, GenericKey.create(fields));
156     }
157 
158     /**
159      * Delete a set of columns from a table.
160      *
161      * @param      column        The one-indexed start column.
162      * @param      len           The number of columns to delete.
163      *
164      * @throws     FitsException if the operation failed
165      * 
166      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
167      *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
168      *                               HDU and editing the header as necessary to incorporate custom entries. May be
169      *                               removed from the API in the future.
170      */
171     public void deleteColumnsIndexZero(int column, int len) throws FitsException {
172         deleteColumnsIndexZero(column, len, columnKeyStems());
173     }
174 
175     /**
176      * Delete a set of columns from a table.
177      *
178      * @param      column        The zero-indexed start column.
179      * @param      len           The number of columns to delete.
180      * @param      fields        Stems for the header fields to be removed for the table.
181      *
182      * @throws     FitsException if the operation failed
183      * 
184      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
185      *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
186      *                               HDU and editing the header as necessary to incorporate custom entries. May be
187      *                               removed from the API in the future.
188      */
189     public void deleteColumnsIndexZero(int column, int len, IFitsHeader[] fields) throws FitsException {
190 
191         if (column < 0 || len < 0 || column + len > getNCols()) {
192             throw new FitsException("Illegal columns deletion request- Start:" + column + " Len:" + len
193                     + " from table with " + getNCols() + " columns");
194         }
195 
196         if (len == 0) {
197             return;
198         }
199 
200         int ncol = getNCols();
201         myData.deleteColumns(column, len);
202 
203         // Get rid of the keywords for the deleted columns
204         for (int col = column; col < column + len; col++) {
205             for (IFitsHeader field : fields) {
206                 myHeader.deleteKey(field.n(col + 1));
207             }
208         }
209 
210         // Shift the keywords for the columns after the deleted columns
211         for (int col = column + len; col < ncol; col++) {
212             for (IFitsHeader field : fields) {
213                 IFitsHeader oldKey = field.n(col + 1);
214                 IFitsHeader newKey = field.n(col + 1 - len);
215                 if (myHeader.containsKey(oldKey)) {
216                     myHeader.replaceKey(oldKey, newKey);
217                 }
218             }
219         }
220         // Update the number of fields.
221         myHeader.getCard(TFIELDS).setValue(getNCols());
222 
223         // Give the data sections a chance to update the header too.
224         myData.updateAfterDelete(ncol, myHeader);
225     }
226 
227     /**
228      * Remove all rows from the table starting at some specific index from the table. Inspired by a routine by R. Mathar
229      * but re-implemented using the DataTable and changes to AsciiTable so that it can be done easily for both Binary
230      * and ASCII tables.
231      *
232      * @param      row           the (0-based) index of the first row to be deleted.
233      *
234      * @throws     FitsException if an error occurs.
235      * 
236      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
237      *                               {@link TableData#deleteRows(int, int)} to edit tables before wrapping them in an
238      *                               HDU and editing the header as necessary to incorporate custom entries. May be
239      *                               removed from the API in the future.
240      */
241     public void deleteRows(final int row) throws FitsException {
242         deleteRows(row, getNRows() - row);
243     }
244 
245     /**
246      * Remove a number of adjacent rows from the table. This routine was inspired by code by R.Mathar but re-implemented
247      * using changes in the ColumnTable class abd AsciiTable so that we can do it for all FITS tables.
248      *
249      * @param      firstRow      the (0-based) index of the first row to be deleted. This is zero-based indexing:
250      *                               0&lt;=firstrow&lt; number of rows.
251      * @param      nRow          the total number of rows to be deleted.
252      *
253      * @throws     FitsException If an error occurs in the deletion.
254      * 
255      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
256      *                               {@link TableData#deleteRows(int, int)} to edit tables before wrapping them in an
257      *                               HDU and editing the header as necessary to incorporate custom entries. May be
258      *                               removed from the API in the future.
259      */
260     public void deleteRows(final int firstRow, int nRow) throws FitsException {
261 
262         // Just ignore invalid requests.
263         if (nRow <= 0 || firstRow >= getNRows() || firstRow <= 0) {
264             return;
265         }
266 
267         /* correct if more rows are requested than available */
268         if (nRow > getNRows() - firstRow) {
269             nRow = getNRows() - firstRow;
270         }
271 
272         myData.deleteRows(firstRow, nRow);
273         myHeader.setNaxis(2, getNRows());
274     }
275 
276     /**
277      * Find the 0-based column index corresponding to a particular column name.
278      *
279      * @return         index of the column
280      *
281      * @param  colName the name of the column
282      */
283     public int findColumn(String colName) {
284         for (int i = 0; i < getNCols(); i++) {
285             String val = myHeader.getStringValue(TTYPEn.n(i + 1));
286             if (val != null && val.trim().equals(colName)) {
287                 return i;
288             }
289         }
290         return -1;
291     }
292 
293     /**
294      * <p>
295      * Returns the data for a particular column in as an array of elements. See {@link TableData#addColumn(Object)} for
296      * more information about the format of data elements in general.
297      * </p>
298      * 
299      * @param  col           The 0-based column index.
300      * 
301      * @return               an array of primitives (for scalar columns), or else an <code>Object[]</code> array, or
302      *                           possibly <code>null</code>
303      * 
304      * @throws FitsException if the table could not be accessed
305      *
306      * @see                  TableData#getColumn(int)
307      * @see                  #setColumn(int, Object)
308      * @see                  #getElement(int, int)
309      * @see                  #getNCols()
310      */
311     public Object getColumn(int col) throws FitsException {
312         return myData.getColumn(col);
313     }
314 
315     /**
316      * <p>
317      * Returns the data for a particular column in as an array of elements. See {@link TableData#addColumn(Object)} for
318      * more information about the format of data elements in general.
319      * </p>
320      * 
321      * @param  colName       The name or ID of the column as stored by the <code>TTYPE</code><i>n</i> FITS header
322      *                           keyword.
323      * 
324      * @return               an array of primitives (for scalar columns), or else an <code>Object[]</code> array, or
325      *                           possibly <code>null</code>
326      * 
327      * @throws FitsException if the table could not be accessed
328      *
329      * @see                  TableData#getColumn(int)
330      * @see                  #setColumn(int, Object)
331      * @see                  #getElement(int, int)
332      * @see                  #getNCols()
333      */
334     public Object getColumn(String colName) throws FitsException {
335         return getColumn(findColumn(colName));
336     }
337 
338     /**
339      * Get the FITS type of a column in the table.
340      *
341      * @param  index         The 0-based index of the column.
342      *
343      * @return               The FITS type.
344      *
345      * @throws FitsException if an invalid index was requested.
346      */
347     public String getColumnFormat(int index) throws FitsException {
348         int flds = myHeader.getIntValue(TFIELDS, 0);
349         if (index < 0 || index >= flds) {
350             throw new FitsException("Bad column index " + index + " (only " + flds + " columns)");
351         }
352 
353         return myHeader.getStringValue(TFORMn.n(index + 1)).trim();
354     }
355 
356     /**
357      * Convenience method for getting column data. Note that this works only for metadata that returns a string value.
358      * This is equivalent to getStringValue(type+index);
359      *
360      * @return       meta data string value
361      *
362      * @param  index index of the colum
363      * @param  type  the key type to get
364      */
365     public String getColumnMeta(int index, String type) {
366         return myHeader.getStringValue(type + (index + 1));
367     }
368 
369     /**
370      * Gets the name of a column in the table, as it appears in this HDU's header. It may differ from a more currently
371      * assigned name of the binary table data column after the HDU creation or reading.
372      *
373      * @param  index The 0-based column index.
374      *
375      * @return       The column name.
376      * 
377      * @see          BinaryTable.ColumnDesc#name()
378      */
379     public String getColumnName(int index) {
380 
381         String ttype = myHeader.getStringValue(TTYPEn.n(index + 1));
382         if (ttype != null) {
383             ttype = ttype.trim();
384         }
385         return ttype;
386     }
387 
388     /**
389      * <p>
390      * Returns the data for all columns in as an array. See {@link TableData#addColumn(Object)} for more information
391      * about the column format of each element in the returned array.
392      * </p>
393      * 
394      * @return               An array containing the column data for all columns. Each entry in the returned array is
395      *                           itself an array of primitives (for scalar columns), or else an <code>Object[]</code>
396      *                           array, or possibly <code>null</code>.
397      * 
398      * @throws FitsException if the table could not be accessed
399      *
400      * @see                  TableData#getColumn(int)
401      * @see                  #setColumn(int, Object)
402      * @see                  #getElement(int, int)
403      * @see                  #getNCols()
404      */
405     public Object[] getColumns() throws FitsException {
406         Object[] result = new Object[getNCols()];
407         for (int i = 0; i < result.length; i++) {
408             result[i] = getColumn(i);
409         }
410         return result;
411     }
412 
413     /**
414      * Returns a specific element from this table
415      * 
416      * @return               a specific element of the table using 0-based indices.
417      *
418      * @param  row           the row index of the element
419      * @param  col           the column index of the element
420      *
421      * @throws FitsException if the operation failed
422      * 
423      * @see                  #getElement(int, int)
424      */
425     public Object getElement(int row, int col) throws FitsException {
426         return myData.getElement(row, col);
427     }
428 
429     /**
430      * Get the number of columns for this table
431      *
432      * @return The number of columns in the table.
433      */
434     public int getNCols() {
435         return myData.getNCols();
436     }
437 
438     /**
439      * Get the number of rows for this table
440      *
441      * @return The number of rows in the table.
442      */
443     public int getNRows() {
444         return myData.getNRows();
445     }
446 
447     /**
448      * Returns a specific row from this table
449      * 
450      * @return               a specific row of the table.
451      *
452      * @param  row           the index of the row to retreive
453      *
454      * @throws FitsException if the operation failed
455      * 
456      * @see                  #setRow(int, Object[])
457      */
458     public Object[] getRow(int row) throws FitsException {
459         return myData.getRow(row);
460     }
461 
462     /**
463      * Update a column within a table. The new column should have the same format ast the column being replaced. See
464      * {@link TableData#addColumn(Object)} for more information about the column data format.
465      *
466      * @param  col           index of the column to replace
467      * @param  newCol        the replacement column
468      *
469      * @throws FitsException if the operation failed
470      * 
471      * @see                  #getColumn(int)
472      * @see                  #setColumn(String, Object)
473      * @see                  TableData#addColumn(Object)
474      */
475     public void setColumn(int col, Object newCol) throws FitsException {
476         myData.setColumn(col, newCol);
477     }
478 
479     /**
480      * Update a column within a table. The new column should have the same format as the column being replaced. See
481      * {@link TableData#addColumn(Object)} for more information about the column data format.
482      *
483      * @param  colName       name of the column to replace
484      * @param  newCol        the replacement column
485      *
486      * @throws FitsException if the operation failed
487      * 
488      * @see                  #getColumn(String)
489      * @see                  #setColumn(int, Object)
490      * @see                  TableData#addColumn(Object)
491      */
492     public void setColumn(String colName, Object newCol) throws FitsException {
493         setColumn(findColumn(colName), newCol);
494     }
495 
496     /**
497      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
498      * be organized together.
499      *
500      * @param  index               The 0-based index of the column
501      * @param  key                 The column key. I.e., the keyword will be key+(index+1)
502      * @param  value               The value to be placed in the header.
503      * @param  comment             The comment for the header
504      * @param  after               Should the header card be after the current column metadata block
505      *                                 (<code>true</code>), or immediately before the TFORM card (<code>false</code>).
506      *
507      * @throws HeaderCardException if the header could not be updated
508      */
509     public void setColumnMeta(int index, IFitsHeader key, String value, String comment, boolean after)
510             throws HeaderCardException {
511         setCurrentColumn(index, after);
512         myHeader.addLine(new HeaderCard(key.n(index + 1).key(), value, comment));
513     }
514 
515     /**
516      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
517      * be organized together.
518      *
519      * @param  index               The 0-based index of the column
520      * @param  key                 The column key. I.e., the keyword will be key+(index+1)
521      * @param  value               The value to be placed in the header.
522      * @param  comment             The comment for the header
523      * @param  after               Should the header card be after the current column metadata block
524      *                                 (<code>true</code>), or immediately before the TFORM card (<code>false</code>).
525      *
526      * @throws HeaderCardException if the header could not be updated
527      *
528      * @since                      1.16
529      */
530     public void setColumnMeta(int index, IFitsHeader key, Number value, String comment, boolean after)
531             throws HeaderCardException {
532         setCurrentColumn(index, after);
533         myHeader.addLine(new HeaderCard(key.n(index + 1).key(), value, comment));
534     }
535 
536     /**
537      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
538      * be organized together.
539      *
540      * @param  index               The 0-based index of the column
541      * @param  key                 The column key. I.e., the keyword will be key+(index+1)
542      * @param  value               The value to be placed in the header.
543      * @param  comment             The comment for the header
544      * @param  after               Should the header card be after the current column metadata block
545      *                                 (<code>true</code>), or immediately before the TFORM card (<code>false</code>).
546      *
547      * @throws HeaderCardException if the header could not be updated
548      */
549     public void setColumnMeta(int index, String key, Boolean value, String comment, boolean after)
550             throws HeaderCardException {
551         setCurrentColumn(index, after);
552         myHeader.addLine(new HeaderCard(key + (index + 1), value, comment));
553     }
554 
555     /**
556      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
557      * be organized together.
558      *
559      * @param  index               The 0-based index of the column
560      * @param  key                 The column key. I.e., the keyword will be key+(index+1)
561      * @param  value               The value to be placed in the header.
562      * @param  comment             The comment for the header
563      * @param  after               Should the header card be after the current column metadata block
564      *                                 (<code>true</code>), or immediately before the TFORM card (<code>false</code>).
565      *
566      * @throws HeaderCardException if the header could not be updated
567      */
568     public void setColumnMeta(int index, String key, Number value, String comment, boolean after)
569             throws HeaderCardException {
570         setCurrentColumn(index, after);
571         myHeader.addLine(new HeaderCard(key + (index + 1), value, comment));
572     }
573 
574     /**
575      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
576      * be organized together.
577      *
578      * @param  index               The 0-based index of the column
579      * @param  key                 The column key. I.e., the keyword will be key+(index+1)
580      * @param  value               The value to be placed in the header.
581      * @param  precision           The maximum number of decimal places to show after the leading figure. (Trailing
582      *                                 zeroes will be ommitted.)
583      * @param  comment             The comment for the header
584      * @param  after               Should the header card be after the current column metadata block
585      *                                 (<code>true</code>), or immediately before the TFORM card (<code>false</code>).
586      *
587      * @throws HeaderCardException if the header could not be updated
588      */
589     public void setColumnMeta(int index, String key, Number value, int precision, String comment, boolean after)
590             throws HeaderCardException {
591         setCurrentColumn(index, after);
592         myHeader.addLine(new HeaderCard(key + (index + 1), value, precision, comment));
593     }
594 
595     /**
596      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
597      * be organized together.
598      *
599      * @param  index               The 0-based index of the column
600      * @param  key                 The column key. I.e., the keyword will be key+(index+1)
601      * @param  value               The value to be placed in the header.
602      * @param  comment             The comment for the header
603      *
604      * @throws HeaderCardException if the header could not be updated
605      */
606     public void setColumnMeta(int index, String key, String value, String comment) throws HeaderCardException {
607         setColumnMeta(index, key, value, comment, true);
608     }
609 
610     /**
611      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
612      * be organized together.
613      *
614      * @param      index               The 0-based index of the column
615      * @param      key                 The column key. I.e., the keyword will be key+(index+1)
616      * @param      value               The value to be placed in the header.
617      * @param      comment             The comment for the header
618      * @param      after               Should the header card be after the current column metadata block (true), or
619      *                                     immediately before the TFORM card (false). @throws FitsException if the
620      *                                     operation failed
621      *
622      * @throws     HeaderCardException if the header could not be updated
623      *
624      * @deprecated                     use {@link #setColumnMeta(int, IFitsHeader, String, String, boolean)}
625      */
626     @Deprecated
627     public void setColumnMeta(int index, String key, String value, String comment, boolean after)
628             throws HeaderCardException {
629         setCurrentColumn(index, after);
630         myHeader.addLine(new HeaderCard(key + (index + 1), value, comment));
631     }
632 
633     /**
634      * Sets the name / ID of a specific column in this table. Naming columns is generally a good idea so that people can
635      * figure out what sort of data actually appears in specific table columns.
636      * 
637      * @param  index                     the column index
638      * @param  name                      the name or ID we want to assing to the column
639      * @param  comment                   Any additional comment we would like to store alongside in the FITS header.
640      *                                       (The comment may be truncated or even ommitted, depending on space
641      *                                       constraints in the FITS header.
642      * 
643      * @throws IndexOutOfBoundsException if the table has no column matching the index
644      * @throws HeaderCardException       if there was a problem wil adding the associated descriptive FITS header
645      *                                       keywords to this table's header.
646      * 
647      * @see                              #getColumnName(int)
648      * @see                              #getDefaultColumnName(int)
649      */
650     public void setColumnName(int index, String name, String comment)
651             throws IndexOutOfBoundsException, HeaderCardException {
652         if (index < 0 || index >= getNCols()) {
653             throw new IndexOutOfBoundsException(
654                     "column index " + index + " is out of bounds for table with " + getNCols() + " columns");
655         }
656         setColumnMeta(index, TTYPEn, name, comment, true);
657     }
658 
659     /**
660      * Set the cursor in the header to point after the metadata for the specified column
661      *
662      * @param      col The 0-based index of the column
663      * 
664      * @deprecated     (<i>for internal use</i>) Will be removed int the future (no longer used).
665      */
666     public void setCurrentColumn(int col) {
667         setCurrentColumn(col, true);
668     }
669 
670     /**
671      * Set the cursor in the header to point either before the TFORMn value or after the column metadata
672      *
673      * @param      col   The 0-based index of the column
674      * @param      after True if the cursor should be placed after the existing column metadata or false if the cursor
675      *                       is to be placed before the TFORM value. If no corresponding TFORM is found, the cursor will
676      *                       be placed at the end of current header.
677      * 
678      * @deprecated       (<i>for internal use</i>) Will have private access in the future.
679      */
680     public void setCurrentColumn(int col, boolean after) {
681         if (after) {
682             myHeader.positionAfterIndex(TFORMn, col + 1);
683         } else {
684             myHeader.findCard(TFORMn.n(col + 1));
685         }
686     }
687 
688     /**
689      * Update a single element within the table.
690      *
691      * @param  row           the row index
692      * @param  col           the column index
693      * @param  element       the replacement element
694      *
695      * @throws FitsException if the operation failed
696      * 
697      * @see                  #getElement(int, int)
698      */
699     public void setElement(int row, int col, Object element) throws FitsException {
700         myData.setElement(row, col, element);
701     }
702 
703     /**
704      * Update a row within a table.
705      *
706      * @param  row           row index
707      * @param  newRow        the replacement row
708      *
709      * @throws FitsException if the operation failed
710      * 
711      * @see                  #getRow(int)
712      */
713     public void setRow(int row, Object[] newRow) throws FitsException {
714         myData.setRow(row, newRow);
715     }
716 }