--- /dev/null
+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
+{
+
+ @SuppressWarnings("unused")
+ public static javax.swing.JTabbedPane createTabbedPane()
+ {
+ // BH 2018 coercing jalview.jbgui.swing.JTabbedPane() for now
+ if (/** @j2sNative false && */
+ true)
+ {
+ // Java
+ return new javax.swing.JTabbedPane();
+ }
+ // JavaScript
+ return (javax.swing.JTabbedPane) (Object) new jalview.jbgui.swing.JTabbedPane();
+ }
+
+ private JPanel pagePanel;
+
+ private JComboBox<String> tabs;
+
+ private Component visComp;
+
+ /**
+ * Only one <code>ChangeEvent</code> is needed per <code>TabPane</code>
+ * 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<String>();
+ 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 <code>ModelChanged</code> 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 <code>ChangeEvents</code> differently
+ * can override this to return a subclass of <code>ModelListener</code> or
+ * another <code>ChangeListener</code> implementation.
+ *
+ * @see #fireStateChanged
+ */
+ protected ChangeListener createChangeListener() {
+ return new ModelListener();
+ }
+
+ /**
+ * Adds a <code>ChangeListener</code> to this tabbedpane.
+ *
+ * @param l the <code>ChangeListener</code> to add
+ * @see #fireStateChanged
+ * @see #removeChangeListener
+ */
+ public void addChangeListener(ChangeListener l) {
+ listenerList.add(ChangeListener.class, l);
+ }
+
+ /**
+ * Removes a <code>ChangeListener</code> from this tabbedpane.
+ *
+ * @param l the <code>ChangeListener</code> 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 <code>ChangeListener</code>s added
+ * to this <code>JTabbedPane</code> with <code>addChangeListener</code>.
+ *
+ * @return all of the <code>ChangeListener</code>s 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 <code>index</code>.
+ *
+ * @param index the index of the item being queried
+ * @return the <code>Component</code> at <code>index</code>
+ * @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<Page> pages = new Lst<Page>();
+
+ 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);
+ }
+
+}