001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the file COPYING. * 009 * COPYING can be found at the root of the source code distribution tree. * 010 * If you do not have access to this file, you may request a copy from * 011 * help@hdfgroup.org. * 012 ****************************************************************************/ 013 014package hdf.view; 015 016import java.awt.Color; 017import java.awt.Component; 018import java.awt.event.ActionEvent; 019import java.awt.event.ActionListener; 020import java.awt.event.KeyEvent; 021import java.awt.event.KeyListener; 022import java.awt.event.MouseEvent; 023import java.io.BufferedInputStream; 024import java.io.BufferedWriter; 025import java.io.File; 026import java.io.FileWriter; 027import java.io.InputStream; 028import java.io.PrintWriter; 029import java.io.RandomAccessFile; 030import java.util.Enumeration; 031import java.util.HashMap; 032import java.util.Iterator; 033import java.util.List; 034import java.util.Map; 035 036import javax.print.Doc; 037import javax.print.DocFlavor; 038import javax.print.DocPrintJob; 039import javax.print.PrintService; 040import javax.print.PrintServiceLookup; 041import javax.print.SimpleDoc; 042import javax.print.StreamPrintServiceFactory; 043import javax.swing.CellEditor; 044import javax.swing.DefaultCellEditor; 045import javax.swing.JFileChooser; 046import javax.swing.JFrame; 047import javax.swing.JInternalFrame; 048import javax.swing.JLabel; 049import javax.swing.JMenu; 050import javax.swing.JMenuBar; 051import javax.swing.JMenuItem; 052import javax.swing.JOptionPane; 053import javax.swing.JPanel; 054import javax.swing.JScrollPane; 055import javax.swing.JTable; 056import javax.swing.JTextArea; 057import javax.swing.JTextField; 058import javax.swing.JViewport; 059import javax.swing.SwingConstants; 060import javax.swing.UIManager; 061import javax.swing.WindowConstants; 062import javax.swing.event.ChangeEvent; 063import javax.swing.event.ListSelectionEvent; 064import javax.swing.table.AbstractTableModel; 065import javax.swing.table.DefaultTableCellRenderer; 066import javax.swing.table.JTableHeader; 067import javax.swing.table.TableCellRenderer; 068import javax.swing.table.TableColumn; 069import javax.swing.table.TableColumnModel; 070 071import hdf.object.Dataset; 072import hdf.object.FileFormat; 073import hdf.object.HObject; 074import hdf.object.ScalarDS; 075 076/** 077 * TextView displays an HDF string dataset in text. 078 * 079 * @author Peter X. Cao 080 * @version 2.4 9/6/2007 081 */ 082public class DefaultTextView extends JInternalFrame implements TextView, 083 ActionListener, KeyListener { 084 private static final long serialVersionUID = 3892752752951438428L; 085 086 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultTextView.class); 087 088 /** 089 * The main HDFView. 090 */ 091 private final ViewManager viewer; 092 093 /** 094 * The Scalar Dataset. 095 */ 096 private ScalarDS dataset; 097 098 /** 099 * The string text. 100 */ 101 private String[] text; 102 103 /** The table to display the text content */ 104 private JTable table; 105 106 private boolean isReadOnly = false; 107 108 private boolean isTextChanged = false; 109 110 private RowHeader rowHeaders = null; 111 112 private int indexBase = 0; 113 114 private TextAreaEditor textEditor = null; 115 116 public DefaultTextView(ViewManager theView) { 117 this(theView, null); 118 } 119 120 /** 121 * Constructs a TextView. 122 * 123 * @param theView 124 * the main HDFView. 125 * @param map 126 * the properties on how to show the data. The map is used to 127 * allow applications to pass properties on how to display the 128 * data, such as, transposing data, showing data as character, 129 * applying bitmask, and etc. Predefined keys are listed at 130 * ViewProperties.DATA_VIEW_KEY. 131 */ 132 public DefaultTextView(ViewManager theView, HashMap map) { 133 viewer = theView; 134 135 text = null; 136 table = null; 137 dataset = null; 138 textEditor = new TextAreaEditor(this); 139 140 if (ViewProperties.isIndexBase1()) 141 indexBase = 1; 142 143 HObject hobject = null; 144 if (map != null) 145 hobject = (HObject) map.get(ViewProperties.DATA_VIEW_KEY.OBJECT); 146 else 147 hobject = theView.getTreeView().getCurrentObject(); 148 149 if (!(hobject instanceof ScalarDS)) { 150 return; 151 } 152 153 dataset = (ScalarDS) hobject; 154 155 if (!dataset.isText()) { 156 viewer.showStatus("Cannot display non-text dataset in text view."); 157 dataset = null; 158 return; 159 } 160 161 isReadOnly = dataset.getFileFormat().isReadOnly(); 162 163 try { 164 text = (String[]) dataset.getData(); 165 } 166 catch (Exception ex) { 167 JOptionPane.showMessageDialog(this, ex.getMessage(), 168 "TextView:"+getTitle(), 169 JOptionPane.ERROR_MESSAGE); 170 text = null; 171 } 172 173 if (text == null) { 174 viewer.showStatus("Loading text dataset failed - " 175 + dataset.getName()); 176 dataset = null; 177 return; 178 } 179 180 String fname = new java.io.File(dataset.getFile()).getName(); 181 this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 182 this.setTitle("TextView - " + dataset.getName() + " - " 183 + dataset.getPath() + " - " + fname); 184 this.setFrameIcon(ViewProperties.getTextIcon()); 185 this.setName("textdata"); 186 187 int rank = dataset.getRank(); 188 long start[] = dataset.getStartDims(); 189 long count[] = dataset.getSelectedDims(); 190 191 String colName = "Data selection: ["+start[0]; 192 for (int i=1; i<rank; i++) { 193 colName += ", "+start[i]; 194 } 195 colName += "] ~ ["+(start[0]+count[0]-1); 196 for (int i=1; i<rank; i++) { 197 colName += ", "+(start[i]+count[i]-1); 198 } 199 colName += "]"; 200 201 table = createTable(colName); 202 203 JTableHeader colHeader = table.getTableHeader(); 204 colHeader.setReorderingAllowed(false); 205 //colHeader.setBackground(Color.black); 206 207 rowHeaders = new RowHeader(table, dataset); 208 209 // add the table to a scroller 210 JScrollPane scrollingTable = new JScrollPane(table); 211 scrollingTable.getVerticalScrollBar().setUnitIncrement(100); 212 scrollingTable.getHorizontalScrollBar().setUnitIncrement(100); 213 214 JViewport viewp = new JViewport(); 215 viewp.add(rowHeaders); 216 viewp.setPreferredSize(rowHeaders.getPreferredSize()); 217 scrollingTable.setRowHeader(viewp); 218 219 TableColumnModel cmodel = table.getColumnModel(); 220 TextAreaRenderer textAreaRenderer = new TextAreaRenderer(); 221 222 cmodel.getColumn(0).setCellRenderer(textAreaRenderer); 223 cmodel.getColumn(0).setCellEditor(textEditor); 224 225 ((JPanel) getContentPane()).add(scrollingTable); 226 227 setJMenuBar(createMenuBar()); 228 } 229 230 public void actionPerformed(ActionEvent e) { 231 Object source = e.getSource(); 232 String cmd = e.getActionCommand(); 233 234 if (cmd.equals("Close")) { 235 dispose(); // terminate the application 236 } 237 else if (cmd.equals("Save to text file")) { 238 try { 239 saveAsText(); 240 } 241 catch (Exception ex) { 242 JOptionPane.showMessageDialog((JFrame) viewer, ex, getTitle(), 243 JOptionPane.ERROR_MESSAGE); 244 } 245 } 246 else if (cmd.equals("Save changes")) { 247 updateValueInFile(); 248 } 249 else if (cmd.equals("Print")) { 250 print(); 251 } 252 } 253 254 /** 255 * Creates a Table to hold a compound dataset. 256 * 257 * @param colName the name of the column 258 */ 259 private JTable createTable(final String colName) { 260 JTable theTable = null; 261 262 AbstractTableModel tm = new AbstractTableModel() 263 { 264 public int getColumnCount() { 265 return 1; 266 } 267 268 public int getRowCount() { 269 return text.length; 270 } 271 272 public String getColumnName(int col) { 273 return colName; 274 } 275 276 public Object getValueAt(int row, int column) 277 { 278 return text[row]; 279 } 280 }; 281 282 theTable = new JTable(tm) { 283 private static final long serialVersionUID = -6571266777012522255L; 284 285 @Override 286 public boolean isCellEditable(int row, int column) { 287 return !isReadOnly; 288 } 289 290 @Override 291 public void editingStopped(ChangeEvent e) { 292 int row = getEditingRow(); 293 int col = getEditingColumn(); 294 super.editingStopped(e); 295 296 Object source = e.getSource(); 297 298 if (source instanceof CellEditor) { 299 CellEditor editor = (CellEditor) source; 300 String cellValue = (String) editor.getCellEditorValue(); 301 text[row] = cellValue; 302 } // if (source instanceof CellEditor) 303 } 304 }; 305 theTable.setName("TextView"); 306 307 return theTable; 308 } 309 310 public void keyPressed(KeyEvent e) { 311 } 312 313 public void keyReleased(KeyEvent e) { 314 } 315 316 public void keyTyped(KeyEvent e) { 317 isTextChanged = true; 318 } 319 320 private JMenuBar createMenuBar() { 321 JMenuBar bar = new JMenuBar(); 322 JMenu menu = new JMenu("Text", false); 323 menu.setMnemonic('T'); 324 bar.add(menu); 325 326 JMenuItem item = new JMenuItem("Save To Text File"); 327 // item.setMnemonic(KeyEvent.VK_T); 328 item.addActionListener(this); 329 item.setActionCommand("Save to text file"); 330 menu.add(item); 331 332 menu.addSeparator(); 333 334 item = new JMenuItem("Save Changes"); 335 item.addActionListener(this); 336 item.setActionCommand("Save changes"); 337 menu.add(item); 338 339 menu.addSeparator(); 340 341 menu.addSeparator(); 342 343 item = new JMenuItem("Close"); 344 item.addActionListener(this); 345 item.setActionCommand("Close"); 346 menu.add(item); 347 348 return bar; 349 } 350 351 /** 352 * Update dataset value in file. The change will go to file. 353 */ 354 public void updateValueInFile() { 355 if (!(dataset instanceof ScalarDS) || isReadOnly || !isTextChanged) return; 356 357 int row = table.getEditingRow(); 358 if (row >= 0) { 359 // make sure to update the current row 360 String cellValue = (String) textEditor.getCellEditorValue(); 361 text[row] = cellValue; 362 } 363 364 try { 365 dataset.write(); 366 } 367 catch (Exception ex) { 368 JOptionPane.showMessageDialog(this, ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE); 369 return; 370 } 371 isTextChanged = false; 372 } 373 374 /** Save data as text. */ 375 private void saveAsText() throws Exception { 376 final JFileChooser fchooser = new JFileChooser(dataset.getFile()); 377 fchooser.setFileFilter(DefaultFileFilter.getFileFilterText()); 378 fchooser.changeToParentDirectory(); 379 fchooser.setDialogTitle("Save Current Data To Text File --- " + dataset.getName()); 380 381 File chosenFile = new File(dataset.getName() + ".txt"); 382 fchooser.setSelectedFile(chosenFile); 383 int returnVal = fchooser.showSaveDialog(this); 384 385 if (returnVal != JFileChooser.APPROVE_OPTION) { 386 return; 387 } 388 389 chosenFile = fchooser.getSelectedFile(); 390 if (chosenFile == null) { 391 return; 392 } 393 394 String fname = chosenFile.getAbsolutePath(); 395 396 // check if the file is in use 397 List fileList = viewer.getTreeView().getCurrentFiles(); 398 if (fileList != null) { 399 FileFormat theFile = null; 400 Iterator iterator = fileList.iterator(); 401 while (iterator.hasNext()) { 402 theFile = (FileFormat) iterator.next(); 403 if (theFile.getFilePath().equals(fname)) { 404 JOptionPane.showMessageDialog(this, "Unable to save data to file \"" + fname 405 + "\". \nThe file is being used.", 406 getTitle(), JOptionPane.ERROR_MESSAGE); 407 return; 408 } 409 } 410 } 411 412 if (chosenFile.exists()) { 413 int newFileFlag = JOptionPane.showConfirmDialog(this, "File exists. Do you want to replace it ?", 414 this.getTitle(), JOptionPane.YES_NO_OPTION); 415 if (newFileFlag == JOptionPane.NO_OPTION) { 416 return; 417 } 418 } 419 420 PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter( 421 chosenFile))); 422 423 int rows = text.length; 424 for (int i = 0; i < rows; i++) { 425 out.print(text[i].trim()); 426 out.println(); 427 out.println(); 428 } 429 430 out.flush(); 431 out.close(); 432 433 viewer.showStatus("Data save to: " + fname); 434 435 try { 436 RandomAccessFile rf = new RandomAccessFile(chosenFile, "r"); 437 long size = rf.length(); 438 rf.close(); 439 viewer.showStatus("File size (bytes): " + size); 440 } 441 catch (Exception ex) { 442 log.debug("raf file size:", ex); 443 } 444 } 445 446 @Override 447 public void dispose() { 448 if (isTextChanged && !isReadOnly) { 449 int op = JOptionPane.showConfirmDialog(this, "\"" 450 + dataset.getName() + "\" has changed.\n" 451 + "Do you want to save the changes?", getTitle(), 452 JOptionPane.YES_NO_OPTION); 453 454 if (op == JOptionPane.YES_OPTION) { 455 updateValueInFile(); 456 } 457 } 458 459 viewer.removeDataView(this); 460 461 super.dispose(); 462 } 463 464 // Implementing DataView. 465 public HObject getDataObject() { 466 return dataset; 467 } 468 469 // Implementing TextView. 470 public String[] getText() { 471 return text; 472 } 473 474 // print the table 475 private void print() { 476 StreamPrintServiceFactory[] spsf = StreamPrintServiceFactory 477 .lookupStreamPrintServiceFactories(null, null); 478 for (int i = 0; i < spsf.length; i++) { 479 System.out.println(spsf[i]); 480 } 481 DocFlavor[] docFlavors = spsf[0].getSupportedDocFlavors(); 482 for (int i = 0; i < docFlavors.length; i++) { 483 System.out.println(docFlavors[i]); 484 } 485 486 // TODO: windows url 487 // Get a text DocFlavor 488 InputStream is = null; 489 try { 490 is = new BufferedInputStream(new java.io.FileInputStream( 491 "e:\\temp\\t.html")); 492 } 493 catch (Exception ex) { 494 log.debug("Get a text DocFlavor:", ex); 495 } 496 DocFlavor flavor = DocFlavor.STRING.TEXT_HTML; 497 498 // Get all available print services 499 PrintService[] services = PrintServiceLookup.lookupPrintServices(null, 500 null); 501 502 // Print this job on the first print server 503 DocPrintJob job = services[0].createPrintJob(); 504 Doc doc = new SimpleDoc(is, flavor, null); 505 506 // Print it 507 try { 508 job.print(doc, null); 509 } 510 catch (Exception ex) { 511 log.debug("print(): failure: ", ex); 512 } 513 } 514 515 private class TextAreaRenderer extends JTextArea implements 516 TableCellRenderer { 517 private static final long serialVersionUID = -5869975162678521978L; 518 519 private final DefaultTableCellRenderer adaptee = new DefaultTableCellRenderer(); 520 521 /** map from table to map of rows to map of column heights */ 522 private final Map cellSizes = new HashMap(); 523 524 public TextAreaRenderer() { 525 setLineWrap(true); 526 setWrapStyleWord(true); 527 } 528 529 public Component getTableCellRendererComponent( 530 // 531 JTable table, Object obj, boolean isSelected, boolean hasFocus, 532 int row, int column) { 533 // set the colours, etc. using the standard for that platform 534 adaptee.getTableCellRendererComponent(table, obj, isSelected, 535 hasFocus, row, column); 536 setForeground(adaptee.getForeground()); 537 setBackground(adaptee.getBackground()); 538 setBorder(adaptee.getBorder()); 539 setFont(adaptee.getFont()); 540 setText(adaptee.getText()); 541 542 // This line was very important to get it working with JDK1.4 543 TableColumnModel columnModel = table.getColumnModel(); 544 setSize(columnModel.getColumn(column).getWidth(), 100000); 545 int height_wanted = (int) getPreferredSize().getHeight(); 546 addSize(table, row, column, height_wanted); 547 height_wanted = findTotalMaximumRowSize(table, row); 548 if (height_wanted != table.getRowHeight(row)) { 549 table.setRowHeight(row, height_wanted); 550 rowHeaders.setRowHeight(row, height_wanted); 551 552 } 553 return this; 554 } 555 556 private void addSize(JTable table, int row, int column, int height) { 557 Map rows = (Map) cellSizes.get(table); 558 if (rows == null) { 559 cellSizes.put(table, rows = new HashMap()); 560 } 561 Map rowheights = (Map) rows.get(new Integer(row)); 562 if (rowheights == null) { 563 rows.put(new Integer(row), rowheights = new HashMap()); 564 } 565 rowheights.put(new Integer(column), new Integer(height)); 566 } 567 568 /** 569 * Look through all columns and get the renderer. If it is also a 570 * TextAreaRenderer, we look at the maximum height in its hash table for 571 * this row. 572 */ 573 private int findTotalMaximumRowSize(JTable table, int row) { 574 int maximum_height = 0; 575 Enumeration columns = table.getColumnModel().getColumns(); 576 while (columns.hasMoreElements()) { 577 TableColumn tc = (TableColumn) columns.nextElement(); 578 TableCellRenderer cellRenderer = tc.getCellRenderer(); 579 if (cellRenderer instanceof TextAreaRenderer) { 580 TextAreaRenderer tar = (TextAreaRenderer) cellRenderer; 581 maximum_height = Math.max(maximum_height, tar 582 .findMaximumRowSize(table, row)); 583 } 584 } 585 return maximum_height; 586 } 587 588 private int findMaximumRowSize(JTable table, int row) { 589 Map rows = (Map) cellSizes.get(table); 590 if (rows == null) { 591 return 0; 592 } 593 Map rowheights = (Map) rows.get(new Integer(row)); 594 if (rowheights == null) { 595 return 0; 596 } 597 int maximum_height = 0; 598 for (Iterator it = rowheights.entrySet().iterator(); it.hasNext();) { 599 Map.Entry entry = (Map.Entry) it.next(); 600 int cellHeight = ((Integer) entry.getValue()).intValue(); 601 maximum_height = Math.max(maximum_height, cellHeight); 602 } 603 return maximum_height; 604 } 605 } 606 607 private class TextAreaEditor extends DefaultCellEditor { 608 private static final long serialVersionUID = 1721646779892184957L; 609 610 public TextAreaEditor(KeyListener keyListener) { 611 super(new JTextField()); 612 613 final JTextArea textArea = new JTextArea(); 614 615 textArea.addKeyListener(keyListener); 616 textArea.setWrapStyleWord(true); 617 textArea.setLineWrap(true); 618 JScrollPane scrollPane = new JScrollPane(textArea); 619 scrollPane.setBorder(null); 620 editorComponent = scrollPane; 621 delegate = new DefaultCellEditor.EditorDelegate() { 622 private static final long serialVersionUID = 7662356579385373160L; 623 624 @Override 625 public void setValue(Object value) { 626 textArea.setText((value != null) ? value.toString() : ""); 627 } 628 629 @Override 630 public Object getCellEditorValue() { 631 return textArea.getText(); 632 } 633 }; 634 } 635 } 636 637 /** RowHeader defines the row header component of the Spreadsheet. */ 638 private class RowHeader extends JTable { 639 private static final long serialVersionUID = 2572539746584274419L; 640 private int currentRowIndex = -1; 641 private int lastRowIndex = -1; 642 private JTable parentTable; 643 644 public RowHeader(JTable pTable, Dataset dset) { 645 // Create a JTable with the same number of rows as 646 // the parent table and one column. 647 super(pTable.getRowCount(), 1); 648 649 long[] startArray = dset.getStartDims(); 650 long[] strideArray = dset.getStride(); 651 int[] selectedIndex = dset.getSelectedIndex(); 652 int start = (int) startArray[selectedIndex[0]]; 653 int stride = (int) strideArray[selectedIndex[0]]; 654 655 // Store the parent table. 656 parentTable = pTable; 657 658 // Set the values of the row headers starting at 0. 659 int n = parentTable.getRowCount(); 660 for (int i = 0; i < n; i++) { 661 setValueAt(new Integer(start + indexBase+ i * stride), i, 0); 662 } 663 664 // Get the only table column. 665 TableColumn col = getColumnModel().getColumn(0); 666 667 // Use the cell renderer in the column. 668 col.setCellRenderer(new RowHeaderRenderer()); 669 } 670 671 /** Overridden to return false since the headers are not editable. */ 672 @Override 673 public boolean isCellEditable(int row, int col) { 674 return false; 675 } 676 677 /** This is called when the selection changes in the row headers. */ 678 @Override 679 public void valueChanged(ListSelectionEvent e) { 680 if (parentTable == null) { 681 return; 682 } 683 684 int rows[] = getSelectedRows(); 685 if ((rows == null) || (rows.length == 0)) { 686 return; 687 } 688 689 parentTable.clearSelection(); 690 parentTable.setRowSelectionInterval(rows[0], rows[rows.length - 1]); 691 parentTable.setColumnSelectionInterval(0, parentTable 692 .getColumnCount() - 1); 693 } 694 695 @Override 696 protected void processMouseMotionEvent(MouseEvent e) { 697 if (e.getID() == MouseEvent.MOUSE_DRAGGED) { 698 int colEnd = rowAtPoint(e.getPoint()); 699 700 if (colEnd < 0) { 701 colEnd = 0; 702 } 703 if (currentRowIndex < 0) { 704 currentRowIndex = 0; 705 } 706 707 parentTable.clearSelection(); 708 709 if (colEnd > currentRowIndex) { 710 parentTable 711 .setRowSelectionInterval(currentRowIndex, colEnd); 712 } 713 else { 714 parentTable 715 .setRowSelectionInterval(colEnd, currentRowIndex); 716 } 717 718 parentTable.setColumnSelectionInterval(0, parentTable 719 .getColumnCount() - 1); 720 } 721 } 722 723 @Override 724 protected void processMouseEvent(MouseEvent e) { 725 int mouseID = e.getID(); 726 727 if (mouseID == MouseEvent.MOUSE_CLICKED) { 728 if (currentRowIndex < 0) { 729 return; 730 } 731 732 if (e.isControlDown()) { 733 // select discontinguous rows 734 parentTable.addRowSelectionInterval(currentRowIndex, 735 currentRowIndex); 736 } 737 else if (e.isShiftDown()) { 738 // select continguous columns 739 if (lastRowIndex < 0) { 740 parentTable.addRowSelectionInterval(0, currentRowIndex); 741 } 742 else if (lastRowIndex < currentRowIndex) { 743 parentTable.addRowSelectionInterval(lastRowIndex, 744 currentRowIndex); 745 } 746 else { 747 parentTable.addRowSelectionInterval(currentRowIndex, 748 lastRowIndex); 749 } 750 } 751 else { 752 // clear old selection and set new column selection 753 parentTable.clearSelection(); 754 parentTable.setRowSelectionInterval(currentRowIndex, 755 currentRowIndex); 756 } 757 758 lastRowIndex = currentRowIndex; 759 760 parentTable.setColumnSelectionInterval(0, parentTable 761 .getColumnCount() - 1); 762 } 763 else if (mouseID == MouseEvent.MOUSE_PRESSED) { 764 currentRowIndex = rowAtPoint(e.getPoint()); 765 } 766 } 767 } // private class RowHeader extends JTable 768 769 /** 770 * RowHeaderRenderer is a custom cell renderer that displays cells as 771 * buttons. 772 */ 773 private class RowHeaderRenderer extends JLabel implements TableCellRenderer { 774 private static final long serialVersionUID = 3081275694689434654L; 775 776 public RowHeaderRenderer() { 777 super(); 778 setHorizontalAlignment(SwingConstants.CENTER); 779 780 setOpaque(true); 781 setBorder(UIManager.getBorder("TableHeader.cellBorder")); 782 setBackground(Color.lightGray); 783 } 784 785 /** Configures the button for the current cell, and returns it. */ 786 public Component getTableCellRendererComponent(JTable table, 787 Object value, boolean isSelected, boolean hasFocus, int row, 788 int column) { 789 setFont(table.getFont()); 790 791 if (value != null) { 792 setText(value.toString()); 793 } 794 795 return this; 796 } 797 } // private class RowHeaderRenderer extends JLabel implements 798 // TableCellRenderer 799 800}