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