source: src/main/java/genius/gui/panels/tab/CloseTabPaneUI.java

Last change on this file was 154, checked in by Tim Baarslag, 6 years ago

Number of parties fixed in csv and GUI log

File size: 43.8 KB
Line 
1/*
2 * To change this template, choose Tools | Templates
3 * and open the template in the editor.
4 */
5
6package genius.gui.panels.tab;
7
8import java.util.Hashtable;
9import java.util.Vector;
10
11/*
12 * David Bismut, davidou@mageos.com
13 * Intern, SETLabs, Infosys Technologies Ltd. May 2004 - Jul 2004
14 * Ecole des Mines de Nantes, France
15 */
16
17/*
18 *
19 * Extended from
20 * @(#)BasicTabbedPaneUI.java 1.126 03/01/23
21 *
22 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
23 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
24 */
25
26import java.awt.Color;
27import java.awt.Component;
28import java.awt.Container;
29import java.awt.Dimension;
30import java.awt.Event;
31import java.awt.Font;
32import java.awt.FontMetrics;
33import java.awt.Graphics;
34import java.awt.Graphics2D;
35import java.awt.Insets;
36import java.awt.LayoutManager;
37import java.awt.Point;
38import java.awt.Rectangle;
39import java.awt.Shape;
40import java.awt.event.ActionEvent;
41import java.awt.event.ActionListener;
42import java.awt.event.ContainerEvent;
43import java.awt.event.ContainerListener;
44import java.awt.event.MouseEvent;
45import java.awt.event.MouseListener;
46import java.awt.event.MouseMotionListener;
47import java.awt.image.BufferedImage;
48import java.io.IOException;
49
50import javax.imageio.ImageIO;
51import javax.swing.AbstractAction;
52import javax.swing.ActionMap;
53import javax.swing.Icon;
54import javax.swing.InputMap;
55import javax.swing.JButton;
56import javax.swing.JComponent;
57import javax.swing.JMenuItem;
58import javax.swing.JPanel;
59import javax.swing.JPopupMenu;
60import javax.swing.JTabbedPane;
61import javax.swing.JViewport;
62import javax.swing.KeyStroke;
63import javax.swing.SwingConstants;
64import javax.swing.SwingUtilities;
65import javax.swing.UIManager;
66import javax.swing.border.Border;
67import javax.swing.border.SoftBevelBorder;
68import javax.swing.event.ChangeEvent;
69import javax.swing.event.ChangeListener;
70import javax.swing.plaf.ActionMapUIResource;
71import javax.swing.plaf.ComponentUI;
72import javax.swing.plaf.InputMapUIResource;
73import javax.swing.plaf.UIResource;
74import javax.swing.plaf.basic.BasicArrowButton;
75import javax.swing.plaf.basic.BasicHTML;
76import javax.swing.plaf.basic.BasicTabbedPaneUI;
77import javax.swing.text.View;
78
79/**
80 * UI for <code>CloseAndMaxTabbedPane</code>.
81 * <p>
82 * Credits to:
83 *
84 * @author Amy Fowler
85 * @author Philip Milne
86 * @author Steve Wilson
87 * @author Tom Santos
88 * @author Dave Moore
89 */
90public class CloseTabPaneUI extends BasicTabbedPaneUI {
91
92 // Instance variables initialized at installation
93
94 private ContainerListener containerListener;
95
96 private Vector htmlViews;
97
98 private Hashtable mnemonicToIndexMap;
99
100 /**
101 * InputMap used for mnemonics. Only non-null if the JTabbedPane has
102 * mnemonics associated with it. Lazily created in initMnemonics.
103 */
104 private InputMap mnemonicInputMap;
105
106 // For use when tabLayoutPolicy = SCROLL_TAB_LAYOUT
107 protected ScrollableTabSupport tabScroller;
108
109 private int tabCount;
110
111 protected MyMouseMotionListener motionListener;
112
113 // UI creation
114
115 private static final int INACTIVE = 0;
116
117 private static final int OVER = 1;
118
119 private static final int PRESSED = 2;
120
121 protected static final int BUTTONSIZE = 16;
122
123 protected static final int WIDTHDELTA = 5;
124
125 private static final Border PRESSEDBORDER = new SoftBevelBorder(
126 SoftBevelBorder.LOWERED);
127
128 private static final Border OVERBORDER = new SoftBevelBorder(
129 SoftBevelBorder.RAISED);
130
131 private BufferedImage closeImgB;
132
133 // private BufferedImage maxImgB;
134
135 private BufferedImage closeImgI;
136
137 // private BufferedImage maxImgI;
138
139 private JButton closeB;
140
141 // private JButton maxB;
142
143 private int overTabIndex = -1;
144
145 private int closeIndexStatus = INACTIVE;
146
147 private int maxIndexStatus = INACTIVE;
148
149 private boolean mousePressed = false;
150
151 private boolean isCloseButtonEnabled = true;
152
153 // private boolean isMaxButtonEnabled = true;
154
155 protected JPopupMenu actionPopupMenu;
156
157 // protected JMenuItem maxItem;
158
159 protected JMenuItem closeItem;
160
161 public CloseTabPaneUI() {
162
163 super();
164
165 try {
166 closeImgI = ImageIO.read(getClass().getResource("delete_edit.gif"));
167 } catch (Exception e1) {
168 e1.printStackTrace();
169 }
170
171 closeImgB = new BufferedImage(BUTTONSIZE, BUTTONSIZE,
172 BufferedImage.TYPE_INT_ARGB);
173
174 closeB = new JButton();
175 closeB.setSize(BUTTONSIZE, BUTTONSIZE);
176
177 // WindowsIconFactory.createFrameCloseIcon().paintIcon(closeB,
178 // closeImgI.createGraphics(), 0, 0);
179 drawButton(closeImgB, BUTTONSIZE, BUTTONSIZE);
180
181 actionPopupMenu = new JPopupMenu();
182
183 closeItem = new JMenuItem("Close");
184
185 closeItem.addActionListener(new ActionListener() {
186 public void actionPerformed(ActionEvent e) {
187 ((CloseTabbedPane) tabPane).fireCloseTabEvent(null,
188 tabPane.getSelectedIndex());
189
190 }
191 });
192
193 setPopupMenu();
194 }
195
196 protected void drawButton(BufferedImage img, int w, int h) {
197 Graphics g = img.getGraphics();
198 g.setColor(Color.BLACK);
199 int fudge = 2;
200 int xw = w - fudge * 2;
201 int yh = h = fudge * 2;
202 g.drawLine(fudge, fudge, xw, yh);
203 g.drawLine(xw, fudge, fudge, yh);
204 g.dispose();
205 }
206
207 protected boolean isOneActionButtonEnabled() {
208 return isCloseButtonEnabled;
209 }
210
211 public boolean isCloseEnabled() {
212 return isCloseButtonEnabled;
213 }
214
215 public void setCloseIcon(boolean b) {
216 isCloseButtonEnabled = b;
217 setPopupMenu();
218 }
219
220 private void setPopupMenu() {
221 actionPopupMenu.removeAll();
222 if (isCloseButtonEnabled)
223 actionPopupMenu.add(closeItem);
224 }
225
226 protected int calculateTabWidth(int tabPlacement, int tabIndex,
227 FontMetrics metrics) {
228 int delta = 2;
229 if (!isOneActionButtonEnabled())
230 delta += 6;
231 else {
232 if (isCloseButtonEnabled)
233 delta += BUTTONSIZE + WIDTHDELTA;
234 }
235
236 return super.calculateTabWidth(tabPlacement, tabIndex, metrics) + delta;
237 }
238
239 protected int calculateTabHeight(int tabPlacement, int tabIndex,
240 int fontHeight) {
241
242 return super.calculateTabHeight(tabPlacement, tabIndex, fontHeight) + 5;
243 }
244
245 protected void layoutLabel(int tabPlacement, FontMetrics metrics,
246 int tabIndex, String title, Icon icon, Rectangle tabRect,
247 Rectangle iconRect, Rectangle textRect, boolean isSelected) {
248 textRect.x = textRect.y = iconRect.x = iconRect.y = 0;
249
250 View v = getTextViewForTab(tabIndex);
251 if (v != null) {
252 tabPane.putClientProperty("html", v);
253 }
254
255 SwingUtilities.layoutCompoundLabel((JComponent) tabPane, metrics,
256 title, icon, SwingUtilities.CENTER, SwingUtilities.LEFT,
257 SwingUtilities.CENTER, SwingUtilities.CENTER, tabRect,
258 iconRect, textRect, textIconGap);
259
260 tabPane.putClientProperty("html", null);
261
262 iconRect.x = tabRect.x + 8;
263 textRect.x = iconRect.x + iconRect.width + textIconGap;
264 }
265
266 protected MouseListener createMouseListener() {
267 return new MyMouseHandler();
268 }
269
270 protected ScrollableTabButton createScrollableTabButton(int direction) {
271 return new ScrollableTabButton(direction);
272 }
273
274 protected Rectangle newCloseRect(Rectangle rect) {
275 int dx = rect.x + rect.width;
276 int dy = (rect.y + rect.height) / 2 - 6;
277 return new Rectangle(dx - BUTTONSIZE - WIDTHDELTA, dy, BUTTONSIZE,
278 BUTTONSIZE);
279 }
280
281 protected void updateOverTab(int x, int y) {
282 if (overTabIndex != (overTabIndex = getTabAtLocation(x, y)))
283 tabScroller.tabPanel.repaint();
284
285 }
286
287 protected void updateCloseIcon(int x, int y) {
288
289 if (overTabIndex != -1) {
290 int newCloseIndexStatus = INACTIVE;
291
292 Rectangle closeRect = newCloseRect(rects[overTabIndex]);
293 if (closeRect.contains(x, y))
294 newCloseIndexStatus = mousePressed ? PRESSED : OVER;
295
296 if (closeIndexStatus != (closeIndexStatus = newCloseIndexStatus))
297 tabScroller.tabPanel.repaint();
298 }
299 }
300
301 private void setTabIcons(int x, int y) {
302 // if the mouse isPressed
303 if (!mousePressed) {
304 updateOverTab(x, y);
305 }
306
307 if (isCloseButtonEnabled)
308 updateCloseIcon(x, y);
309 }
310
311 public static ComponentUI createUI(JComponent c) {
312 return new CloseTabPaneUI();
313 }
314
315 /**
316 * Invoked by <code>installUI</code> to createFrom a layout manager object
317 * to manage the <code>JTabbedPane</code>.
318 *
319 * see {@link JTabbedPane#getTabLayoutPolicy()}
320 *
321 * @return a layout manager object
322 *
323 */
324 protected LayoutManager createLayoutManager() {
325
326 return new TabbedPaneScrollLayout();
327
328 }
329
330 /*
331 * In an attempt to preserve backward compatibility for programs which have
332 * extended BasicTabbedPaneUI to do their own layout, the UI uses the
333 * installed layoutManager (and not tabLayoutPolicy) to determine if
334 * scrollTabLayout is enabled.
335 */
336
337 /**
338 * Creates and installs any required subcomponents for the JTabbedPane.
339 * Invoked by installUI.
340 *
341 * @since 1.4
342 */
343 protected void installComponents() {
344
345 if (tabScroller == null) {
346 tabScroller = new ScrollableTabSupport(tabPane.getTabPlacement());
347 tabPane.add(tabScroller.viewport);
348 tabPane.add(tabScroller.scrollForwardButton);
349 tabPane.add(tabScroller.scrollBackwardButton);
350 }
351
352 }
353
354 /**
355 * Removes any installed subcomponents from the JTabbedPane. Invoked by
356 * uninstallUI.
357 *
358 * @since 1.4
359 */
360 protected void uninstallComponents() {
361
362 tabPane.remove(tabScroller.viewport);
363 tabPane.remove(tabScroller.scrollForwardButton);
364 tabPane.remove(tabScroller.scrollBackwardButton);
365 tabScroller = null;
366
367 }
368
369 protected void installListeners() {
370 if ((propertyChangeListener = createPropertyChangeListener()) != null) {
371 tabPane.addPropertyChangeListener(propertyChangeListener);
372 }
373 if ((tabChangeListener = createChangeListener()) != null) {
374 tabPane.addChangeListener(tabChangeListener);
375 }
376 if ((mouseListener = createMouseListener()) != null) {
377 tabScroller.tabPanel.addMouseListener(mouseListener);
378 }
379
380 if ((focusListener = createFocusListener()) != null) {
381 tabPane.addFocusListener(focusListener);
382 }
383
384 // PENDING(api) : See comment for ContainerHandler
385 if ((containerListener = new ContainerHandler()) != null) {
386 tabPane.addContainerListener(containerListener);
387 if (tabPane.getTabCount() > 0) {
388 htmlViews = createHTMLVector();
389 }
390 }
391
392 if ((motionListener = new MyMouseMotionListener()) != null) {
393 tabScroller.tabPanel.addMouseMotionListener(motionListener);
394 }
395
396 }
397
398 protected void uninstallListeners() {
399 if (mouseListener != null) {
400 tabScroller.tabPanel.removeMouseListener(mouseListener);
401 mouseListener = null;
402 }
403
404 if (motionListener != null) {
405 tabScroller.tabPanel.removeMouseMotionListener(motionListener);
406 motionListener = null;
407 }
408
409 if (focusListener != null) {
410 tabPane.removeFocusListener(focusListener);
411 focusListener = null;
412 }
413
414 // PENDING(api): See comment for ContainerHandler
415 if (containerListener != null) {
416 tabPane.removeContainerListener(containerListener);
417 containerListener = null;
418 if (htmlViews != null) {
419 htmlViews.removeAllElements();
420 htmlViews = null;
421 }
422 }
423 if (tabChangeListener != null) {
424 tabPane.removeChangeListener(tabChangeListener);
425 tabChangeListener = null;
426 }
427 if (propertyChangeListener != null) {
428 tabPane.removePropertyChangeListener(propertyChangeListener);
429 propertyChangeListener = null;
430 }
431
432 }
433
434 protected ChangeListener createChangeListener() {
435 return new TabSelectionHandler();
436 }
437
438 protected void installKeyboardActions() {
439 InputMap km = getMyInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
440
441 SwingUtilities.replaceUIInputMap(tabPane,
442 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, km);
443 km = getMyInputMap(JComponent.WHEN_FOCUSED);
444 SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, km);
445
446 ActionMap am = createMyActionMap();
447
448 SwingUtilities.replaceUIActionMap(tabPane, am);
449
450 tabScroller.scrollForwardButton.setAction(am
451 .get("scrollTabsForwardAction"));
452 tabScroller.scrollBackwardButton.setAction(am
453 .get("scrollTabsBackwardAction"));
454
455 }
456
457 InputMap getMyInputMap(int condition) {
458 if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
459 return (InputMap) UIManager.get("TabbedPane.ancestorInputMap");
460 } else if (condition == JComponent.WHEN_FOCUSED) {
461 return (InputMap) UIManager.get("TabbedPane.focusInputMap");
462 }
463 return null;
464 }
465
466 ActionMap createMyActionMap() {
467 ActionMap map = new ActionMapUIResource();
468 map.put("navigateNext", new NextAction());
469 map.put("navigatePrevious", new PreviousAction());
470 map.put("navigateRight", new RightAction());
471 map.put("navigateLeft", new LeftAction());
472 map.put("navigateUp", new UpAction());
473 map.put("navigateDown", new DownAction());
474 map.put("navigatePageUp", new PageUpAction());
475 map.put("navigatePageDown", new PageDownAction());
476 map.put("requestFocus", new RequestFocusAction());
477 map.put("requestFocusForVisibleComponent",
478 new RequestFocusForVisibleAction());
479 map.put("setSelectedIndex", new SetSelectedIndexAction());
480 map.put("scrollTabsForwardAction", new ScrollTabsForwardAction());
481 map.put("scrollTabsBackwardAction", new ScrollTabsBackwardAction());
482 return map;
483 }
484
485 protected void uninstallKeyboardActions() {
486 SwingUtilities.replaceUIActionMap(tabPane, null);
487 SwingUtilities.replaceUIInputMap(tabPane,
488 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
489 SwingUtilities
490 .replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, null);
491 }
492
493 /**
494 * Reloads the mnemonics. This should be invoked when a memonic changes,
495 * when the title of a mnemonic changes, or when tabs are added/removed.
496 */
497 private void updateMnemonics() {
498 resetMnemonics();
499 for (int counter = tabPane.getTabCount() - 1; counter >= 0; counter--) {
500 int mnemonic = tabPane.getMnemonicAt(counter);
501
502 if (mnemonic > 0) {
503 addMnemonic(counter, mnemonic);
504 }
505 }
506 }
507
508 /**
509 * Resets the mnemonics bindings to an empty state.
510 */
511 private void resetMnemonics() {
512 if (mnemonicToIndexMap != null) {
513 mnemonicToIndexMap.clear();
514 mnemonicInputMap.clear();
515 }
516 }
517
518 /**
519 * Adds the specified mnemonic at the specified index.
520 */
521 private void addMnemonic(int index, int mnemonic) {
522 if (mnemonicToIndexMap == null) {
523 initMnemonics();
524 }
525 mnemonicInputMap.put(KeyStroke.getKeyStroke(mnemonic, Event.ALT_MASK),
526 "setSelectedIndex");
527 mnemonicToIndexMap.put(new Integer(mnemonic), new Integer(index));
528 }
529
530 /**
531 * Installs the state needed for mnemonics.
532 */
533 private void initMnemonics() {
534 mnemonicToIndexMap = new Hashtable();
535 mnemonicInputMap = new InputMapUIResource();
536 mnemonicInputMap.setParent(SwingUtilities.getUIInputMap(tabPane,
537 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT));
538 SwingUtilities
539 .replaceUIInputMap(tabPane,
540 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
541 mnemonicInputMap);
542 }
543
544 // UI Rendering
545
546 public void paint(Graphics g, JComponent c) {
547 int tc = tabPane.getTabCount();
548
549 if (tabCount != tc) {
550 tabCount = tc;
551 updateMnemonics();
552 }
553
554 int selectedIndex = tabPane.getSelectedIndex();
555 int tabPlacement = tabPane.getTabPlacement();
556
557 ensureCurrentLayout();
558
559 // Paint content border
560 paintContentBorder(g, tabPlacement, selectedIndex);
561
562 }
563
564 protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects,
565 int tabIndex, Rectangle iconRect, Rectangle textRect) {
566 Rectangle tabRect = rects[tabIndex];
567 int selectedIndex = tabPane.getSelectedIndex();
568 boolean isSelected = selectedIndex == tabIndex;
569 boolean isOver = overTabIndex == tabIndex;
570 Graphics2D g2 = null;
571 Shape save = null;
572 boolean cropShape = false;
573 int cropx = 0;
574 int cropy = 0;
575
576 if (g instanceof Graphics2D) {
577 g2 = (Graphics2D) g;
578
579 // Render visual for cropped tab edge...
580 Rectangle viewRect = tabScroller.viewport.getViewRect();
581 int cropline;
582
583 cropline = viewRect.x + viewRect.width;
584 if ((tabRect.x < cropline)
585 && (tabRect.x + tabRect.width > cropline)) {
586
587 cropx = cropline - 1;
588 cropy = tabRect.y;
589 cropShape = true;
590 }
591
592 if (cropShape) {
593 save = g2.getClip();
594 g2.clipRect(tabRect.x, tabRect.y, tabRect.width, tabRect.height);
595
596 }
597 }
598
599 paintTabBackground(g, tabPlacement, tabIndex, tabRect.x, tabRect.y,
600 tabRect.width, tabRect.height, isSelected);
601
602 paintTabBorder(g, tabPlacement, tabIndex, tabRect.x, tabRect.y,
603 tabRect.width, tabRect.height, isSelected);
604
605 String title = tabPane.getTitleAt(tabIndex);
606 Font font = tabPane.getFont();
607 FontMetrics metrics = g.getFontMetrics(font);
608 Icon icon = getIconForTab(tabIndex);
609
610 layoutLabel(tabPlacement, metrics, tabIndex, title, icon, tabRect,
611 iconRect, textRect, isSelected);
612
613 paintText(g, tabPlacement, font, metrics, tabIndex, title, textRect,
614 isSelected);
615
616 paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
617
618 paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect,
619 textRect, isSelected);
620
621 if (cropShape) {
622 paintCroppedTabEdge(g, tabPlacement, tabIndex, isSelected, cropx,
623 cropy);
624 g2.setClip(save);
625
626 } else if (isOver || isSelected) {
627
628 int dx = tabRect.x + tabRect.width - BUTTONSIZE - WIDTHDELTA;
629 int dy = (tabRect.y + tabRect.height) / 2 - 6;
630
631 if (isCloseButtonEnabled)
632 paintCloseIcon(g2, dx, dy, isOver);
633 }
634
635 }
636
637 protected void paintCloseIcon(Graphics g, int dx, int dy, boolean isOver) {
638 paintActionButton(g, dx, dy, closeIndexStatus, isOver, closeB,
639 closeImgB);
640 g.drawImage(closeImgI, dx, dy + 1, null);
641 }
642
643 protected void paintActionButton(Graphics g, int dx, int dy, int status,
644 boolean isOver, JButton button, BufferedImage image) {
645
646 button.setBorder(null);
647
648 if (isOver) {
649 switch (status) {
650 case OVER:
651 button.setBorder(OVERBORDER);
652 break;
653 case PRESSED:
654 button.setBorder(PRESSEDBORDER);
655 break;
656 }
657 }
658
659 button.setBackground(tabScroller.tabPanel.getBackground());
660 button.paint(image.getGraphics());
661 g.drawImage(image, dx, dy, null);
662 }
663
664 /*
665 * This method will createFrom and return a polygon shape for the given tab
666 * rectangle which has been cropped at the specified cropline with a torn
667 * edge visual. e.g. A "File" tab which has cropped been cropped just after
668 * the "i": ------------- | ..... | | . | | ... . | | . . | | . . | | . . |
669 * --------------
670 *
671 * The x, y arrays below define the pattern used to createFrom a "torn" edge
672 * segment which is repeated to fill the edge of the tab. For tabs placed on
673 * TOP and BOTTOM, this righthand torn edge is created by line segments
674 * which are defined by coordinates obtained by subtracting xCropLen[i] from
675 * (tab.x + tab.width) and adding yCroplen[i] to (tab.y). For tabs placed on
676 * LEFT or RIGHT, the bottom torn edge is created by subtracting xCropLen[i]
677 * from (tab.y + tab.height) and adding yCropLen[i] to (tab.x).
678 */
679
680 private void paintCroppedTabEdge(Graphics g, int tabPlacement,
681 int tabIndex, boolean isSelected, int x, int y) {
682
683 g.setColor(shadow);
684 g.drawLine(x, y, x, y + rects[tabIndex].height);
685
686 }
687
688 private void ensureCurrentLayout() {
689 if (!tabPane.isValid()) {
690 tabPane.validate();
691 }
692 /*
693 * If tabPane doesn't have a peer yet, the validate() call will silently
694 * fail. We handle that by forcing a layout if tabPane is still invalid.
695 * See bug 4237677.
696 */
697 if (!tabPane.isValid()) {
698 TabbedPaneLayout layout = (TabbedPaneLayout) tabPane.getLayout();
699 layout.calculateLayoutInfo();
700 }
701 }
702
703 /**
704 * Returns the bounds of the specified tab in the coordinate space of the
705 * JTabbedPane component. This is required because the tab rects are by
706 * default defined in the coordinate space of the component where they are
707 * rendered, which could be the JTabbedPane (for WRAP_TAB_LAYOUT) or a
708 * ScrollableTabPanel (SCROLL_TAB_LAYOUT). This method should be used
709 * whenever the tab rectangle must be relative to the JTabbedPane itself and
710 * the result should be placed in a designated Rectangle object (rather than
711 * instantiating and returning a new Rectangle each time). The tab index
712 * parameter must be a valid tabbed pane tab index (0 to tab count - 1,
713 * inclusive). The destination rectangle parameter must be a valid
714 * <code>Rectangle</code> instance. The handling of invalid parameters is
715 * unspecified.
716 *
717 * @param tabIndex
718 * the index of the tab
719 * @param dest
720 * the rectangle where the result should be placed
721 * @return the resulting rectangle
722 *
723 * @since 1.4
724 */
725
726 protected Rectangle getTabBounds(int tabIndex, Rectangle dest) {
727 dest.width = rects[tabIndex].width;
728 dest.height = rects[tabIndex].height;
729
730 Point vpp = tabScroller.viewport.getLocation();
731 Point viewp = tabScroller.viewport.getViewPosition();
732 dest.x = rects[tabIndex].x + vpp.x - viewp.x;
733 dest.y = rects[tabIndex].y + vpp.y - viewp.y;
734
735 return dest;
736 }
737
738 private int getTabAtLocation(int x, int y) {
739 ensureCurrentLayout();
740
741 int tabCount = tabPane.getTabCount();
742 for (int i = 0; i < tabCount; i++) {
743 if (rects[i].contains(x, y)) {
744 return i;
745 }
746 }
747 return -1;
748 }
749
750 public int getOverTabIndex() {
751 return overTabIndex;
752 }
753
754 /**
755 * Returns the index of the tab closest to the passed in location, note that
756 * the returned tab may not contain the location x,y.
757 */
758 private int getClosestTab(int x, int y) {
759 int min = 0;
760 int tabCount = Math.min(rects.length, tabPane.getTabCount());
761 int max = tabCount;
762 int tabPlacement = tabPane.getTabPlacement();
763 boolean useX = (tabPlacement == TOP || tabPlacement == BOTTOM);
764 int want = (useX) ? x : y;
765
766 while (min != max) {
767 int current = (max + min) / 2;
768 int minLoc;
769 int maxLoc;
770
771 if (useX) {
772 minLoc = rects[current].x;
773 maxLoc = minLoc + rects[current].width;
774 } else {
775 minLoc = rects[current].y;
776 maxLoc = minLoc + rects[current].height;
777 }
778 if (want < minLoc) {
779 max = current;
780 if (min == max) {
781 return Math.max(0, current - 1);
782 }
783 } else if (want >= maxLoc) {
784 min = current;
785 if (max - min <= 1) {
786 return Math.max(current + 1, tabCount - 1);
787 }
788 } else {
789 return current;
790 }
791 }
792 return min;
793 }
794
795 // BasicTabbedPaneUI methods
796
797 // Tab Navigation methods
798
799 // REMIND(aim,7/29/98): This method should be made
800 // protected in the next release where
801 // API changes are allowed
802 //
803 boolean requestMyFocusForVisibleComponent() {
804 Component visibleComponent = getVisibleComponent();
805 if (visibleComponent.isFocusTraversable()) {
806 visibleComponent.requestFocus();
807 return true;
808 } else if (visibleComponent instanceof JComponent) {
809 if (((JComponent) visibleComponent).requestDefaultFocus()) {
810 return true;
811 }
812 }
813 return false;
814 }
815
816 private static class RightAction extends AbstractAction {
817
818 private static final long serialVersionUID = 935893229208903734L;
819
820 public void actionPerformed(ActionEvent e) {
821 JTabbedPane pane = (JTabbedPane) e.getSource();
822 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
823 ui.navigateSelectedTab(EAST);
824 }
825 };
826
827 private static class LeftAction extends AbstractAction {
828 /**
829 *
830 */
831 private static final long serialVersionUID = 4809159341704902394L;
832
833 public void actionPerformed(ActionEvent e) {
834 JTabbedPane pane = (JTabbedPane) e.getSource();
835 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
836 ui.navigateSelectedTab(WEST);
837 }
838 };
839
840 private static class UpAction extends AbstractAction {
841 /**
842 *
843 */
844 private static final long serialVersionUID = 7625909677342383641L;
845
846 public void actionPerformed(ActionEvent e) {
847 JTabbedPane pane = (JTabbedPane) e.getSource();
848 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
849 ui.navigateSelectedTab(NORTH);
850 }
851 };
852
853 private static class DownAction extends AbstractAction {
854 /**
855 *
856 */
857 private static final long serialVersionUID = -8694915120302734352L;
858
859 public void actionPerformed(ActionEvent e) {
860 JTabbedPane pane = (JTabbedPane) e.getSource();
861 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
862 ui.navigateSelectedTab(SOUTH);
863 }
864 };
865
866 private static class NextAction extends AbstractAction {
867 /**
868 *
869 */
870 private static final long serialVersionUID = -6878700030400531959L;
871
872 public void actionPerformed(ActionEvent e) {
873 JTabbedPane pane = (JTabbedPane) e.getSource();
874 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
875 ui.navigateSelectedTab(NEXT);
876 }
877 };
878
879 private static class PreviousAction extends AbstractAction {
880 /**
881 *
882 */
883 private static final long serialVersionUID = -6457669199117221643L;
884
885 public void actionPerformed(ActionEvent e) {
886 JTabbedPane pane = (JTabbedPane) e.getSource();
887 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
888 ui.navigateSelectedTab(PREVIOUS);
889 }
890 };
891
892 private static class PageUpAction extends AbstractAction {
893 /**
894 *
895 */
896 private static final long serialVersionUID = 7982625940083686135L;
897
898 public void actionPerformed(ActionEvent e) {
899 JTabbedPane pane = (JTabbedPane) e.getSource();
900 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
901 int tabPlacement = pane.getTabPlacement();
902 if (tabPlacement == TOP || tabPlacement == BOTTOM) {
903 ui.navigateSelectedTab(WEST);
904 } else {
905 ui.navigateSelectedTab(NORTH);
906 }
907 }
908 };
909
910 private static class PageDownAction extends AbstractAction {
911 /**
912 *
913 */
914 private static final long serialVersionUID = -5282341515109000329L;
915
916 public void actionPerformed(ActionEvent e) {
917 JTabbedPane pane = (JTabbedPane) e.getSource();
918 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
919 int tabPlacement = pane.getTabPlacement();
920 if (tabPlacement == TOP || tabPlacement == BOTTOM) {
921 ui.navigateSelectedTab(EAST);
922 } else {
923 ui.navigateSelectedTab(SOUTH);
924 }
925 }
926 };
927
928 private static class RequestFocusAction extends AbstractAction {
929 /**
930 *
931 */
932 private static final long serialVersionUID = -6217783952850344598L;
933
934 public void actionPerformed(ActionEvent e) {
935 JTabbedPane pane = (JTabbedPane) e.getSource();
936 pane.requestFocus();
937 }
938 };
939
940 private static class RequestFocusForVisibleAction extends AbstractAction {
941 /**
942 *
943 */
944 private static final long serialVersionUID = 3084200378882675448L;
945
946 public void actionPerformed(ActionEvent e) {
947 JTabbedPane pane = (JTabbedPane) e.getSource();
948 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
949 ui.requestMyFocusForVisibleComponent();
950 }
951 };
952
953 /**
954 * Selects a tab in the JTabbedPane based on the String of the action
955 * command. The tab selected is based on the first tab that has a mnemonic
956 * matching the first character of the action command.
957 */
958 private static class SetSelectedIndexAction extends AbstractAction {
959 /**
960 *
961 */
962 private static final long serialVersionUID = 1387941409542691929L;
963
964 public void actionPerformed(ActionEvent e) {
965 JTabbedPane pane = (JTabbedPane) e.getSource();
966
967 if (pane != null && (pane.getUI() instanceof CloseTabPaneUI)) {
968 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
969 String command = e.getActionCommand();
970
971 if (command != null && command.length() > 0) {
972 int mnemonic = (int) e.getActionCommand().charAt(0);
973 if (mnemonic >= 'a' && mnemonic <= 'z') {
974 mnemonic -= ('a' - 'A');
975 }
976 Integer index = (Integer) ui.mnemonicToIndexMap
977 .get(new Integer(mnemonic));
978 if (index != null && pane.isEnabledAt(index.intValue())) {
979 pane.setSelectedIndex(index.intValue());
980 }
981 }
982 }
983 }
984 };
985
986 private static class ScrollTabsForwardAction extends AbstractAction {
987 /**
988 *
989 */
990 private static final long serialVersionUID = -6666938254664028073L;
991
992 public void actionPerformed(ActionEvent e) {
993 JTabbedPane pane = null;
994 Object src = e.getSource();
995 if (src instanceof JTabbedPane) {
996 pane = (JTabbedPane) src;
997 } else if (src instanceof ScrollableTabButton) {
998 pane = (JTabbedPane) ((ScrollableTabButton) src).getParent();
999 } else {
1000 return; // shouldn't happen
1001 }
1002 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
1003
1004 ui.tabScroller.scrollForward(pane.getTabPlacement());
1005
1006 }
1007 }
1008
1009 private static class ScrollTabsBackwardAction extends AbstractAction {
1010 /**
1011 *
1012 */
1013 private static final long serialVersionUID = -1987973308242859217L;
1014
1015 public void actionPerformed(ActionEvent e) {
1016 JTabbedPane pane = null;
1017 Object src = e.getSource();
1018 if (src instanceof JTabbedPane) {
1019 pane = (JTabbedPane) src;
1020 } else if (src instanceof ScrollableTabButton) {
1021 pane = (JTabbedPane) ((ScrollableTabButton) src).getParent();
1022 } else {
1023 return; // shouldn't happen
1024 }
1025 CloseTabPaneUI ui = (CloseTabPaneUI) pane.getUI();
1026
1027 ui.tabScroller.scrollBackward(pane.getTabPlacement());
1028
1029 }
1030 }
1031
1032 /**
1033 * This inner class is marked &quot;public&quot; due to a compiler bug. This
1034 * class should be treated as a &quot;protected&quot; inner class.
1035 * Instantiate it only within subclasses of BasicTabbedPaneUI.
1036 */
1037
1038 private class TabbedPaneScrollLayout extends TabbedPaneLayout {
1039
1040 protected int preferredTabAreaHeight(int tabPlacement, int width) {
1041 return calculateMaxTabHeight(tabPlacement);
1042 }
1043
1044 protected int preferredTabAreaWidth(int tabPlacement, int height) {
1045 return calculateMaxTabWidth(tabPlacement);
1046 }
1047
1048 public void layoutContainer(Container parent) {
1049 int tabPlacement = tabPane.getTabPlacement();
1050 int tabCount = tabPane.getTabCount();
1051 Insets insets = tabPane.getInsets();
1052 int selectedIndex = tabPane.getSelectedIndex();
1053 Component visibleComponent = getVisibleComponent();
1054
1055 calculateLayoutInfo();
1056
1057 if (selectedIndex < 0) {
1058 if (visibleComponent != null) {
1059 // The last tab was removed, so remove the component
1060 setVisibleComponent(null);
1061 }
1062 } else {
1063 Component selectedComponent = tabPane
1064 .getComponentAt(selectedIndex);
1065 boolean shouldChangeFocus = false;
1066
1067 // In order to allow programs to use a single component
1068 // as the display for multiple tabs, we will not change
1069 // the visible compnent if the currently selected tab
1070 // has a null component. This is a bit dicey, as we don't
1071 // explicitly state we support this in the spec, but since
1072 // programs are now depending on this, we're making it work.
1073 //
1074 if (selectedComponent != null) {
1075 if (selectedComponent != visibleComponent
1076 && visibleComponent != null) {
1077 if (SwingUtilities.findFocusOwner(visibleComponent) != null) {
1078 shouldChangeFocus = true;
1079 }
1080 }
1081 setVisibleComponent(selectedComponent);
1082 }
1083 int tx, ty, tw, th; // tab area bounds
1084 int cx, cy, cw, ch; // content area bounds
1085 Insets contentInsets = getContentBorderInsets(tabPlacement);
1086 Rectangle bounds = tabPane.getBounds();
1087 int numChildren = tabPane.getComponentCount();
1088
1089 if (numChildren > 0) {
1090
1091 // calculate tab area bounds
1092 tw = bounds.width - insets.left - insets.right;
1093 th = calculateTabAreaHeight(tabPlacement, runCount,
1094 maxTabHeight);
1095 tx = insets.left;
1096 ty = insets.top;
1097
1098 // calculate content area bounds
1099 cx = tx + contentInsets.left;
1100 cy = ty + th + contentInsets.top;
1101 cw = bounds.width - insets.left - insets.right
1102 - contentInsets.left - contentInsets.right;
1103 ch = bounds.height - insets.top - insets.bottom - th
1104 - contentInsets.top - contentInsets.bottom;
1105
1106 for (int i = 0; i < numChildren; i++) {
1107 Component child = tabPane.getComponent(i);
1108
1109 if (child instanceof ScrollableTabViewport) {
1110 JViewport viewport = (JViewport) child;
1111 Rectangle viewRect = viewport.getViewRect();
1112 int vw = tw;
1113 int vh = th;
1114
1115 int totalTabWidth = rects[tabCount - 1].x
1116 + rects[tabCount - 1].width;
1117 if (totalTabWidth > tw) {
1118 // Need to allow space for scrollbuttons
1119 vw = Math.max(tw - 36, 36);
1120 ;
1121 if (totalTabWidth - viewRect.x <= vw) {
1122 // Scrolled to the end, so ensure the
1123 // viewport size is
1124 // such that the scroll offset aligns with a
1125 // tab
1126 vw = totalTabWidth - viewRect.x;
1127 }
1128 }
1129
1130 child.setBounds(tx, ty, vw, vh);
1131
1132 } else if (child instanceof ScrollableTabButton) {
1133 ScrollableTabButton scrollbutton = (ScrollableTabButton) child;
1134 Dimension bsize = scrollbutton.getPreferredSize();
1135 int bx = 0;
1136 int by = 0;
1137 int bw = bsize.width;
1138 int bh = bsize.height;
1139 boolean visible = false;
1140
1141 int totalTabWidth = rects[tabCount - 1].x
1142 + rects[tabCount - 1].width;
1143
1144 if (totalTabWidth > tw) {
1145 int dir = scrollbutton.scrollsForward() ? EAST
1146 : WEST;
1147 scrollbutton.setDirection(dir);
1148 visible = true;
1149 bx = dir == EAST ? bounds.width - insets.left
1150 - bsize.width : bounds.width
1151 - insets.left - 2 * bsize.width;
1152 by = (tabPlacement == TOP ? ty + th
1153 - bsize.height : ty);
1154 }
1155
1156 child.setVisible(visible);
1157 if (visible) {
1158 child.setBounds(bx, by, bw, bh);
1159 }
1160
1161 } else {
1162 // All content children...
1163 child.setBounds(cx, cy, cw, ch);
1164 }
1165 }
1166 if (shouldChangeFocus) {
1167 if (!requestMyFocusForVisibleComponent()) {
1168 tabPane.requestFocus();
1169 }
1170 }
1171 }
1172 }
1173 }
1174
1175 protected void calculateTabRects(int tabPlacement, int tabCount) {
1176 FontMetrics metrics = getFontMetrics();
1177 Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
1178 int i;
1179
1180 int x = tabAreaInsets.left - 2;
1181 int y = tabAreaInsets.top;
1182 int totalWidth = 0;
1183 int totalHeight = 0;
1184
1185 //
1186 // Calculate bounds within which a tab run must fit
1187 //
1188
1189 maxTabHeight = calculateMaxTabHeight(tabPlacement);
1190
1191 runCount = 0;
1192 selectedRun = -1;
1193
1194 if (tabCount == 0) {
1195 return;
1196 }
1197
1198 selectedRun = 0;
1199 runCount = 1;
1200
1201 // Run through tabs and lay them out in a single run
1202 Rectangle rect;
1203 for (i = 0; i < tabCount; i++) {
1204 rect = rects[i];
1205
1206 if (i > 0) {
1207 rect.x = rects[i - 1].x + rects[i - 1].width - 1;
1208 } else {
1209 tabRuns[0] = 0;
1210 maxTabWidth = 0;
1211 totalHeight += maxTabHeight;
1212 rect.x = x;
1213 }
1214 rect.width = calculateTabWidth(tabPlacement, i, metrics);
1215 totalWidth = rect.x + rect.width;
1216 maxTabWidth = Math.max(maxTabWidth, rect.width);
1217
1218 rect.y = y;
1219 rect.height = maxTabHeight /* - 2 */;
1220
1221 }
1222
1223 // tabPanel.setSize(totalWidth, totalHeight);
1224 tabScroller.tabPanel.setPreferredSize(new Dimension(totalWidth,
1225 totalHeight));
1226 }
1227 }
1228
1229 private class ScrollableTabSupport implements ChangeListener {
1230 public ScrollableTabViewport viewport;
1231
1232 public ScrollableTabPanel tabPanel;
1233
1234 public ScrollableTabButton scrollForwardButton;
1235
1236 public ScrollableTabButton scrollBackwardButton;
1237
1238 public int leadingTabIndex;
1239
1240 private Point tabViewPosition = new Point(0, 0);
1241
1242 ScrollableTabSupport(int tabPlacement) {
1243 viewport = new ScrollableTabViewport();
1244 tabPanel = new ScrollableTabPanel();
1245 viewport.setView(tabPanel);
1246 viewport.addChangeListener(this);
1247
1248 scrollForwardButton = createScrollableTabButton(EAST);
1249 scrollBackwardButton = createScrollableTabButton(WEST);
1250 // scrollForwardButton = new ScrollableTabButton(EAST);
1251 // scrollBackwardButton = new ScrollableTabButton(WEST);
1252 }
1253
1254 public void scrollForward(int tabPlacement) {
1255 Dimension viewSize = viewport.getViewSize();
1256 Rectangle viewRect = viewport.getViewRect();
1257
1258 if (tabPlacement == TOP || tabPlacement == BOTTOM) {
1259 if (viewRect.width >= viewSize.width - viewRect.x) {
1260 return; // no room left to scroll
1261 }
1262 } else { // tabPlacement == LEFT || tabPlacement == RIGHT
1263 if (viewRect.height >= viewSize.height - viewRect.y) {
1264 return;
1265 }
1266 }
1267 setLeadingTabIndex(tabPlacement, leadingTabIndex + 1);
1268 }
1269
1270 public void scrollBackward(int tabPlacement) {
1271 if (leadingTabIndex == 0) {
1272 return; // no room left to scroll
1273 }
1274 setLeadingTabIndex(tabPlacement, leadingTabIndex - 1);
1275 }
1276
1277 public void setLeadingTabIndex(int tabPlacement, int index) {
1278 leadingTabIndex = index;
1279 Dimension viewSize = viewport.getViewSize();
1280 Rectangle viewRect = viewport.getViewRect();
1281
1282 tabViewPosition.x = leadingTabIndex == 0 ? 0
1283 : rects[leadingTabIndex].x;
1284
1285 if ((viewSize.width - tabViewPosition.x) < viewRect.width) {
1286 // We've scrolled to the end, so adjust the viewport size
1287 // to ensure the view position remains aligned on a tab boundary
1288 Dimension extentSize = new Dimension(viewSize.width
1289 - tabViewPosition.x, viewRect.height);
1290 viewport.setExtentSize(extentSize);
1291 }
1292
1293 viewport.setViewPosition(tabViewPosition);
1294 }
1295
1296 public void stateChanged(ChangeEvent e) {
1297 JViewport viewport = (JViewport) e.getSource();
1298 int tabPlacement = tabPane.getTabPlacement();
1299 int tabCount = tabPane.getTabCount();
1300 Rectangle vpRect = viewport.getBounds();
1301 Dimension viewSize = viewport.getViewSize();
1302 Rectangle viewRect = viewport.getViewRect();
1303
1304 leadingTabIndex = getClosestTab(viewRect.x, viewRect.y);
1305
1306 // If the tab isn't right aligned, adjust it.
1307 if (leadingTabIndex + 1 < tabCount) {
1308
1309 if (rects[leadingTabIndex].x < viewRect.x) {
1310 leadingTabIndex++;
1311 }
1312
1313 }
1314 Insets contentInsets = getContentBorderInsets(tabPlacement);
1315
1316 tabPane.repaint(vpRect.x, vpRect.y + vpRect.height, vpRect.width,
1317 contentInsets.top);
1318 scrollBackwardButton.setEnabled(viewRect.x > 0);
1319 scrollForwardButton.setEnabled(leadingTabIndex < tabCount - 1
1320 && viewSize.width - viewRect.x > viewRect.width);
1321
1322 }
1323
1324 public String toString() {
1325 return new String("viewport.viewSize=" + viewport.getViewSize()
1326 + "\n" + "viewport.viewRectangle=" + viewport.getViewRect()
1327 + "\n" + "leadingTabIndex=" + leadingTabIndex + "\n"
1328 + "tabViewPosition=" + tabViewPosition);
1329 }
1330
1331 }
1332
1333 private class ScrollableTabViewport extends JViewport implements UIResource {
1334 /**
1335 *
1336 */
1337 private static final long serialVersionUID = -1242867759592475276L;
1338
1339 public ScrollableTabViewport() {
1340 super();
1341 setScrollMode(SIMPLE_SCROLL_MODE);
1342 }
1343 }
1344
1345 private class ScrollableTabPanel extends JPanel implements UIResource {
1346 /**
1347 *
1348 */
1349 private static final long serialVersionUID = -1464842471862829924L;
1350
1351 public ScrollableTabPanel() {
1352 setLayout(null);
1353 }
1354
1355 public void paintComponent(Graphics g) {
1356 super.paintComponent(g);
1357 CloseTabPaneUI.this.paintTabArea(g, tabPane.getTabPlacement(),
1358 tabPane.getSelectedIndex());
1359
1360 }
1361 }
1362
1363 protected class ScrollableTabButton extends BasicArrowButton implements
1364 UIResource, SwingConstants {
1365 /**
1366 *
1367 */
1368 private static final long serialVersionUID = -495311838796397754L;
1369
1370 public ScrollableTabButton(int direction) {
1371 super(direction, UIManager.getColor("TabbedPane.selected"),
1372 UIManager.getColor("TabbedPane.shadow"), UIManager
1373 .getColor("TabbedPane.darkShadow"), UIManager
1374 .getColor("TabbedPane.highlight"));
1375
1376 }
1377
1378 public boolean scrollsForward() {
1379 return direction == EAST || direction == SOUTH;
1380 }
1381
1382 }
1383
1384 /**
1385 * This inner class is marked &quot;public&quot; due to a compiler bug. This
1386 * class should be treated as a &quot;protected&quot; inner class.
1387 * Instantiate it only within subclasses of BasicTabbedPaneUI.
1388 */
1389 public class TabSelectionHandler implements ChangeListener {
1390 public void stateChanged(ChangeEvent e) {
1391 JTabbedPane tabPane = (JTabbedPane) e.getSource();
1392 tabPane.revalidate();
1393 tabPane.repaint();
1394
1395 if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) {
1396 int index = tabPane.getSelectedIndex();
1397 if (index < rects.length && index != -1) {
1398 tabScroller.tabPanel.scrollRectToVisible(rects[index]);
1399 }
1400 }
1401 }
1402 }
1403
1404 /**
1405 * This inner class is marked &quot;public&quot; due to a compiler bug. This
1406 * class should be treated as a &quot;protected&quot; inner class.
1407 * Instantiate it only within subclasses of BasicTabbedPaneUI.
1408 */
1409
1410 /*
1411 * GES 2/3/99: The container listener code was added to support HTML
1412 * rendering of tab titles.
1413 *
1414 * Ideally, we would be able to listen for property changes when a tab is
1415 * added or its text modified. At the moment there are no such events
1416 * because the Beans spec doesn't allow 'indexed' property changes (i.e. tab
1417 * 2's text changed from A to B).
1418 *
1419 * In order to get around this, we listen for tabs to be added or removed by
1420 * listening for the container events. we then queue up a runnable (so the
1421 * component has a chance to complete the add) which checks the tab title of
1422 * the new component to see if it requires HTML rendering.
1423 *
1424 * The Views (one per tab title requiring HTML rendering) are stored in the
1425 * htmlViews Vector, which is only allocated after the first time we run
1426 * into an HTML tab. Note that this vector is kept in step with the number
1427 * of pages, and nulls are added for those pages whose tab title do not
1428 * require HTML rendering.
1429 *
1430 * This makes it easy for the paint and layout code to tell whether to
1431 * invoke the HTML engine without having to check the string during
1432 * time-sensitive operations.
1433 *
1434 * When we have added a way to listen for tab additions and changes to tab
1435 * text, this code should be removed and replaced by something which uses
1436 * that.
1437 */
1438
1439 private class ContainerHandler implements ContainerListener {
1440 public void componentAdded(ContainerEvent e) {
1441 JTabbedPane tp = (JTabbedPane) e.getContainer();
1442 Component child = e.getChild();
1443 if (child instanceof UIResource) {
1444 return;
1445 }
1446 int index = tp.indexOfComponent(child);
1447 String title = tp.getTitleAt(index);
1448 boolean isHTML = BasicHTML.isHTMLString(title);
1449 if (isHTML) {
1450 if (htmlViews == null) { // Initialize vector
1451 htmlViews = createHTMLVector();
1452 } else { // Vector already exists
1453 View v = BasicHTML.createHTMLView(tp, title);
1454 htmlViews.insertElementAt(v, index);
1455 }
1456 } else { // Not HTML
1457 if (htmlViews != null) { // Add placeholder
1458 htmlViews.insertElementAt(null, index);
1459 } // else nada!
1460 }
1461 }
1462
1463 public void componentRemoved(ContainerEvent e) {
1464 JTabbedPane tp = (JTabbedPane) e.getContainer();
1465 Component child = e.getChild();
1466 if (child instanceof UIResource) {
1467 return;
1468 }
1469
1470 // NOTE 4/15/2002 (joutwate):
1471 // This fix is implemented using client properties since there is
1472 // currently no IndexPropertyChangeEvent. Once
1473 // IndexPropertyChangeEvents have been added this code should be
1474 // modified to use it.
1475 Integer indexObj = (Integer) tp
1476 .getClientProperty("__index_to_remove__");
1477 if (indexObj != null) {
1478 int index = indexObj.intValue();
1479 if (htmlViews != null && htmlViews.size() >= index) {
1480 htmlViews.removeElementAt(index);
1481 }
1482 }
1483 }
1484 }
1485
1486 private Vector<View> createHTMLVector() {
1487 Vector<View> htmlViews = new Vector<View>();
1488 int count = tabPane.getTabCount();
1489 if (count > 0) {
1490 for (int i = 0; i < count; i++) {
1491 String title = tabPane.getTitleAt(i);
1492 if (BasicHTML.isHTMLString(title)) {
1493 htmlViews.addElement(BasicHTML.createHTMLView(tabPane,
1494 title));
1495 } else {
1496 htmlViews.addElement(null);
1497 }
1498 }
1499 }
1500 return htmlViews;
1501 }
1502
1503 class MyMouseHandler extends MouseHandler {
1504 public MyMouseHandler() {
1505 super();
1506 }
1507
1508 public void mousePressed(MouseEvent e) {
1509 if (closeIndexStatus == OVER) {
1510 closeIndexStatus = PRESSED;
1511 tabScroller.tabPanel.repaint();
1512 return;
1513 }
1514
1515 if (maxIndexStatus == OVER) {
1516 maxIndexStatus = PRESSED;
1517 tabScroller.tabPanel.repaint();
1518 return;
1519 }
1520
1521 }
1522
1523 public void mouseClicked(MouseEvent e) {
1524 super.mousePressed(e);
1525 if (e.getClickCount() > 1 && overTabIndex != -1) {
1526 ((CloseTabbedPane) tabPane).fireDoubleClickTabEvent(e,
1527 overTabIndex);
1528 }
1529 }
1530
1531 public void mouseReleased(MouseEvent e) {
1532
1533 updateOverTab(e.getX(), e.getY());
1534
1535 if (overTabIndex == -1) {
1536 if (e.isPopupTrigger())
1537 ((CloseTabbedPane) tabPane).firePopupOutsideTabEvent(e);
1538 return;
1539 }
1540
1541 if (isOneActionButtonEnabled() && e.isPopupTrigger()) {
1542 super.mousePressed(e);
1543
1544 closeIndexStatus = INACTIVE; // Prevent undesired action when
1545 maxIndexStatus = INACTIVE; // right-clicking on icons
1546
1547 actionPopupMenu.show(tabScroller.tabPanel, e.getX(), e.getY());
1548 return;
1549 }
1550
1551 if (closeIndexStatus == PRESSED) {
1552 closeIndexStatus = OVER;
1553 tabScroller.tabPanel.repaint();
1554 ((CloseTabbedPane) tabPane).fireCloseTabEvent(e, overTabIndex);
1555 return;
1556 }
1557
1558 if (maxIndexStatus == PRESSED) {
1559 maxIndexStatus = OVER;
1560 tabScroller.tabPanel.repaint();
1561 ((CloseTabbedPane) tabPane).fireMaxTabEvent(e, overTabIndex);
1562 return;
1563 }
1564
1565 }
1566
1567 public void mouseExited(MouseEvent e) {
1568 if (!mousePressed) {
1569 overTabIndex = -1;
1570 tabScroller.tabPanel.repaint();
1571 }
1572 }
1573
1574 }
1575
1576 class MyMouseMotionListener implements MouseMotionListener {
1577
1578 public void mouseMoved(MouseEvent e) {
1579 if (actionPopupMenu.isVisible())
1580 return; // No updates when popup is visible
1581 mousePressed = false;
1582 setTabIcons(e.getX(), e.getY());
1583 }
1584
1585 public void mouseDragged(MouseEvent e) {
1586 if (actionPopupMenu.isVisible())
1587 return; // No updates when popup is visible
1588 mousePressed = true;
1589 setTabIcons(e.getX(), e.getY());
1590 }
1591 }
1592
1593}
Note: See TracBrowser for help on using the repository browser.