001/* 002 * $Id: HeavyTabbedPane.java,v 1.7 2011/03/24 16:06:34 davep Exp $ 003 * 004 * This file is part of McIDAS-V 005 * 006 * Copyright 2007-2011 007 * Space Science and Engineering Center (SSEC) 008 * University of Wisconsin - Madison 009 * 1225 W. Dayton Street, Madison, WI 53706, USA 010 * https://www.ssec.wisc.edu/mcidas 011 * 012 * All Rights Reserved 013 * 014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 015 * some McIDAS-V source code is based on IDV and VisAD source code. 016 * 017 * McIDAS-V is free software; you can redistribute it and/or modify 018 * it under the terms of the GNU Lesser Public License as published by 019 * the Free Software Foundation; either version 3 of the License, or 020 * (at your option) any later version. 021 * 022 * McIDAS-V is distributed in the hope that it will be useful, 023 * but WITHOUT ANY WARRANTY; without even the implied warranty of 024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 025 * GNU Lesser Public License for more details. 026 * 027 * You should have received a copy of the GNU Lesser Public License 028 * along with this program. If not, see http://www.gnu.org/licenses. 029 */ 030 031package edu.wisc.ssec.mcidasv.ui; 032 033import java.awt.Component; 034import java.util.ArrayList; 035import java.util.List; 036 037import javax.swing.Icon; 038import javax.swing.JPanel; 039import javax.swing.JTabbedPane; 040 041/** 042 * A {@link javax.swing.JTabbedPane} implementation that allows tabbed heavy-weight 043 * components. When a component is added to a tab it is cached and an associated 044 * light-weight stand-in component and added instead. When a tab is selected the 045 * light-weight stand in is removed and it's heavy-weight counter-part is displayed. 046 * When another tab is selected the reverse happens. 047 * <p> 048 * This was originally written to facilitate the use of <tt>Canvas3D</tt> objects in 049 * a <tt>JTabbedPane</tt>, but I believe it will work for any heavy-weight component. 050 * <p> 051 * 052 * @author <a href="https://www.ssec.wisc.edu/cgi-bin/email_form.cgi?name=Flynn,%20Bruce">Bruce Flynn, SSEC</a> 053 * @version $Id: HeavyTabbedPane.java,v 1.7 2011/03/24 16:06:34 davep Exp $ 054 */ 055public class HeavyTabbedPane extends JTabbedPane { 056 private static final long serialVersionUID = -3903797547171213551L; 057 058 /** 059 * Delay in milliseconds for <tt>ChangeEvent</tt>s. This prevents some 060 * re-draw issues that popup with the heavy weight components. 061 */ 062 protected long heavyWeightDelay = 0; 063 064 /** 065 * Components, in tab index order, that will be displayed when a 066 * tab is selected. 067 */ 068 private List<Component> comps = new ArrayList<Component>(); 069 /** 070 * Components, in tab index order, that will be displayed when a 071 * tab is not selected. These should never actually be visible to the 072 * user. 073 */ 074 private List<Component> blanks = new ArrayList<Component>(); 075 076 /** 077 * Create and return the component to be used when a tab is not visible. 078 * @return Component used for tabs that are not currently selected. 079 */ 080 protected Component blank() { 081 return new JPanel(); 082 } 083 084 /** 085 * Set the delay to wait before firing a state change event. 086 * @param d If >= 0, no delay will be used. 087 */ 088 protected void setHeavyWeightDeleay(long d) { 089 if (d < 0) d = 0; 090 heavyWeightDelay = d; 091 } 092 093 @Override 094 public void insertTab(String title, Icon ico, Component comp, String tip, int idx) { 095 Component blank = blank(); 096 blanks.add(idx, blank); 097 comps.add(idx, comp); 098 super.insertTab(title, ico, blank, tip, idx); 099 } 100 101 @Override 102 public int indexOfComponent(Component comp) { 103 // if the tab count does not equal the size of the component caches 104 // this was probably called by something internal. This ensures we 105 // don't return an errant value. 106 if (getTabCount() == blanks.size() && getTabCount() == comps.size()) { 107 if (comps.contains(comp)) { 108 return comps.indexOf(comp); 109 } else if (blanks.contains(comp)) { 110 return blanks.indexOf(comp); 111 } 112 } 113 return -1; 114 } 115 116 @Override 117 public Component getComponentAt(int idx) { 118 // return the actual component, not the blank 119 return comps.get(idx); 120 } 121 122 @Override 123 public void setComponentAt(int idx, Component comp) { 124 // no need to change the blanks 125 comps.set(idx, comp); 126 super.setComponentAt(idx, comp); 127 } 128 129 @Override 130 public void setSelectedIndex(int idx) { 131 int prevIdx = getSelectedIndex(); 132 super.setSelectedIndex(idx); 133 // show the actual component for the selected index and change 134 // the other to it's blank 135 if (prevIdx != -1 && idx != -1) { 136 super.setComponentAt(prevIdx, blanks.get(prevIdx)); 137 super.setComponentAt(idx, comps.get(idx)); 138 } 139 } 140 141 @Override 142 public void setSelectedComponent(Component comp) { 143 if (comp == null || comps.indexOf(comp) < 0) { 144 throw new IllegalArgumentException("Component not found in tabbed pane"); 145 } 146 int idx = comps.indexOf(comp); 147 setSelectedIndex(idx); 148 } 149 150 @Override 151 public void removeTabAt(int idx) { 152 super.removeTabAt(idx); 153 comps.remove(idx); 154 blanks.remove(idx); 155 } 156 157 @Override 158 public void remove(int idx) { 159 removeTabAt(idx); 160 } 161 162 @Override 163 public void removeAll() { 164 super.removeAll(); 165 comps.clear(); 166 blanks.clear(); 167 } 168 169 /** 170 * <tt>ChangeEvent</tt> are delayed by the heavy weight delay 171 * milliseconds to aid in the proper rendering of heavy weight components. 172 * @see javax.swing.JTabbedPane#fireStateChanged() 173 */ 174 @Override 175 protected void fireStateChanged() { 176 try { 177 Thread.sleep(heavyWeightDelay); 178 } catch (InterruptedException e) {} 179 super.fireStateChanged(); 180 } 181 182// public static void main(String[] args) throws Exception { 183// javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getCrossPlatformLookAndFeelClassName()); 184// JFrame frame = new JFrame("J3DTabbedPane"); 185// frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 186// final JTabbedPane tabs = new HeavyTabbedPane(); 187// frame.setLayout(new BorderLayout()); 188// frame.add(tabs, BorderLayout.CENTER); 189// JPanel panel = new JPanel(); 190// panel.setLayout(new BorderLayout()); 191// panel.setName("BluePanel"); 192// panel.add(new JLabel("Actual"), BorderLayout.BEFORE_FIRST_LINE); 193// panel.setBackground(Color.BLUE); 194// DisplayImpl display = new DisplayImplJ3D("Blue"); 195// panel.add(display.getComponent(), BorderLayout.CENTER); 196// tabs.add("BluePanel", panel); 197// panel = new JPanel(); 198// panel.setLayout(new BorderLayout()); 199// display = new DisplayImplJ3D("Red"); 200// panel.add(display.getComponent(), BorderLayout.CENTER); 201// panel.setName("RedPanel"); 202// panel.add(new JLabel("Actual"), BorderLayout.BEFORE_FIRST_LINE); 203// panel.setBackground(Color.RED); 204// tabs.add("RedPanel", panel); 205// frame.setSize(400, 600); 206// frame.setVisible(true); 207// 208// tabs.addChangeListener(new ChangeListener() { 209// public void stateChanged(ChangeEvent e) { 210// System.err.println(); 211// for (int i=0; i<tabs.getTabCount(); i++) { 212// System.err.println("Tab " + i + " " + tabs.getComponentAt(i).getName()); 213// } 214// } 215// }); 216// } 217}