1 package jalview.jbgui.swing;
3 import jalview.fts.core.GFTSPanel;
5 import java.awt.Component;
6 import java.awt.Dimension;
7 import java.awt.event.ItemEvent;
8 import java.awt.event.ItemListener;
10 import javax.swing.BoxLayout;
11 import javax.swing.Icon;
12 import javax.swing.JComboBox;
13 import javax.swing.JComponent;
14 import javax.swing.JPanel;
15 import javax.swing.ToolTipManager;
16 import javax.swing.event.ChangeEvent;
17 import javax.swing.event.ChangeListener;
18 import javax.swing.event.EventListenerList;
20 import javajs.util.Lst;
22 @SuppressWarnings("serial")
23 public class JTabbedPane extends JPanel
26 @SuppressWarnings("unused")
27 public static javax.swing.JTabbedPane createTabbedPane()
29 // BH 2018 coercing jalview.jbgui.swing.JTabbedPane() for now
30 if (/** @j2sNative false && */
34 return new javax.swing.JTabbedPane();
37 return (javax.swing.JTabbedPane) (Object) new jalview.jbgui.swing.JTabbedPane();
40 private JPanel pagePanel;
42 private JComboBox<String> tabs;
44 private Component visComp;
47 * Only one <code>ChangeEvent</code> is needed per <code>TabPane</code>
49 * event's only (read-only) state is the source property. The source
50 * of events generated here is always "this".
52 protected transient ChangeEvent changeEvent = null;
55 /** just faking a JTabbedPane here using a drop-down combo box and a JPanel
57 This will take considerably more work to make it right in general.
62 pagePanel = new JPanel();
63 pagePanel.setLayout(new BoxLayout(pagePanel, BoxLayout.PAGE_AXIS));
64 tabs = new JComboBox<String>();
65 tabs.setMaximumSize(new Dimension(150, 15));
66 tabs.addItemListener(new ItemListener()
70 public void itemStateChanged(ItemEvent e)
76 setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
81 public void setTitleAt(int index, String title)
83 Page page = pages.get(index);
84 String oldTitle = page.title;
87 if (oldTitle != title)
89 firePropertyChange("indexForTitle", -1, index);
91 page.updateDisplayedMnemonicIndex();
92 // if ((oldTitle != title) && (accessibleContext != null)) {
93 // accessibleContext.firePropertyChange(
94 // AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
97 if (title == null || oldTitle == null || !title.equals(oldTitle))
104 public String getTitleAt(int index)
106 return pages.get(index).title;
110 * We pass <code>ModelChanged</code> events along to the listeners with
111 * the tabbedpane (instead of the model itself) as the event source.
113 protected class ModelListener implements ChangeListener {
115 public void stateChanged(ChangeEvent e) {
121 * Subclasses that want to handle <code>ChangeEvents</code> differently
122 * can override this to return a subclass of <code>ModelListener</code> or
123 * another <code>ChangeListener</code> implementation.
125 * @see #fireStateChanged
127 protected ChangeListener createChangeListener() {
128 return new ModelListener();
132 * Adds a <code>ChangeListener</code> to this tabbedpane.
134 * @param l the <code>ChangeListener</code> to add
135 * @see #fireStateChanged
136 * @see #removeChangeListener
138 public void addChangeListener(ChangeListener l) {
139 listenerList.add(ChangeListener.class, l);
143 * Removes a <code>ChangeListener</code> from this tabbedpane.
145 * @param l the <code>ChangeListener</code> to remove
146 * @see #fireStateChanged
147 * @see #addChangeListener
149 public void removeChangeListener(ChangeListener l) {
150 listenerList.remove(ChangeListener.class, l);
153 public void setSelectedComponent(JPanel structureTab)
155 // TODO Auto-generated method stub
160 * Returns an array of all the <code>ChangeListener</code>s added
161 * to this <code>JTabbedPane</code> with <code>addChangeListener</code>.
163 * @return all of the <code>ChangeListener</code>s added or an empty
164 * array if no listeners have been added
167 public ChangeListener[] getChangeListeners() {
168 return (ChangeListener[])listenerList.getListeners(
169 ChangeListener.class);
173 * Sends a {@code ChangeEvent}, with this {@code JTabbedPane} as the source,
174 * to each registered listener. This method is called each time there is
175 * a change to either the selected index or the selected tab in the
176 * {@code JTabbedPane}. Usually, the selected index and selected tab change
177 * together. However, there are some cases, such as tab addition, where the
178 * selected index changes and the same tab remains selected. There are other
179 * cases, such as deleting the selected tab, where the index remains the
180 * same, but a new tab moves to that index. Events are fired for all of
183 * @see #addChangeListener
184 * @see EventListenerList
186 protected void fireStateChanged() {
187 /* --- Begin code to deal with visibility --- */
189 /* This code deals with changing the visibility of components to
190 * hide and show the contents for the selected tab. It duplicates
191 * logic already present in BasicTabbedPaneUI, logic that is
192 * processed during the layout pass. This code exists to allow
193 * developers to do things that are quite difficult to accomplish
194 * with the previous model of waiting for the layout pass to process
195 * visibility changes; such as requesting focus on the new visible
198 * For the average code, using the typical JTabbedPane methods,
199 * all visibility changes will now be processed here. However,
200 * the code in BasicTabbedPaneUI still exists, for the purposes
201 * of backward compatibility. Therefore, when making changes to
202 * this code, ensure that the BasicTabbedPaneUI code is kept in
206 int selIndex = getSelectedIndex();
208 /* if the selection is now nothing */
210 /* if there was a previous visible component */
211 if (visComp != null && visComp.isVisible()) {
212 /* make it invisible */
213 visComp.setVisible(false);
216 /* now there's no visible component */
219 /* else - the selection is now something */
221 /* Fetch the component for the new selection */
222 Component newComp = getComponentAt(selIndex);
224 /* if the new component is non-null and different */
225 if (newComp != null && newComp != visComp) {
226 //SwingJS X: Key Focus
227 // boolean shouldChangeFocus = false;
229 /* Note: the following (clearing of the old visible component)
230 * is inside this if-statement for good reason: Tabbed pane
231 * should continue to show the previously visible component
232 * if there is no component for the chosen tab.
235 /* if there was a previous visible component */
236 if (visComp != null) {
237 //SwingJS X: Key Focus
238 // shouldChangeFocus =
239 // (SwingUtilities.findFocusOwner(visComp) != null);
241 /* if it's still visible */
242 if (visComp.isVisible()) {
243 /* make it invisible */
244 visComp.setVisible(false);
248 if (!newComp.isVisible()) {
249 newComp.setVisible(true);
252 //SwingJS X: Key Focus
253 // if (shouldChangeFocus) {
254 // SwingUtilities2.tabbedPaneChangeFocusTo(newComp);
258 } /* else - the visible component shouldn't changed */
261 /* --- End code to deal with visibility --- */
263 // Guaranteed to return a non-null array
264 Object[] listeners = listenerList.getListenerList();
265 // Process the listeners last to first, notifying
266 // those that are interested in this event
267 for (int i = listeners.length-2; i>=0; i-=2) {
268 if (listeners[i]==ChangeListener.class) {
269 // Lazily create the event:
270 if (changeEvent == null)
271 changeEvent = new ChangeEvent(this);
272 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
283 JComponent component;
285 public void updateDisplayedMnemonicIndex()
287 // TODO Auto-generated method stub
292 public Component getSelectedComponent()
294 int i = getSelectedIndex();
295 return (i < 0 ? null : getComponent(i));
300 * Returns the component at <code>index</code>.
302 * @param index the index of the item being queried
303 * @return the <code>Component</code> at <code>index</code>
304 * @exception IndexOutOfBoundsException if index is out of range
305 * (index < 0 || index >= tab count)
307 * @see #setComponentAt
309 public Component getComponentAt(int index) {
310 return pages.get(index).component;
313 Lst<Page> pages = new Lst<Page>();
315 public Component add(String title, Component panel)
317 add(panel, title, pages.size());
321 public void addTab(String name, Component panel)
323 add(panel, name, Integer.MAX_VALUE);
326 public void add(Component panel, String title, int index)
328 addIndex((JComponent) panel, title, index);
332 private void addIndex(JComponent panel, String title, int index)
334 // improperly allowing for multiple instances of a panel
335 Page page = new Page();
336 page.component = panel;
338 panel.setVisible(true);
339 if (index < pages.size())
341 pages.get(index).component = panel;
350 public void insertTab(String title, Icon icon, Component component,
351 String tip, int index)
353 // int newIndex = index;
355 addIndex((JComponent) component, title, index);
357 // // If component already exists, remove corresponding
358 // // tab so that new tab gets added correctly
359 // // Note: we are allowing component=null because of compatibility,
360 // // but we really should throw an exception because much of the
361 // // rest of the JTabbedPane implementation isn't designed to deal
362 // // with null components for tabs.
363 // int removeIndex = indexOfComponent(component);
364 // if (component != null && removeIndex != -1) {
365 // removeTabAt(removeIndex);
366 // if (newIndex > removeIndex) {
371 // int selectedIndex = getSelectedIndex();
375 // new Page(this, title != null? title : "", icon, null, component, tip));
378 // if (component != null) {
379 // addImpl(component, null, -1);
380 // component.setVisible(false);
382 // firePropertyChange("indexForNullComponent", -1, index);
385 // if (pages.size() == 1) {
386 // setSelectedIndex(0);
389 // if (selectedIndex >= newIndex) {
390 // setSelectedIndexImpl(selectedIndex + 1, false);
393 // if (!haveRegistered && tip != null) {
394 // ToolTipManager.sharedInstance().registerComponent(this);
395 // haveRegistered = true;
398 // if (accessibleContext != null) {
399 // accessibleContext.firePropertyChange(
400 // AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
405 private void update(boolean combo)
409 int i0 = tabs.getSelectedIndex();
410 tabs.removeAllItems();
411 for (int i = 0; i < pages.size(); i++)
413 tabs.addItem(pages.get(i).tab);
415 tabs.setSelectedIndex(i0 < 0 ? 0 : i0);
417 pagePanel.removeAll();
418 int selected = getSelectedIndex();
420 {// && bsEnabled.get(selected)) {
421 pagePanel.add(pages.get(selected).component);
427 public void setComponentAt(int index, JPanel panel)
429 if (index < 0 || index >= pages.size())
430 throw new IndexOutOfBoundsException();
431 pages.get(index).component = panel;
435 public int getTabCount()
437 return tabs.getItemCount();
440 public void setSelectedIndex(int index)
442 tabs.setSelectedIndex(index);
446 public int getSelectedIndex()
448 return tabs.getSelectedIndex();
451 public void setEnabledAt(int index, boolean bEnable)
453 // bsEnabled.setBitTo(index, bEnable);
454 // if (!bEnable && index == getSelectedIndex()) {
455 // for (int i = index - 1; --i >= 0;) {
456 // if (bsEnabled.get(i)) {
457 // setSelectedIndex(i);
462 // update(false, true);
465 public void remove(int n)
467 pages.removeItemAt(n);
468 tabs.removeItemAt(n);
470 // bsEnabled.clearAll();
471 // bsEnabled.set(lastSelected);