1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60:
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78:
79:
82: public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
83: {
84:
91: public class FocusHandler extends FocusAdapter
92: {
93:
98: public void focusGained(FocusEvent e)
99: {
100:
101: }
102:
103:
108: public void focusLost(FocusEvent e)
109: {
110:
111: }
112: }
113:
114:
123: public class MouseHandler extends MouseAdapter
124: {
125:
131: public void mousePressed(MouseEvent e)
132: {
133: int x = e.getX();
134: int y = e.getY();
135: int tabCount = tabPane.getTabCount();
136:
137: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
138: {
139: if (e.getSource() == incrButton)
140: {
141: if (++currentScrollLocation >= tabCount)
142: currentScrollLocation = tabCount - 1;
143:
144: int width = 0;
145: for (int i = currentScrollLocation - 1; i < tabCount; i++)
146: width += rects[i].width;
147: if (width < viewport.getWidth())
148:
149:
150: currentScrollLocation--;
151: else if (! decrButton.isEnabled())
152: decrButton.setEnabled(true);
153: tabPane.revalidate();
154: tabPane.repaint();
155: return;
156: }
157: else if (e.getSource() == decrButton)
158: {
159: if (--currentScrollLocation < 0)
160: currentScrollLocation = 0;
161: if (currentScrollLocation == 0)
162: decrButton.setEnabled(false);
163: else if (! incrButton.isEnabled())
164: incrButton.setEnabled(true);
165: tabPane.revalidate();
166: tabPane.repaint();
167: return;
168: }
169: }
170:
171: int index = tabForCoordinate(tabPane, x, y);
172:
173:
174:
175: if (index != -1 && tabPane.isEnabledAt(index))
176: tabPane.setSelectedIndex(index);
177: tabPane.revalidate();
178: tabPane.repaint();
179: }
180: }
181:
182:
189: public class PropertyChangeHandler implements PropertyChangeListener
190: {
191:
197: public void propertyChange(PropertyChangeEvent e)
198: {
199: if (e.getPropertyName().equals("tabLayoutPolicy"))
200: {
201: layoutManager = createLayoutManager();
202:
203: tabPane.setLayout(layoutManager);
204: }
205: else if (e.getPropertyName().equals("tabPlacement")
206: && tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
207: {
208: incrButton = createIncreaseButton();
209: decrButton = createDecreaseButton();
210: }
211: tabPane.layout();
212: tabPane.repaint();
213: }
214: }
215:
216:
225: public class TabbedPaneLayout implements LayoutManager
226: {
227:
233: public void addLayoutComponent(String name, Component comp)
234: {
235:
236: }
237:
238:
242: public void calculateLayoutInfo()
243: {
244: calculateTabRects(tabPane.getTabPlacement(), tabPane.getTabCount());
245:
246: if (tabPane.getSelectedIndex() != -1)
247: {
248: Component visible = getVisibleComponent();
249: Insets insets = getContentBorderInsets(tabPane.getTabPlacement());
250: if (visible != null)
251: visible.setBounds(contentRect.x + insets.left,
252: contentRect.y + insets.top,
253: contentRect.width - insets.left - insets.right,
254: contentRect.height - insets.top - insets.bottom);
255: }
256: }
257:
258:
266: protected Dimension calculateSize(boolean minimum)
267: {
268: int tabPlacement = tabPane.getTabPlacement();
269: int width = 0;
270: int height = 0;
271:
272: int componentHeight = 0;
273: int componentWidth = 0;
274: Component c;
275: Dimension dims;
276: for (int i = 0; i < tabPane.getTabCount(); i++)
277: {
278: c = tabPane.getComponentAt(i);
279: if (c == null)
280: continue;
281: calcRect = c.getBounds();
282: dims = c.getPreferredSize();
283: if (dims != null)
284: {
285: componentHeight = Math.max(componentHeight, dims.height);
286: componentWidth = Math.max(componentWidth, dims.width);
287: }
288: }
289: Insets insets = tabPane.getInsets();
290:
291: if (tabPlacement == SwingConstants.TOP
292: || tabPlacement == SwingConstants.BOTTOM)
293: {
294: int min = calculateMaxTabWidth(tabPlacement);
295: width = Math.max(min, componentWidth);
296:
297: int tabAreaHeight = preferredTabAreaHeight(tabPlacement, width);
298: height = tabAreaHeight + componentHeight;
299: }
300: else
301: {
302: int min = calculateMaxTabHeight(tabPlacement);
303: height = Math.max(min, componentHeight);
304:
305: int tabAreaWidth = preferredTabAreaWidth(tabPlacement, height);
306: width = tabAreaWidth + componentWidth;
307: }
308:
309: return new Dimension(width, height);
310: }
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
330: protected void calculateTabRects(int tabPlacement, int tabCount)
331: {
332: if (tabCount == 0)
333: return;
334: assureRectsCreated(tabCount);
335:
336: FontMetrics fm = getFontMetrics();
337: SwingUtilities.calculateInnerArea(tabPane, calcRect);
338: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
339: Insets insets = tabPane.getInsets();
340: int max = 0;
341: int runs = 0;
342: int start = getTabRunIndent(tabPlacement, 1);
343: if (tabPlacement == SwingConstants.TOP
344: || tabPlacement == SwingConstants.BOTTOM)
345: {
346: int maxHeight = calculateMaxTabHeight(tabPlacement);
347:
348: calcRect.width -= tabAreaInsets.left + tabAreaInsets.right;
349: max = calcRect.width + tabAreaInsets.left + insets.left;
350: start += tabAreaInsets.left + insets.left;
351: int width = 0;
352: int runWidth = start;
353:
354: for (int i = 0; i < tabCount; i++)
355: {
356: width = calculateTabWidth(tabPlacement, i, fm);
357:
358: if (runWidth + width > max)
359: {
360: runWidth = tabAreaInsets.left + insets.left
361: + getTabRunIndent(tabPlacement, ++runs);
362: rects[i] = new Rectangle(runWidth,
363: insets.top + tabAreaInsets.top,
364: width, maxHeight);
365: runWidth += width;
366: if (runs > tabRuns.length - 1)
367: expandTabRunsArray();
368: tabRuns[runs] = i;
369: }
370: else
371: {
372: rects[i] = new Rectangle(runWidth,
373: insets.top + tabAreaInsets.top,
374: width, maxHeight);
375: runWidth += width;
376: }
377: }
378: runs++;
379: tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right;
380: tabAreaRect.height = runs * maxTabHeight
381: - (runs - 1) * tabRunOverlay
382: + tabAreaInsets.top + tabAreaInsets.bottom;
383: contentRect.width = tabAreaRect.width;
384: contentRect.height = tabPane.getHeight() - insets.top
385: - insets.bottom - tabAreaRect.height;
386: contentRect.x = insets.left;
387: tabAreaRect.x = insets.left;
388: if (tabPlacement == SwingConstants.BOTTOM)
389: {
390: contentRect.y = insets.top;
391: tabAreaRect.y = contentRect.y + contentRect.height;
392: }
393: else
394: {
395: tabAreaRect.y = insets.top;
396: contentRect.y = tabAreaRect.y + tabAreaRect.height;
397: }
398: }
399: else
400: {
401: int maxWidth = calculateMaxTabWidth(tabPlacement);
402: calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom;
403: max = calcRect.height + tabAreaInsets.top + insets.top;
404:
405: int height = 0;
406: start += tabAreaInsets.top + insets.top;
407: int runHeight = start;
408:
409: int fontHeight = fm.getHeight();
410:
411: for (int i = 0; i < tabCount; i++)
412: {
413: height = calculateTabHeight(tabPlacement, i, fontHeight);
414: if (runHeight + height > max)
415: {
416: runHeight = tabAreaInsets.top + insets.top
417: + getTabRunIndent(tabPlacement, ++runs);
418: rects[i] = new Rectangle(insets.left + tabAreaInsets.left,
419: runHeight, maxWidth, height);
420: runHeight += height;
421: if (runs > tabRuns.length - 1)
422: expandTabRunsArray();
423: tabRuns[runs] = i;
424: }
425: else
426: {
427: rects[i] = new Rectangle(insets.left + tabAreaInsets.left,
428: runHeight, maxWidth, height);
429: runHeight += height;
430: }
431: }
432: runs++;
433:
434: tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay
435: + tabAreaInsets.left + tabAreaInsets.right;
436: tabAreaRect.height = tabPane.getHeight() - insets.top
437: - insets.bottom;
438: tabAreaRect.y = insets.top;
439: contentRect.width = tabPane.getWidth() - insets.left - insets.right
440: - tabAreaRect.width;
441: contentRect.height = tabAreaRect.height;
442: contentRect.y = insets.top;
443: if (tabPlacement == SwingConstants.LEFT)
444: {
445: tabAreaRect.x = insets.left;
446: contentRect.x = tabAreaRect.x + tabAreaRect.width;
447: }
448: else
449: {
450: contentRect.x = insets.left;
451: tabAreaRect.x = contentRect.x + contentRect.width;
452: }
453: }
454: runCount = runs;
455:
456: tabRuns[0] = 0;
457: normalizeTabRuns(tabPlacement, tabCount, start, max);
458: selectedRun = getRunForTab(tabCount, tabPane.getSelectedIndex());
459: if (shouldRotateTabRuns(tabPlacement))
460: rotateTabRuns(tabPlacement, selectedRun);
461:
462:
463: for (int i = 0; i < runCount; i++)
464: {
465: int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1;
466: if (first == tabCount)
467: first = 0;
468: int last = lastTabInRun(tabCount, i);
469: if (shouldPadTabRun(tabPlacement, i))
470: padTabRun(tabPlacement, first, last, max);
471:
472:
473: if (tabPlacement == SwingConstants.TOP && i > 0)
474: {
475: for (int j = first; j <= last; j++)
476: rects[j].y += (runCount - i) * maxTabHeight
477: - (runCount - i) * tabRunOverlay;
478: }
479:
480: if (tabPlacement == SwingConstants.BOTTOM)
481: {
482: int height = tabPane.getBounds().height - insets.bottom
483: - tabAreaInsets.bottom;
484: int adjustment;
485: if (i == 0)
486: adjustment = height - maxTabHeight;
487: else
488: adjustment = height - (runCount - i + 1) * maxTabHeight
489: - (runCount - i) * tabRunOverlay;
490:
491: for (int j = first; j <= last; j++)
492: rects[j].y = adjustment;
493: }
494:
495: if (tabPlacement == SwingConstants.LEFT && i > 0)
496: {
497: for (int j = first; j <= last; j++)
498: rects[j].x += (runCount - i) * maxTabWidth
499: - (runCount - i) * tabRunOverlay;
500: }
501:
502: if (tabPlacement == SwingConstants.RIGHT)
503: {
504: int width = tabPane.getBounds().width - insets.right
505: - tabAreaInsets.right;
506: int adjustment;
507: if (i == 0)
508: adjustment = width - maxTabWidth;
509: else
510: adjustment = width - (runCount - i + 1) * maxTabWidth
511: + (runCount - i) * tabRunOverlay;
512:
513: for (int j = first; j <= last; j++)
514: rects[j].x = adjustment;
515: }
516: }
517: padSelectedTab(tabPlacement, tabPane.getSelectedIndex());
518: }
519:
520:
527: public void layoutContainer(Container parent)
528: {
529: calculateLayoutInfo();
530: }
531:
532:
539: public Dimension minimumLayoutSize(Container parent)
540: {
541: return calculateSize(false);
542: }
543:
544:
545:
546:
547:
548:
549:
550:
551:
552:
561: protected void normalizeTabRuns(int tabPlacement, int tabCount, int start,
562: int max)
563: {
564: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
565: if (tabPlacement == SwingUtilities.TOP
566: || tabPlacement == SwingUtilities.BOTTOM)
567: {
568:
569:
570: for (int i = 1; i < runCount; i++)
571: {
572: Rectangle currRun = rects[lastTabInRun(tabCount, i)];
573: Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))];
574: int spaceInCurr = currRun.x + currRun.width;
575: int spaceInNext = nextRun.x + nextRun.width;
576:
577: int diffNow = spaceInCurr - spaceInNext;
578: int diffLater = (spaceInCurr - currRun.width)
579: - (spaceInNext + currRun.width);
580: while (Math.abs(diffLater) < Math.abs(diffNow)
581: && spaceInNext + currRun.width < max)
582: {
583: tabRuns[i]--;
584: spaceInNext += currRun.width;
585: spaceInCurr -= currRun.width;
586: currRun = rects[lastTabInRun(tabCount, i)];
587: diffNow = spaceInCurr - spaceInNext;
588: diffLater = (spaceInCurr - currRun.width)
589: - (spaceInNext + currRun.width);
590: }
591:
592:
593: int first = lastTabInRun(tabCount, i) + 1;
594: int last = lastTabInRun(tabCount, getNextTabRun(i));
595: int currX = tabAreaInsets.left;
596: for (int j = first; j <= last; j++)
597: {
598: rects[j].x = currX;
599: currX += rects[j].width;
600: }
601: }
602: }
603: else
604: {
605: for (int i = 1; i < runCount; i++)
606: {
607: Rectangle currRun = rects[lastTabInRun(tabCount, i)];
608: Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))];
609: int spaceInCurr = currRun.y + currRun.height;
610: int spaceInNext = nextRun.y + nextRun.height;
611:
612: int diffNow = spaceInCurr - spaceInNext;
613: int diffLater = (spaceInCurr - currRun.height)
614: - (spaceInNext + currRun.height);
615: while (Math.abs(diffLater) < Math.abs(diffNow)
616: && spaceInNext + currRun.height < max)
617: {
618: tabRuns[i]--;
619: spaceInNext += currRun.height;
620: spaceInCurr -= currRun.height;
621: currRun = rects[lastTabInRun(tabCount, i)];
622: diffNow = spaceInCurr - spaceInNext;
623: diffLater = (spaceInCurr - currRun.height)
624: - (spaceInNext + currRun.height);
625: }
626:
627: int first = lastTabInRun(tabCount, i) + 1;
628: int last = lastTabInRun(tabCount, getNextTabRun(i));
629: int currY = tabAreaInsets.top;
630: for (int j = first; j <= last; j++)
631: {
632: rects[j].y = currY;
633: currY += rects[j].height;
634: }
635: }
636: }
637: }
638:
639:
646: protected void padSelectedTab(int tabPlacement, int selectedIndex)
647: {
648: Insets insets = getSelectedTabPadInsets(tabPlacement);
649: rects[selectedIndex].x -= insets.left;
650: rects[selectedIndex].y -= insets.top;
651: rects[selectedIndex].width += insets.left + insets.right;
652: rects[selectedIndex].height += insets.top + insets.bottom;
653: }
654:
655:
656:
657:
658:
659:
660:
661:
671: protected void padTabRun(int tabPlacement, int start, int end, int max)
672: {
673: if (tabPlacement == SwingConstants.TOP
674: || tabPlacement == SwingConstants.BOTTOM)
675: {
676: int runWidth = rects[end].x + rects[end].width;
677: int spaceRemaining = max - runWidth;
678: int numTabs = end - start + 1;
679:
680:
681: int spaceAllocated = spaceRemaining / numTabs;
682: int currX = rects[start].x;
683: for (int i = start; i <= end; i++)
684: {
685: rects[i].x = currX;
686: rects[i].width += spaceAllocated;
687: currX += rects[i].width;
688:
689:
690:
691:
692: if (i == end && rects[i].x + rects[i].width != max)
693: rects[i].width = max - rects[i].x;
694: }
695: }
696: else
697: {
698: int runHeight = rects[end].y + rects[end].height;
699: int spaceRemaining = max - runHeight;
700: int numTabs = end - start + 1;
701:
702: int spaceAllocated = spaceRemaining / numTabs;
703: int currY = rects[start].y;
704: for (int i = start; i <= end; i++)
705: {
706: rects[i].y = currY;
707: rects[i].height += spaceAllocated;
708: currY += rects[i].height;
709: if (i == end && rects[i].y + rects[i].height != max)
710: rects[i].height = max - rects[i].y;
711: }
712: }
713: }
714:
715:
722: public Dimension preferredLayoutSize(Container parent)
723: {
724: return calculateSize(false);
725: }
726:
727:
736: protected int preferredTabAreaHeight(int tabPlacement, int width)
737: {
738: if (tabPane.getTabCount() == 0)
739: return calculateTabAreaHeight(tabPlacement, 0, 0);
740:
741: int runs = 0;
742: int runWidth = 0;
743: int tabWidth = 0;
744:
745: FontMetrics fm = getFontMetrics();
746:
747: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
748: Insets insets = tabPane.getInsets();
749:
750:
751: width -= tabAreaInsets.left + tabAreaInsets.right + insets.left
752: + insets.right;
753:
754:
755:
756:
757:
758:
759: for (int i = 0; i < tabPane.getTabCount(); i++)
760: {
761: tabWidth = calculateTabWidth(tabPlacement, i, fm);
762: if (runWidth + tabWidth > width)
763: {
764: runWidth = tabWidth;
765: runs++;
766: }
767: else
768: runWidth += tabWidth;
769: }
770: runs++;
771:
772: int maxTabHeight = calculateMaxTabHeight(tabPlacement);
773: int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs,
774: maxTabHeight);
775: return tabAreaHeight;
776: }
777:
778:
787: protected int preferredTabAreaWidth(int tabPlacement, int height)
788: {
789: if (tabPane.getTabCount() == 0)
790: return calculateTabAreaHeight(tabPlacement, 0, 0);
791:
792: int runs = 0;
793: int runHeight = 0;
794: int tabHeight = 0;
795:
796: FontMetrics fm = getFontMetrics();
797:
798: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
799: Insets insets = tabPane.getInsets();
800:
801: height -= tabAreaInsets.top + tabAreaInsets.bottom + insets.top
802: + insets.bottom;
803: int fontHeight = fm.getHeight();
804:
805: for (int i = 0; i < tabPane.getTabCount(); i++)
806: {
807: tabHeight = calculateTabHeight(tabPlacement, i, fontHeight);
808: if (runHeight + tabHeight > height)
809: {
810: runHeight = tabHeight;
811: runs++;
812: }
813: else
814: runHeight += tabHeight;
815: }
816: runs++;
817:
818: int maxTabWidth = calculateMaxTabWidth(tabPlacement);
819: int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth);
820: return tabAreaWidth;
821: }
822:
823:
831: protected void rotateTabRuns(int tabPlacement, int selectedRun)
832: {
833: if (runCount == 1 || selectedRun == 1 || selectedRun == -1)
834: return;
835: int[] newTabRuns = new int[tabRuns.length];
836: int currentRun = selectedRun;
837: int i = 1;
838: do
839: {
840: newTabRuns[i] = tabRuns[currentRun];
841: currentRun = getNextTabRun(currentRun);
842: i++;
843: }
844: while (i < runCount);
845: if (runCount > 1)
846: newTabRuns[0] = tabRuns[currentRun];
847:
848: tabRuns = newTabRuns;
849: BasicTabbedPaneUI.this.selectedRun = 1;
850: }
851:
852:
858: public void removeLayoutComponent(Component comp)
859: {
860:
861: }
862: }
863:
864:
868: private class TabbedPaneScrollLayout extends TabbedPaneLayout
869: {
870:
877: public Dimension preferredLayoutSize(Container parent)
878: {
879: return super.calculateSize(true);
880: }
881:
882:
889: public Dimension minimumLayoutSize(Container parent)
890: {
891: return super.calculateSize(true);
892: }
893:
894:
902: protected int preferredTabAreaHeight(int tabPlacement, int width)
903: {
904: if (tabPane.getTabCount() == 0)
905: return calculateTabAreaHeight(tabPlacement, 0, 0);
906:
907: int runs = 1;
908:
909: int maxTabHeight = calculateMaxTabHeight(tabPlacement);
910: int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs,
911: maxTabHeight);
912: return tabAreaHeight;
913: }
914:
915:
923: protected int preferredTabAreaWidth(int tabPlacement, int height)
924: {
925: if (tabPane.getTabCount() == 0)
926: return calculateTabAreaHeight(tabPlacement, 0, 0);
927:
928: int runs = 1;
929:
930: int maxTabWidth = calculateMaxTabWidth(tabPlacement);
931: int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth);
932: return tabAreaWidth;
933: }
934:
935:
944: protected void calculateTabRects(int tabPlacement, int tabCount)
945: {
946: if (tabCount == 0)
947: return;
948: assureRectsCreated(tabCount);
949:
950: FontMetrics fm = getFontMetrics();
951: SwingUtilities.calculateInnerArea(tabPane, calcRect);
952: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
953: Insets insets = tabPane.getInsets();
954: int max = 0;
955: int runs = 1;
956: int start = 0;
957: int top = 0;
958: if (tabPlacement == SwingConstants.TOP
959: || tabPlacement == SwingConstants.BOTTOM)
960: {
961: int maxHeight = calculateMaxTabHeight(tabPlacement);
962: calcRect.width -= tabAreaInsets.left + tabAreaInsets.right;
963: max = calcRect.width + tabAreaInsets.left + insets.left;
964: start = tabAreaInsets.left + insets.left;
965: int width = 0;
966: int runWidth = start;
967: top = insets.top + tabAreaInsets.top;
968: for (int i = 0; i < tabCount; i++)
969: {
970: width = calculateTabWidth(tabPlacement, i, fm);
971:
972: rects[i] = new Rectangle(runWidth, top, width, maxHeight);
973: runWidth += width;
974: }
975: tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right;
976: tabAreaRect.height = runs * maxTabHeight
977: - (runs - 1) * tabRunOverlay
978: + tabAreaInsets.top + tabAreaInsets.bottom;
979: contentRect.width = tabAreaRect.width;
980: contentRect.height = tabPane.getHeight() - insets.top
981: - insets.bottom - tabAreaRect.height;
982: contentRect.x = insets.left;
983: tabAreaRect.x = insets.left;
984: if (tabPlacement == SwingConstants.BOTTOM)
985: {
986: contentRect.y = insets.top;
987: tabAreaRect.y = contentRect.y + contentRect.height;
988: }
989: else
990: {
991: tabAreaRect.y = insets.top;
992: contentRect.y = tabAreaRect.y + tabAreaRect.height;
993: }
994: }
995: else
996: {
997: int maxWidth = calculateMaxTabWidth(tabPlacement);
998:
999: calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom;
1000: max = calcRect.height + tabAreaInsets.top;
1001: int height = 0;
1002: start = tabAreaInsets.top + insets.top;
1003: int runHeight = start;
1004: int fontHeight = fm.getHeight();
1005: top = insets.left + tabAreaInsets.left;
1006: for (int i = 0; i < tabCount; i++)
1007: {
1008: height = calculateTabHeight(tabPlacement, i, fontHeight);
1009: rects[i] = new Rectangle(top, runHeight, maxWidth, height);
1010: runHeight += height;
1011: }
1012: tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay
1013: + tabAreaInsets.left + tabAreaInsets.right;
1014: tabAreaRect.height = tabPane.getHeight() - insets.top
1015: - insets.bottom;
1016: tabAreaRect.y = insets.top;
1017: contentRect.width = tabPane.getWidth() - insets.left - insets.right
1018: - tabAreaRect.width;
1019: contentRect.height = tabAreaRect.height;
1020: contentRect.y = insets.top;
1021: if (tabPlacement == SwingConstants.LEFT)
1022: {
1023: tabAreaRect.x = insets.left;
1024: contentRect.x = tabAreaRect.x + tabAreaRect.width;
1025: }
1026: else
1027: {
1028: contentRect.x = insets.left;
1029: tabAreaRect.x = contentRect.x + contentRect.width;
1030: }
1031: }
1032: runCount = runs;
1033:
1034: padSelectedTab(tabPlacement, tabPane.getSelectedIndex());
1035: }
1036:
1037:
1044: public void layoutContainer(Container pane)
1045: {
1046: super.layoutContainer(pane);
1047: int tabCount = tabPane.getTabCount();
1048: Point p = null;
1049: if (tabCount == 0)
1050: return;
1051: int tabPlacement = tabPane.getTabPlacement();
1052: incrButton.hide();
1053: decrButton.hide();
1054: if (tabPlacement == SwingConstants.TOP
1055: || tabPlacement == SwingConstants.BOTTOM)
1056: {
1057: if (tabAreaRect.x + tabAreaRect.width < rects[tabCount - 1].x
1058: + rects[tabCount - 1].width)
1059: {
1060: Dimension incrDims = incrButton.getPreferredSize();
1061: Dimension decrDims = decrButton.getPreferredSize();
1062:
1063: decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
1064: - incrDims.width - decrDims.width,
1065: tabAreaRect.y, decrDims.width,
1066: tabAreaRect.height);
1067: incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
1068: - incrDims.width, tabAreaRect.y,
1069: decrDims.width, tabAreaRect.height);
1070:
1071: tabAreaRect.width -= decrDims.width + incrDims.width;
1072: incrButton.show();
1073: decrButton.show();
1074: }
1075: }
1076:
1077: if (tabPlacement == SwingConstants.LEFT
1078: || tabPlacement == SwingConstants.RIGHT)
1079: {
1080: if (tabAreaRect.y + tabAreaRect.height < rects[tabCount - 1].y
1081: + rects[tabCount - 1].height)
1082: {
1083: Dimension incrDims = incrButton.getPreferredSize();
1084: Dimension decrDims = decrButton.getPreferredSize();
1085:
1086: decrButton.setBounds(tabAreaRect.x,
1087: tabAreaRect.y + tabAreaRect.height
1088: - incrDims.height - decrDims.height,
1089: tabAreaRect.width, decrDims.height);
1090: incrButton.setBounds(tabAreaRect.x,
1091: tabAreaRect.y + tabAreaRect.height
1092: - incrDims.height, tabAreaRect.width,
1093: incrDims.height);
1094:
1095: tabAreaRect.height -= decrDims.height + incrDims.height;
1096: incrButton.show();
1097: decrButton.show();
1098: }
1099: }
1100: viewport.setBounds(tabAreaRect.x, tabAreaRect.y, tabAreaRect.width,
1101: tabAreaRect.height);
1102: int tabC = tabPane.getTabCount() - 1;
1103: if (tabCount > 0)
1104: {
1105: int w = Math.max(rects[tabC].width + rects[tabC].x, tabAreaRect.width);
1106: int h = Math.max(rects[tabC].height, tabAreaRect.height);
1107: p = findPointForIndex(currentScrollLocation);
1108:
1109:
1110:
1111: panel.setSize(w + p.x, h + p.y);
1112: }
1113: viewport.setViewPosition(p);
1114: viewport.repaint();
1115: }
1116: }
1117:
1118:
1125: public class TabSelectionHandler implements ChangeListener
1126: {
1127:
1133: public void stateChanged(ChangeEvent e)
1134: {
1135: selectedRun = getRunForTab(tabPane.getTabCount(),
1136: tabPane.getSelectedIndex());
1137: tabPane.revalidate();
1138: tabPane.repaint();
1139: }
1140: }
1141:
1142:
1147: private class ScrollingPanel extends JPanel
1148: {
1149:
1152: private class ScrollingPanelUI extends BasicPanelUI
1153: {
1154:
1161: public void paint(Graphics g, JComponent c)
1162: {
1163: paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
1164: }
1165: }
1166:
1167:
1171: public void updateUI()
1172: {
1173: setUI((PanelUI) new ScrollingPanelUI());
1174: }
1175: }
1176:
1177:
1183: private class ScrollingViewport extends JViewport implements UIResource
1184: {
1185: }
1186:
1187:
1191: private class ScrollingButton extends BasicArrowButton implements UIResource
1192: {
1193:
1198: public ScrollingButton(int dir)
1199: {
1200: super(dir);
1201: }
1202: }
1203:
1204:
1206: transient ScrollingButton incrButton;
1207:
1208:
1210: transient ScrollingButton decrButton;
1211:
1212:
1214: transient ScrollingViewport viewport;
1215:
1216:
1218: transient ScrollingPanel panel;
1219:
1220:
1222: transient int currentScrollLocation;
1223:
1224:
1225: protected Rectangle calcRect;
1226:
1227:
1228: protected Rectangle[] rects;
1229:
1230:
1231: protected Insets contentBorderInsets;
1232:
1233:
1234: protected Insets selectedTabPadInsets;
1235:
1236:
1237: protected Insets tabAreaInsets;
1238:
1239:
1240: protected Insets tabInsets;
1241:
1242:
1246: protected Color darkShadow;
1247:
1248:
1249: protected Color focus;
1250:
1251:
1252: protected Color highlight;
1253:
1254:
1255: protected Color lightHighlight;
1256:
1257:
1258: protected Color shadow;
1259:
1260:
1261: protected int maxTabHeight;
1262:
1263:
1264: protected int maxTabWidth;
1265:
1266:
1267: protected int runCount;
1268:
1269:
1270: protected int selectedRun;
1271:
1272:
1273: protected int tabRunOverlay;
1274:
1275:
1276: protected int textIconGap;
1277:
1278:
1279:
1280:
1281:
1282:
1283:
1284:
1285:
1286:
1287:
1288: protected int[] tabRuns;
1289:
1290:
1295: protected KeyStroke downKey;
1296:
1297:
1302: protected KeyStroke leftKey;
1303:
1304:
1309: protected KeyStroke rightKey;
1310:
1311:
1316: protected KeyStroke upKey;
1317:
1318:
1319: protected FocusListener focusListener;
1320:
1321:
1322: protected MouseListener mouseListener;
1323:
1324:
1325: protected PropertyChangeListener propertyChangeListener;
1326:
1327:
1328: protected ChangeListener tabChangeListener;
1329:
1330:
1331: protected JTabbedPane tabPane;
1332:
1333:
1335: transient LayoutManager layoutManager;
1336:
1337:
1339: transient Rectangle tabAreaRect;
1340:
1341:
1343: transient Rectangle contentRect;
1344:
1345:
1348: public BasicTabbedPaneUI()
1349: {
1350: super();
1351: }
1352:
1353:
1360: ScrollingButton createIncreaseButton()
1361: {
1362: if (incrButton == null)
1363: incrButton = new ScrollingButton(SwingConstants.NORTH);
1364: if (tabPane.getTabPlacement() == SwingConstants.TOP
1365: || tabPane.getTabPlacement() == SwingConstants.BOTTOM)
1366: incrButton.setDirection(SwingConstants.EAST);
1367: else
1368: incrButton.setDirection(SwingConstants.SOUTH);
1369: return incrButton;
1370: }
1371:
1372:
1379: ScrollingButton createDecreaseButton()
1380: {
1381: if (decrButton == null)
1382: decrButton = new ScrollingButton(SwingConstants.SOUTH);
1383: if (tabPane.getTabPlacement() == SwingConstants.TOP
1384: || tabPane.getTabPlacement() == SwingConstants.BOTTOM)
1385: decrButton.setDirection(SwingConstants.WEST);
1386: else
1387: decrButton.setDirection(SwingConstants.NORTH);
1388: return decrButton;
1389: }
1390:
1391:
1400: Point findPointForIndex(int index)
1401: {
1402: int tabPlacement = tabPane.getTabPlacement();
1403: int selectedIndex = tabPane.getSelectedIndex();
1404: Insets insets = getSelectedTabPadInsets(tabPlacement);
1405: int w = 0;
1406: int h = 0;
1407:
1408: if (tabPlacement == TOP || tabPlacement == BOTTOM)
1409: {
1410: if (index > 0)
1411: {
1412: w += rects[index - 1].x + rects[index - 1].width;
1413: if (index > selectedIndex)
1414: w -= insets.left + insets.right;
1415: }
1416: }
1417:
1418: else
1419: {
1420: if (index > 0)
1421: {
1422: h += rects[index - 1].y + rects[index - 1].height;
1423: if (index > selectedIndex)
1424: h -= insets.top + insets.bottom;
1425: }
1426: }
1427:
1428: Point p = new Point(w, h);
1429: return p;
1430: }
1431:
1432:
1439: public static ComponentUI createUI(JComponent c)
1440: {
1441: return new BasicTabbedPaneUI();
1442: }
1443:
1444:
1449: public void installUI(JComponent c)
1450: {
1451: super.installUI(c);
1452: if (c instanceof JTabbedPane)
1453: {
1454: tabPane = (JTabbedPane) c;
1455:
1456: installComponents();
1457: installDefaults();
1458: installListeners();
1459: installKeyboardActions();
1460:
1461: layoutManager = createLayoutManager();
1462: tabPane.setLayout(layoutManager);
1463: tabPane.layout();
1464: }
1465: }
1466:
1467:
1472: public void uninstallUI(JComponent c)
1473: {
1474: layoutManager = null;
1475:
1476: uninstallKeyboardActions();
1477: uninstallListeners();
1478: uninstallDefaults();
1479: uninstallComponents();
1480:
1481: tabPane = null;
1482: }
1483:
1484:
1492: protected LayoutManager createLayoutManager()
1493: {
1494: if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
1495: return new TabbedPaneLayout();
1496: else
1497: {
1498: incrButton = createIncreaseButton();
1499: decrButton = createDecreaseButton();
1500: viewport = new ScrollingViewport();
1501: viewport.setLayout(null);
1502: panel = new ScrollingPanel();
1503: viewport.setView(panel);
1504: tabPane.add(incrButton);
1505: tabPane.add(decrButton);
1506: tabPane.add(viewport);
1507: currentScrollLocation = 0;
1508: decrButton.setEnabled(false);
1509: panel.addMouseListener(mouseListener);
1510: incrButton.addMouseListener(mouseListener);
1511: decrButton.addMouseListener(mouseListener);
1512: viewport.setBackground(Color.LIGHT_GRAY);
1513:
1514: return new TabbedPaneScrollLayout();
1515: }
1516: }
1517:
1518:
1521: protected void installComponents()
1522: {
1523:
1524: }
1525:
1526:
1529: protected void uninstallComponents()
1530: {
1531:
1532: }
1533:
1534:
1537: protected void installDefaults()
1538: {
1539: UIDefaults defaults = UIManager.getLookAndFeelDefaults();
1540:
1541: tabPane.setFont(defaults.getFont("TabbedPane.font"));
1542: tabPane.setForeground(defaults.getColor("TabbedPane.foreground"));
1543: tabPane.setBackground(defaults.getColor("TabbedPane.background"));
1544: tabPane.setOpaque(false);
1545:
1546: highlight = defaults.getColor("TabbedPane.highlight");
1547: lightHighlight = defaults.getColor("TabbedPane.lightHighlight");
1548:
1549: shadow = defaults.getColor("TabbedPane.shadow");
1550: darkShadow = defaults.getColor("TabbedPane.darkShadow");
1551:
1552: focus = defaults.getColor("TabbedPane.focus");
1553:
1554: textIconGap = defaults.getInt("TabbedPane.textIconGap");
1555: tabRunOverlay = defaults.getInt("TabbedPane.tabRunOverlay");
1556:
1557: tabInsets = defaults.getInsets("TabbedPane.tabbedPaneTabInsets");
1558: selectedTabPadInsets = defaults.getInsets("TabbedPane.tabbedPaneTabPadInsets");
1559: tabAreaInsets = defaults.getInsets("TabbedPane.tabbedPaneTabAreaInsets");
1560: contentBorderInsets = defaults.getInsets("TabbedPane.tabbedPaneContentBorderInsets");
1561:
1562: calcRect = new Rectangle();
1563: tabRuns = new int[10];
1564: tabAreaRect = new Rectangle();
1565: contentRect = new Rectangle();
1566: }
1567:
1568:
1571: protected void uninstallDefaults()
1572: {
1573: calcRect = null;
1574: tabAreaRect = null;
1575: contentRect = null;
1576: tabRuns = null;
1577:
1578: contentBorderInsets = null;
1579: tabAreaInsets = null;
1580: selectedTabPadInsets = null;
1581: tabInsets = null;
1582:
1583: focus = null;
1584: darkShadow = null;
1585: shadow = null;
1586: lightHighlight = null;
1587: highlight = null;
1588:
1589: tabPane.setBackground(null);
1590: tabPane.setForeground(null);
1591: tabPane.setFont(null);
1592: }
1593:
1594:
1597: protected void installListeners()
1598: {
1599: mouseListener = createMouseListener();
1600: tabChangeListener = createChangeListener();
1601: propertyChangeListener = createPropertyChangeListener();
1602: focusListener = createFocusListener();
1603:
1604: tabPane.addMouseListener(mouseListener);
1605: tabPane.addChangeListener(tabChangeListener);
1606: tabPane.addPropertyChangeListener(propertyChangeListener);
1607: tabPane.addFocusListener(focusListener);
1608: }
1609:
1610:
1613: protected void uninstallListeners()
1614: {
1615: tabPane.removeFocusListener(focusListener);
1616: tabPane.removePropertyChangeListener(propertyChangeListener);
1617: tabPane.removeChangeListener(tabChangeListener);
1618: tabPane.removeMouseListener(mouseListener);
1619:
1620: focusListener = null;
1621: propertyChangeListener = null;
1622: tabChangeListener = null;
1623: mouseListener = null;
1624: }
1625:
1626:
1631: protected MouseListener createMouseListener()
1632: {
1633: return new MouseHandler();
1634: }
1635:
1636:
1641: protected FocusListener createFocusListener()
1642: {
1643: return new FocusHandler();
1644: }
1645:
1646:
1651: protected ChangeListener createChangeListener()
1652: {
1653: return new TabSelectionHandler();
1654: }
1655:
1656:
1661: protected PropertyChangeListener createPropertyChangeListener()
1662: {
1663: return new PropertyChangeHandler();
1664: }
1665:
1666:
1669: protected void installKeyboardActions()
1670: {
1671:
1672: }
1673:
1674:
1677: protected void uninstallKeyboardActions()
1678: {
1679:
1680: }
1681:
1682:
1689: public Dimension getMinimumSize(JComponent c)
1690: {
1691: return layoutManager.minimumLayoutSize(tabPane);
1692: }
1693:
1694:
1701: public Dimension getMaximumSize(JComponent c)
1702: {
1703: return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
1704: }
1705:
1706:
1712: public void paint(Graphics g, JComponent c)
1713: {
1714: if (tabPane.getTabCount() == 0)
1715: return;
1716: if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
1717: paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
1718: paintContentBorder(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
1719: }
1720:
1721:
1729: protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex)
1730: {
1731: Rectangle ir = new Rectangle();
1732: Rectangle tr = new Rectangle();
1733:
1734: boolean isScroll = tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT;
1735:
1736:
1737:
1738: int tabCount = tabPane.getTabCount();
1739: int currRun = 1;
1740: if (tabCount < 1)
1741: return;
1742:
1743: if (runCount > 1)
1744: currRun = 0;
1745: for (int i = 0; i < runCount; i++)
1746: {
1747: int first = lastTabInRun(tabCount, getPreviousTabRun(currRun)) + 1;
1748: if (isScroll)
1749: first = currentScrollLocation;
1750: else if (first == tabCount)
1751: first = 0;
1752: int last = lastTabInRun(tabCount, currRun);
1753: if (isScroll)
1754: {
1755: for (int k = first; k < tabCount; k++)
1756: {
1757: if (rects[k].x + rects[k].width - rects[first].x > viewport
1758: .getWidth())
1759: {
1760: last = k;
1761: break;
1762: }
1763: }
1764: }
1765:
1766: for (int j = first; j <= last; j++)
1767: {
1768: if (j != selectedIndex || isScroll)
1769: paintTab(g, tabPlacement, rects, j, ir, tr);
1770: }
1771: currRun = getPreviousTabRun(currRun);
1772: }
1773: if (! isScroll)
1774: paintTab(g, tabPlacement, rects, selectedIndex, ir, tr);
1775: }
1776:
1777:
1788: protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects,
1789: int tabIndex, Rectangle iconRect, Rectangle textRect)
1790: {
1791: FontMetrics fm = getFontMetrics();
1792: Icon icon = getIconForTab(tabIndex);
1793: String title = tabPane.getTitleAt(tabIndex);
1794: boolean isSelected = tabIndex == tabPane.getSelectedIndex();
1795: calcRect = getTabBounds(tabPane, tabIndex);
1796:
1797: int x = calcRect.x;
1798: int y = calcRect.y;
1799: int w = calcRect.width;
1800: int h = calcRect.height;
1801: if (getRunForTab(tabPane.getTabCount(), tabIndex) == 1)
1802: {
1803: Insets insets = getTabAreaInsets(tabPlacement);
1804: switch (tabPlacement)
1805: {
1806: case TOP:
1807: h += insets.bottom;
1808: break;
1809: case LEFT:
1810: w += insets.right;
1811: break;
1812: case BOTTOM:
1813: y -= insets.top;
1814: h += insets.top;
1815: break;
1816: case RIGHT:
1817: x -= insets.left;
1818: w += insets.left;
1819: break;
1820: }
1821: }
1822:
1823: layoutLabel(tabPlacement, fm, tabIndex, title, icon, calcRect, iconRect,
1824: textRect, isSelected);
1825: paintTabBackground(g, tabPlacement, tabIndex, x, y, w, h, isSelected);
1826: paintTabBorder(g, tabPlacement, tabIndex, x, y, w, h, isSelected);
1827:
1828:
1829: if (icon != null)
1830: paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
1831: if (title != null && ! title.equals(""))
1832: paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title,
1833: textRect, isSelected);
1834: }
1835:
1836:
1850: protected void layoutLabel(int tabPlacement, FontMetrics metrics,
1851: int tabIndex, String title, Icon icon,
1852: Rectangle tabRect, Rectangle iconRect,
1853: Rectangle textRect, boolean isSelected)
1854: {
1855: SwingUtilities.layoutCompoundLabel(metrics, title, icon,
1856: SwingConstants.CENTER,
1857: SwingConstants.CENTER,
1858: SwingConstants.CENTER,
1859: SwingConstants.CENTER, tabRect,
1860: iconRect, textRect, textIconGap);
1861:
1862: int shiftX = getTabLabelShiftX(tabPlacement, tabIndex, isSelected);
1863: int shiftY = getTabLabelShiftY(tabPlacement, tabIndex, isSelected);
1864:
1865: iconRect.x += shiftX;
1866: iconRect.y += shiftY;
1867:
1868: textRect.x += shiftX;
1869: textRect.y += shiftY;
1870: }
1871:
1872:
1882: protected void paintIcon(Graphics g, int tabPlacement, int tabIndex,
1883: Icon icon, Rectangle iconRect, boolean isSelected)
1884: {
1885: icon.paintIcon(tabPane, g, iconRect.x, iconRect.y);
1886: }
1887:
1888:
1900: protected void paintText(Graphics g, int tabPlacement, Font font,
1901: FontMetrics metrics, int tabIndex, String title,
1902: Rectangle textRect, boolean isSelected)
1903: {
1904: View textView = getTextViewForTab(tabIndex);
1905: if (textView != null)
1906: {
1907: textView.paint(g, textRect);
1908: return;
1909: }
1910:
1911: Color fg = tabPane.getForegroundAt(tabIndex);
1912: if (fg == null)
1913: fg = tabPane.getForeground();
1914: Color bg = tabPane.getBackgroundAt(tabIndex);
1915: if (bg == null)
1916: bg = tabPane.getBackground();
1917:
1918: Color saved_color = g.getColor();
1919: Font f = g.getFont();
1920: g.setFont(font);
1921:
1922: if (tabPane.isEnabledAt(tabIndex))
1923: {
1924: g.setColor(fg);
1925:
1926: int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
1927:
1928: if (mnemIndex != -1)
1929: BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
1930: textRect.x,
1931: textRect.y
1932: + metrics.getAscent());
1933: else
1934: g.drawString(title, textRect.x, textRect.y + metrics.getAscent());
1935: }
1936: else
1937: {
1938: g.setColor(bg.brighter());
1939:
1940: int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
1941:
1942: if (mnemIndex != -1)
1943: BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
1944: textRect.x, textRect.y);
1945: else
1946: g.drawString(title, textRect.x, textRect.y);
1947:
1948: g.setColor(bg.darker());
1949: if (mnemIndex != -1)
1950: BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
1951: textRect.x + 1,
1952: textRect.y + 1);
1953: else
1954: g.drawString(title, textRect.x + 1, textRect.y + 1);
1955: }
1956:
1957: g.setColor(saved_color);
1958: g.setFont(f);
1959: }
1960:
1961:
1971: protected int getTabLabelShiftX(int tabPlacement, int tabIndex,
1972: boolean isSelected)
1973: {
1974:
1975: return 0;
1976: }
1977:
1978:
1988: protected int getTabLabelShiftY(int tabPlacement, int tabIndex,
1989: boolean isSelected)
1990: {
1991:
1992: return 0;
1993: }
1994:
1995:
2006: protected void paintFocusIndicator(Graphics g, int tabPlacement,
2007: Rectangle[] rects, int tabIndex,
2008: Rectangle iconRect, Rectangle textRect,
2009: boolean isSelected)
2010: {
2011: Color saved = g.getColor();
2012: calcRect = iconRect.union(textRect);
2013:
2014: g.setColor(focus);
2015:
2016: g.drawRect(calcRect.x, calcRect.y, calcRect.width, calcRect.height);
2017:
2018: g.setColor(saved);
2019: }
2020:
2021:
2033: protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex,
2034: int x, int y, int w, int h, boolean isSelected)
2035: {
2036: Color saved = g.getColor();
2037:
2038: if (! isSelected || tabPlacement != SwingConstants.TOP)
2039: {
2040: g.setColor(shadow);
2041: g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
2042: g.setColor(darkShadow);
2043: g.drawLine(x, y + h, x + w, y + h);
2044: }
2045:
2046: if (! isSelected || tabPlacement != SwingConstants.LEFT)
2047: {
2048: g.setColor(darkShadow);
2049: g.drawLine(x + w, y, x + w, y + h);
2050: g.setColor(shadow);
2051: g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
2052: }
2053:
2054: if (! isSelected || tabPlacement != SwingConstants.RIGHT)
2055: {
2056: g.setColor(lightHighlight);
2057: g.drawLine(x, y, x, y + h);
2058: }
2059:
2060: if (! isSelected || tabPlacement != SwingConstants.BOTTOM)
2061: {
2062: g.setColor(lightHighlight);
2063: g.drawLine(x, y, x + w, y);
2064: }
2065:
2066: g.setColor(saved);
2067: }
2068:
2069:
2081: protected void paintTabBackground(Graphics g, int tabPlacement,
2082: int tabIndex, int x, int y, int w, int h,
2083: boolean isSelected)
2084: {
2085: Color saved = g.getColor();
2086: if (isSelected)
2087: g.setColor(Color.LIGHT_GRAY);
2088: else
2089: {
2090: Color bg = tabPane.getBackgroundAt(tabIndex);
2091: if (bg == null)
2092: bg = Color.GRAY;
2093: g.setColor(bg);
2094: }
2095:
2096: g.fillRect(x, y, w, h);
2097:
2098: g.setColor(saved);
2099: }
2100:
2101:
2108: protected void paintContentBorder(Graphics g, int tabPlacement,
2109: int selectedIndex)
2110: {
2111: Insets insets = getContentBorderInsets(tabPlacement);
2112: int x = contentRect.x;
2113: int y = contentRect.y;
2114: int w = contentRect.width;
2115: int h = contentRect.height;
2116: paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2117: paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2118: paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2119: paintContentBorderRightEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2120: }
2121:
2122:
2133: protected void paintContentBorderTopEdge(Graphics g, int tabPlacement,
2134: int selectedIndex, int x, int y,
2135: int w, int h)
2136: {
2137: Color saved = g.getColor();
2138: g.setColor(lightHighlight);
2139:
2140: int startgap = rects[selectedIndex].x;
2141: int endgap = rects[selectedIndex].x + rects[selectedIndex].width;
2142:
2143: int diff = 0;
2144:
2145: if (tabPlacement == SwingConstants.TOP)
2146: {
2147: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2148: {
2149: Point p = findPointForIndex(currentScrollLocation);
2150: diff = p.x;
2151: }
2152:
2153: g.drawLine(x, y, startgap - diff, y);
2154: g.drawLine(endgap - diff, y, x + w, y);
2155: }
2156: else
2157: g.drawLine(x, y, x + w, y);
2158:
2159: g.setColor(saved);
2160: }
2161:
2162:
2173: protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement,
2174: int selectedIndex, int x, int y,
2175: int w, int h)
2176: {
2177: Color saved = g.getColor();
2178: g.setColor(lightHighlight);
2179:
2180: int startgap = rects[selectedIndex].y;
2181: int endgap = rects[selectedIndex].y + rects[selectedIndex].height;
2182:
2183: int diff = 0;
2184:
2185: if (tabPlacement == SwingConstants.LEFT)
2186: {
2187: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2188: {
2189: Point p = findPointForIndex(currentScrollLocation);
2190: diff = p.y;
2191: }
2192:
2193: g.drawLine(x, y, x, startgap - diff);
2194: g.drawLine(x, endgap - diff, x, y + h);
2195: }
2196: else
2197: g.drawLine(x, y, x, y + h);
2198:
2199: g.setColor(saved);
2200: }
2201:
2202:
2213: protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement,
2214: int selectedIndex, int x, int y,
2215: int w, int h)
2216: {
2217: Color saved = g.getColor();
2218:
2219: int startgap = rects[selectedIndex].x;
2220: int endgap = rects[selectedIndex].x + rects[selectedIndex].width;
2221:
2222: int diff = 0;
2223:
2224: if (tabPlacement == SwingConstants.BOTTOM)
2225: {
2226: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2227: {
2228: Point p = findPointForIndex(currentScrollLocation);
2229: diff = p.x;
2230: }
2231:
2232: g.setColor(shadow);
2233: g.drawLine(x + 1, y + h - 1, startgap - diff, y + h - 1);
2234: g.drawLine(endgap - diff, y + h - 1, x + w - 1, y + h - 1);
2235:
2236: g.setColor(darkShadow);
2237: g.drawLine(x, y + h, startgap - diff, y + h);
2238: g.drawLine(endgap - diff, y + h, x + w, y + h);
2239: }
2240: else
2241: {
2242: g.setColor(shadow);
2243: g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
2244: g.setColor(darkShadow);
2245: g.drawLine(x, y + h, x + w, y + h);
2246: }
2247:
2248: g.setColor(saved);
2249: }
2250:
2251:
2262: protected void paintContentBorderRightEdge(Graphics g, int tabPlacement,
2263: int selectedIndex, int x, int y,
2264: int w, int h)
2265: {
2266: Color saved = g.getColor();
2267: int startgap = rects[selectedIndex].y;
2268: int endgap = rects[selectedIndex].y + rects[selectedIndex].height;
2269:
2270: int diff = 0;
2271:
2272: if (tabPlacement == SwingConstants.RIGHT)
2273: {
2274: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2275: {
2276: Point p = findPointForIndex(currentScrollLocation);
2277: diff = p.y;
2278: }
2279:
2280: g.setColor(shadow);
2281: g.drawLine(x + w - 1, y + 1, x + w - 1, startgap - diff);
2282: g.drawLine(x + w - 1, endgap - diff, x + w - 1, y + h - 1);
2283:
2284: g.setColor(darkShadow);
2285: g.drawLine(x + w, y, x + w, startgap - diff);
2286: g.drawLine(x + w, endgap - diff, x + w, y + h);
2287: }
2288: else
2289: {
2290: g.setColor(shadow);
2291: g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
2292: g.setColor(darkShadow);
2293: g.drawLine(x + w, y, x + w, y + h);
2294: }
2295:
2296: g.setColor(saved);
2297: }
2298:
2299:
2307: public Rectangle getTabBounds(JTabbedPane pane, int i)
2308: {
2309: return rects[i];
2310: }
2311:
2312:
2319: public int getTabRunCount(JTabbedPane pane)
2320: {
2321: return runCount;
2322: }
2323:
2324:
2333: public int tabForCoordinate(JTabbedPane pane, int x, int y)
2334: {
2335: Point p = new Point(x, y);
2336: int tabCount = tabPane.getTabCount();
2337: int currRun = 1;
2338: for (int i = 0; i < runCount; i++)
2339: {
2340: int first = lastTabInRun(tabCount, getPreviousTabRun(currRun)) + 1;
2341: if (first == tabCount)
2342: first = 0;
2343: int last = lastTabInRun(tabCount, currRun);
2344: for (int j = first; j <= last; j++)
2345: {
2346: if (getTabBounds(pane, j).contains(p))
2347: return j;
2348: }
2349: currRun = getNextTabRun(currRun);
2350: }
2351: return -1;
2352: }
2353:
2354:
2362: protected Rectangle getTabBounds(int tabIndex, Rectangle dest)
2363: {
2364: dest.setBounds(getTabBounds(tabPane, tabIndex));
2365: return dest;
2366: }
2367:
2368:
2373: protected Component getVisibleComponent()
2374: {
2375: return tabPane.getComponentAt(tabPane.getSelectedIndex());
2376: }
2377:
2378:
2383: protected void setVisibleComponent(Component component)
2384: {
2385: component.setVisible(true);
2386: tabPane.setSelectedComponent(component);
2387: }
2388:
2389:
2395: protected void assureRectsCreated(int tabCount)
2396: {
2397: if (rects == null)
2398: rects = new Rectangle[tabCount];
2399: if (tabCount == rects.length)
2400: return;
2401: else
2402: {
2403: int numToCopy = Math.min(tabCount, rects.length);
2404: Rectangle[] tmp = new Rectangle[tabCount];
2405: System.arraycopy(rects, 0, tmp, 0, numToCopy);
2406: rects = tmp;
2407: }
2408: }
2409:
2410:
2414: protected void expandTabRunsArray()
2415: {
2416:
2417: if (tabRuns == null)
2418: tabRuns = new int[10];
2419: else
2420: {
2421: int[] newRuns = new int[tabRuns.length + 10];
2422: System.arraycopy(tabRuns, 0, newRuns, 0, tabRuns.length);
2423: tabRuns = newRuns;
2424: }
2425: }
2426:
2427:
2435: protected int getRunForTab(int tabCount, int tabIndex)
2436: {
2437: if (runCount == 1 && tabIndex < tabCount && tabIndex >= 0)
2438: return 1;
2439: for (int i = 0; i < runCount; i++)
2440: {
2441: int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1;
2442: if (first == tabCount)
2443: first = 0;
2444: int last = lastTabInRun(tabCount, i);
2445: if (last >= tabIndex && first <= tabIndex)
2446: return i;
2447: }
2448: return -1;
2449: }
2450:
2451:
2459: protected int lastTabInRun(int tabCount, int run)
2460: {
2461: if (tabRuns[run] == 0)
2462: return tabCount - 1;
2463: else
2464: return tabRuns[run] - 1;
2465: }
2466:
2467:
2474: protected int getTabRunOverlay(int tabPlacement)
2475: {
2476: return tabRunOverlay;
2477: }
2478:
2479:
2488: protected int getTabRunIndent(int tabPlacement, int run)
2489: {
2490: return 0;
2491: }
2492:
2493:
2501: protected boolean shouldPadTabRun(int tabPlacement, int run)
2502: {
2503: return true;
2504: }
2505:
2506:
2513: protected boolean shouldRotateTabRuns(int tabPlacement)
2514: {
2515: return true;
2516: }
2517:
2518:
2527: protected Icon getIconForTab(int tabIndex)
2528: {
2529: if (tabPane.isEnabledAt(tabIndex))
2530: return tabPane.getIconAt(tabIndex);
2531: else
2532: return tabPane.getDisabledIconAt(tabIndex);
2533: }
2534:
2535:
2542: protected View getTextViewForTab(int tabIndex)
2543: {
2544: return null;
2545: }
2546:
2547:
2557: protected int calculateTabHeight(int tabPlacement, int tabIndex,
2558: int fontHeight)
2559: {
2560: Icon icon = getIconForTab(tabIndex);
2561: Insets insets = getTabInsets(tabPlacement, tabIndex);
2562:
2563: if (icon != null)
2564: {
2565: Rectangle vr = new Rectangle();
2566: Rectangle ir = new Rectangle();
2567: Rectangle tr = new Rectangle();
2568: layoutLabel(tabPlacement, getFontMetrics(), tabIndex,
2569: tabPane.getTitleAt(tabIndex), icon, vr, ir, tr,
2570: tabIndex == tabPane.getSelectedIndex());
2571: calcRect = tr.union(ir);
2572: }
2573: else
2574: calcRect.height = fontHeight;
2575:
2576: calcRect.height += insets.top + insets.bottom;
2577: return calcRect.height;
2578: }
2579:
2580:
2587: protected int calculateMaxTabHeight(int tabPlacement)
2588: {
2589: maxTabHeight = 0;
2590:
2591: FontMetrics fm = getFontMetrics();
2592: int fontHeight = fm.getHeight();
2593:
2594: for (int i = 0; i < tabPane.getTabCount(); i++)
2595: maxTabHeight = Math.max(calculateTabHeight(tabPlacement, i, fontHeight),
2596: maxTabHeight);
2597:
2598: return maxTabHeight;
2599: }
2600:
2601:
2611: protected int calculateTabWidth(int tabPlacement, int tabIndex,
2612: FontMetrics metrics)
2613: {
2614: Icon icon = getIconForTab(tabIndex);
2615: Insets insets = getTabInsets(tabPlacement, tabIndex);
2616:
2617: if (icon != null)
2618: {
2619: Rectangle vr = new Rectangle();
2620: Rectangle ir = new Rectangle();
2621: Rectangle tr = new Rectangle();
2622: layoutLabel(tabPlacement, getFontMetrics(), tabIndex,
2623: tabPane.getTitleAt(tabIndex), icon, vr, ir, tr,
2624: tabIndex == tabPane.getSelectedIndex());
2625: calcRect = tr.union(ir);
2626: }
2627: else
2628: calcRect.width = metrics.stringWidth(tabPane.getTitleAt(tabIndex));
2629:
2630: calcRect.width += insets.left + insets.right;
2631: return calcRect.width;
2632: }
2633:
2634:
2641: protected int calculateMaxTabWidth(int tabPlacement)
2642: {
2643: maxTabWidth = 0;
2644:
2645: FontMetrics fm = getFontMetrics();
2646:
2647: for (int i = 0; i < tabPane.getTabCount(); i++)
2648: maxTabWidth = Math.max(calculateTabWidth(tabPlacement, i, fm),
2649: maxTabWidth);
2650:
2651: return maxTabWidth;
2652: }
2653:
2654:
2664: protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount,
2665: int maxTabHeight)
2666: {
2667: Insets insets = getTabAreaInsets(tabPlacement);
2668: int tabAreaHeight = horizRunCount * maxTabHeight
2669: - (horizRunCount - 1) * tabRunOverlay;
2670:
2671: tabAreaHeight += insets.top + insets.bottom;
2672:
2673: return tabAreaHeight;
2674: }
2675:
2676:
2686: protected int calculateTabAreaWidth(int tabPlacement, int vertRunCount,
2687: int maxTabWidth)
2688: {
2689: Insets insets = getTabAreaInsets(tabPlacement);
2690: int tabAreaWidth = vertRunCount * maxTabWidth
2691: - (vertRunCount - 1) * tabRunOverlay;
2692:
2693: tabAreaWidth += insets.left + insets.right;
2694:
2695: return tabAreaWidth;
2696: }
2697:
2698:
2706: protected Insets getTabInsets(int tabPlacement, int tabIndex)
2707: {
2708: Insets target = new Insets(0, 0, 0, 0);
2709: rotateInsets(tabInsets, target, tabPlacement);
2710: return target;
2711: }
2712:
2713:
2720: protected Insets getSelectedTabPadInsets(int tabPlacement)
2721: {
2722: Insets target = new Insets(0, 0, 0, 0);
2723: rotateInsets(selectedTabPadInsets, target, tabPlacement);
2724: return target;
2725: }
2726:
2727:
2734: protected Insets getTabAreaInsets(int tabPlacement)
2735: {
2736: Insets target = new Insets(0, 0, 0, 0);
2737: rotateInsets(tabAreaInsets, target, tabPlacement);
2738: return target;
2739: }
2740:
2741:
2748: protected Insets getContentBorderInsets(int tabPlacement)
2749: {
2750: Insets target = new Insets(0, 0, 0, 0);
2751: rotateInsets(contentBorderInsets, target, tabPlacement);
2752: return target;
2753: }
2754:
2755:
2760: protected FontMetrics getFontMetrics()
2761: {
2762: FontMetrics fm = tabPane.getToolkit().getFontMetrics(tabPane.getFont());
2763: return fm;
2764: }
2765:
2766:
2772: protected void navigateSelectedTab(int direction)
2773: {
2774: int tabPlacement = tabPane.getTabPlacement();
2775: if (tabPlacement == SwingConstants.TOP
2776: || tabPlacement == SwingConstants.BOTTOM)
2777: {
2778: if (direction == SwingConstants.WEST)
2779: selectPreviousTabInRun(tabPane.getSelectedIndex());
2780: else if (direction == SwingConstants.EAST)
2781: selectNextTabInRun(tabPane.getSelectedIndex());
2782:
2783: else
2784: {
2785: int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
2786: tabPane.getSelectedIndex(),
2787: (tabPlacement == SwingConstants.RIGHT)
2788: ? true : false);
2789: selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
2790: offset);
2791: }
2792: }
2793: if (tabPlacement == SwingConstants.LEFT
2794: || tabPlacement == SwingConstants.RIGHT)
2795: {
2796: if (direction == SwingConstants.NORTH)
2797: selectPreviousTabInRun(tabPane.getSelectedIndex());
2798: else if (direction == SwingConstants.SOUTH)
2799: selectNextTabInRun(tabPane.getSelectedIndex());
2800: else
2801: {
2802: int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
2803: tabPane.getSelectedIndex(),
2804: (tabPlacement == SwingConstants.RIGHT)
2805: ? true : false);
2806: selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
2807: offset);
2808: }
2809: }
2810: }
2811:
2812:
2817: protected void selectNextTabInRun(int current)
2818: {
2819: tabPane.setSelectedIndex(getNextTabIndexInRun(tabPane.getTabCount(),
2820: current));
2821: }
2822:
2823:
2828: protected void selectPreviousTabInRun(int current)
2829: {
2830: tabPane.setSelectedIndex(getPreviousTabIndexInRun(tabPane.getTabCount(),
2831: current));
2832: }
2833:
2834:
2839: protected void selectNextTab(int current)
2840: {
2841: tabPane.setSelectedIndex(getNextTabIndex(current));
2842: }
2843:
2844:
2849: protected void selectPreviousTab(int current)
2850: {
2851: tabPane.setSelectedIndex(getPreviousTabIndex(current));
2852: }
2853:
2854:
2865: protected void selectAdjacentRunTab(int tabPlacement, int tabIndex,
2866: int offset)
2867: {
2868: int x = rects[tabIndex].x + rects[tabIndex].width / 2;
2869: int y = rects[tabIndex].y + rects[tabIndex].height / 2;
2870:
2871: switch (tabPlacement)
2872: {
2873: case SwingConstants.TOP:
2874: case SwingConstants.BOTTOM:
2875: y += offset;
2876: break;
2877: case SwingConstants.RIGHT:
2878: case SwingConstants.LEFT:
2879: x += offset;
2880: break;
2881: }
2882:
2883: int index = tabForCoordinate(tabPane, x, y);
2884: if (index != -1)
2885: tabPane.setSelectedIndex(index);
2886: }
2887:
2888:
2889:
2890:
2891:
2892:
2893:
2894:
2909: protected int getTabRunOffset(int tabPlacement, int tabCount, int tabIndex,
2910: boolean forward)
2911: {
2912: int currRun = getRunForTab(tabCount, tabIndex);
2913: int offset;
2914: int nextRun = (forward) ? getNextTabRun(currRun) : getPreviousTabRun(currRun);
2915: if (tabPlacement == SwingConstants.TOP
2916: || tabPlacement == SwingConstants.BOTTOM)
2917: offset = rects[lastTabInRun(tabCount, nextRun)].y
2918: - rects[lastTabInRun(tabCount, currRun)].y;
2919: else
2920: offset = rects[lastTabInRun(tabCount, nextRun)].x
2921: - rects[lastTabInRun(tabCount, currRun)].x;
2922: return offset;
2923: }
2924:
2925:
2932: protected int getPreviousTabIndex(int base)
2933: {
2934: base--;
2935: if (base < 0)
2936: return tabPane.getTabCount() - 1;
2937: return base;
2938: }
2939:
2940:
2947: protected int getNextTabIndex(int base)
2948: {
2949: base++;
2950: if (base == tabPane.getTabCount())
2951: return 0;
2952: return base;
2953: }
2954:
2955:
2964: protected int getNextTabIndexInRun(int tabCount, int base)
2965: {
2966: int index = getNextTabIndex(base);
2967: int run = getRunForTab(tabCount, base);
2968: if (index == lastTabInRun(tabCount, run) + 1)
2969: index = lastTabInRun(tabCount, getPreviousTabRun(run)) + 1;
2970: return getNextTabIndex(base);
2971: }
2972:
2973:
2982: protected int getPreviousTabIndexInRun(int tabCount, int base)
2983: {
2984: int index = getPreviousTabIndex(base);
2985: int run = getRunForTab(tabCount, base);
2986: if (index == lastTabInRun(tabCount, getPreviousTabRun(run)))
2987: index = lastTabInRun(tabCount, run);
2988: return getPreviousTabIndex(base);
2989: }
2990:
2991:
2998: protected int getPreviousTabRun(int baseRun)
2999: {
3000: if (getTabRunCount(tabPane) == 1)
3001: return 1;
3002:
3003: int prevRun = --baseRun;
3004: if (prevRun < 0)
3005: prevRun = getTabRunCount(tabPane) - 1;
3006: return prevRun;
3007: }
3008:
3009:
3016: protected int getNextTabRun(int baseRun)
3017: {
3018: if (getTabRunCount(tabPane) == 1)
3019: return 1;
3020:
3021: int nextRun = ++baseRun;
3022: if (nextRun == getTabRunCount(tabPane))
3023: nextRun = 0;
3024: return nextRun;
3025: }
3026:
3027:
3039: protected static void rotateInsets(Insets topInsets, Insets targetInsets,
3040: int targetPlacement)
3041: {
3042:
3043:
3044: switch (targetPlacement)
3045: {
3046: case SwingConstants.TOP:
3047: targetInsets.top = topInsets.top;
3048: targetInsets.left = topInsets.left;
3049: targetInsets.right = topInsets.right;
3050: targetInsets.bottom = topInsets.bottom;
3051: break;
3052: case SwingConstants.LEFT:
3053: targetInsets.left = topInsets.top;
3054: targetInsets.top = topInsets.left;
3055: targetInsets.right = topInsets.bottom;
3056: targetInsets.bottom = topInsets.right;
3057: break;
3058: case SwingConstants.BOTTOM:
3059: targetInsets.top = topInsets.bottom;
3060: targetInsets.bottom = topInsets.top;
3061: targetInsets.left = topInsets.left;
3062: targetInsets.right = topInsets.right;
3063: break;
3064: case SwingConstants.RIGHT:
3065: targetInsets.top = topInsets.left;
3066: targetInsets.left = topInsets.bottom;
3067: targetInsets.bottom = topInsets.right;
3068: targetInsets.right = topInsets.top;
3069: break;
3070: }
3071: }
3072: }