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: if (runWidth + width > max)
358: {
359: runWidth = tabAreaInsets.left + insets.left
360: + getTabRunIndent(tabPlacement, ++runs);
361: rects[i] = new Rectangle(runWidth,
362: insets.top + tabAreaInsets.top,
363: width, maxHeight);
364: runWidth += width;
365: if (runs > tabRuns.length - 1)
366: expandTabRunsArray();
367: tabRuns[runs] = i;
368: }
369: else
370: {
371: rects[i] = new Rectangle(runWidth,
372: insets.top + tabAreaInsets.top,
373: width, maxHeight);
374: runWidth += width;
375: }
376: }
377: runs++;
378: tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right;
379: tabAreaRect.height = runs * maxTabHeight
380: - (runs - 1) * tabRunOverlay
381: + tabAreaInsets.top + tabAreaInsets.bottom;
382: contentRect.width = tabAreaRect.width;
383: contentRect.height = tabPane.getHeight() - insets.top
384: - insets.bottom - tabAreaRect.height;
385: contentRect.x = insets.left;
386: tabAreaRect.x = insets.left;
387: if (tabPlacement == SwingConstants.BOTTOM)
388: {
389: contentRect.y = insets.top;
390: tabAreaRect.y = contentRect.y + contentRect.height;
391: }
392: else
393: {
394: tabAreaRect.y = insets.top;
395: contentRect.y = tabAreaRect.y + tabAreaRect.height;
396: }
397: }
398: else
399: {
400: int maxWidth = calculateMaxTabWidth(tabPlacement);
401: calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom;
402: max = calcRect.height + tabAreaInsets.top + insets.top;
403:
404: int height = 0;
405: start += tabAreaInsets.top + insets.top;
406: int runHeight = start;
407:
408: int fontHeight = fm.getHeight();
409:
410: for (int i = 0; i < tabCount; i++)
411: {
412: height = calculateTabHeight(tabPlacement, i, fontHeight);
413: if (runHeight + height > max)
414: {
415: runHeight = tabAreaInsets.top + insets.top
416: + getTabRunIndent(tabPlacement, ++runs);
417: rects[i] = new Rectangle(insets.left + tabAreaInsets.left,
418: runHeight, maxWidth, height);
419: runHeight += height;
420: if (runs > tabRuns.length - 1)
421: expandTabRunsArray();
422: tabRuns[runs] = i;
423: }
424: else
425: {
426: rects[i] = new Rectangle(insets.left + tabAreaInsets.left,
427: runHeight, maxWidth, height);
428: runHeight += height;
429: }
430: }
431: runs++;
432:
433: tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay
434: + tabAreaInsets.left + tabAreaInsets.right;
435: tabAreaRect.height = tabPane.getHeight() - insets.top
436: - insets.bottom;
437: tabAreaRect.y = insets.top;
438: contentRect.width = tabPane.getWidth() - insets.left - insets.right
439: - tabAreaRect.width;
440: contentRect.height = tabAreaRect.height;
441: contentRect.y = insets.top;
442: if (tabPlacement == SwingConstants.LEFT)
443: {
444: tabAreaRect.x = insets.left;
445: contentRect.x = tabAreaRect.x + tabAreaRect.width;
446: }
447: else
448: {
449: contentRect.x = insets.left;
450: tabAreaRect.x = contentRect.x + contentRect.width;
451: }
452: }
453: runCount = runs;
454:
455: tabRuns[0] = 0;
456: normalizeTabRuns(tabPlacement, tabCount, start, max);
457: selectedRun = getRunForTab(tabCount, tabPane.getSelectedIndex());
458: if (shouldRotateTabRuns(tabPlacement))
459: rotateTabRuns(tabPlacement, selectedRun);
460:
461:
462: for (int i = 0; i < runCount; i++)
463: {
464: int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1;
465: if (first == tabCount)
466: first = 0;
467: int last = lastTabInRun(tabCount, i);
468: if (shouldPadTabRun(tabPlacement, i))
469: padTabRun(tabPlacement, first, last, max);
470:
471:
472: if (tabPlacement == SwingConstants.TOP && i > 0)
473: {
474: for (int j = first; j <= last; j++)
475: rects[j].y += (runCount - i) * maxTabHeight
476: - (runCount - i) * tabRunOverlay;
477: }
478:
479: if (tabPlacement == SwingConstants.BOTTOM)
480: {
481: int height = tabPane.getBounds().height - insets.bottom
482: - tabAreaInsets.bottom;
483: int adjustment;
484: if (i == 0)
485: adjustment = height - maxTabHeight;
486: else
487: adjustment = height - (runCount - i + 1) * maxTabHeight
488: - (runCount - i) * tabRunOverlay;
489:
490: for (int j = first; j <= last; j++)
491: rects[j].y = adjustment;
492: }
493:
494: if (tabPlacement == SwingConstants.LEFT && i > 0)
495: {
496: for (int j = first; j <= last; j++)
497: rects[j].x += (runCount - i) * maxTabWidth
498: - (runCount - i) * tabRunOverlay;
499: }
500:
501: if (tabPlacement == SwingConstants.RIGHT)
502: {
503: int width = tabPane.getBounds().width - insets.right
504: - tabAreaInsets.right;
505: int adjustment;
506: if (i == 0)
507: adjustment = width - maxTabWidth;
508: else
509: adjustment = width - (runCount - i + 1) * maxTabWidth
510: + (runCount - i) * tabRunOverlay;
511:
512: for (int j = first; j <= last; j++)
513: rects[j].x = adjustment;
514: }
515: }
516: padSelectedTab(tabPlacement, tabPane.getSelectedIndex());
517: }
518:
519:
526: public void layoutContainer(Container parent)
527: {
528: calculateLayoutInfo();
529: }
530:
531:
538: public Dimension minimumLayoutSize(Container parent)
539: {
540: return calculateSize(false);
541: }
542:
543:
544:
545:
546:
547:
548:
549:
550:
551:
560: protected void normalizeTabRuns(int tabPlacement, int tabCount, int start,
561: int max)
562: {
563: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
564: if (tabPlacement == SwingUtilities.TOP
565: || tabPlacement == SwingUtilities.BOTTOM)
566: {
567:
568:
569: for (int i = 1; i < runCount; i++)
570: {
571: Rectangle currRun = rects[lastTabInRun(tabCount, i)];
572: Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))];
573: int spaceInCurr = currRun.x + currRun.width;
574: int spaceInNext = nextRun.x + nextRun.width;
575:
576: int diffNow = spaceInCurr - spaceInNext;
577: int diffLater = (spaceInCurr - currRun.width)
578: - (spaceInNext + currRun.width);
579: while (Math.abs(diffLater) < Math.abs(diffNow)
580: && spaceInNext + currRun.width < max)
581: {
582: tabRuns[i]--;
583: spaceInNext += currRun.width;
584: spaceInCurr -= currRun.width;
585: currRun = rects[lastTabInRun(tabCount, i)];
586: diffNow = spaceInCurr - spaceInNext;
587: diffLater = (spaceInCurr - currRun.width)
588: - (spaceInNext + currRun.width);
589: }
590:
591:
592: int first = lastTabInRun(tabCount, i) + 1;
593: int last = lastTabInRun(tabCount, getNextTabRun(i));
594: int currX = tabAreaInsets.left;
595: for (int j = first; j <= last; j++)
596: {
597: rects[j].x = currX;
598: currX += rects[j].width;
599: }
600: }
601: }
602: else
603: {
604: for (int i = 1; i < runCount; i++)
605: {
606: Rectangle currRun = rects[lastTabInRun(tabCount, i)];
607: Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))];
608: int spaceInCurr = currRun.y + currRun.height;
609: int spaceInNext = nextRun.y + nextRun.height;
610:
611: int diffNow = spaceInCurr - spaceInNext;
612: int diffLater = (spaceInCurr - currRun.height)
613: - (spaceInNext + currRun.height);
614: while (Math.abs(diffLater) < Math.abs(diffNow)
615: && spaceInNext + currRun.height < max)
616: {
617: tabRuns[i]--;
618: spaceInNext += currRun.height;
619: spaceInCurr -= currRun.height;
620: currRun = rects[lastTabInRun(tabCount, i)];
621: diffNow = spaceInCurr - spaceInNext;
622: diffLater = (spaceInCurr - currRun.height)
623: - (spaceInNext + currRun.height);
624: }
625:
626: int first = lastTabInRun(tabCount, i) + 1;
627: int last = lastTabInRun(tabCount, getNextTabRun(i));
628: int currY = tabAreaInsets.top;
629: for (int j = first; j <= last; j++)
630: {
631: rects[j].y = currY;
632: currY += rects[j].height;
633: }
634: }
635: }
636: }
637:
638:
645: protected void padSelectedTab(int tabPlacement, int selectedIndex)
646: {
647: Insets insets = getSelectedTabPadInsets(tabPlacement);
648: rects[selectedIndex].x -= insets.left;
649: rects[selectedIndex].y -= insets.top;
650: rects[selectedIndex].width += insets.left + insets.right;
651: rects[selectedIndex].height += insets.top + insets.bottom;
652: }
653:
654:
655:
656:
657:
658:
659:
660:
670: protected void padTabRun(int tabPlacement, int start, int end, int max)
671: {
672: if (tabPlacement == SwingConstants.TOP
673: || tabPlacement == SwingConstants.BOTTOM)
674: {
675: int runWidth = rects[end].x + rects[end].width;
676: int spaceRemaining = max - runWidth;
677: int numTabs = end - start + 1;
678:
679:
680: int spaceAllocated = spaceRemaining / numTabs;
681: int currX = rects[start].x;
682: for (int i = start; i <= end; i++)
683: {
684: rects[i].x = currX;
685: rects[i].width += spaceAllocated;
686: currX += rects[i].width;
687:
688:
689:
690:
691: if (i == end && rects[i].x + rects[i].width != max)
692: rects[i].width = max - rects[i].x;
693: }
694: }
695: else
696: {
697: int runHeight = rects[end].y + rects[end].height;
698: int spaceRemaining = max - runHeight;
699: int numTabs = end - start + 1;
700:
701: int spaceAllocated = spaceRemaining / numTabs;
702: int currY = rects[start].y;
703: for (int i = start; i <= end; i++)
704: {
705: rects[i].y = currY;
706: rects[i].height += spaceAllocated;
707: currY += rects[i].height;
708: if (i == end && rects[i].y + rects[i].height != max)
709: rects[i].height = max - rects[i].y;
710: }
711: }
712: }
713:
714:
721: public Dimension preferredLayoutSize(Container parent)
722: {
723: return calculateSize(false);
724: }
725:
726:
735: protected int preferredTabAreaHeight(int tabPlacement, int width)
736: {
737: if (tabPane.getTabCount() == 0)
738: return calculateTabAreaHeight(tabPlacement, 0, 0);
739:
740: int runs = 0;
741: int runWidth = 0;
742: int tabWidth = 0;
743:
744: FontMetrics fm = getFontMetrics();
745:
746: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
747: Insets insets = tabPane.getInsets();
748:
749:
750: width -= tabAreaInsets.left + tabAreaInsets.right + insets.left
751: + insets.right;
752:
753:
754:
755:
756:
757:
758: for (int i = 0; i < tabPane.getTabCount(); i++)
759: {
760: tabWidth = calculateTabWidth(tabPlacement, i, fm);
761: if (runWidth + tabWidth > width)
762: {
763: runWidth = tabWidth;
764: runs++;
765: }
766: else
767: runWidth += tabWidth;
768: }
769: runs++;
770:
771: int maxTabHeight = calculateMaxTabHeight(tabPlacement);
772: int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs,
773: maxTabHeight);
774: return tabAreaHeight;
775: }
776:
777:
786: protected int preferredTabAreaWidth(int tabPlacement, int height)
787: {
788: if (tabPane.getTabCount() == 0)
789: return calculateTabAreaHeight(tabPlacement, 0, 0);
790:
791: int runs = 0;
792: int runHeight = 0;
793: int tabHeight = 0;
794:
795: FontMetrics fm = getFontMetrics();
796:
797: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
798: Insets insets = tabPane.getInsets();
799:
800: height -= tabAreaInsets.top + tabAreaInsets.bottom + insets.top
801: + insets.bottom;
802: int fontHeight = fm.getHeight();
803:
804: for (int i = 0; i < tabPane.getTabCount(); i++)
805: {
806: tabHeight = calculateTabHeight(tabPlacement, i, fontHeight);
807: if (runHeight + tabHeight > height)
808: {
809: runHeight = tabHeight;
810: runs++;
811: }
812: else
813: runHeight += tabHeight;
814: }
815: runs++;
816:
817: int maxTabWidth = calculateMaxTabWidth(tabPlacement);
818: int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth);
819: return tabAreaWidth;
820: }
821:
822:
830: protected void rotateTabRuns(int tabPlacement, int selectedRun)
831: {
832: if (runCount == 1 || selectedRun == 1 || selectedRun == -1)
833: return;
834: int[] newTabRuns = new int[tabRuns.length];
835: int currentRun = selectedRun;
836: int i = 1;
837: do
838: {
839: newTabRuns[i] = tabRuns[currentRun];
840: currentRun = getNextTabRun(currentRun);
841: i++;
842: }
843: while (i < runCount);
844: if (runCount > 1)
845: newTabRuns[0] = tabRuns[currentRun];
846:
847: tabRuns = newTabRuns;
848: BasicTabbedPaneUI.this.selectedRun = 1;
849: }
850:
851:
857: public void removeLayoutComponent(Component comp)
858: {
859:
860: }
861: }
862:
863:
867: private class TabbedPaneScrollLayout extends TabbedPaneLayout
868: {
869:
876: public Dimension preferredLayoutSize(Container parent)
877: {
878: return super.calculateSize(true);
879: }
880:
881:
888: public Dimension minimumLayoutSize(Container parent)
889: {
890: return super.calculateSize(true);
891: }
892:
893:
901: protected int preferredTabAreaHeight(int tabPlacement, int width)
902: {
903: if (tabPane.getTabCount() == 0)
904: return calculateTabAreaHeight(tabPlacement, 0, 0);
905:
906: int runs = 1;
907:
908: int maxTabHeight = calculateMaxTabHeight(tabPlacement);
909: int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs,
910: maxTabHeight);
911: return tabAreaHeight;
912: }
913:
914:
922: protected int preferredTabAreaWidth(int tabPlacement, int height)
923: {
924: if (tabPane.getTabCount() == 0)
925: return calculateTabAreaHeight(tabPlacement, 0, 0);
926:
927: int runs = 1;
928:
929: int maxTabWidth = calculateMaxTabWidth(tabPlacement);
930: int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth);
931: return tabAreaWidth;
932: }
933:
934:
943: protected void calculateTabRects(int tabPlacement, int tabCount)
944: {
945: if (tabCount == 0)
946: return;
947: assureRectsCreated(tabCount);
948:
949: FontMetrics fm = getFontMetrics();
950: SwingUtilities.calculateInnerArea(tabPane, calcRect);
951: Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
952: Insets insets = tabPane.getInsets();
953: int max = 0;
954: int runs = 1;
955: int start = 0;
956: int top = 0;
957: if (tabPlacement == SwingConstants.TOP
958: || tabPlacement == SwingConstants.BOTTOM)
959: {
960: int maxHeight = calculateMaxTabHeight(tabPlacement);
961: calcRect.width -= tabAreaInsets.left + tabAreaInsets.right;
962: max = calcRect.width + tabAreaInsets.left + insets.left;
963: start = tabAreaInsets.left + insets.left;
964: int width = 0;
965: int runWidth = start;
966: top = insets.top + tabAreaInsets.top;
967: for (int i = 0; i < tabCount; i++)
968: {
969: width = calculateTabWidth(tabPlacement, i, fm);
970:
971: rects[i] = new Rectangle(runWidth, top, width, maxHeight);
972: runWidth += width;
973: }
974: tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right;
975: tabAreaRect.height = runs * maxTabHeight
976: - (runs - 1) * tabRunOverlay
977: + tabAreaInsets.top + tabAreaInsets.bottom;
978: contentRect.width = tabAreaRect.width;
979: contentRect.height = tabPane.getHeight() - insets.top
980: - insets.bottom - tabAreaRect.height;
981: contentRect.x = insets.left;
982: tabAreaRect.x = insets.left;
983: if (tabPlacement == SwingConstants.BOTTOM)
984: {
985: contentRect.y = insets.top;
986: tabAreaRect.y = contentRect.y + contentRect.height;
987: }
988: else
989: {
990: tabAreaRect.y = insets.top;
991: contentRect.y = tabAreaRect.y + tabAreaRect.height;
992: }
993: }
994: else
995: {
996: int maxWidth = calculateMaxTabWidth(tabPlacement);
997:
998: calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom;
999: max = calcRect.height + tabAreaInsets.top;
1000: int height = 0;
1001: start = tabAreaInsets.top + insets.top;
1002: int runHeight = start;
1003: int fontHeight = fm.getHeight();
1004: top = insets.left + tabAreaInsets.left;
1005: for (int i = 0; i < tabCount; i++)
1006: {
1007: height = calculateTabHeight(tabPlacement, i, fontHeight);
1008: rects[i] = new Rectangle(top, runHeight, maxWidth, height);
1009: runHeight += height;
1010: }
1011: tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay
1012: + tabAreaInsets.left + tabAreaInsets.right;
1013: tabAreaRect.height = tabPane.getHeight() - insets.top
1014: - insets.bottom;
1015: tabAreaRect.y = insets.top;
1016: contentRect.width = tabPane.getWidth() - insets.left - insets.right
1017: - tabAreaRect.width;
1018: contentRect.height = tabAreaRect.height;
1019: contentRect.y = insets.top;
1020: if (tabPlacement == SwingConstants.LEFT)
1021: {
1022: tabAreaRect.x = insets.left;
1023: contentRect.x = tabAreaRect.x + tabAreaRect.width;
1024: }
1025: else
1026: {
1027: contentRect.x = insets.left;
1028: tabAreaRect.x = contentRect.x + contentRect.width;
1029: }
1030: }
1031: runCount = runs;
1032:
1033: padSelectedTab(tabPlacement, tabPane.getSelectedIndex());
1034: }
1035:
1036:
1043: public void layoutContainer(Container pane)
1044: {
1045: super.layoutContainer(pane);
1046: int tabCount = tabPane.getTabCount();
1047: Point p = null;
1048: if (tabCount == 0)
1049: return;
1050: int tabPlacement = tabPane.getTabPlacement();
1051: incrButton.hide();
1052: decrButton.hide();
1053: if (tabPlacement == SwingConstants.TOP
1054: || tabPlacement == SwingConstants.BOTTOM)
1055: {
1056: if (tabAreaRect.x + tabAreaRect.width < rects[tabCount - 1].x
1057: + rects[tabCount - 1].width)
1058: {
1059: Dimension incrDims = incrButton.getPreferredSize();
1060: Dimension decrDims = decrButton.getPreferredSize();
1061:
1062: decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
1063: - incrDims.width - decrDims.width,
1064: tabAreaRect.y, decrDims.width,
1065: tabAreaRect.height);
1066: incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
1067: - incrDims.width, tabAreaRect.y,
1068: decrDims.width, tabAreaRect.height);
1069:
1070: tabAreaRect.width -= decrDims.width + incrDims.width;
1071: incrButton.show();
1072: decrButton.show();
1073: }
1074: }
1075:
1076: if (tabPlacement == SwingConstants.LEFT
1077: || tabPlacement == SwingConstants.RIGHT)
1078: {
1079: if (tabAreaRect.y + tabAreaRect.height < rects[tabCount - 1].y
1080: + rects[tabCount - 1].height)
1081: {
1082: Dimension incrDims = incrButton.getPreferredSize();
1083: Dimension decrDims = decrButton.getPreferredSize();
1084:
1085: decrButton.setBounds(tabAreaRect.x,
1086: tabAreaRect.y + tabAreaRect.height
1087: - incrDims.height - decrDims.height,
1088: tabAreaRect.width, decrDims.height);
1089: incrButton.setBounds(tabAreaRect.x,
1090: tabAreaRect.y + tabAreaRect.height
1091: - incrDims.height, tabAreaRect.width,
1092: incrDims.height);
1093:
1094: tabAreaRect.height -= decrDims.height + incrDims.height;
1095: incrButton.show();
1096: decrButton.show();
1097: }
1098: }
1099: viewport.setBounds(tabAreaRect.x, tabAreaRect.y, tabAreaRect.width,
1100: tabAreaRect.height);
1101: int tabC = tabPane.getTabCount() - 1;
1102: if (tabCount > 0)
1103: {
1104: int w = Math.max(rects[tabC].width + rects[tabC].x, tabAreaRect.width);
1105: int h = Math.max(rects[tabC].height, tabAreaRect.height);
1106: p = findPointForIndex(currentScrollLocation);
1107:
1108:
1109:
1110: panel.setSize(w + p.x, h + p.y);
1111: }
1112: viewport.setViewPosition(p);
1113: viewport.repaint();
1114: }
1115: }
1116:
1117:
1124: public class TabSelectionHandler implements ChangeListener
1125: {
1126:
1132: public void stateChanged(ChangeEvent e)
1133: {
1134: selectedRun = getRunForTab(tabPane.getTabCount(),
1135: tabPane.getSelectedIndex());
1136: tabPane.revalidate();
1137: tabPane.repaint();
1138: }
1139: }
1140:
1141:
1146: private class ScrollingPanel extends JPanel
1147: {
1148:
1151: private class ScrollingPanelUI extends BasicPanelUI
1152: {
1153:
1160: public void paint(Graphics g, JComponent c)
1161: {
1162: paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
1163: }
1164: }
1165:
1166:
1170: public void updateUI()
1171: {
1172: setUI((PanelUI) new ScrollingPanelUI());
1173: }
1174: }
1175:
1176:
1182: private class ScrollingViewport extends JViewport implements UIResource
1183: {
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: LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background",
1540: "TabbedPane.foreground",
1541: "TabbedPane.font");
1542: tabPane.setOpaque(false);
1543:
1544: highlight = UIManager.getColor("TabbedPane.highlight");
1545: lightHighlight = UIManager.getColor("TabbedPane.lightHighlight");
1546:
1547: shadow = UIManager.getColor("TabbedPane.shadow");
1548: darkShadow = UIManager.getColor("TabbedPane.darkShadow");
1549:
1550: focus = UIManager.getColor("TabbedPane.focus");
1551:
1552: textIconGap = UIManager.getInt("TabbedPane.textIconGap");
1553: tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay");
1554:
1555: tabInsets = UIManager.getInsets("TabbedPane.tabbedPaneTabInsets");
1556: selectedTabPadInsets = UIManager.getInsets("TabbedPane.tabbedPaneTabPadInsets");
1557: tabAreaInsets = UIManager.getInsets("TabbedPane.tabbedPaneTabAreaInsets");
1558: contentBorderInsets = UIManager.getInsets("TabbedPane.tabbedPaneContentBorderInsets");
1559:
1560: calcRect = new Rectangle();
1561: tabRuns = new int[10];
1562: tabAreaRect = new Rectangle();
1563: contentRect = new Rectangle();
1564: }
1565:
1566:
1569: protected void uninstallDefaults()
1570: {
1571: calcRect = null;
1572: tabAreaRect = null;
1573: contentRect = null;
1574: tabRuns = null;
1575:
1576: contentBorderInsets = null;
1577: tabAreaInsets = null;
1578: selectedTabPadInsets = null;
1579: tabInsets = null;
1580:
1581: focus = null;
1582: darkShadow = null;
1583: shadow = null;
1584: lightHighlight = null;
1585: highlight = null;
1586:
1587: tabPane.setBackground(null);
1588: tabPane.setForeground(null);
1589: tabPane.setFont(null);
1590: }
1591:
1592:
1595: protected void installListeners()
1596: {
1597: mouseListener = createMouseListener();
1598: tabChangeListener = createChangeListener();
1599: propertyChangeListener = createPropertyChangeListener();
1600: focusListener = createFocusListener();
1601:
1602: tabPane.addMouseListener(mouseListener);
1603: tabPane.addChangeListener(tabChangeListener);
1604: tabPane.addPropertyChangeListener(propertyChangeListener);
1605: tabPane.addFocusListener(focusListener);
1606: }
1607:
1608:
1611: protected void uninstallListeners()
1612: {
1613: tabPane.removeFocusListener(focusListener);
1614: tabPane.removePropertyChangeListener(propertyChangeListener);
1615: tabPane.removeChangeListener(tabChangeListener);
1616: tabPane.removeMouseListener(mouseListener);
1617:
1618: focusListener = null;
1619: propertyChangeListener = null;
1620: tabChangeListener = null;
1621: mouseListener = null;
1622: }
1623:
1624:
1629: protected MouseListener createMouseListener()
1630: {
1631: return new MouseHandler();
1632: }
1633:
1634:
1639: protected FocusListener createFocusListener()
1640: {
1641: return new FocusHandler();
1642: }
1643:
1644:
1649: protected ChangeListener createChangeListener()
1650: {
1651: return new TabSelectionHandler();
1652: }
1653:
1654:
1659: protected PropertyChangeListener createPropertyChangeListener()
1660: {
1661: return new PropertyChangeHandler();
1662: }
1663:
1664:
1667: protected void installKeyboardActions()
1668: {
1669:
1670: }
1671:
1672:
1675: protected void uninstallKeyboardActions()
1676: {
1677:
1678: }
1679:
1680:
1687: public Dimension getMinimumSize(JComponent c)
1688: {
1689: return layoutManager.minimumLayoutSize(tabPane);
1690: }
1691:
1692:
1699: public Dimension getMaximumSize(JComponent c)
1700: {
1701: return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
1702: }
1703:
1704:
1710: public void paint(Graphics g, JComponent c)
1711: {
1712: if (tabPane.getTabCount() == 0)
1713: return;
1714: if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
1715: paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
1716: paintContentBorder(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
1717: }
1718:
1719:
1727: protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex)
1728: {
1729: Rectangle ir = new Rectangle();
1730: Rectangle tr = new Rectangle();
1731:
1732: boolean isScroll = tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT;
1733:
1734:
1735:
1736: int tabCount = tabPane.getTabCount();
1737: int currRun = 1;
1738:
1739: if (tabCount > runCount)
1740: runCount = tabCount;
1741:
1742: if (tabCount < 1)
1743: return;
1744:
1745: if (runCount > 1)
1746: currRun = 0;
1747: for (int i = 0; i < runCount; i++)
1748: {
1749: int first = lastTabInRun(tabCount, getPreviousTabRun(currRun)) + 1;
1750: if (isScroll)
1751: first = currentScrollLocation;
1752: else if (first == tabCount)
1753: first = 0;
1754: int last = lastTabInRun(tabCount, currRun);
1755: if (isScroll)
1756: {
1757: for (int k = first; k < tabCount; k++)
1758: {
1759: if (rects[k].x + rects[k].width - rects[first].x > viewport
1760: .getWidth())
1761: {
1762: last = k;
1763: break;
1764: }
1765: }
1766: }
1767:
1768: for (int j = first; j <= last; j++)
1769: {
1770: if (j != selectedIndex || isScroll)
1771: paintTab(g, tabPlacement, rects, j, ir, tr);
1772: }
1773: currRun = getPreviousTabRun(currRun);
1774: }
1775: if (! isScroll)
1776: paintTab(g, tabPlacement, rects, selectedIndex, ir, tr);
1777: }
1778:
1779:
1790: protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects,
1791: int tabIndex, Rectangle iconRect, Rectangle textRect)
1792: {
1793: FontMetrics fm = getFontMetrics();
1794: Icon icon = getIconForTab(tabIndex);
1795: String title = tabPane.getTitleAt(tabIndex);
1796: boolean isSelected = tabIndex == tabPane.getSelectedIndex();
1797: calcRect = getTabBounds(tabPane, tabIndex);
1798:
1799: int x = calcRect.x;
1800: int y = calcRect.y;
1801: int w = calcRect.width;
1802: int h = calcRect.height;
1803: if (getRunForTab(tabPane.getTabCount(), tabIndex) == 1)
1804: {
1805: Insets insets = getTabAreaInsets(tabPlacement);
1806: switch (tabPlacement)
1807: {
1808: case TOP:
1809: h += insets.bottom;
1810: break;
1811: case LEFT:
1812: w += insets.right;
1813: break;
1814: case BOTTOM:
1815: y -= insets.top;
1816: h += insets.top;
1817: break;
1818: case RIGHT:
1819: x -= insets.left;
1820: w += insets.left;
1821: break;
1822: }
1823: }
1824:
1825: layoutLabel(tabPlacement, fm, tabIndex, title, icon, calcRect, iconRect,
1826: textRect, isSelected);
1827: paintTabBackground(g, tabPlacement, tabIndex, x, y, w, h, isSelected);
1828: paintTabBorder(g, tabPlacement, tabIndex, x, y, w, h, isSelected);
1829:
1830:
1831: if (icon != null)
1832: paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
1833: if (title != null && ! title.equals(""))
1834: paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title,
1835: textRect, isSelected);
1836: }
1837:
1838:
1852: protected void layoutLabel(int tabPlacement, FontMetrics metrics,
1853: int tabIndex, String title, Icon icon,
1854: Rectangle tabRect, Rectangle iconRect,
1855: Rectangle textRect, boolean isSelected)
1856: {
1857: SwingUtilities.layoutCompoundLabel(metrics, title, icon,
1858: SwingConstants.CENTER,
1859: SwingConstants.CENTER,
1860: SwingConstants.CENTER,
1861: SwingConstants.RIGHT, tabRect,
1862: iconRect, textRect, textIconGap);
1863:
1864: int shiftX = getTabLabelShiftX(tabPlacement, tabIndex, isSelected);
1865: int shiftY = getTabLabelShiftY(tabPlacement, tabIndex, isSelected);
1866:
1867: iconRect.x += shiftX;
1868: iconRect.y += shiftY;
1869:
1870: textRect.x += shiftX;
1871: textRect.y += shiftY;
1872: }
1873:
1874:
1884: protected void paintIcon(Graphics g, int tabPlacement, int tabIndex,
1885: Icon icon, Rectangle iconRect, boolean isSelected)
1886: {
1887: icon.paintIcon(tabPane, g, iconRect.x, iconRect.y);
1888: }
1889:
1890:
1902: protected void paintText(Graphics g, int tabPlacement, Font font,
1903: FontMetrics metrics, int tabIndex, String title,
1904: Rectangle textRect, boolean isSelected)
1905: {
1906: View textView = getTextViewForTab(tabIndex);
1907: if (textView != null)
1908: {
1909: textView.paint(g, textRect);
1910: return;
1911: }
1912:
1913: Color fg = tabPane.getForegroundAt(tabIndex);
1914: if (fg == null)
1915: fg = tabPane.getForeground();
1916: Color bg = tabPane.getBackgroundAt(tabIndex);
1917: if (bg == null)
1918: bg = tabPane.getBackground();
1919:
1920: Color saved_color = g.getColor();
1921: Font f = g.getFont();
1922: g.setFont(font);
1923:
1924: if (tabPane.isEnabledAt(tabIndex))
1925: {
1926: g.setColor(fg);
1927:
1928: int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
1929:
1930: if (mnemIndex != -1)
1931: BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
1932: textRect.x,
1933: textRect.y
1934: + metrics.getAscent());
1935: else
1936: g.drawString(title, textRect.x, textRect.y + metrics.getAscent());
1937: }
1938: else
1939: {
1940: g.setColor(bg.brighter());
1941:
1942: int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
1943:
1944: if (mnemIndex != -1)
1945: BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
1946: textRect.x, textRect.y);
1947: else
1948: g.drawString(title, textRect.x, textRect.y);
1949:
1950: g.setColor(bg.darker());
1951: if (mnemIndex != -1)
1952: BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
1953: textRect.x + 1,
1954: textRect.y + 1);
1955: else
1956: g.drawString(title, textRect.x + 1, textRect.y + 1);
1957: }
1958:
1959: g.setColor(saved_color);
1960: g.setFont(f);
1961: }
1962:
1963:
1973: protected int getTabLabelShiftX(int tabPlacement, int tabIndex,
1974: boolean isSelected)
1975: {
1976:
1977: return 0;
1978: }
1979:
1980:
1990: protected int getTabLabelShiftY(int tabPlacement, int tabIndex,
1991: boolean isSelected)
1992: {
1993:
1994: return 0;
1995: }
1996:
1997:
2008: protected void paintFocusIndicator(Graphics g, int tabPlacement,
2009: Rectangle[] rects, int tabIndex,
2010: Rectangle iconRect, Rectangle textRect,
2011: boolean isSelected)
2012: {
2013: Color saved = g.getColor();
2014: calcRect = iconRect.union(textRect);
2015:
2016: g.setColor(focus);
2017:
2018: g.drawRect(calcRect.x, calcRect.y, calcRect.width, calcRect.height);
2019:
2020: g.setColor(saved);
2021: }
2022:
2023:
2035: protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex,
2036: int x, int y, int w, int h, boolean isSelected)
2037: {
2038: Color saved = g.getColor();
2039:
2040: if (! isSelected || tabPlacement != SwingConstants.TOP)
2041: {
2042: g.setColor(shadow);
2043: g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
2044: g.setColor(darkShadow);
2045: g.drawLine(x, y + h, x + w, y + h);
2046: }
2047:
2048: if (! isSelected || tabPlacement != SwingConstants.LEFT)
2049: {
2050: g.setColor(darkShadow);
2051: g.drawLine(x + w, y, x + w, y + h);
2052: g.setColor(shadow);
2053: g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
2054: }
2055:
2056: if (! isSelected || tabPlacement != SwingConstants.RIGHT)
2057: {
2058: g.setColor(lightHighlight);
2059: g.drawLine(x, y, x, y + h);
2060: }
2061:
2062: if (! isSelected || tabPlacement != SwingConstants.BOTTOM)
2063: {
2064: g.setColor(lightHighlight);
2065: g.drawLine(x, y, x + w, y);
2066: }
2067:
2068: g.setColor(saved);
2069: }
2070:
2071:
2083: protected void paintTabBackground(Graphics g, int tabPlacement,
2084: int tabIndex, int x, int y, int w, int h,
2085: boolean isSelected)
2086: {
2087: Color saved = g.getColor();
2088: if (isSelected)
2089: g.setColor(Color.LIGHT_GRAY);
2090: else
2091: {
2092: Color bg = tabPane.getBackgroundAt(tabIndex);
2093: if (bg == null)
2094: bg = Color.GRAY;
2095: g.setColor(bg);
2096: }
2097:
2098: g.fillRect(x, y, w, h);
2099:
2100: g.setColor(saved);
2101: }
2102:
2103:
2110: protected void paintContentBorder(Graphics g, int tabPlacement,
2111: int selectedIndex)
2112: {
2113: Insets insets = getContentBorderInsets(tabPlacement);
2114: int x = contentRect.x;
2115: int y = contentRect.y;
2116: int w = contentRect.width;
2117: int h = contentRect.height;
2118: paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2119: paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2120: paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2121: paintContentBorderRightEdge(g, tabPlacement, selectedIndex, x, y, w, h);
2122: }
2123:
2124:
2135: protected void paintContentBorderTopEdge(Graphics g, int tabPlacement,
2136: int selectedIndex, int x, int y,
2137: int w, int h)
2138: {
2139: Color saved = g.getColor();
2140: g.setColor(lightHighlight);
2141:
2142: int startgap = rects[selectedIndex].x;
2143: int endgap = rects[selectedIndex].x + rects[selectedIndex].width;
2144:
2145: int diff = 0;
2146:
2147: if (tabPlacement == SwingConstants.TOP)
2148: {
2149: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2150: {
2151: Point p = findPointForIndex(currentScrollLocation);
2152: diff = p.x;
2153: }
2154:
2155: g.drawLine(x, y, startgap - diff, y);
2156: g.drawLine(endgap - diff, y, x + w, y);
2157: }
2158: else
2159: g.drawLine(x, y, x + w, y);
2160:
2161: g.setColor(saved);
2162: }
2163:
2164:
2175: protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement,
2176: int selectedIndex, int x, int y,
2177: int w, int h)
2178: {
2179: Color saved = g.getColor();
2180: g.setColor(lightHighlight);
2181:
2182: int startgap = rects[selectedIndex].y;
2183: int endgap = rects[selectedIndex].y + rects[selectedIndex].height;
2184:
2185: int diff = 0;
2186:
2187: if (tabPlacement == SwingConstants.LEFT)
2188: {
2189: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2190: {
2191: Point p = findPointForIndex(currentScrollLocation);
2192: diff = p.y;
2193: }
2194:
2195: g.drawLine(x, y, x, startgap - diff);
2196: g.drawLine(x, endgap - diff, x, y + h);
2197: }
2198: else
2199: g.drawLine(x, y, x, y + h);
2200:
2201: g.setColor(saved);
2202: }
2203:
2204:
2215: protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement,
2216: int selectedIndex, int x, int y,
2217: int w, int h)
2218: {
2219: Color saved = g.getColor();
2220:
2221: int startgap = rects[selectedIndex].x;
2222: int endgap = rects[selectedIndex].x + rects[selectedIndex].width;
2223:
2224: int diff = 0;
2225:
2226: if (tabPlacement == SwingConstants.BOTTOM)
2227: {
2228: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2229: {
2230: Point p = findPointForIndex(currentScrollLocation);
2231: diff = p.x;
2232: }
2233:
2234: g.setColor(shadow);
2235: g.drawLine(x + 1, y + h - 1, startgap - diff, y + h - 1);
2236: g.drawLine(endgap - diff, y + h - 1, x + w - 1, y + h - 1);
2237:
2238: g.setColor(darkShadow);
2239: g.drawLine(x, y + h, startgap - diff, y + h);
2240: g.drawLine(endgap - diff, y + h, x + w, y + h);
2241: }
2242: else
2243: {
2244: g.setColor(shadow);
2245: g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
2246: g.setColor(darkShadow);
2247: g.drawLine(x, y + h, x + w, y + h);
2248: }
2249:
2250: g.setColor(saved);
2251: }
2252:
2253:
2264: protected void paintContentBorderRightEdge(Graphics g, int tabPlacement,
2265: int selectedIndex, int x, int y,
2266: int w, int h)
2267: {
2268: Color saved = g.getColor();
2269: int startgap = rects[selectedIndex].y;
2270: int endgap = rects[selectedIndex].y + rects[selectedIndex].height;
2271:
2272: int diff = 0;
2273:
2274: if (tabPlacement == SwingConstants.RIGHT)
2275: {
2276: if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
2277: {
2278: Point p = findPointForIndex(currentScrollLocation);
2279: diff = p.y;
2280: }
2281:
2282: g.setColor(shadow);
2283: g.drawLine(x + w - 1, y + 1, x + w - 1, startgap - diff);
2284: g.drawLine(x + w - 1, endgap - diff, x + w - 1, y + h - 1);
2285:
2286: g.setColor(darkShadow);
2287: g.drawLine(x + w, y, x + w, startgap - diff);
2288: g.drawLine(x + w, endgap - diff, x + w, y + h);
2289: }
2290: else
2291: {
2292: g.setColor(shadow);
2293: g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
2294: g.setColor(darkShadow);
2295: g.drawLine(x + w, y, x + w, y + h);
2296: }
2297:
2298: g.setColor(saved);
2299: }
2300:
2301:
2309: public Rectangle getTabBounds(JTabbedPane pane, int i)
2310: {
2311: return rects[i];
2312: }
2313:
2314:
2321: public int getTabRunCount(JTabbedPane pane)
2322: {
2323: return runCount;
2324: }
2325:
2326:
2335: public int tabForCoordinate(JTabbedPane pane, int x, int y)
2336: {
2337: Point p = new Point(x, y);
2338: int tabCount = tabPane.getTabCount();
2339: int currRun = 1;
2340: for (int i = 0; i < runCount; i++)
2341: {
2342: int first = lastTabInRun(tabCount, getPreviousTabRun(currRun)) + 1;
2343: if (first == tabCount)
2344: first = 0;
2345: int last = lastTabInRun(tabCount, currRun);
2346: for (int j = first; j <= last; j++)
2347: {
2348: if (getTabBounds(pane, j).contains(p))
2349: return j;
2350: }
2351: currRun = getNextTabRun(currRun);
2352: }
2353: return -1;
2354: }
2355:
2356:
2364: protected Rectangle getTabBounds(int tabIndex, Rectangle dest)
2365: {
2366: dest.setBounds(getTabBounds(tabPane, tabIndex));
2367: return dest;
2368: }
2369:
2370:
2375: protected Component getVisibleComponent()
2376: {
2377: return tabPane.getComponentAt(tabPane.getSelectedIndex());
2378: }
2379:
2380:
2385: protected void setVisibleComponent(Component component)
2386: {
2387: component.setVisible(true);
2388: tabPane.setSelectedComponent(component);
2389: }
2390:
2391:
2397: protected void assureRectsCreated(int tabCount)
2398: {
2399: if (rects == null)
2400: rects = new Rectangle[tabCount];
2401: if (tabCount == rects.length)
2402: return;
2403: else
2404: {
2405: int numToCopy = Math.min(tabCount, rects.length);
2406: Rectangle[] tmp = new Rectangle[tabCount];
2407: System.arraycopy(rects, 0, tmp, 0, numToCopy);
2408: rects = tmp;
2409: }
2410: }
2411:
2412:
2416: protected void expandTabRunsArray()
2417: {
2418:
2419: if (tabRuns == null)
2420: tabRuns = new int[10];
2421: else
2422: {
2423: int[] newRuns = new int[tabRuns.length + 10];
2424: System.arraycopy(tabRuns, 0, newRuns, 0, tabRuns.length);
2425: tabRuns = newRuns;
2426: }
2427: }
2428:
2429:
2437: protected int getRunForTab(int tabCount, int tabIndex)
2438: {
2439: if (runCount == 1 && tabIndex < tabCount && tabIndex >= 0)
2440: return 1;
2441: for (int i = 0; i < runCount; i++)
2442: {
2443: int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1;
2444: if (first == tabCount)
2445: first = 0;
2446: int last = lastTabInRun(tabCount, i);
2447: if (last >= tabIndex && first <= tabIndex)
2448: return i;
2449: }
2450: return -1;
2451: }
2452:
2453:
2461: protected int lastTabInRun(int tabCount, int run)
2462: {
2463: if (tabRuns[run] == 0)
2464: return tabCount - 1;
2465: else
2466: return tabRuns[run] - 1;
2467: }
2468:
2469:
2476: protected int getTabRunOverlay(int tabPlacement)
2477: {
2478: return tabRunOverlay;
2479: }
2480:
2481:
2490: protected int getTabRunIndent(int tabPlacement, int run)
2491: {
2492: return 0;
2493: }
2494:
2495:
2503: protected boolean shouldPadTabRun(int tabPlacement, int run)
2504: {
2505: return true;
2506: }
2507:
2508:
2515: protected boolean shouldRotateTabRuns(int tabPlacement)
2516: {
2517: return true;
2518: }
2519:
2520:
2529: protected Icon getIconForTab(int tabIndex)
2530: {
2531: if (tabPane.isEnabledAt(tabIndex))
2532: return tabPane.getIconAt(tabIndex);
2533: else
2534: return tabPane.getDisabledIconAt(tabIndex);
2535: }
2536:
2537:
2544: protected View getTextViewForTab(int tabIndex)
2545: {
2546: return null;
2547: }
2548:
2549:
2559: protected int calculateTabHeight(int tabPlacement, int tabIndex,
2560: int fontHeight)
2561: {
2562: Icon icon = getIconForTab(tabIndex);
2563: Insets insets = getTabInsets(tabPlacement, tabIndex);
2564:
2565: int height = 0;
2566: if (icon != null)
2567: {
2568: Rectangle vr = new Rectangle();
2569: Rectangle ir = new Rectangle();
2570: Rectangle tr = new Rectangle();
2571: layoutLabel(tabPlacement, getFontMetrics(), tabIndex,
2572: tabPane.getTitleAt(tabIndex), icon, vr, ir, tr,
2573: tabIndex == tabPane.getSelectedIndex());
2574: height = tr.union(ir).height;
2575: }
2576: else
2577: height = fontHeight;
2578:
2579: height += insets.top + insets.bottom;
2580: return height;
2581: }
2582:
2583:
2590: protected int calculateMaxTabHeight(int tabPlacement)
2591: {
2592: maxTabHeight = 0;
2593:
2594: FontMetrics fm = getFontMetrics();
2595: int fontHeight = fm.getHeight();
2596:
2597: for (int i = 0; i < tabPane.getTabCount(); i++)
2598: maxTabHeight = Math.max(calculateTabHeight(tabPlacement, i, fontHeight),
2599: maxTabHeight);
2600:
2601: return maxTabHeight;
2602: }
2603:
2604:
2614: protected int calculateTabWidth(int tabPlacement, int tabIndex,
2615: FontMetrics metrics)
2616: {
2617: Icon icon = getIconForTab(tabIndex);
2618: Insets insets = getTabInsets(tabPlacement, tabIndex);
2619:
2620: int width = 0;
2621: if (icon != null)
2622: {
2623: Rectangle vr = new Rectangle();
2624: Rectangle ir = new Rectangle();
2625: Rectangle tr = new Rectangle();
2626: layoutLabel(tabPlacement, getFontMetrics(), tabIndex,
2627: tabPane.getTitleAt(tabIndex), icon, vr, ir, tr,
2628: tabIndex == tabPane.getSelectedIndex());
2629: width = tr.union(ir).width;
2630: }
2631: else
2632: width = metrics.stringWidth(tabPane.getTitleAt(tabIndex));
2633:
2634: width += insets.left + insets.right;
2635: return width;
2636: }
2637:
2638:
2645: protected int calculateMaxTabWidth(int tabPlacement)
2646: {
2647: maxTabWidth = 0;
2648:
2649: FontMetrics fm = getFontMetrics();
2650:
2651: for (int i = 0; i < tabPane.getTabCount(); i++)
2652: maxTabWidth = Math.max(calculateTabWidth(tabPlacement, i, fm),
2653: maxTabWidth);
2654:
2655: return maxTabWidth;
2656: }
2657:
2658:
2668: protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount,
2669: int maxTabHeight)
2670: {
2671: Insets insets = getTabAreaInsets(tabPlacement);
2672: int tabAreaHeight = horizRunCount * maxTabHeight
2673: - (horizRunCount - 1) * tabRunOverlay;
2674:
2675: tabAreaHeight += insets.top + insets.bottom;
2676:
2677: return tabAreaHeight;
2678: }
2679:
2680:
2690: protected int calculateTabAreaWidth(int tabPlacement, int vertRunCount,
2691: int maxTabWidth)
2692: {
2693: Insets insets = getTabAreaInsets(tabPlacement);
2694: int tabAreaWidth = vertRunCount * maxTabWidth
2695: - (vertRunCount - 1) * tabRunOverlay;
2696:
2697: tabAreaWidth += insets.left + insets.right;
2698:
2699: return tabAreaWidth;
2700: }
2701:
2702:
2710: protected Insets getTabInsets(int tabPlacement, int tabIndex)
2711: {
2712: Insets target = new Insets(0, 0, 0, 0);
2713: rotateInsets(tabInsets, target, tabPlacement);
2714: return target;
2715: }
2716:
2717:
2724: protected Insets getSelectedTabPadInsets(int tabPlacement)
2725: {
2726: Insets target = new Insets(0, 0, 0, 0);
2727: rotateInsets(selectedTabPadInsets, target, tabPlacement);
2728: return target;
2729: }
2730:
2731:
2738: protected Insets getTabAreaInsets(int tabPlacement)
2739: {
2740: Insets target = new Insets(0, 0, 0, 0);
2741: rotateInsets(tabAreaInsets, target, tabPlacement);
2742: return target;
2743: }
2744:
2745:
2752: protected Insets getContentBorderInsets(int tabPlacement)
2753: {
2754: Insets target = new Insets(0, 0, 0, 0);
2755: rotateInsets(contentBorderInsets, target, tabPlacement);
2756: return target;
2757: }
2758:
2759:
2764: protected FontMetrics getFontMetrics()
2765: {
2766: FontMetrics fm = tabPane.getToolkit().getFontMetrics(tabPane.getFont());
2767: return fm;
2768: }
2769:
2770:
2776: protected void navigateSelectedTab(int direction)
2777: {
2778: int tabPlacement = tabPane.getTabPlacement();
2779: if (tabPlacement == SwingConstants.TOP
2780: || tabPlacement == SwingConstants.BOTTOM)
2781: {
2782: if (direction == SwingConstants.WEST)
2783: selectPreviousTabInRun(tabPane.getSelectedIndex());
2784: else if (direction == SwingConstants.EAST)
2785: selectNextTabInRun(tabPane.getSelectedIndex());
2786:
2787: else
2788: {
2789: int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
2790: tabPane.getSelectedIndex(),
2791: (tabPlacement == SwingConstants.RIGHT)
2792: ? true : false);
2793: selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
2794: offset);
2795: }
2796: }
2797: if (tabPlacement == SwingConstants.LEFT
2798: || tabPlacement == SwingConstants.RIGHT)
2799: {
2800: if (direction == SwingConstants.NORTH)
2801: selectPreviousTabInRun(tabPane.getSelectedIndex());
2802: else if (direction == SwingConstants.SOUTH)
2803: selectNextTabInRun(tabPane.getSelectedIndex());
2804: else
2805: {
2806: int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
2807: tabPane.getSelectedIndex(),
2808: (tabPlacement == SwingConstants.RIGHT)
2809: ? true : false);
2810: selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
2811: offset);
2812: }
2813: }
2814: }
2815:
2816:
2821: protected void selectNextTabInRun(int current)
2822: {
2823: tabPane.setSelectedIndex(getNextTabIndexInRun(tabPane.getTabCount(),
2824: current));
2825: }
2826:
2827:
2832: protected void selectPreviousTabInRun(int current)
2833: {
2834: tabPane.setSelectedIndex(getPreviousTabIndexInRun(tabPane.getTabCount(),
2835: current));
2836: }
2837:
2838:
2843: protected void selectNextTab(int current)
2844: {
2845: tabPane.setSelectedIndex(getNextTabIndex(current));
2846: }
2847:
2848:
2853: protected void selectPreviousTab(int current)
2854: {
2855: tabPane.setSelectedIndex(getPreviousTabIndex(current));
2856: }
2857:
2858:
2869: protected void selectAdjacentRunTab(int tabPlacement, int tabIndex,
2870: int offset)
2871: {
2872: int x = rects[tabIndex].x + rects[tabIndex].width / 2;
2873: int y = rects[tabIndex].y + rects[tabIndex].height / 2;
2874:
2875: switch (tabPlacement)
2876: {
2877: case SwingConstants.TOP:
2878: case SwingConstants.BOTTOM:
2879: y += offset;
2880: break;
2881: case SwingConstants.RIGHT:
2882: case SwingConstants.LEFT:
2883: x += offset;
2884: break;
2885: }
2886:
2887: int index = tabForCoordinate(tabPane, x, y);
2888: if (index != -1)
2889: tabPane.setSelectedIndex(index);
2890: }
2891:
2892:
2893:
2894:
2895:
2896:
2897:
2898:
2913: protected int getTabRunOffset(int tabPlacement, int tabCount, int tabIndex,
2914: boolean forward)
2915: {
2916: int currRun = getRunForTab(tabCount, tabIndex);
2917: int offset;
2918: int nextRun = (forward) ? getNextTabRun(currRun) : getPreviousTabRun(currRun);
2919: if (tabPlacement == SwingConstants.TOP
2920: || tabPlacement == SwingConstants.BOTTOM)
2921: offset = rects[lastTabInRun(tabCount, nextRun)].y
2922: - rects[lastTabInRun(tabCount, currRun)].y;
2923: else
2924: offset = rects[lastTabInRun(tabCount, nextRun)].x
2925: - rects[lastTabInRun(tabCount, currRun)].x;
2926: return offset;
2927: }
2928:
2929:
2936: protected int getPreviousTabIndex(int base)
2937: {
2938: base--;
2939: if (base < 0)
2940: return tabPane.getTabCount() - 1;
2941: return base;
2942: }
2943:
2944:
2951: protected int getNextTabIndex(int base)
2952: {
2953: base++;
2954: if (base == tabPane.getTabCount())
2955: return 0;
2956: return base;
2957: }
2958:
2959:
2968: protected int getNextTabIndexInRun(int tabCount, int base)
2969: {
2970: int index = getNextTabIndex(base);
2971: int run = getRunForTab(tabCount, base);
2972: if (index == lastTabInRun(tabCount, run) + 1)
2973: index = lastTabInRun(tabCount, getPreviousTabRun(run)) + 1;
2974: return getNextTabIndex(base);
2975: }
2976:
2977:
2986: protected int getPreviousTabIndexInRun(int tabCount, int base)
2987: {
2988: int index = getPreviousTabIndex(base);
2989: int run = getRunForTab(tabCount, base);
2990: if (index == lastTabInRun(tabCount, getPreviousTabRun(run)))
2991: index = lastTabInRun(tabCount, run);
2992: return getPreviousTabIndex(base);
2993: }
2994:
2995:
3002: protected int getPreviousTabRun(int baseRun)
3003: {
3004: if (getTabRunCount(tabPane) == 1)
3005: return 1;
3006:
3007: int prevRun = --baseRun;
3008: if (prevRun < 0)
3009: prevRun = getTabRunCount(tabPane) - 1;
3010: return prevRun;
3011: }
3012:
3013:
3020: protected int getNextTabRun(int baseRun)
3021: {
3022: if (getTabRunCount(tabPane) == 1)
3023: return 1;
3024:
3025: int nextRun = ++baseRun;
3026: if (nextRun == getTabRunCount(tabPane))
3027: nextRun = 0;
3028: return nextRun;
3029: }
3030:
3031:
3043: protected static void rotateInsets(Insets topInsets, Insets targetInsets,
3044: int targetPlacement)
3045: {
3046:
3047:
3048: switch (targetPlacement)
3049: {
3050: case SwingConstants.TOP:
3051: targetInsets.top = topInsets.top;
3052: targetInsets.left = topInsets.left;
3053: targetInsets.right = topInsets.right;
3054: targetInsets.bottom = topInsets.bottom;
3055: break;
3056: case SwingConstants.LEFT:
3057: targetInsets.left = topInsets.top;
3058: targetInsets.top = topInsets.left;
3059: targetInsets.right = topInsets.bottom;
3060: targetInsets.bottom = topInsets.right;
3061: break;
3062: case SwingConstants.BOTTOM:
3063: targetInsets.top = topInsets.bottom;
3064: targetInsets.bottom = topInsets.top;
3065: targetInsets.left = topInsets.left;
3066: targetInsets.right = topInsets.right;
3067: break;
3068: case SwingConstants.RIGHT:
3069: targetInsets.top = topInsets.left;
3070: targetInsets.left = topInsets.bottom;
3071: targetInsets.bottom = topInsets.right;
3072: targetInsets.right = topInsets.top;
3073: break;
3074: }
3075: }
3076: }