1 /* 2 * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.tools.jconsole.inspector; 27 28 import javax.swing.*; 29 import javax.swing.event.*; 30 import javax.swing.table.*; 31 import javax.swing.tree.*; 32 import javax.swing.border.*; 33 import java.awt.BorderLayout; 34 import java.awt.GridLayout; 35 import java.awt.FlowLayout; 36 import java.awt.Component; 37 import java.awt.EventQueue; 38 import java.awt.Color; 39 import java.awt.Font; 40 import java.awt.Rectangle; 41 import java.awt.event.*; 42 import java.awt.Insets; 43 import java.awt.Dimension; 44 import java.awt.GridBagConstraints; 45 import java.awt.GridBagLayout; 46 import java.util.*; 47 import java.io.*; 48 import java.lang.reflect.Array; 49 50 import javax.management.*; 51 import javax.management.openmbean.*; 52 53 import sun.tools.jconsole.BorderedComponent; 54 import sun.tools.jconsole.JConsole; 55 import sun.tools.jconsole.LabeledComponent; 56 import sun.tools.jconsole.Resources; 57 import sun.tools.jconsole.VariableGridLayout; 58 59 @SuppressWarnings("serial") 60 public class XOpenTypeViewer extends JPanel implements ActionListener { 61 JButton prev, incr, decr, tabularPrev, tabularNext; 62 JLabel compositeLabel, tabularLabel; 63 JScrollPane container; 64 XOpenTypeData current; 65 XOpenTypeDataListener listener = new XOpenTypeDataListener(); 66 67 private static final String compositeNavigationSingle = 68 Resources.getText("MBeansTab.compositeNavigationSingle"); 69 private static final String tabularNavigationSingle = 70 Resources.getText("MBeansTab.tabularNavigationSingle"); 71 72 private static TableCellEditor editor = 73 new Utils.ReadOnlyTableCellEditor(new JTextField()); 74 75 class XOpenTypeDataListener extends MouseAdapter { 76 XOpenTypeDataListener() { 77 } 78 79 public void mousePressed(MouseEvent e) { 80 if(e.getButton() == MouseEvent.BUTTON1) { 81 if(e.getClickCount() >= 2) { 82 XOpenTypeData elem = getSelectedViewedOpenType(); 83 if(elem != null) { 84 try { 85 elem.viewed(XOpenTypeViewer.this); 86 }catch(Exception ex) { 87 //Nothing to change, the element 88 //can't be displayed 89 } 90 } 91 } 92 } 93 } 94 95 private XOpenTypeData getSelectedViewedOpenType() { 96 int row = XOpenTypeViewer.this.current.getSelectedRow(); 97 int col = XOpenTypeViewer.this.current.getSelectedColumn(); 98 Object elem = 99 XOpenTypeViewer.this.current.getModel().getValueAt(row, col); 100 if(elem instanceof XOpenTypeData) 101 return (XOpenTypeData) elem; 102 else 103 return null; 104 } 105 } 106 107 static interface Navigatable { 108 public void incrElement(); 109 public void decrElement(); 110 public boolean canDecrement(); 111 public boolean canIncrement(); 112 public int getElementCount(); 113 public int getSelectedElementIndex(); 114 } 115 116 static interface XViewedTabularData extends Navigatable { 117 } 118 119 static interface XViewedArrayData extends Navigatable { 120 } 121 122 static abstract class XOpenTypeData extends JTable { 123 XOpenTypeData parent; 124 private Color defaultColor; 125 protected int col1Width = -1; 126 protected int col2Width = -1; 127 private boolean init; 128 private Font normalFont, boldFont; 129 protected XOpenTypeData(XOpenTypeData parent) { 130 this.parent = parent; 131 } 132 133 public XOpenTypeData getViewedParent() { 134 return parent; 135 } 136 137 public String getToolTip(int row, int col) { 138 if(col == 1) { 139 Object value = getModel().getValueAt(row, col); 140 if (value != null) { 141 if(isClickableElement(value)) 142 return Resources.getText("Double click to visualize") 143 + ". " + value.toString(); 144 else 145 return value.toString(); 146 } 147 } 148 return null; 149 } 150 151 public TableCellRenderer getCellRenderer(int row, int column) { 152 DefaultTableCellRenderer tcr = 153 (DefaultTableCellRenderer)super.getCellRenderer(row,column); 154 tcr.setToolTipText(getToolTip(row,column)); 155 return tcr; 156 } 157 158 public void renderKey(String key, Component comp) { 159 comp.setFont(normalFont); 160 } 161 162 public Component prepareRenderer(TableCellRenderer renderer, 163 int row, int column) { 164 Component comp = super.prepareRenderer(renderer, row, column); 165 166 if (normalFont == null) { 167 normalFont = comp.getFont(); 168 boldFont = normalFont.deriveFont(Font.BOLD); 169 } 170 171 Object o = ((DefaultTableModel) getModel()).getValueAt(row, column); 172 if (column == 0) { 173 String key = o.toString(); 174 renderKey(key, comp); 175 } else { 176 if (isClickableElement(o)) { 177 comp.setFont(boldFont); 178 } else { 179 comp.setFont(normalFont); 180 } 181 } 182 183 return comp; 184 } 185 186 protected boolean isClickableElement(Object obj) { 187 if (obj instanceof XOpenTypeData) { 188 if (obj instanceof Navigatable) { 189 return (((Navigatable) obj).getElementCount() != 0); 190 } else { 191 return (obj instanceof XCompositeData); 192 } 193 } 194 return false; 195 } 196 197 protected void updateColumnWidth() { 198 if (!init) { 199 TableColumnModel colModel = getColumnModel(); 200 if (col2Width == -1) { 201 col1Width = col1Width * 7; 202 if (col1Width < 203 getPreferredScrollableViewportSize().getWidth()) { 204 col1Width = (int) 205 getPreferredScrollableViewportSize().getWidth(); 206 } 207 colModel.getColumn(0).setPreferredWidth(col1Width); 208 init = true; 209 return; 210 } 211 col1Width = (col1Width * 7) + 7; 212 col1Width = Math.max(col1Width, 70); 213 col2Width = (col2Width * 7) + 7; 214 if (col1Width + col2Width < 215 getPreferredScrollableViewportSize().getWidth()) { 216 col2Width = (int) 217 getPreferredScrollableViewportSize().getWidth() - 218 col1Width; 219 } 220 colModel.getColumn(0).setPreferredWidth(col1Width); 221 colModel.getColumn(1).setPreferredWidth(col2Width); 222 init = true; 223 } 224 } 225 226 public abstract void viewed(XOpenTypeViewer viewer) throws Exception; 227 228 protected void initTable(String[] columnNames) { 229 setRowSelectionAllowed(false); 230 setColumnSelectionAllowed(false); 231 getTableHeader().setReorderingAllowed(false); 232 ((DefaultTableModel) getModel()).setColumnIdentifiers(columnNames); 233 for (Enumeration<TableColumn> e = getColumnModel().getColumns(); 234 e.hasMoreElements();) { 235 TableColumn tc = e.nextElement(); 236 tc.setCellEditor(editor); 237 } 238 addKeyListener(new Utils.CopyKeyAdapter()); 239 setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); 240 setPreferredScrollableViewportSize(new Dimension(350, 200)); 241 } 242 243 protected void emptyTable() { 244 invalidate(); 245 while (getModel().getRowCount()>0) 246 ((DefaultTableModel) getModel()).removeRow(0); 247 validate(); 248 } 249 250 public void setValueAt(Object value, int row, int col) { 251 } 252 } 253 254 static class TabularDataComparator implements Comparator<CompositeData> { 255 256 private final List<String> indexNames; 257 258 public TabularDataComparator(TabularType type) { 259 indexNames = type.getIndexNames(); 260 } 261 262 @SuppressWarnings("unchecked") 263 public int compare(CompositeData o1, CompositeData o2) { 264 for (String key : indexNames) { 265 Object c1 = o1.get(key); 266 Object c2 = o2.get(key); 267 if (c1 instanceof Comparable && c2 instanceof Comparable) { 268 int result = ((Comparable) c1).compareTo(c2); 269 if (result != 0) 270 return result; 271 } 272 } 273 return 0; 274 } 275 } 276 277 static class XTabularData extends XCompositeData 278 implements XViewedTabularData { 279 280 final TabularData tabular; 281 final TabularType type; 282 int currentIndex = 0; 283 final Object[] elements; 284 final int size; 285 private Font normalFont, italicFont; 286 287 @SuppressWarnings("unchecked") 288 public XTabularData(XOpenTypeData parent, TabularData tabular) { 289 super(parent, accessFirstElement(tabular)); 290 this.tabular = tabular; 291 type = tabular.getTabularType(); 292 size = tabular.values().size(); 293 if (size > 0) { 294 // Order tabular data elements using index names 295 List<CompositeData> data = new ArrayList<CompositeData>( 296 (Collection<CompositeData>) tabular.values()); 297 Collections.sort(data, new TabularDataComparator(type)); 298 elements = data.toArray(); 299 loadCompositeData((CompositeData) elements[0]); 300 } else { 301 elements = new Object[0]; 302 } 303 } 304 305 private static CompositeData accessFirstElement(TabularData tabular) { 306 if(tabular.values().size() == 0) return null; 307 return (CompositeData) tabular.values().toArray()[0]; 308 } 309 310 public void renderKey(String key, Component comp) { 311 if (normalFont == null) { 312 normalFont = comp.getFont(); 313 italicFont = normalFont.deriveFont(Font.ITALIC); 314 } 315 for(Object k : type.getIndexNames()) { 316 if(key.equals(k)) 317 comp.setFont(italicFont); 318 } 319 } 320 321 public int getElementCount() { 322 return size; 323 } 324 325 public int getSelectedElementIndex() { 326 return currentIndex; 327 } 328 329 public void incrElement() { 330 currentIndex++; 331 loadCompositeData((CompositeData)elements[currentIndex]); 332 } 333 334 public void decrElement() { 335 currentIndex--; 336 loadCompositeData((CompositeData)elements[currentIndex]); 337 } 338 339 public boolean canDecrement() { 340 if(currentIndex == 0) 341 return false; 342 else 343 return true; 344 } 345 346 public boolean canIncrement(){ 347 if(size == 0 || 348 currentIndex == size -1) 349 return false; 350 else 351 return true; 352 } 353 354 public String toString() { 355 return type == null ? "" : type.getDescription(); 356 } 357 } 358 359 static class XCompositeData extends XOpenTypeData { 360 protected final String[] columnNames = { 361 Resources.getText("Name"), Resources.getText("Value") 362 }; 363 CompositeData composite; 364 365 public XCompositeData() { 366 super(null); 367 initTable(columnNames); 368 } 369 370 //In sync with array, no init table. 371 public XCompositeData(XOpenTypeData parent) { 372 super(parent); 373 } 374 375 public XCompositeData(XOpenTypeData parent, 376 CompositeData composite) { 377 super(parent); 378 initTable(columnNames); 379 if(composite != null) { 380 this.composite = composite; 381 loadCompositeData(composite); 382 } 383 } 384 385 public void viewed(XOpenTypeViewer viewer) throws Exception { 386 viewer.setOpenType(this); 387 updateColumnWidth(); 388 } 389 390 public String toString() { 391 return composite == null ? "" : 392 composite.getCompositeType().getTypeName(); 393 } 394 395 protected Object formatKey(String key) { 396 return key; 397 } 398 399 private void load(CompositeData data) { 400 CompositeType type = data.getCompositeType(); 401 Set keys = type.keySet(); 402 Iterator it = keys.iterator(); 403 Object[] rowData = new Object[2]; 404 while (it.hasNext()) { 405 String key = (String) it.next(); 406 Object val = data.get(key); 407 rowData[0] = formatKey(key); 408 if (val == null) { 409 rowData[1] = ""; 410 } else { 411 OpenType openType = type.getType(key); 412 if (openType instanceof CompositeType) { 413 rowData[1] = 414 new XCompositeData(this, (CompositeData) val); 415 } else if (openType instanceof ArrayType) { 416 rowData[1] = 417 new XArrayData(this, (ArrayType) openType, val); 418 } else if (openType instanceof SimpleType) { 419 rowData[1] = val; 420 } else if (openType instanceof TabularType) { 421 rowData[1] = new XTabularData(this, (TabularData) val); 422 } 423 } 424 // Update column width 425 String str = null; 426 if (rowData[0] != null) { 427 str = rowData[0].toString(); 428 if (str.length() > col1Width) { 429 col1Width = str.length(); 430 } 431 } 432 if (rowData[1] != null) { 433 str = rowData[1].toString(); 434 if (str.length() > col2Width) { 435 col2Width = str.length(); 436 } 437 } 438 ((DefaultTableModel) getModel()).addRow(rowData); 439 } 440 } 441 442 protected void loadCompositeData(CompositeData data) { 443 composite = data; 444 emptyTable(); 445 load(data); 446 DefaultTableModel tableModel = (DefaultTableModel) getModel(); 447 tableModel.newDataAvailable(new TableModelEvent(tableModel)); 448 } 449 } 450 451 static class XArrayData extends XCompositeData 452 implements XViewedArrayData { 453 454 private int dimension; 455 private int size; 456 private OpenType elemType; 457 private Object val; 458 private boolean isCompositeType; 459 private boolean isTabularType; 460 private int currentIndex; 461 private CompositeData[] elements; 462 private final String[] arrayColumns = {Resources.getText("Value")}; 463 private Font normalFont, boldFont; 464 465 XArrayData(XOpenTypeData parent, ArrayType type, Object val) { 466 this(parent, type.getDimension(), type.getElementOpenType(), val); 467 } 468 469 XArrayData(XOpenTypeData parent, int dimension, 470 OpenType elemType, Object val) { 471 super(parent); 472 this.dimension = dimension; 473 this.elemType = elemType; 474 this.val = val; 475 String[] columns = null; 476 477 if (dimension > 1) return; 478 479 isCompositeType = (elemType instanceof CompositeType); 480 isTabularType = (elemType instanceof TabularType); 481 columns = isCompositeType ? columnNames : arrayColumns; 482 483 initTable(columns); 484 loadArray(); 485 } 486 487 public void viewed(XOpenTypeViewer viewer) throws Exception { 488 if (size == 0) 489 throw new Exception(Resources.getText("Empty array")); 490 if (dimension > 1) 491 throw new Exception(Resources.getText("Dimension is not " + 492 "supported:") + 493 dimension); 494 super.viewed(viewer); 495 } 496 497 public int getElementCount() { 498 return size; 499 } 500 501 public int getSelectedElementIndex() { 502 return currentIndex; 503 } 504 505 public void renderKey(String key, Component comp) { 506 if (normalFont == null) { 507 normalFont = comp.getFont(); 508 boldFont = normalFont.deriveFont(Font.BOLD); 509 } 510 if (isTabularType) { 511 comp.setFont(boldFont); 512 } 513 } 514 515 public void incrElement() { 516 currentIndex++; 517 loadCompositeData(elements[currentIndex]); 518 } 519 520 public void decrElement() { 521 currentIndex--; 522 loadCompositeData(elements[currentIndex]); 523 } 524 525 public boolean canDecrement() { 526 if (isCompositeType && currentIndex > 0) { 527 return true; 528 } 529 return false; 530 } 531 532 public boolean canIncrement() { 533 if (isCompositeType && currentIndex < size - 1) { 534 return true; 535 } 536 return false; 537 } 538 539 private void loadArray() { 540 if (isCompositeType) { 541 elements = (CompositeData[]) val; 542 size = elements.length; 543 if (size != 0) { 544 loadCompositeData(elements[0]); 545 } 546 } else { 547 load(); 548 } 549 } 550 551 private void load() { 552 Object[] rowData = new Object[1]; 553 size = Array.getLength(val); 554 for (int i = 0; i < size; i++) { 555 rowData[0] = isTabularType ? 556 new XTabularData(this, (TabularData) Array.get(val, i)) : 557 Array.get(val, i); 558 String str = rowData[0].toString(); 559 if (str.length() > col1Width) { 560 col1Width = str.length(); 561 } 562 ((DefaultTableModel) getModel()).addRow(rowData); 563 } 564 } 565 566 public String toString() { 567 if (dimension > 1) { 568 return Resources.getText("Dimension is not supported:") + 569 dimension; 570 } else { 571 return elemType.getTypeName() + "[" + size + "]"; 572 } 573 } 574 } 575 576 /** 577 * The supplied value is viewable iff: 578 * - it's a CompositeData/TabularData, or 579 * - it's a non-empty array of CompositeData/TabularData, or 580 * - it's a non-empty Collection of CompositeData/TabularData. 581 */ 582 public static boolean isViewableValue(Object value) { 583 // Check for CompositeData/TabularData 584 // 585 if (value instanceof CompositeData || value instanceof TabularData) { 586 return true; 587 } 588 // Check for non-empty array of CompositeData/TabularData 589 // 590 if (value instanceof CompositeData[] || value instanceof TabularData[]) { 591 return Array.getLength(value) > 0; 592 } 593 // Check for non-empty Collection of CompositeData/TabularData 594 // 595 if (value instanceof Collection) { 596 Collection<?> c = (Collection<?>) value; 597 if (c.isEmpty()) { 598 // Empty Collections are not viewable 599 // 600 return false; 601 } else { 602 // Only Collections of CompositeData/TabularData are viewable 603 // 604 return Utils.isUniformCollection(c, CompositeData.class) || 605 Utils.isUniformCollection(c, TabularData.class); 606 } 607 } 608 return false; 609 } 610 611 public static Component loadOpenType(Object value) { 612 Component comp = null; 613 if(isViewableValue(value)) { 614 XOpenTypeViewer open = 615 new XOpenTypeViewer(value); 616 comp = open; 617 } 618 return comp; 619 } 620 621 private XOpenTypeViewer(Object value) { 622 XOpenTypeData comp = null; 623 if (value instanceof CompositeData) { 624 comp = new XCompositeData(null, (CompositeData) value); 625 } else if (value instanceof TabularData) { 626 comp = new XTabularData(null, (TabularData) value); 627 } else if (value instanceof CompositeData[]) { 628 CompositeData cda[] = (CompositeData[]) value; 629 CompositeType ct = cda[0].getCompositeType(); 630 comp = new XArrayData(null, 1, ct, cda); 631 } else if (value instanceof TabularData[]) { 632 TabularData tda[] = (TabularData[]) value; 633 TabularType tt = tda[0].getTabularType(); 634 comp = new XArrayData(null, 1, tt, tda); 635 } else if (value instanceof Collection) { 636 // At this point we know 'value' is a uniform collection, either 637 // Collection<CompositeData> or Collection<TabularData>, because 638 // isViewableValue() has been called before calling the private 639 // XOpenTypeViewer() constructor. 640 // 641 Object e = ((Collection<?>) value).iterator().next(); 642 if (e instanceof CompositeData) { 643 Collection<?> cdc = (Collection<?>) value; 644 CompositeData cda[] = cdc.toArray(new CompositeData[0]); 645 CompositeType ct = cda[0].getCompositeType(); 646 comp = new XArrayData(null, 1, ct, cda); 647 } else if (e instanceof TabularData) { 648 Collection<?> tdc = (Collection<?>) value; 649 TabularData tda[] = tdc.toArray(new TabularData[0]); 650 TabularType tt = tda[0].getTabularType(); 651 comp = new XArrayData(null, 1, tt, tda); 652 } 653 } 654 setupDisplay(comp); 655 try { 656 comp.viewed(this); 657 } catch (Exception e) { 658 // Nothing to change, the element can't be displayed 659 if (JConsole.isDebug()) { 660 System.out.println("Exception viewing openType : " + e); 661 e.printStackTrace(); 662 } 663 } 664 } 665 666 void setOpenType(XOpenTypeData data) { 667 if (current != null) { 668 current.removeMouseListener(listener); 669 } 670 671 current = data; 672 673 // Enable/Disable the previous (<<) button 674 if (current.getViewedParent() == null) { 675 prev.setEnabled(false); 676 } else { 677 prev.setEnabled(true); 678 } 679 680 // Set the listener to handle double-click mouse events 681 current.addMouseListener(listener); 682 683 // Enable/Disable the tabular buttons 684 if (!(data instanceof XViewedTabularData)) { 685 tabularPrev.setEnabled(false); 686 tabularNext.setEnabled(false); 687 tabularLabel.setText(tabularNavigationSingle); 688 tabularLabel.setEnabled(false); 689 } else { 690 XViewedTabularData tabular = (XViewedTabularData) data; 691 tabularNext.setEnabled(tabular.canIncrement()); 692 tabularPrev.setEnabled(tabular.canDecrement()); 693 boolean hasMoreThanOneElement = 694 tabular.canIncrement() || tabular.canDecrement(); 695 if (hasMoreThanOneElement) { 696 tabularLabel.setText( 697 Resources.getText("MBeansTab.tabularNavigationMultiple", 698 String.format("%d", tabular.getSelectedElementIndex() + 1), 699 String.format("%d", tabular.getElementCount()))); 700 } else { 701 tabularLabel.setText(tabularNavigationSingle); 702 } 703 tabularLabel.setEnabled(hasMoreThanOneElement); 704 } 705 706 // Enable/Disable the composite buttons 707 if (!(data instanceof XViewedArrayData)) { 708 incr.setEnabled(false); 709 decr.setEnabled(false); 710 compositeLabel.setText(compositeNavigationSingle); 711 compositeLabel.setEnabled(false); 712 } else { 713 XViewedArrayData array = (XViewedArrayData) data; 714 incr.setEnabled(array.canIncrement()); 715 decr.setEnabled(array.canDecrement()); 716 boolean hasMoreThanOneElement = 717 array.canIncrement() || array.canDecrement(); 718 if (hasMoreThanOneElement) { 719 compositeLabel.setText( 720 Resources.getText("MBeansTab.compositeNavigationMultiple", 721 String.format("%d", array.getSelectedElementIndex() + 1), 722 String.format("%d", array.getElementCount()))); 723 } else { 724 compositeLabel.setText(compositeNavigationSingle); 725 } 726 compositeLabel.setEnabled(hasMoreThanOneElement); 727 } 728 729 container.invalidate(); 730 container.setViewportView(current); 731 container.validate(); 732 } 733 734 public void actionPerformed(ActionEvent event) { 735 if (event.getSource() instanceof JButton) { 736 JButton b = (JButton) event.getSource(); 737 if (b == prev) { 738 XOpenTypeData parent = current.getViewedParent(); 739 try { 740 parent.viewed(this); 741 } catch (Exception e) { 742 //Nothing to change, the element can't be displayed 743 } 744 } else if (b == incr) { 745 ((XViewedArrayData) current).incrElement(); 746 try { 747 current.viewed(this); 748 } catch (Exception e) { 749 //Nothing to change, the element can't be displayed 750 } 751 } else if (b == decr) { 752 ((XViewedArrayData) current).decrElement(); 753 try { 754 current.viewed(this); 755 } catch (Exception e) { 756 //Nothing to change, the element can't be displayed 757 } 758 } else if (b == tabularNext) { 759 ((XViewedTabularData) current).incrElement(); 760 try { 761 current.viewed(this); 762 } catch (Exception e) { 763 //Nothing to change, the element can't be displayed 764 } 765 } else if (b == tabularPrev) { 766 ((XViewedTabularData) current).decrElement(); 767 try { 768 current.viewed(this); 769 } catch (Exception e) { 770 //Nothing to change, the element can't be displayed 771 } 772 } 773 } 774 } 775 776 private void setupDisplay(XOpenTypeData data) { 777 setBackground(Color.white); 778 container = 779 new JScrollPane(data, 780 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 781 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 782 783 JPanel buttons = new JPanel(new FlowLayout(FlowLayout.LEFT)); 784 tabularPrev = new JButton(Resources.getText("<")); 785 tabularNext = new JButton(Resources.getText(">")); 786 JPanel tabularButtons = new JPanel(new FlowLayout(FlowLayout.LEFT)); 787 tabularButtons.add(tabularPrev); 788 tabularPrev.addActionListener(this); 789 tabularLabel = new JLabel(tabularNavigationSingle); 790 tabularLabel.setEnabled(false); 791 tabularButtons.add(tabularLabel); 792 tabularButtons.add(tabularNext); 793 tabularNext.addActionListener(this); 794 tabularButtons.setBackground(Color.white); 795 796 prev = new JButton(Resources.getText("<<")); 797 prev.addActionListener(this); 798 buttons.add(prev); 799 800 incr = new JButton(Resources.getText(">")); 801 incr.addActionListener(this); 802 decr = new JButton(Resources.getText("<")); 803 decr.addActionListener(this); 804 805 JPanel array = new JPanel(); 806 array.setBackground(Color.white); 807 array.add(decr); 808 compositeLabel = new JLabel(compositeNavigationSingle); 809 compositeLabel.setEnabled(false); 810 array.add(compositeLabel); 811 array.add(incr); 812 813 buttons.add(array); 814 setLayout(new BorderLayout()); 815 buttons.setBackground(Color.white); 816 817 JPanel navigationPanel = new JPanel(new BorderLayout()); 818 navigationPanel.setBackground(Color.white); 819 navigationPanel.add(tabularButtons, BorderLayout.NORTH); 820 navigationPanel.add(buttons, BorderLayout.WEST); 821 add(navigationPanel, BorderLayout.NORTH); 822 823 add(container, BorderLayout.CENTER); 824 Dimension d = new Dimension((int)container.getPreferredSize(). 825 getWidth() + 20, 826 (int)container.getPreferredSize(). 827 getHeight() + 20); 828 setPreferredSize(d); 829 } 830 }