package jalview.jbgui.swing; import jalview.fts.core.GFTSPanel; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.ToolTipManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; import javajs.util.Lst; @SuppressWarnings("serial") public class JTabbedPane extends JPanel { // no longer necessary private JPanel pagePanel; private JComboBox tabs; private Component visComp; /** * Only one ChangeEvent is needed per TabPane * instance since the * event's only (read-only) state is the source property. The source * of events generated here is always "this". */ protected transient ChangeEvent changeEvent = null; /** just faking a JTabbedPane here using a drop-down combo box and a JPanel This will take considerably more work to make it right in general. */ private JTabbedPane() { pagePanel = new JPanel(); pagePanel.setLayout(new BoxLayout(pagePanel, BoxLayout.PAGE_AXIS)); tabs = new JComboBox(); tabs.setMaximumSize(new Dimension(150, 15)); tabs.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { update(false); } }); setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); add(tabs); add(pagePanel); } public void setTitleAt(int index, String title) { Page page = pages.get(index); String oldTitle = page.title; page.title = title; if (oldTitle != title) { firePropertyChange("indexForTitle", -1, index); } page.updateDisplayedMnemonicIndex(); // if ((oldTitle != title) && (accessibleContext != null)) { // accessibleContext.firePropertyChange( // AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY, // oldTitle, title); // } if (title == null || oldTitle == null || !title.equals(oldTitle)) { revalidate(); repaint(); } } public String getTitleAt(int index) { return pages.get(index).title; } /** * We pass ModelChanged events along to the listeners with * the tabbedpane (instead of the model itself) as the event source. */ protected class ModelListener implements ChangeListener { @Override public void stateChanged(ChangeEvent e) { fireStateChanged(); } } /** * Subclasses that want to handle ChangeEvents differently * can override this to return a subclass of ModelListener or * another ChangeListener implementation. * * @see #fireStateChanged */ protected ChangeListener createChangeListener() { return new ModelListener(); } /** * Adds a ChangeListener to this tabbedpane. * * @param l the ChangeListener to add * @see #fireStateChanged * @see #removeChangeListener */ public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); } /** * Removes a ChangeListener from this tabbedpane. * * @param l the ChangeListener to remove * @see #fireStateChanged * @see #addChangeListener */ public void removeChangeListener(ChangeListener l) { listenerList.remove(ChangeListener.class, l); } public void setSelectedComponent(JPanel structureTab) { // TODO Auto-generated method stub } /** * Returns an array of all the ChangeListeners added * to this JTabbedPane with addChangeListener. * * @return all of the ChangeListeners added or an empty * array if no listeners have been added * @since 1.4 */ public ChangeListener[] getChangeListeners() { return (ChangeListener[])listenerList.getListeners( ChangeListener.class); } /** * Sends a {@code ChangeEvent}, with this {@code JTabbedPane} as the source, * to each registered listener. This method is called each time there is * a change to either the selected index or the selected tab in the * {@code JTabbedPane}. Usually, the selected index and selected tab change * together. However, there are some cases, such as tab addition, where the * selected index changes and the same tab remains selected. There are other * cases, such as deleting the selected tab, where the index remains the * same, but a new tab moves to that index. Events are fired for all of * these cases. * * @see #addChangeListener * @see EventListenerList */ protected void fireStateChanged() { /* --- Begin code to deal with visibility --- */ /* This code deals with changing the visibility of components to * hide and show the contents for the selected tab. It duplicates * logic already present in BasicTabbedPaneUI, logic that is * processed during the layout pass. This code exists to allow * developers to do things that are quite difficult to accomplish * with the previous model of waiting for the layout pass to process * visibility changes; such as requesting focus on the new visible * component. * * For the average code, using the typical JTabbedPane methods, * all visibility changes will now be processed here. However, * the code in BasicTabbedPaneUI still exists, for the purposes * of backward compatibility. Therefore, when making changes to * this code, ensure that the BasicTabbedPaneUI code is kept in * synch. */ int selIndex = getSelectedIndex(); /* if the selection is now nothing */ if (selIndex < 0) { /* if there was a previous visible component */ if (visComp != null && visComp.isVisible()) { /* make it invisible */ visComp.setVisible(false); } /* now there's no visible component */ visComp = null; /* else - the selection is now something */ } else { /* Fetch the component for the new selection */ Component newComp = getComponentAt(selIndex); /* if the new component is non-null and different */ if (newComp != null && newComp != visComp) { //SwingJS X: Key Focus // boolean shouldChangeFocus = false; /* Note: the following (clearing of the old visible component) * is inside this if-statement for good reason: Tabbed pane * should continue to show the previously visible component * if there is no component for the chosen tab. */ /* if there was a previous visible component */ if (visComp != null) { //SwingJS X: Key Focus // shouldChangeFocus = // (SwingUtilities.findFocusOwner(visComp) != null); /* if it's still visible */ if (visComp.isVisible()) { /* make it invisible */ visComp.setVisible(false); } } if (!newComp.isVisible()) { newComp.setVisible(true); } //SwingJS X: Key Focus // if (shouldChangeFocus) { // SwingUtilities2.tabbedPaneChangeFocusTo(newComp); // } visComp = newComp; } /* else - the visible component shouldn't changed */ } /* --- End code to deal with visibility --- */ // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==ChangeListener.class) { // Lazily create the event: if (changeEvent == null) changeEvent = new ChangeEvent(this); ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); } } } private class Page { public String title; String tab; JComponent component; public void updateDisplayedMnemonicIndex() { // TODO Auto-generated method stub } } public Component getSelectedComponent() { int i = getSelectedIndex(); return (i < 0 ? null : getComponent(i)); } /** * Returns the component at index. * * @param index the index of the item being queried * @return the Component at index * @exception IndexOutOfBoundsException if index is out of range * (index < 0 || index >= tab count) * * @see #setComponentAt */ public Component getComponentAt(int index) { return pages.get(index).component; } Lst pages = new Lst(); public Component add(String title, Component panel) { add(panel, title, pages.size()); return panel; } public void addTab(String name, Component panel) { add(panel, name, Integer.MAX_VALUE); } public void add(Component panel, String title, int index) { addIndex((JComponent) panel, title, index); } private void addIndex(JComponent panel, String title, int index) { // improperly allowing for multiple instances of a panel Page page = new Page(); page.component = panel; page.tab = title; panel.setVisible(true); if (index < pages.size()) { pages.get(index).component = panel; } else { pages.addLast(page); } update(true); } public void insertTab(String title, Icon icon, Component component, String tip, int index) { // int newIndex = index; addIndex((JComponent) component, title, index); // // // If component already exists, remove corresponding // // tab so that new tab gets added correctly // // Note: we are allowing component=null because of compatibility, // // but we really should throw an exception because much of the // // rest of the JTabbedPane implementation isn't designed to deal // // with null components for tabs. // int removeIndex = indexOfComponent(component); // if (component != null && removeIndex != -1) { // removeTabAt(removeIndex); // if (newIndex > removeIndex) { // newIndex--; // } // } // // int selectedIndex = getSelectedIndex(); // // pages.add( // newIndex, // new Page(this, title != null? title : "", icon, null, component, tip)); // // // if (component != null) { // addImpl(component, null, -1); // component.setVisible(false); // } else { // firePropertyChange("indexForNullComponent", -1, index); // } // // if (pages.size() == 1) { // setSelectedIndex(0); // } // // if (selectedIndex >= newIndex) { // setSelectedIndexImpl(selectedIndex + 1, false); // } // // if (!haveRegistered && tip != null) { // ToolTipManager.sharedInstance().registerComponent(this); // haveRegistered = true; // } // if (accessibleContext != null) { // accessibleContext.firePropertyChange( // AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY, // null, component); // } } private void update(boolean combo) { if (combo) { int i0 = tabs.getSelectedIndex(); tabs.removeAllItems(); for (int i = 0; i < pages.size(); i++) { tabs.addItem(pages.get(i).tab); } tabs.setSelectedIndex(i0 < 0 ? 0 : i0); } pagePanel.removeAll(); int selected = getSelectedIndex(); if (selected >= 0) {// && bsEnabled.get(selected)) { pagePanel.add(pages.get(selected).component); } revalidate(); repaint(); } public void setComponentAt(int index, JPanel panel) { if (index < 0 || index >= pages.size()) throw new IndexOutOfBoundsException(); pages.get(index).component = panel; update(false); } public int getTabCount() { return tabs.getItemCount(); } public void setSelectedIndex(int index) { tabs.setSelectedIndex(index); update(false); } public int getSelectedIndex() { return tabs.getSelectedIndex(); } public void setEnabledAt(int index, boolean bEnable) { // bsEnabled.setBitTo(index, bEnable); // if (!bEnable && index == getSelectedIndex()) { // for (int i = index - 1; --i >= 0;) { // if (bsEnabled.get(i)) { // setSelectedIndex(i); // return; // } // } // } // update(false, true); } public void remove(int n) { pages.removeItemAt(n); tabs.removeItemAt(n); update(false); // bsEnabled.clearAll(); // bsEnabled.set(lastSelected); } }