1:
37:
38:
39: package ;
40:
41: import ;
42:
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: import ;
61: import ;
62:
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: import ;
79: import ;
80:
81:
84: public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
85: {
86:
93: public class FocusHandler extends FocusAdapter
94: {
95:
100: public void focusGained(FocusEvent e)
101: {
102:
103: }
104:
105:
110: public void focusLost(FocusEvent e)
111: {
112:
113: }
114: }
115:
116:
125: public class MouseHandler extends MouseAdapter
126: {
127:
133: public void mousePressed(MouseEvent e)
134: {
135: if (tabPane.isEnabled())
136: {
137: int index = tabForCoordinate(tabPane, e.getX(), e.getY());
138: if (index >= 0 && tabPane.isEnabledAt(index))
139: {
140: tabPane.setSelectedIndex(index);
141: }
142: }
143: }
144:
145:
151: public void mouseEntered(MouseEvent ev)
152: {
153: int tabIndex = tabForCoordinate(tabPane, ev.getX(), ev.getY());
154: setRolloverTab(tabIndex);
155: }
156:
157:
163: public void mouseExited(MouseEvent ev)
164: {
165: setRolloverTab(-1);
166: }
167:
168:
174: public void mouseMoved(MouseEvent ev)
175: {
176: int tabIndex = tabForCoordinate(tabPane, ev.getX(), ev.getY());
177: setRolloverTab(tabIndex);
178: }
179: }
180:
181:
188: public class PropertyChangeHandler implements PropertyChangeListener
189: {
190:
196: public void propertyChange(PropertyChangeEvent e)
197: {
198: if (e.getPropertyName().equals("tabLayoutPolicy"))
199: {
200: layoutManager = createLayoutManager();
201:
202: tabPane.setLayout(layoutManager);
203: }
204: else if (e.getPropertyName().equals("tabPlacement")
205: && tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
206: {
207: incrButton = createIncreaseButton();
208: decrButton = createDecreaseButton();
209: }
210: tabPane.revalidate();
211: tabPane.repaint();
212: }
213: }
214:
215:
224: public class TabbedPaneLayout implements LayoutManager
225: {
226:
232: public void addLayoutComponent(String name, Component comp)
233: {
234:
235: }
236:
237:
241: public void calculateLayoutInfo()
242: {
243: int count = tabPane.getTabCount();
244: assureRectsCreated(count);
245: calculateTabRects(tabPane.getTabPlacement(), count);
246: tabRunsDirty = false;
247: }
248:
249:
257: protected Dimension calculateSize(boolean minimum)
258: {
259: int tabPlacement = tabPane.getTabPlacement();
260:
261: int width = 0;
262: int height = 0;
263: Component c;
264: Dimension dims;
265:
266:
267:
268: for (int i = 0; i < tabPane.getTabCount(); i++)
269: {
270: c = tabPane.getComponentAt(i);
271: if (c == null)
272: continue;
273: dims = minimum ? c.getMinimumSize() : c.getPreferredSize();
274: if (dims != null)
275: {
276: height = Math.max(height, dims.height);
277: width = Math.max(width, dims.width);
278: }
279: }
280:
281: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
282: if (tabPlacement == SwingConstants.TOP
283: || tabPlacement == SwingConstants.BOTTOM)
284: {
285: int min = calculateMaxTabWidth(tabPlacement);
286: width = Math.max(min, width);
287: int tabAreaHeight = preferredTabAreaHeight(tabPlacement,
288: width - tabAreaInsets.left
289: -tabAreaInsets.right);
290: height += tabAreaHeight;
291: }
292: else
293: {
294: int min = calculateMaxTabHeight(tabPlacement);
295: height = Math.max(min, height);
296: int tabAreaWidth = preferredTabAreaWidth(tabPlacement,
297: height - tabAreaInsets.top
298: - tabAreaInsets.bottom);
299: width += tabAreaWidth;
300: }
301:
302: Insets tabPaneInsets = tabPane.getInsets();
303: return new Dimension(width + tabPaneInsets.left + tabPaneInsets.right,
304: height + tabPaneInsets.top + tabPaneInsets.bottom);
305: }
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
325: protected void calculateTabRects(int tabPlacement, int tabCount)
326: {
327: Insets insets = tabPane.getInsets();
328: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
329: Dimension size = tabPane.getSize();
330:
331:
332: int x;
333: int y;
334:
335: int breakAt;
336:
337:
338: switch (tabPlacement)
339: {
340: case LEFT:
341: maxTabWidth = calculateMaxTabWidth(tabPlacement);
342: x = insets.left + tabAreaInsets.left;
343: y = insets.top + tabAreaInsets.top;
344: breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
345: break;
346: case RIGHT:
347: maxTabWidth = calculateMaxTabWidth(tabPlacement);
348: x = size.width - (insets.right + tabAreaInsets.right) - maxTabWidth;
349: y = insets.top + tabAreaInsets.top;
350: breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
351: break;
352: case BOTTOM:
353: maxTabHeight = calculateMaxTabHeight(tabPlacement);
354: x = insets.left + tabAreaInsets.left;
355: y = size.height - (insets.bottom + tabAreaInsets.bottom)
356: - maxTabHeight;
357: breakAt = size.width - (insets.right + tabAreaInsets.right);
358: break;
359: case TOP:
360: default:
361: maxTabHeight = calculateMaxTabHeight(tabPlacement);
362: x = insets.left + tabAreaInsets.left;
363: y = insets.top + tabAreaInsets.top;
364: breakAt = size.width - (insets.right + tabAreaInsets.right);
365: break;
366: }
367:
368: if (tabCount == 0)
369: return;
370:
371: FontMetrics fm = getFontMetrics();
372: runCount = 0;
373: selectedRun = -1;
374: int selectedIndex = tabPane.getSelectedIndex();
375:
376: Rectangle rect;
377:
378:
379: if (tabPlacement == SwingConstants.TOP
380: || tabPlacement == SwingConstants.BOTTOM)
381: {
382: for (int i = 0; i < tabCount; i++)
383: {
384: rect = rects[i];
385: if (i > 0)
386: {
387: rect.x = rects[i - 1].x + rects[i - 1].width;
388: }
389: else
390: {
391: tabRuns[0] = 0;
392: runCount = 1;
393: maxTabWidth = 0;
394: rect.x = x;
395: }
396: rect.width = calculateTabWidth(tabPlacement, i, fm);
397: maxTabWidth = Math.max(maxTabWidth, rect.width);
398:
399: if (rect.x != 2 + insets.left && rect.x + rect.width > breakAt)
400: {
401: if (runCount > tabRuns.length - 1)
402: expandTabRunsArray();
403: tabRuns[runCount] = i;
404: runCount++;
405: rect.x = x;
406: }
407:
408: rect.y = y;
409: rect.height = maxTabHeight;
410: if (i == selectedIndex)
411: selectedRun = runCount - 1;
412:
413: }
414: }
415: else
416: {
417: for (int i = 0; i < tabCount; i++)
418: {
419: rect = rects[i];
420: if (i > 0)
421: {
422: rect.y = rects[i - 1].y + rects[i - 1].height;
423: }
424: else
425: {
426: tabRuns[0] = 0;
427: runCount = 1;
428: maxTabHeight = 0;
429: rect.y = y;
430: }
431: rect.height = calculateTabHeight(tabPlacement, i,
432: fm.getHeight());
433: maxTabHeight = Math.max(maxTabHeight, rect.height);
434:
435: if (rect.y != 2 + insets.top && rect.y + rect.height > breakAt)
436: {
437: if (runCount > tabRuns.length - 1)
438: expandTabRunsArray();
439: tabRuns[runCount] = i;
440: runCount++;
441: rect.y = y;
442: }
443:
444: rect.x = x;
445: rect.width = maxTabWidth;
446:
447: if (i == selectedIndex)
448: selectedRun = runCount - 1;
449: }
450: }
451:
452: if (runCount > 1)
453: {
454: int start;
455: if (tabPlacement == SwingConstants.TOP
456: || tabPlacement == SwingConstants.BOTTOM)
457: start = y;
458: else
459: start = x;
460: normalizeTabRuns(tabPlacement, tabCount, start, breakAt);
461: selectedRun = getRunForTab(tabCount, selectedIndex);
462: if (shouldRotateTabRuns(tabPlacement))
463: {
464: rotateTabRuns(tabPlacement, selectedRun);
465: }
466: }
467:
468:
469: int tabRunOverlay = getTabRunOverlay(tabPlacement);
470: for (int i = runCount - 1; i >= 0; --i)
471: {
472: int start = tabRuns[i];
473: int nextIndex;
474: if (i == runCount - 1)
475: nextIndex = 0;
476: else
477: nextIndex = i + 1;
478: int next = tabRuns[nextIndex];
479: int end = (next != 0 ? next - 1 : tabCount - 1);
480: if (tabPlacement == SwingConstants.TOP
481: || tabPlacement == SwingConstants.BOTTOM)
482: {
483: for (int j = start; j <= end; ++j)
484: {
485: rect = rects[j];
486: rect.y = y;
487: rect.x += getTabRunIndent(tabPlacement, i);
488: }
489: if (shouldPadTabRun(tabPlacement, i))
490: {
491: padTabRun(tabPlacement, start, end, breakAt);
492: }
493: if (tabPlacement == BOTTOM)
494: y -= (maxTabHeight - tabRunOverlay);
495: else
496: y += (maxTabHeight - tabRunOverlay);
497: }
498: else
499: {
500: for (int j = start; j <= end; ++j)
501: {
502: rect = rects[j];
503: rect.x = x;
504: rect.y += getTabRunIndent(tabPlacement, i);
505: }
506: if (shouldPadTabRun(tabPlacement, i))
507: {
508: padTabRun(tabPlacement, start, end, breakAt);
509: }
510: if (tabPlacement == RIGHT)
511: x -= (maxTabWidth - tabRunOverlay);
512: else
513: x += (maxTabWidth - tabRunOverlay);
514:
515: }
516: }
517: padSelectedTab(tabPlacement, selectedIndex);
518: }
519:
520:
527: public void layoutContainer(Container parent)
528: {
529: calculateLayoutInfo();
530:
531: int tabPlacement = tabPane.getTabPlacement();
532: Insets insets = tabPane.getInsets();
533: int childCount = tabPane.getComponentCount();
534: if (childCount > 0)
535: {
536: int compX;
537: int compY;
538: int tabAreaWidth = 0;
539: int tabAreaHeight = 0;
540: switch (tabPlacement)
541: {
542: case LEFT:
543: tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount,
544: maxTabWidth);
545: compX = tabAreaWidth + insets.left + contentBorderInsets.left;
546: compY = insets.top + contentBorderInsets.top;
547: break;
548: case RIGHT:
549: tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount,
550: maxTabWidth);
551: compX = insets.left + contentBorderInsets.left;
552: compY = insets.top + contentBorderInsets.top;
553: break;
554: case BOTTOM:
555: tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount,
556: maxTabHeight);
557: compX = insets.left + contentBorderInsets.left;
558: compY = insets.top + contentBorderInsets.top;
559: break;
560: case TOP:
561: default:
562: tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount,
563: maxTabHeight);
564: compX = insets.left + contentBorderInsets.left;
565: compY = tabAreaHeight + insets.top + contentBorderInsets.top;
566: }
567: Rectangle bounds = tabPane.getBounds();
568: int compWidth = bounds.width - tabAreaWidth - insets.left
569: - insets.right - contentBorderInsets.left
570: - contentBorderInsets.right;
571: int compHeight = bounds.height - tabAreaHeight - insets.top
572: - insets.bottom - contentBorderInsets.top
573: - contentBorderInsets.bottom;
574:
575:
576: for (int i = 0; i < childCount; ++i)
577: {
578: Component c = tabPane.getComponent(i);
579: c.setBounds(compX, compY, compWidth, compHeight);
580: }
581: }
582: }
583:
584:
591: public Dimension minimumLayoutSize(Container parent)
592: {
593: return calculateSize(false);
594: }
595:
596:
597:
598:
599:
600:
601:
602:
603:
604:
613: protected void normalizeTabRuns(int tabPlacement, int tabCount, int start,
614: int max)
615: {
616: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
617: if (tabPlacement == SwingUtilities.TOP
618: || tabPlacement == SwingUtilities.BOTTOM)
619: {
620:
621:
622: for (int i = 1; i < runCount; i++)
623: {
624: Rectangle currRun = rects[lastTabInRun(tabCount, i)];
625: Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))];
626: int spaceInCurr = currRun.x + currRun.width;
627: int spaceInNext = nextRun.x + nextRun.width;
628:
629: int diffNow = spaceInCurr - spaceInNext;
630: int diffLater = (spaceInCurr - currRun.width)
631: - (spaceInNext + currRun.width);
632: while (Math.abs(diffLater) < Math.abs(diffNow)
633: && spaceInNext + currRun.width < max)
634: {
635: tabRuns[i]--;
636: spaceInNext += currRun.width;
637: spaceInCurr -= currRun.width;
638: currRun = rects[lastTabInRun(tabCount, i)];
639: diffNow = spaceInCurr - spaceInNext;
640: diffLater = (spaceInCurr - currRun.width)
641: - (spaceInNext + currRun.width);
642: }
643:
644:
645: int first = lastTabInRun(tabCount, i) + 1;
646: int last = lastTabInRun(tabCount, getNextTabRun(i));
647: int currX = tabAreaInsets.left;
648: for (int j = first; j <= last; j++)
649: {
650: rects[j].x = currX;
651: currX += rects[j].width;
652: }
653: }
654: }
655: else
656: {
657: for (int i = 1; i < runCount; i++)
658: {
659: Rectangle currRun = rects[lastTabInRun(tabCount, i)];
660: Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))];
661: int spaceInCurr = currRun.y + currRun.height;
662: int spaceInNext = nextRun.y + nextRun.height;
663:
664: int diffNow = spaceInCurr - spaceInNext;
665: int diffLater = (spaceInCurr - currRun.height)
666: - (spaceInNext + currRun.height);
667: while (Math.abs(diffLater) < Math.abs(diffNow)
668: && spaceInNext + currRun.height < max)
669: {
670: tabRuns[i]--;
671: spaceInNext += currRun.height;
672: spaceInCurr -= currRun.height;
673: currRun = rects[lastTabInRun(tabCount, i)];
674: diffNow = spaceInCurr - spaceInNext;
675: diffLater = (spaceInCurr - currRun.height)
676: - (spaceInNext + currRun.height);
677: }
678:
679: int first = lastTabInRun(tabCount, i) + 1;
680: int last = lastTabInRun(tabCount, getNextTabRun(i));
681: int currY = tabAreaInsets.top;
682: for (int j = first; j <= last; j++)
683: {
684: rects[j].y = currY;
685: currY += rects[j].height;
686: }
687: }
688: }
689: }
690:
691:
698: protected void padSelectedTab(int tabPlacement, int selectedIndex)
699: {
700: Insets insets = getSelectedTabPadInsets(tabPlacement);
701: rects[selectedIndex].x -= insets.left;
702: rects[selectedIndex].y -= insets.top;
703: rects[selectedIndex].width += insets.left + insets.right;
704: rects[selectedIndex].height += insets.top + insets.bottom;
705: }
706:
707:
708:
709:
710:
711:
712:
713:
723: protected void padTabRun(int tabPlacement, int start, int end, int max)
724: {
725: if (tabPlacement == SwingConstants.TOP
726: || tabPlacement == SwingConstants.BOTTOM)
727: {
728: int runWidth = rects[end].x + rects[end].width;
729: int spaceRemaining = max - runWidth;
730: int numTabs = end - start + 1;
731:
732:
733: int spaceAllocated = spaceRemaining / numTabs;
734: int currX = rects[start].x;
735: for (int i = start; i <= end; i++)
736: {
737: rects[i].x = currX;
738: rects[i].width += spaceAllocated;
739: currX += rects[i].width;
740:
741:
742:
743:
744: if (i == end && rects[i].x + rects[i].width != max)
745: rects[i].width = max - rects[i].x;
746: }
747: }
748: else
749: {
750: int runHeight = rects[end].y + rects[end].height;
751: int spaceRemaining = max - runHeight;
752: int numTabs = end - start + 1;
753:
754: int spaceAllocated = spaceRemaining / numTabs;
755: int currY = rects[start].y;
756: for (int i = start; i <= end; i++)
757: {
758: rects[i].y = currY;
759: rects[i].height += spaceAllocated;
760: currY += rects[i].height;
761: if (i == end && rects[i].y + rects[i].height != max)
762: rects[i].height = max - rects[i].y;
763: }
764: }
765: }
766:
767:
774: public Dimension preferredLayoutSize(Container parent)
775: {
776: return calculateSize(false);
777: }
778:
779:
788: protected int preferredTabAreaHeight(int tabPlacement, int width)
789: {
790: if (tabPane.getTabCount() == 0)
791: return calculateTabAreaHeight(tabPlacement, 0, 0);
792:
793: int runs = 0;
794: int runWidth = 0;
795: int tabWidth = 0;
796:
797: FontMetrics fm = getFontMetrics();
798:
799: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
800: Insets insets = tabPane.getInsets();
801:
802:
803: width -= tabAreaInsets.left + tabAreaInsets.right + insets.left
804: + insets.right;
805:
806:
807:
808:
809:
810:
811: for (int i = 0; i < tabPane.getTabCount(); i++)
812: {
813: tabWidth = calculateTabWidth(tabPlacement, i, fm);
814: if (runWidth + tabWidth > width)
815: {
816: runWidth = tabWidth;
817: runs++;
818: }
819: else
820: runWidth += tabWidth;
821: }
822: runs++;
823:
824: int maxTabHeight = calculateMaxTabHeight(tabPlacement);
825: int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs,
826: maxTabHeight);
827: return tabAreaHeight;
828: }
829:
830:
839: protected int preferredTabAreaWidth(int tabPlacement, int height)
840: {
841: if (tabPane.getTabCount() == 0)
842: return calculateTabAreaHeight(tabPlacement, 0, 0);
843:
844: int runs = 0;
845: int runHeight = 0;
846: int tabHeight = 0;
847:
848: FontMetrics fm = getFontMetrics();
849:
850: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
851: Insets insets = tabPane.getInsets();
852:
853: height -= tabAreaInsets.top + tabAreaInsets.bottom + insets.top
854: + insets.bottom;
855: int fontHeight = fm.getHeight();
856:
857: for (int i = 0; i < tabPane.getTabCount(); i++)
858: {
859: tabHeight = calculateTabHeight(tabPlacement, i, fontHeight);
860: if (runHeight + tabHeight > height)
861: {
862: runHeight = tabHeight;
863: runs++;
864: }
865: else
866: runHeight += tabHeight;
867: }
868: runs++;
869:
870: int maxTabWidth = calculateMaxTabWidth(tabPlacement);
871: int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth);
872: return tabAreaWidth;
873: }
874:
875:
883: protected void rotateTabRuns(int tabPlacement, int selectedRun)
884: {
885: if (runCount == 1 || selectedRun == 1 || selectedRun == -1)
886: return;
887: int[] newTabRuns = new int[tabRuns.length];
888: int currentRun = selectedRun;
889: int i = 1;
890: do
891: {
892: newTabRuns[i] = tabRuns[currentRun];
893: currentRun = getNextTabRun(currentRun);
894: i++;
895: }
896: while (i < runCount);
897: if (runCount > 1)
898: newTabRuns[0] = tabRuns[currentRun];
899:
900: tabRuns = newTabRuns;
901: BasicTabbedPaneUI.this.selectedRun = 1;
902: }
903:
904:
910: public void removeLayoutComponent(Component comp)
911: {
912:
913: }
914: }
915:
916:
920: private class TabbedPaneScrollLayout extends TabbedPaneLayout
921: {
922:
929: public Dimension preferredLayoutSize(Container parent)
930: {
931: return super.calculateSize(true);
932: }
933:
934:
941: public Dimension minimumLayoutSize(Container parent)
942: {
943: return super.calculateSize(true);
944: }
945:
946:
954: protected int preferredTabAreaHeight(int tabPlacement, int width)
955: {
956: if (tabPane.getTabCount() == 0)
957: return calculateTabAreaHeight(tabPlacement, 0, 0);
958:
959: int runs = 1;
960:
961: int maxTabHeight = calculateMaxTabHeight(tabPlacement);
962: int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs,
963: maxTabHeight);
964: return tabAreaHeight;
965: }
966:
967:
975: protected int preferredTabAreaWidth(int tabPlacement, int height)
976: {
977: if (tabPane.getTabCount() == 0)
978: return calculateTabAreaHeight(tabPlacement, 0, 0);
979:
980: int runs = 1;
981:
982: int maxTabWidth = calculateMaxTabWidth(tabPlacement);
983: int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth);
984: return tabAreaWidth;
985: }
986:
987:
996: protected void calculateTabRects(int tabPlacement, int tabCount)
997: {
998: if (tabCount == 0)
999: return;
1000:
1001: FontMetrics fm = getFontMetrics();
1002: SwingUtilities.calculateInnerArea(tabPane, calcRect);
1003: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
1004: Insets insets = tabPane.getInsets();
1005: int runs = 1;
1006: int start = 0;
1007: int top = 0;
1008: if (tabPlacement == SwingConstants.TOP
1009: || tabPlacement == SwingConstants.BOTTOM)
1010: {
1011: int maxHeight = calculateMaxTabHeight(tabPlacement);
1012: calcRect.width -= tabAreaInsets.left + tabAreaInsets.right;
1013: start = tabAreaInsets.left + insets.left;
1014: int width = 0;
1015: int runWidth = start;
1016: top = insets.top + tabAreaInsets.top;
1017: for (int i = 0; i < tabCount; i++)
1018: {
1019: width = calculateTabWidth(tabPlacement, i, fm);
1020:
1021: rects[i] = new Rectangle(runWidth, top, width, maxHeight);
1022: runWidth += width;
1023: }
1024: tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right;
1025: tabAreaRect.height = runs * maxTabHeight
1026: - (runs - 1) * tabRunOverlay
1027: + tabAreaInsets.top + tabAreaInsets.bottom;
1028: contentRect.width = tabAreaRect.width;
1029: contentRect.height = tabPane.getHeight() - insets.top
1030: - insets.bottom - tabAreaRect.height;
1031: contentRect.x = insets.left;
1032: tabAreaRect.x = insets.left;
1033: if (tabPlacement == SwingConstants.BOTTOM)
1034: {
1035: contentRect.y = insets.top;
1036: tabAreaRect.y = contentRect.y + contentRect.height;
1037: }
1038: else
1039: {
1040: tabAreaRect.y = insets.top;
1041: contentRect.y = tabAreaRect.y + tabAreaRect.height;
1042: }
1043: }
1044: else
1045: {
1046: int maxWidth = calculateMaxTabWidth(tabPlacement);
1047:
1048: calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom;
1049: int height = 0;
1050: start = tabAreaInsets.top + insets.top;
1051: int runHeight = start;
1052: int fontHeight = fm.getHeight();
1053: top = insets.left + tabAreaInsets.left;
1054: for (int i = 0; i < tabCount; i++)
1055: {
1056: height = calculateTabHeight(tabPlacement, i, fontHeight);
1057: rects[i] = new Rectangle(top, runHeight, maxWidth, height);
1058: runHeight += height;
1059: }
1060: tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay
1061: + tabAreaInsets.left + tabAreaInsets.right;
1062: tabAreaRect.height = tabPane.getHeight() - insets.top
1063: - insets.bottom;
1064: tabAreaRect.y = insets.top;
1065: contentRect.width = tabPane.getWidth() - insets.left - insets.right
1066: - tabAreaRect.width;
1067: contentRect.height = tabAreaRect.height;
1068: contentRect.y = insets.top;
1069: if (tabPlacement == SwingConstants.LEFT)
1070: {
1071: tabAreaRect.x = insets.left;
1072: contentRect.x = tabAreaRect.x + tabAreaRect.width;
1073: }
1074: else
1075: {
1076: contentRect.x = insets.left;
1077: tabAreaRect.x = contentRect.x + contentRect.width;
1078: }
1079: }
1080: runCount = runs;
1081: if (runCount > tabRuns.length)
1082: expandTabRunsArray();
1083:
1084: padSelectedTab(tabPlacement, tabPane.getSelectedIndex());
1085: }
1086:
1087:
1094: public void layoutContainer(Container pane)
1095: {
1096: super.layoutContainer(pane);
1097: int tabCount = tabPane.getTabCount();
1098: Point p = null;
1099: if (tabCount == 0)
1100: return;
1101: int tabPlacement = tabPane.getTabPlacement();
1102: incrButton.setVisible(false);
1103: decrButton.setVisible(false);
1104: if (tabPlacement == SwingConstants.TOP
1105: || tabPlacement == SwingConstants.BOTTOM)
1106: {
1107: if (tabAreaRect.x + tabAreaRect.width < rects[tabCount - 1].x
1108: + rects[tabCount - 1].width)
1109: {
1110: Dimension incrDims = incrButton.getPreferredSize();
1111: Dimension decrDims = decrButton.getPreferredSize();
1112:
1113: decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
1114: - incrDims.width - decrDims.width,
1115: tabAreaRect.y, decrDims.width,
1116: tabAreaRect.height);
1117: incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
1118: - incrDims.width, tabAreaRect.y,
1119: decrDims.width, tabAreaRect.height);
1120:
1121: tabAreaRect.width -= decrDims.width + incrDims.width;
1122: incrButton.setVisible(true);
1123: decrButton.setVisible(true);
1124: }
1125: }
1126:
1127: if (tabPlacement == SwingConstants.LEFT
1128: || tabPlacement == SwingConstants.RIGHT)
1129: {
1130: if (tabAreaRect.y + tabAreaRect.height < rects[tabCount - 1].y
1131: + rects[tabCount - 1].height)
1132: {
1133: Dimension incrDims = incrButton.getPreferredSize();
1134: Dimension decrDims = decrButton.getPreferredSize();
1135:
1136: decrButton.setBounds(tabAreaRect.x,
1137: tabAreaRect.y + tabAreaRect.height
1138: - incrDims.height - decrDims.height,
1139: tabAreaRect.width, decrDims.height);
1140: incrButton.setBounds(tabAreaRect.x,
1141: tabAreaRect.y + tabAreaRect.height
1142: - incrDims.height, tabAreaRect.width,
1143: incrDims.height);
1144:
1145: tabAreaRect.height -= decrDims.height + incrDims.height;
1146: incrButton.setVisible(true);
1147: decrButton.setVisible(true);
1148: }
1149: }
1150: viewport.setBounds(tabAreaRect.x, tabAreaRect.y, tabAreaRect.width,
1151: tabAreaRect.height);
1152: int tabC = tabPane.getTabCount() - 1;
1153: if (tabCount > 0)
1154: {
1155: int w = Math.max(rects[tabC].width + rects[tabC].x, tabAreaRect.width);
1156: int h = Math.max(rects[tabC].height, tabAreaRect.height);
1157: p = findPointForIndex(currentScrollLocation);
1158:
1159:
1160:
1161: panel.setSize(w + p.x, h + p.y);
1162: }
1163: viewport.setViewPosition(p);
1164: viewport.repaint();
1165: }
1166: }
1167:
1168:
1175: public class TabSelectionHandler implements ChangeListener
1176: {
1177:
1183: public void stateChanged(ChangeEvent e)
1184: {
1185: selectedRun = getRunForTab(tabPane.getTabCount(),
1186: tabPane.getSelectedIndex());
1187: tabPane.revalidate();
1188: tabPane.repaint();
1189: }
1190: }
1191:
1192:
1197: private class ScrollingPanel extends JPanel
1198: {
1199:
1202: private class ScrollingPanelUI extends BasicPanelUI
1203: {
1204:
1211: public void paint(Graphics g, JComponent c)
1212: {
1213: paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
1214: }
1215: }
1216:
1217:
1221: public void updateUI()
1222: {
1223: setUI((PanelUI) new ScrollingPanelUI());
1224: }
1225: }
1226:
1227:
1233: private class ScrollingViewport extends JViewport implements UIResource
1234: {
1235:
1236: }
1237:
1238:
1242: private class ScrollingButton extends BasicArrowButton implements UIResource
1243: {
1244:
1249: public ScrollingButton(int dir)
1250: {
1251: super(dir);
1252: }
1253: }
1254:
1255:
1257: transient ScrollingButton incrButton;
1258:
1259:
1261: transient ScrollingButton decrButton;
1262:
1263:
1265: transient ScrollingViewport viewport;
1266:
1267:
1269: transient ScrollingPanel panel;
1270:
1271:
1273: transient int currentScrollLocation;
1274:
1275:
1276: protected Rectangle calcRect;
1277:
1278:
1279: protected Rectangle[] rects;
1280:
1281:
1282: protected Insets contentBorderInsets;
1283:
1284:
1285: protected Insets selectedTabPadInsets;
1286:
1287:
1288: protected Insets tabAreaInsets;
1289:
1290:
1291: protected Insets tabInsets;
1292:
1293:
1297: protected Color darkShadow;
1298:
1299:
1300: protected Color focus;
1301:
1302:
1303: protected Color highlight;
1304:
1305:
1306: protected Color lightHighlight;
1307:
1308:
1309: protected Color shadow;
1310:
1311:
1312: protected int maxTabHeight;
1313:
1314:
1315: protected int maxTabWidth;
1316:
1317:
1318: protected int runCount;
1319:
1320:
1321: protected int selectedRun;
1322:
1323:
1324: protected int tabRunOverlay;
1325:
1326:
1327: protected int textIconGap;
1328:
1329:
1330:
1331:
1332:
1333:
1334:
1335:
1336:
1337:
1338:
1339: protected int[] tabRuns;
1340:
1341:
1345: boolean tabRunsDirty;
1346:
1347:
1352: protected KeyStroke downKey;
1353:
1354:
1359: protected KeyStroke leftKey;
1360:
1361:
1366: protected KeyStroke rightKey;
1367:
1368:
1373: protected KeyStroke upKey;
1374:
1375:
1376: protected FocusListener focusListener;
1377:
1378:
1379: protected MouseListener mouseListener;
1380:
1381:
1382: protected PropertyChangeListener propertyChangeListener;
1383:
1384:
1385: protected ChangeListener tabChangeListener;
1386:
1387:
1388: protected JTabbedPane tabPane;
1389:
1390:
1392: transient LayoutManager layoutManager;
1393:
1394:
1396: transient Rectangle tabAreaRect;
1397:
1398:
1400: transient Rectangle contentRect;
1401:
1402:
1405: private int rolloverTab;
1406:
1407:
1411: private boolean tabsOpaque;
1412:
1413:
1416: public BasicTabbedPaneUI()
1417: {
1418: super();
1419: rects = new Rectangle[0];
1420: tabRuns = new int[10];
1421: }
1422:
1423:
1430: ScrollingButton createIncreaseButton()
1431: {
1432: if (incrButton == null)
1433: incrButton = new ScrollingButton(SwingConstants.NORTH);
1434: if (tabPane.getTabPlacement() == SwingConstants.TOP
1435: || tabPane.getTabPlacement() == SwingConstants.BOTTOM)
1436: incrButton.setDirection(SwingConstants.EAST);
1437: else
1438: incrButton.setDirection(SwingConstants.SOUTH);
1439: return incrButton;
1440: }
1441:
1442:
1449: ScrollingButton createDecreaseButton()
1450: {
1451: if (decrButton == null)
1452: decrButton = new ScrollingButton(SwingConstants.SOUTH);
1453: if (tabPane.getTabPlacement() == SwingConstants.TOP
1454: || tabPane.getTabPlacement() == SwingConstants.BOTTOM)
1455: decrButton.setDirection(SwingConstants.WEST);
1456: else
1457: decrButton.setDirection(SwingConstants.NORTH);
1458: return decrButton;
1459: }
1460:
1461:
1470: Point findPointForIndex(int index)
1471: {
1472: int tabPlacement = tabPane.getTabPlacement();
1473: int selectedIndex = tabPane.getSelectedIndex();
1474: Insets insets = getSelectedTabPadInsets(tabPlacement);
1475: int w = 0;
1476: int h = 0;
1477:
1478: if (tabPlacement == TOP || tabPlacement == BOTTOM)
1479: {
1480: if (index > 0)
1481: {
1482: w += rects[index - 1].x + rects[index - 1].width;
1483: if (index > selectedIndex)
1484: w -= insets.left + insets.right;
1485: }
1486: }
1487:
1488: else
1489: {
1490: if (index > 0)
1491: {
1492: h += rects[index - 1].y + rects[index - 1].height;
1493: if (index > selectedIndex)
1494: h -= insets.top + insets.bottom;
1495: }
1496: }
1497:
1498: Point p = new Point(w, h);
1499: return p;
1500: }
1501:
1502:
1509: public static ComponentUI createUI(JComponent c)
1510: {
1511: return new BasicTabbedPaneUI();
1512: }
1513:
1514:
1519: public void installUI(JComponent c)
1520: {
1521: super.installUI(c);
1522: if (c instanceof JTabbedPane)
1523: {
1524: tabPane = (JTabbedPane) c;
1525:
1526: installComponents();
1527: installDefaults();
1528: installListeners();
1529: installKeyboardActions();
1530:
1531: layoutManager = createLayoutManager();
1532: tabPane.setLayout(layoutManager);
1533: }
1534: }
1535:
1536:
1541: public void uninstallUI(JComponent c)
1542: {
1543: layoutManager = null;
1544:
1545: uninstallKeyboardActions();
1546: uninstallListeners();
1547: uninstallDefaults();
1548: uninstallComponents();
1549:
1550: tabPane = null;
1551: }
1552:
1553:
1561: protected LayoutManager createLayoutManager()
1562: {
1563: if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
1564: return new TabbedPaneLayout();
1565: else
1566: {
1567: incrButton = createIncreaseButton();
1568: decrButton = createDecreaseButton();
1569: viewport = new ScrollingViewport();
1570: viewport.setLayout(null);
1571: panel = new ScrollingPanel();
1572: viewport.setView(panel);
1573: tabPane.add(incrButton);
1574: tabPane.add(decrButton);
1575: tabPane.add(viewport);
1576: currentScrollLocation = 0;
1577: decrButton.setEnabled(false);
1578: panel.addMouseListener(mouseListener);
1579: incrButton.addMouseListener(mouseListener);
1580: decrButton.addMouseListener(mouseListener);
1581: viewport.setBackground(Color.LIGHT_GRAY);
1582:
1583: return new TabbedPaneScrollLayout();
1584: }
1585: }
1586:
1587:
1590: protected void installComponents()
1591: {
1592:
1593: }
1594:
1595:
1598: protected void uninstallComponents()
1599: {
1600:
1601: }
1602:
1603:
1606: protected void installDefaults()
1607: {
1608: LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background",
1609: "TabbedPane.foreground",
1610: "TabbedPane.font");
1611: tabPane.setOpaque(false);
1612:
1613: highlight = UIManager.getColor("TabbedPane.highlight");
1614: lightHighlight = UIManager.getColor("TabbedPane.lightHighlight");
1615:
1616: shadow = UIManager.getColor("TabbedPane.shadow");
1617: darkShadow = UIManager.getColor("TabbedPane.darkShadow");
1618:
1619: focus = UIManager.getColor("TabbedPane.focus");
1620:
1621: textIconGap = UIManager.getInt("TabbedPane.textIconGap");
1622: tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay");
1623:
1624: tabInsets = UIManager.getInsets("TabbedPane.tabInsets");
1625: selectedTabPadInsets = UIManager.getInsets("TabbedPane.tabbedPaneTabPadInsets");
1626: tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
1627: contentBorderInsets = UIManager.getInsets("TabbedPane.tabbedPaneContentBorderInsets");
1628: tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
1629:
1630: calcRect = new Rectangle();
1631: tabRuns = new int[10];
1632: tabAreaRect = new Rectangle();
1633: contentRect = new Rectangle();
1634: }
1635:
1636:
1639: protected void uninstallDefaults()
1640: {
1641: calcRect = null;
1642: tabAreaRect = null;
1643: contentRect = null;
1644: tabRuns = null;
1645:
1646: contentBorderInsets = null;
1647: tabAreaInsets = null;
1648: selectedTabPadInsets = null;
1649: tabInsets = null;
1650:
1651: focus = null;
1652: darkShadow = null;
1653: shadow = null;
1654: lightHighlight = null;
1655: highlight = null;
1656:
1657:
1658: LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background",
1659: "TabbedPane.foreground",
1660: "TabbedPane.font");
1661: }
1662:
1663:
1666: protected void installListeners()
1667: {
1668: mouseListener = createMouseListener();
1669: tabChangeListener = createChangeListener();
1670: propertyChangeListener = createPropertyChangeListener();
1671: focusListener = createFocusListener();
1672:
1673: tabPane.addMouseListener(mouseListener);
1674: tabPane.addChangeListener(tabChangeListener);
1675: tabPane.addPropertyChangeListener(propertyChangeListener);
1676: tabPane.addFocusListener(focusListener);
1677: }
1678:
1679:
1682: protected void uninstallListeners()
1683: {
1684: tabPane.removeFocusListener(focusListener);
1685: tabPane.removePropertyChangeListener(propertyChangeListener);
1686: tabPane.removeChangeListener(tabChangeListener);
1687: tabPane.removeMouseListener(mouseListener);
1688:
1689: focusListener = null;
1690: propertyChangeListener = null;
1691: tabChangeListener = null;
1692: mouseListener = null;
1693: }
1694:
1695:
1700: protected MouseListener createMouseListener()
1701: {
1702: return new MouseHandler();
1703: }
1704:
1705:
1710: protected FocusListener createFocusListener()
1711: {
1712: return new FocusHandler();
1713: }
1714:
1715:
1720: protected ChangeListener createChangeListener()
1721: {
1722: return new TabSelectionHandler();
1723: }
1724:
1725:
1730: protected PropertyChangeListener createPropertyChangeListener()
1731: {
1732: return new PropertyChangeHandler();
1733: }
1734:
1735:
1738: protected void installKeyboardActions()
1739: throws NotImplementedException
1740: {
1741:
1742: }
1743:
1744:
1747: protected void uninstallKeyboardActions()
1748: throws NotImplementedException
1749: {
1750:
1751: }
1752:
1753:
1760: public Dimension getMinimumSize(JComponent c)
1761: {
1762: return layoutManager.minimumLayoutSize(tabPane);
1763: }
1764:
1765:
1772: public Dimension getMaximumSize(JComponent c)
1773: {
1774: return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
1775: }
1776:
1777:
1783: public void paint(Graphics g, JComponent c)
1784: {
1785: if (!tabPane.isValid())
1786: tabPane.validate();
1787:
1788: if (tabPane.getTabCount() == 0)
1789: return;
1790: if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
1791: paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
1792: paintContentBorder(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
1793: }
1794:
1795:
1803: protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex)
1804: {
1805: Rectangle ir = new Rectangle();
1806: Rectangle tr = new Rectangle();
1807:
1808: boolean isScroll = tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT;
1809:
1810:
1811:
1812: int tabCount = tabPane.getTabCount();
1813: for (int i = runCount - 1; i >= 0; --i)
1814: {
1815: int start = tabRuns[i];
1816: int next;
1817: if (i == runCount - 1)
1818: next = tabRuns[0];
1819: else
1820: next = tabRuns[i + 1];
1821: int end = (next != 0 ? next - 1 : tabCount - 1);
1822: for (int j = start; j <= end; ++j)
1823: {
1824: if (j != selectedIndex)
1825: {
1826: paintTab(g, tabPlacement, rects, j, ir, tr);
1827: }
1828: }
1829: }
1830:
1831:
1832: if (selectedIndex >= 0)
1833: paintTab(g, tabPlacement, rects, selectedIndex, ir, tr);
1834: }
1835:
1836:
1847: protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects,
1848: int tabIndex, Rectangle iconRect, Rectangle textRect)
1849: {
1850: Rectangle rect = rects[tabIndex];
1851: boolean isSelected = tabIndex == tabPane.getSelectedIndex();
1852:
1853: if (tabsOpaque || tabPane.isOpaque())
1854: {
1855: paintTabBackground(g, tabPlacement, tabIndex, rect.x, rect.y,
1856: rect.width, rect.height, isSelected);
1857: }
1858:
1859:
1860: paintTabBorder(g, tabPlacement, tabIndex, rect.x, rect.y, rect.width,
1861: rect.height, isSelected);
1862:
1863:
1864:
1865: FontMetrics fm = getFontMetrics();
1866: Icon icon = getIconForTab(tabIndex);
1867: String title = tabPane.getTitleAt(tabIndex);
1868: layoutLabel(tabPlacement, fm, tabIndex, title, icon, rect, iconRect,
1869: textRect, isSelected);
1870:
1871: paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title,
1872: textRect, isSelected);
1873:
1874: paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
1875:
1876: paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect, textRect,
1877: isSelected);
1878: }
1879:
1880:
1894: protected void layoutLabel(int tabPlacement, FontMetrics metrics,
1895: int tabIndex, String title, Icon icon,
1896: Rectangle tabRect, Rectangle iconRect,
1897: Rectangle textRect, boolean isSelected)
1898: {
1899: SwingUtilities.layoutCompoundLabel(metrics, title, icon,
1900: SwingConstants.CENTER,
1901: SwingConstants.CENTER,
1902: SwingConstants.CENTER,
1903: SwingConstants.RIGHT, tabRect,
1904: iconRect, textRect, textIconGap);
1905:
1906: int shiftX = getTabLabelShiftX(tabPlacement, tabIndex, isSelected);
1907: int shiftY = getTabLabelShiftY(tabPlacement, tabIndex, isSelected);
1908:
1909: iconRect.x += shiftX;
1910: iconRect.y += shiftY;
1911:
1912: textRect.x += shiftX;
1913: textRect.y += shiftY;
1914: }
1915:
1916:
1926: protected void paintIcon(Graphics g, int tabPlacement, int tabIndex,
1927: Icon icon, Rectangle iconRect, boolean isSelected)
1928: {
1929: if (icon != null)
1930: icon.paintIcon(tabPane, g, iconRect.x, iconRect.y);
1931: }
1932:
1933:
1945: protected void paintText(Graphics g, int tabPlacement, Font font,
1946: FontMetrics metrics, int tabIndex, String title,
1947: Rectangle textRect, boolean isSelected)
1948: {
1949: g.setFont(font);
1950: View textView = getTextViewForTab(tabIndex);
1951: if (textView != null)
1952: {
1953: textView.paint(g, textRect);
1954: return;
1955: }
1956:
1957: int ascent = metrics.getAscent();
1958:
1959: int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
1960: if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex))
1961: {
1962: Color fg = tabPane.getForegroundAt(tabIndex);
1963: if (isSelected && (fg instanceof UIResource))
1964: {
1965: Color selectionForeground =
1966: UIManager.getColor("TabbedPane.selectionForeground");
1967: if (selectionForeground != null)
1968: fg = selectionForeground;
1969: }
1970: g.setColor(fg);
1971:
1972: if (mnemIndex != -1)
1973: BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
1974: textRect.x,
1975: textRect.y + ascent);
1976: else
1977: g.drawString(title, textRect.x, textRect.y + ascent);
1978: }
1979: else
1980: {
1981: Color bg = tabPane.getBackgroundAt(tabIndex);
1982: g.setColor(bg.brighter());
1983: if (mnemIndex != -1)
1984: BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
1985: textRect.x, textRect.y
1986: + ascent);
1987: else
1988: g.drawString(title, textRect.x, textRect.y + ascent);
1989:
1990: g.setColor(bg.darker());
1991: if (mnemIndex != -1)
1992: BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
1993: textRect.x + 1,
1994: textRect.y + 1
1995: + ascent);
1996: else
1997: g.drawString(title, textRect.x + 1, textRect.y + 1 + ascent);
1998: }
1999: }
2000:
2001:
2011: protected int getTabLabelShiftX(int tabPlacement, int tabIndex,
2012: boolean isSelected)
2013: {
2014:
2015: return 0;
2016: }
2017:
2018:
2028: protected int getTabLabelShiftY(int tabPlacement, int tabIndex,
2029: boolean isSelected)
2030: {
2031:
2032: return 0;
2033: }
2034:
2035:
2046: protected void paintFocusIndicator(Graphics g, int tabPlacement,
2047: Rectangle[] rects, int tabIndex,
2048: Rectangle iconRect, Rectangle textRect,
2049: boolean isSelected)
2050: {
2051: if (tabPane.hasFocus() && isSelected)
2052: {
2053: Rectangle rect = rects[tabIndex];
2054:
2055: int x;
2056: int y;
2057: int w;
2058: int h;
2059:
2060: g.setColor(focus);
2061: switch (tabPlacement)
2062: {
2063: case LEFT:
2064: x = rect.x + 3;
2065: y = rect.y + 3;
2066: w = rect.width - 5;
2067: h = rect.height - 6;
2068: break;
2069: case RIGHT:
2070: x = rect.x + 2;
2071: y = rect.y + 3;
2072: w = rect.width - 6;
2073: h = rect.height - 5;
2074: break;
2075: case BOTTOM:
2076: x = rect.x + 3;
2077: y = rect.y + 2;
2078: w = rect.width - 6;
2079: h = rect.height - 5;
2080: break;
2081: case TOP:
2082: default:
2083: x = rect.x + 3;
2084: y = rect.y + 3;
2085: w = rect.width - 6;
2086: h = rect.height - 5;
2087: }
2088: BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
2089: }
2090: }
2091:
2092:
2104: protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex,
2105: int x, int y, int w, int h, boolean isSelected)
2106: {
2107: Color saved = g.getColor();
2108:
2109: if (! isSelected || tabPlacement != SwingConstants.TOP)
2110: {
2111: g.setColor(shadow);
2112: g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
2113: g.setColor(darkShadow);
2114: g.drawLine(x, y + h, x + w, y + h);
2115: }
2116:
2117: if (! isSelected || tabPlacement != SwingConstants.LEFT)
2118: {
2119: g.setColor(darkShadow);
2120: g.drawLine(x + w, y, x + w, y + h);
2121: g.setColor(shadow);
2122: g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
2123: }
2124:
2125: if (! isSelected || tabPlacement != SwingConstants.RIGHT)
2126: {
2127: g.setColor(lightHighlight);
2128: g.drawLine(x, y, x, y + h);
2129: }
2130:
2131: if (! isSelected || tabPlacement != SwingConstants.BOTTOM)
2132: {
2133: g.setColor(lightHighlight);
2134: g.drawLine(x, y, x + w, y);
2135: }
2136:
2137: g.setColor(saved);
2138: }
2139:
2140:
2152: protected void paintTabBackground(Graphics g, int tabPlacement,
2153: int tabIndex, int x, int y, int w, int h,
2154: boolean isSelected)
2155: {
2156: Color saved = g.getColor();
2157: if (isSelected)
2158: g.setColor(Color.LIGHT_GRAY);
2159: else
2160: {
2161: Color bg = tabPane.getBackgroundAt(tabIndex);
2162: if (bg == null)
2163: bg = Color.GRAY;
2164: g.setColor(bg);
2165: }
2166:
2167: g.fillRect(x, y, w, h);
2168:
2169: g.setColor(saved);
2170: }
2171:
2172:
2179: protected void paintContentBorder(Graphics g, int tabPlacement,
2180: int selectedIndex)
2181: {
2182: int width = tabPane.getWidth();
2183: int height = tabPane.getHeight();
2184: Insets insets = tabPane.getInsets();
2185: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
2186:
2187:
2188: int x = insets.left;
2189: int y = insets.top;
2190: int w = width - insets.left - insets.right;
2191: int h = height - insets.top - insets.bottom;
2192:
2193: switch (tabPlacement)
2194: {
2195: case LEFT:
2196: x += calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
2197: w -= (x - insets.left);
2198: break;
2199: case RIGHT:
2200: w -= calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
2201: break;
2202: case BOTTOM:
2203: h -= calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
2204: break;
2205: case TOP:
2206: default:
2207: y += calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
2208: h -= (y - insets.top);
2209: }
2210:
2211:
2212: if (tabPane.isOpaque())
2213: {
2214: Color bg = UIManager.getColor("TabbedPane.contentAreaColor");
2215: g.setColor(bg);
2216: g.fillRect(x, y, w, h);
2217: }
2218:
2219:
2220: paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2221: paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2222: paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2223: paintContentBorderRightEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2224: }
2225:
2226:
2237: protected void paintContentBorderTopEdge(Graphics g, int tabPlacement,
2238: int selectedIndex, int x, int y,
2239: int w, int h)
2240: {
2241: Color saved = g.getColor();
2242: g.setColor(lightHighlight);
2243:
2244: int startgap = rects[selectedIndex].x;
2245: int endgap = rects[selectedIndex].x + rects[selectedIndex].width;
2246:
2247: int diff = 0;
2248:
2249: if (tabPlacement == SwingConstants.TOP)
2250: {
2251: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2252: {
2253: Point p = findPointForIndex(currentScrollLocation);
2254: diff = p.x;
2255: }
2256:
2257: g.drawLine(x, y, startgap - diff, y);
2258: g.drawLine(endgap - diff, y, x + w, y);
2259: }
2260: else
2261: g.drawLine(x, y, x + w, y);
2262:
2263: g.setColor(saved);
2264: }
2265:
2266:
2277: protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement,
2278: int selectedIndex, int x, int y,
2279: int w, int h)
2280: {
2281: Color saved = g.getColor();
2282: g.setColor(lightHighlight);
2283:
2284: int startgap = rects[selectedIndex].y;
2285: int endgap = rects[selectedIndex].y + rects[selectedIndex].height;
2286:
2287: int diff = 0;
2288:
2289: if (tabPlacement == SwingConstants.LEFT)
2290: {
2291: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2292: {
2293: Point p = findPointForIndex(currentScrollLocation);
2294: diff = p.y;
2295: }
2296:
2297: g.drawLine(x, y, x, startgap - diff);
2298: g.drawLine(x, endgap - diff, x, y + h);
2299: }
2300: else
2301: g.drawLine(x, y, x, y + h);
2302:
2303: g.setColor(saved);
2304: }
2305:
2306:
2317: protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement,
2318: int selectedIndex, int x, int y,
2319: int w, int h)
2320: {
2321: Color saved = g.getColor();
2322:
2323: int startgap = rects[selectedIndex].x;
2324: int endgap = rects[selectedIndex].x + rects[selectedIndex].width;
2325:
2326: int diff = 0;
2327:
2328: if (tabPlacement == SwingConstants.BOTTOM)
2329: {
2330: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2331: {
2332: Point p = findPointForIndex(currentScrollLocation);
2333: diff = p.x;
2334: }
2335:
2336: g.setColor(shadow);
2337: g.drawLine(x + 1, y + h - 1, startgap - diff, y + h - 1);
2338: g.drawLine(endgap - diff, y + h - 1, x + w - 1, y + h - 1);
2339:
2340: g.setColor(darkShadow);
2341: g.drawLine(x, y + h, startgap - diff, y + h);
2342: g.drawLine(endgap - diff, y + h, x + w, y + h);
2343: }
2344: else
2345: {
2346: g.setColor(shadow);
2347: g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
2348: g.setColor(darkShadow);
2349: g.drawLine(x, y + h, x + w, y + h);
2350: }
2351:
2352: g.setColor(saved);
2353: }
2354:
2355:
2366: protected void paintContentBorderRightEdge(Graphics g, int tabPlacement,
2367: int selectedIndex, int x, int y,
2368: int w, int h)
2369: {
2370: Color saved = g.getColor();
2371: int startgap = rects[selectedIndex].y;
2372: int endgap = rects[selectedIndex].y + rects[selectedIndex].height;
2373:
2374: int diff = 0;
2375:
2376: if (tabPlacement == SwingConstants.RIGHT)
2377: {
2378: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2379: {
2380: Point p = findPointForIndex(currentScrollLocation);
2381: diff = p.y;
2382: }
2383:
2384: g.setColor(shadow);
2385: g.drawLine(x + w - 1, y + 1, x + w - 1, startgap - diff);
2386: g.drawLine(x + w - 1, endgap - diff, x + w - 1, y + h - 1);
2387:
2388: g.setColor(darkShadow);
2389: g.drawLine(x + w, y, x + w, startgap - diff);
2390: g.drawLine(x + w, endgap - diff, x + w, y + h);
2391: }
2392: else
2393: {
2394: g.setColor(shadow);
2395: g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
2396: g.setColor(darkShadow);
2397: g.drawLine(x + w, y, x + w, y + h);
2398: }
2399:
2400: g.setColor(saved);
2401: }
2402:
2403:
2411: public Rectangle getTabBounds(JTabbedPane pane, int i)
2412: {
2413: return rects[i];
2414: }
2415:
2416:
2423: public int getTabRunCount(JTabbedPane pane)
2424: {
2425: return runCount;
2426: }
2427:
2428:
2437: public int tabForCoordinate(JTabbedPane pane, int x, int y)
2438: {
2439: if (! tabPane.isValid())
2440: tabPane.validate();
2441:
2442: int tabCount = tabPane.getTabCount();
2443: int index = -1;
2444: for (int i = 0; i < tabCount; ++i)
2445: {
2446: if (rects[i].contains(x, y))
2447: {
2448: index = i;
2449: break;
2450: }
2451: }
2452:
2453:
2454:
2455: return index;
2456: }
2457:
2458:
2466: protected Rectangle getTabBounds(int tabIndex, Rectangle dest)
2467: {
2468: dest.setBounds(getTabBounds(tabPane, tabIndex));
2469: return dest;
2470: }
2471:
2472:
2477: protected Component getVisibleComponent()
2478: {
2479: return tabPane.getComponentAt(tabPane.getSelectedIndex());
2480: }
2481:
2482:
2487: protected void setVisibleComponent(Component component)
2488: {
2489: component.setVisible(true);
2490: tabPane.setSelectedComponent(component);
2491: }
2492:
2493:
2499: protected void assureRectsCreated(int tabCount)
2500: {
2501: if (rects.length < tabCount)
2502: {
2503: Rectangle[] old = rects;
2504: rects = new Rectangle[tabCount];
2505: System.arraycopy(old, 0, rects, 0, old.length);
2506: for (int i = old.length; i < rects.length; i++)
2507: rects[i] = new Rectangle();
2508: }
2509: }
2510:
2511:
2515: protected void expandTabRunsArray()
2516: {
2517:
2518: if (tabRuns == null)
2519: tabRuns = new int[10];
2520: else
2521: {
2522: int[] newRuns = new int[tabRuns.length + 10];
2523: System.arraycopy(tabRuns, 0, newRuns, 0, tabRuns.length);
2524: tabRuns = newRuns;
2525: }
2526: }
2527:
2528:
2536: protected int getRunForTab(int tabCount, int tabIndex)
2537: {
2538: if (runCount == 1 && tabIndex < tabCount && tabIndex >= 0)
2539: return 1;
2540: for (int i = 0; i < runCount; i++)
2541: {
2542: int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1;
2543: if (first == tabCount)
2544: first = 0;
2545: int last = lastTabInRun(tabCount, i);
2546: if (last >= tabIndex && first <= tabIndex)
2547: return i;
2548: }
2549: return -1;
2550: }
2551:
2552:
2560: protected int lastTabInRun(int tabCount, int run)
2561: {
2562: int lastTab;
2563: if (runCount == 1)
2564: lastTab = tabCount - 1;
2565: else
2566: {
2567: int nextRun;
2568: if (run == runCount - 1)
2569: nextRun = 0;
2570: else
2571: nextRun = run + 1;
2572:
2573: if (tabRuns[nextRun] == 0)
2574: lastTab = tabCount - 1;
2575: else
2576: lastTab = tabRuns[nextRun] - 1;
2577: }
2578: return lastTab;
2579: }
2580:
2581:
2588: protected int getTabRunOverlay(int tabPlacement)
2589: {
2590: return tabRunOverlay;
2591: }
2592:
2593:
2602: protected int getTabRunIndent(int tabPlacement, int run)
2603: {
2604: return 0;
2605: }
2606:
2607:
2615: protected boolean shouldPadTabRun(int tabPlacement, int run)
2616: {
2617: return true;
2618: }
2619:
2620:
2627: protected boolean shouldRotateTabRuns(int tabPlacement)
2628: {
2629: return true;
2630: }
2631:
2632:
2641: protected Icon getIconForTab(int tabIndex)
2642: {
2643: if (tabPane.isEnabledAt(tabIndex))
2644: return tabPane.getIconAt(tabIndex);
2645: else
2646: return tabPane.getDisabledIconAt(tabIndex);
2647: }
2648:
2649:
2656: protected View getTextViewForTab(int tabIndex)
2657: {
2658: return null;
2659: }
2660:
2661:
2671: protected int calculateTabHeight(int tabPlacement, int tabIndex,
2672: int fontHeight)
2673: {
2674:
2675:
2676: int height = fontHeight;
2677: Icon icon = getIconForTab(tabIndex);
2678: Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
2679: if (icon != null)
2680: height = Math.max(height, icon.getIconHeight());
2681: height += tabInsets.top + tabInsets.bottom + 2;
2682: return height;
2683: }
2684:
2685:
2692: protected int calculateMaxTabHeight(int tabPlacement)
2693: {
2694: maxTabHeight = 0;
2695:
2696: FontMetrics fm = getFontMetrics();
2697: int fontHeight = fm.getHeight();
2698:
2699: for (int i = 0; i < tabPane.getTabCount(); i++)
2700: maxTabHeight = Math.max(calculateTabHeight(tabPlacement, i, fontHeight),
2701: maxTabHeight);
2702:
2703: return maxTabHeight;
2704: }
2705:
2706:
2716: protected int calculateTabWidth(int tabPlacement, int tabIndex,
2717: FontMetrics metrics)
2718: {
2719: Icon icon = getIconForTab(tabIndex);
2720: Insets insets = getTabInsets(tabPlacement, tabIndex);
2721:
2722: int width = 0;
2723: if (icon != null)
2724: {
2725: Rectangle vr = new Rectangle();
2726: Rectangle ir = new Rectangle();
2727: Rectangle tr = new Rectangle();
2728: layoutLabel(tabPlacement, getFontMetrics(), tabIndex,
2729: tabPane.getTitleAt(tabIndex), icon, vr, ir, tr,
2730: tabIndex == tabPane.getSelectedIndex());
2731: width = tr.union(ir).width;
2732: }
2733: else
2734: width = metrics.stringWidth(tabPane.getTitleAt(tabIndex));
2735:
2736: width += insets.left + insets.right;
2737: return width;
2738: }
2739:
2740:
2747: protected int calculateMaxTabWidth(int tabPlacement)
2748: {
2749: maxTabWidth = 0;
2750:
2751: FontMetrics fm = getFontMetrics();
2752:
2753: for (int i = 0; i < tabPane.getTabCount(); i++)
2754: maxTabWidth = Math.max(calculateTabWidth(tabPlacement, i, fm),
2755: maxTabWidth);
2756:
2757: return maxTabWidth;
2758: }
2759:
2760:
2770: protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount,
2771: int maxTabHeight)
2772: {
2773: Insets insets = getTabAreaInsets(tabPlacement);
2774: int tabAreaHeight = horizRunCount * maxTabHeight
2775: - (horizRunCount - 1) * tabRunOverlay;
2776:
2777: tabAreaHeight += insets.top + insets.bottom;
2778:
2779: return tabAreaHeight;
2780: }
2781:
2782:
2792: protected int calculateTabAreaWidth(int tabPlacement, int vertRunCount,
2793: int maxTabWidth)
2794: {
2795: Insets insets = getTabAreaInsets(tabPlacement);
2796: int tabAreaWidth = vertRunCount * maxTabWidth
2797: - (vertRunCount - 1) * tabRunOverlay;
2798:
2799: tabAreaWidth += insets.left + insets.right;
2800:
2801: return tabAreaWidth;
2802: }
2803:
2804:
2812: protected Insets getTabInsets(int tabPlacement, int tabIndex)
2813: {
2814: return tabInsets;
2815: }
2816:
2817:
2824: protected Insets getSelectedTabPadInsets(int tabPlacement)
2825: {
2826: Insets target = new Insets(0, 0, 0, 0);
2827: rotateInsets(selectedTabPadInsets, target, tabPlacement);
2828: return target;
2829: }
2830:
2831:
2838: protected Insets getTabAreaInsets(int tabPlacement)
2839: {
2840: Insets target = new Insets(0, 0, 0, 0);
2841: rotateInsets(tabAreaInsets, target, tabPlacement);
2842: return target;
2843: }
2844:
2845:
2852: protected Insets getContentBorderInsets(int tabPlacement)
2853: {
2854: Insets target = new Insets(0, 0, 0, 0);
2855: rotateInsets(contentBorderInsets, target, tabPlacement);
2856: return target;
2857: }
2858:
2859:
2864: protected FontMetrics getFontMetrics()
2865: {
2866: FontMetrics fm = tabPane.getFontMetrics(tabPane.getFont());
2867: return fm;
2868: }
2869:
2870:
2876: protected void navigateSelectedTab(int direction)
2877: {
2878: int tabPlacement = tabPane.getTabPlacement();
2879: if (tabPlacement == SwingConstants.TOP
2880: || tabPlacement == SwingConstants.BOTTOM)
2881: {
2882: if (direction == SwingConstants.WEST)
2883: selectPreviousTabInRun(tabPane.getSelectedIndex());
2884: else if (direction == SwingConstants.EAST)
2885: selectNextTabInRun(tabPane.getSelectedIndex());
2886:
2887: else
2888: {
2889: int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
2890: tabPane.getSelectedIndex(),
2891: (tabPlacement == SwingConstants.RIGHT)
2892: ? true : false);
2893: selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
2894: offset);
2895: }
2896: }
2897: if (tabPlacement == SwingConstants.LEFT
2898: || tabPlacement == SwingConstants.RIGHT)
2899: {
2900: if (direction == SwingConstants.NORTH)
2901: selectPreviousTabInRun(tabPane.getSelectedIndex());
2902: else if (direction == SwingConstants.SOUTH)
2903: selectNextTabInRun(tabPane.getSelectedIndex());
2904: else
2905: {
2906: int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
2907: tabPane.getSelectedIndex(),
2908: (tabPlacement == SwingConstants.RIGHT)
2909: ? true : false);
2910: selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
2911: offset);
2912: }
2913: }
2914: }
2915:
2916:
2921: protected void selectNextTabInRun(int current)
2922: {
2923: tabPane.setSelectedIndex(getNextTabIndexInRun(tabPane.getTabCount(),
2924: current));
2925: }
2926:
2927:
2932: protected void selectPreviousTabInRun(int current)
2933: {
2934: tabPane.setSelectedIndex(getPreviousTabIndexInRun(tabPane.getTabCount(),
2935: current));
2936: }
2937:
2938:
2943: protected void selectNextTab(int current)
2944: {
2945: tabPane.setSelectedIndex(getNextTabIndex(current));
2946: }
2947:
2948:
2953: protected void selectPreviousTab(int current)
2954: {
2955: tabPane.setSelectedIndex(getPreviousTabIndex(current));
2956: }
2957:
2958:
2969: protected void selectAdjacentRunTab(int tabPlacement, int tabIndex,
2970: int offset)
2971: {
2972: int x = rects[tabIndex].x + rects[tabIndex].width / 2;
2973: int y = rects[tabIndex].y + rects[tabIndex].height / 2;
2974:
2975: switch (tabPlacement)
2976: {
2977: case SwingConstants.TOP:
2978: case SwingConstants.BOTTOM:
2979: y += offset;
2980: break;
2981: case SwingConstants.RIGHT:
2982: case SwingConstants.LEFT:
2983: x += offset;
2984: break;
2985: }
2986:
2987: int index = tabForCoordinate(tabPane, x, y);
2988: if (index != -1)
2989: tabPane.setSelectedIndex(index);
2990: }
2991:
2992:
2993:
2994:
2995:
2996:
2997:
2998:
3013: protected int getTabRunOffset(int tabPlacement, int tabCount, int tabIndex,
3014: boolean forward)
3015: {
3016: int currRun = getRunForTab(tabCount, tabIndex);
3017: int offset;
3018: int nextRun = (forward) ? getNextTabRun(currRun) : getPreviousTabRun(currRun);
3019: if (tabPlacement == SwingConstants.TOP
3020: || tabPlacement == SwingConstants.BOTTOM)
3021: offset = rects[lastTabInRun(tabCount, nextRun)].y
3022: - rects[lastTabInRun(tabCount, currRun)].y;
3023: else
3024: offset = rects[lastTabInRun(tabCount, nextRun)].x
3025: - rects[lastTabInRun(tabCount, currRun)].x;
3026: return offset;
3027: }
3028:
3029:
3036: protected int getPreviousTabIndex(int base)
3037: {
3038: base--;
3039: if (base < 0)
3040: return tabPane.getTabCount() - 1;
3041: return base;
3042: }
3043:
3044:
3051: protected int getNextTabIndex(int base)
3052: {
3053: base++;
3054: if (base == tabPane.getTabCount())
3055: return 0;
3056: return base;
3057: }
3058:
3059:
3068: protected int getNextTabIndexInRun(int tabCount, int base)
3069: {
3070: int index = getNextTabIndex(base);
3071: int run = getRunForTab(tabCount, base);
3072: if (index == lastTabInRun(tabCount, run) + 1)
3073: index = lastTabInRun(tabCount, getPreviousTabRun(run)) + 1;
3074: return getNextTabIndex(base);
3075: }
3076:
3077:
3086: protected int getPreviousTabIndexInRun(int tabCount, int base)
3087: {
3088: int index = getPreviousTabIndex(base);
3089: int run = getRunForTab(tabCount, base);
3090: if (index == lastTabInRun(tabCount, getPreviousTabRun(run)))
3091: index = lastTabInRun(tabCount, run);
3092: return getPreviousTabIndex(base);
3093: }
3094:
3095:
3102: protected int getPreviousTabRun(int baseRun)
3103: {
3104: if (getTabRunCount(tabPane) == 1)
3105: return 1;
3106:
3107: int prevRun = --baseRun;
3108: if (prevRun < 0)
3109: prevRun = getTabRunCount(tabPane) - 1;
3110: return prevRun;
3111: }
3112:
3113:
3120: protected int getNextTabRun(int baseRun)
3121: {
3122: if (getTabRunCount(tabPane) == 1)
3123: return 1;
3124:
3125: int nextRun = ++baseRun;
3126: if (nextRun == getTabRunCount(tabPane))
3127: nextRun = 0;
3128: return nextRun;
3129: }
3130:
3131:
3143: protected static void rotateInsets(Insets topInsets, Insets targetInsets,
3144: int targetPlacement)
3145: {
3146:
3147:
3148: switch (targetPlacement)
3149: {
3150: case SwingConstants.TOP:
3151: targetInsets.top = topInsets.top;
3152: targetInsets.left = topInsets.left;
3153: targetInsets.right = topInsets.right;
3154: targetInsets.bottom = topInsets.bottom;
3155: break;
3156: case SwingConstants.LEFT:
3157: targetInsets.left = topInsets.top;
3158: targetInsets.top = topInsets.left;
3159: targetInsets.right = topInsets.bottom;
3160: targetInsets.bottom = topInsets.right;
3161: break;
3162: case SwingConstants.BOTTOM:
3163: targetInsets.top = topInsets.bottom;
3164: targetInsets.bottom = topInsets.top;
3165: targetInsets.left = topInsets.left;
3166: targetInsets.right = topInsets.right;
3167: break;
3168: case SwingConstants.RIGHT:
3169: targetInsets.top = topInsets.left;
3170: targetInsets.left = topInsets.bottom;
3171: targetInsets.bottom = topInsets.right;
3172: targetInsets.right = topInsets.top;
3173: break;
3174: }
3175: }
3176:
3177:
3187: protected void setRolloverTab(int index)
3188: {
3189: rolloverTab = index;
3190: }
3191:
3192:
3201: protected int getRolloverTab()
3202: {
3203: return rolloverTab;
3204: }
3205: }