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