OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [javax/] [swing/] [plaf/] [basic/] [BasicTabbedPaneUI.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* BasicTabbedPaneUI.java --
2
   Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package javax.swing.plaf.basic;
40
 
41
import java.awt.Color;
42
import java.awt.Component;
43
import java.awt.Container;
44
import java.awt.Dimension;
45
import java.awt.Font;
46
import java.awt.FontMetrics;
47
import java.awt.Graphics;
48
import java.awt.Insets;
49
import java.awt.LayoutManager;
50
import java.awt.Point;
51
import java.awt.Rectangle;
52
import java.awt.event.FocusAdapter;
53
import java.awt.event.FocusEvent;
54
import java.awt.event.FocusListener;
55
import java.awt.event.MouseAdapter;
56
import java.awt.event.MouseEvent;
57
import java.awt.event.MouseListener;
58
import java.beans.PropertyChangeEvent;
59
import java.beans.PropertyChangeListener;
60
 
61
import javax.swing.Icon;
62
import javax.swing.JComponent;
63
import javax.swing.JPanel;
64
import javax.swing.JTabbedPane;
65
import javax.swing.JViewport;
66
import javax.swing.KeyStroke;
67
import javax.swing.LookAndFeel;
68
import javax.swing.SwingConstants;
69
import javax.swing.SwingUtilities;
70
import javax.swing.UIManager;
71
import javax.swing.event.ChangeEvent;
72
import javax.swing.event.ChangeListener;
73
import javax.swing.plaf.ComponentUI;
74
import javax.swing.plaf.PanelUI;
75
import javax.swing.plaf.TabbedPaneUI;
76
import javax.swing.plaf.UIResource;
77
import javax.swing.text.View;
78
 
79
/**
80
 * This is the Basic Look and Feel's UI delegate for JTabbedPane.
81
 */
82
public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
83
{
84
  /**
85
   * A helper class that handles focus.
86
   *
87
   * @specnote Apparently this class was intended to be protected,
88
   *           but was made public by a compiler bug and is now
89
   *           public for compatibility.
90
   */
91
  public class FocusHandler extends FocusAdapter
92
  {
93
    /**
94
     * This method is called when the component gains focus.
95
     *
96
     * @param e The FocusEvent.
97
     */
98
    public void focusGained(FocusEvent e)
99
    {
100
      // FIXME: Implement.
101
    }
102
 
103
    /**
104
     * This method is called when the component loses focus.
105
     *
106
     * @param e The FocusEvent.
107
     */
108
    public void focusLost(FocusEvent e)
109
    {
110
      // FIXME: Implement.
111
    }
112
  }
113
 
114
  /**
115
   * A helper class for determining if mouse presses occur inside tabs and
116
   * sets the index appropriately. In SCROLL_TAB_MODE, this class also
117
   * handles the mouse clicks on the scrolling buttons.
118
   *
119
   * @specnote Apparently this class was intended to be protected,
120
   *           but was made public by a compiler bug and is now
121
   *           public for compatibility.
122
   */
123
  public class MouseHandler extends MouseAdapter
124
  {
125
    /**
126
     * This method is called when the mouse is pressed. The index cannot
127
     * change to a tab that is  not enabled.
128
     *
129
     * @param e The MouseEvent.
130
     */
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
                // FIXME: Still getting mouse events after the button is disabled.
149
                //      incrButton.setEnabled(false);
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
      // We need to check since there are areas where tabs cannot be
174
      // e.g. in the inset area.
175
      if (index != -1 && tabPane.isEnabledAt(index))
176
        tabPane.setSelectedIndex(index);
177
      tabPane.revalidate();
178
      tabPane.repaint();
179
    }
180
  }
181
 
182
  /**
183
   * This class handles PropertyChangeEvents fired from the JTabbedPane.
184
   *
185
   * @specnote Apparently this class was intended to be protected,
186
   *           but was made public by a compiler bug and is now
187
   *           public for compatibility.
188
   */
189
  public class PropertyChangeHandler implements PropertyChangeListener
190
  {
191
    /**
192
     * This method is called whenever one of the properties of the JTabbedPane
193
     * changes.
194
     *
195
     * @param e The PropertyChangeEvent.
196
     */
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
  /**
217
   * A LayoutManager responsible for placing all the tabs and the visible
218
   * component inside the JTabbedPane. This class is only used for
219
   * WRAP_TAB_LAYOUT.
220
   *
221
   * @specnote Apparently this class was intended to be protected,
222
   *           but was made public by a compiler bug and is now
223
   *           public for compatibility.
224
   */
225
  public class TabbedPaneLayout implements LayoutManager
226
  {
227
    /**
228
     * This method is called when a component is added to the JTabbedPane.
229
     *
230
     * @param name The name of the component.
231
     * @param comp The component being added.
232
     */
233
    public void addLayoutComponent(String name, Component comp)
234
    {
235
      // Do nothing.
236
    }
237
 
238
    /**
239
     * This method is called when the rectangles need to be calculated. It
240
     * also fixes the size of the visible component.
241
     */
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
    /**
259
     * This method calculates the size of the the JTabbedPane.
260
     *
261
     * @param minimum Whether the JTabbedPane will try to be as small as it
262
     *        can.
263
     *
264
     * @return The desired size of the JTabbedPane.
265
     */
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
    // if tab placement is LEFT OR RIGHT, they share width.
313
    // if tab placement is TOP OR BOTTOM, they share height
314
    // PRE STEP: finds the default sizes for the labels as well as their locations.
315
    // AND where they will be placed within the run system.
316
    // 1. calls normalizeTab Runs.
317
    // 2. calls rotate tab runs.
318
    // 3. pads the tab runs.
319
    // 4. pads the selected tab.
320
 
321
    /**
322
     * This method is called to calculate the tab rectangles.  This method
323
     * will calculate the size and position of all  rectangles (taking into
324
     * account which ones should be in which tab run). It will pad them and
325
     * normalize them  as necessary.
326
     *
327
     * @param tabPlacement The JTabbedPane's tab placement.
328
     * @param tabCount The run the current selection is in.
329
     */
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
      // Need to pad the runs and move them to the correct location.
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
          // Done padding, now need to move it.
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
    /**
520
     * This method is called when the JTabbedPane is laid out in
521
     * WRAP_TAB_LAYOUT. It calls calculateLayoutInfo to  find the positions
522
     * of all its components.
523
     *
524
     * @param parent The Container to lay out.
525
     */
526
    public void layoutContainer(Container parent)
527
    {
528
      calculateLayoutInfo();
529
    }
530
 
531
    /**
532
     * This method returns the minimum layout size for the given container.
533
     *
534
     * @param parent The container that is being sized.
535
     *
536
     * @return The minimum size.
537
     */
538
    public Dimension minimumLayoutSize(Container parent)
539
    {
540
      return calculateSize(false);
541
    }
542
 
543
    // If there is more free space in an adjacent run AND the tab in the run can fit in the 
544
    // adjacent run, move it. This method is not perfect, it is merely an approximation.
545
    // If you play around with Sun's JTabbedPane, you'll see that 
546
    // it does do some pretty strange things with regards to not moving tabs 
547
    // that should be moved. 
548
    // start = the x position where the tabs will begin
549
    // max = the maximum position of where the tabs can go to (tabAreaInsets.left + the width of the tab area)
550
 
551
    /**
552
     * This method tries to "even out" the number of tabs in each run based on
553
     * their widths.
554
     *
555
     * @param tabPlacement The JTabbedPane's tab placement.
556
     * @param tabCount The number of tabs.
557
     * @param start The x position where the tabs will begin.
558
     * @param max The maximum x position where the tab can run to.
559
     */
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
          // We should only do this for runCount - 1, cause we can only shift that many times between
568
          // runs.
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
              // Fix the bounds.
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
    /**
639
     * This method pads the tab at the selected index by the  selected tab pad
640
     * insets (so that it looks larger).
641
     *
642
     * @param tabPlacement The placement of the tabs.
643
     * @param selectedIndex The selected index.
644
     */
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
    // If the tabs on the run don't fill the width of the window, make it fit now.
655
    // start = starting index of the run
656
    // end = last index of the run
657
    // max = tabAreaInsets.left + width (or equivalent)
658
    // assert start <= end.
659
 
660
    /**
661
     * This method makes each tab in the run larger so that the  tabs expand
662
     * to fill the runs width/height (depending on tabPlacement).
663
     *
664
     * @param tabPlacement The placement of the tabs.
665
     * @param start The index of the first tab.
666
     * @param end The last index of the tab
667
     * @param max The amount of space in the run (width for TOP and BOTTOM
668
     *        tabPlacement).
669
     */
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
          // now divvy up the space.
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
              // This is used because since the spaceAllocated 
688
              // variable is an int, it rounds down. Sometimes,
689
              // we don't fill an entire row, so we make it do
690
              // so now.
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
    /**
715
     * This method returns the preferred layout size for the given container.
716
     *
717
     * @param parent The container to size.
718
     *
719
     * @return The preferred layout size.
720
     */
721
    public Dimension preferredLayoutSize(Container parent)
722
    {
723
      return calculateSize(false);
724
    }
725
 
726
    /**
727
     * This method returns the preferred tab height given a tabPlacement and
728
     * width.
729
     *
730
     * @param tabPlacement The JTabbedPane's tab placement.
731
     * @param width The expected width.
732
     *
733
     * @return The preferred tab area height.
734
     */
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
      // Only interested in width, this is a messed up rectangle now.
750
      width -= tabAreaInsets.left + tabAreaInsets.right + insets.left
751
      + insets.right;
752
 
753
      // The reason why we can't use runCount:
754
      // This method is only called to calculate the size request
755
      // for the tabbedPane. However, this size request is dependent on 
756
      // our desired width. We need to find out what the height would
757
      // be IF we got our desired width.
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
    /**
778
     * This method calculates the preferred tab area width given a tab
779
     * placement and height.
780
     *
781
     * @param tabPlacement The JTabbedPane's tab placement.
782
     * @param height The expected height.
783
     *
784
     * @return The preferred tab area width.
785
     */
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
    /**
823
     * This method rotates the places each run in the correct place  the
824
     * tabRuns array. See the comment for tabRuns for how the runs are placed
825
     * in the array.
826
     *
827
     * @param tabPlacement The JTabbedPane's tab placement.
828
     * @param selectedRun The run the current selection is in.
829
     */
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
    /**
852
     * This method is called when a component is removed  from the
853
     * JTabbedPane.
854
     *
855
     * @param comp The component removed.
856
     */
857
    public void removeLayoutComponent(Component comp)
858
    {
859
      // Do nothing.
860
    }
861
  }
862
 
863
  /**
864
   * This class acts as the LayoutManager for the JTabbedPane in
865
   * SCROLL_TAB_MODE.
866
   */
867
  private class TabbedPaneScrollLayout extends TabbedPaneLayout
868
  {
869
    /**
870
     * This method returns the preferred layout size for the given container.
871
     *
872
     * @param parent The container to calculate a size for.
873
     *
874
     * @return The preferred layout size.
875
     */
876
    public Dimension preferredLayoutSize(Container parent)
877
    {
878
      return super.calculateSize(true);
879
    }
880
 
881
    /**
882
     * This method returns the minimum layout size for the given container.
883
     *
884
     * @param parent The container to calculate a size for.
885
     *
886
     * @return The minimum layout size.
887
     */
888
    public Dimension minimumLayoutSize(Container parent)
889
    {
890
      return super.calculateSize(true);
891
    }
892
 
893
    /**
894
     * This method calculates the tab area height given  a desired width.
895
     *
896
     * @param tabPlacement The JTabbedPane's tab placement.
897
     * @param width The expected width.
898
     *
899
     * @return The tab area height given the width.
900
     */
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
    /**
915
     * This method calculates the tab area width given a desired height.
916
     *
917
     * @param tabPlacement The JTabbedPane's tab placement.
918
     * @param height The expected height.
919
     *
920
     * @return The tab area width given the height.
921
     */
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
    /**
935
     * This method is called to calculate the tab rectangles.  This method
936
     * will calculate the size and position of all  rectangles (taking into
937
     * account which ones should be in which tab run). It will pad them and
938
     * normalize them  as necessary.
939
     *
940
     * @param tabPlacement The JTabbedPane's tab placement.
941
     * @param tabCount The number of tabs.
942
     */
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
    /**
1037
     * This method is called when the JTabbedPane is laid out in
1038
     * SCROLL_TAB_LAYOUT. It finds the position for all components in the
1039
     * JTabbedPane.
1040
     *
1041
     * @param pane The JTabbedPane to be laid out.
1042
     */
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
          // we want to cover that entire space so that borders that run under
1109
          // the tab area don't show up when we move the viewport around.
1110
          panel.setSize(w + p.x, h + p.y);
1111
        }
1112
      viewport.setViewPosition(p);
1113
      viewport.repaint();
1114
    }
1115
  }
1116
 
1117
  /**
1118
   * This class handles ChangeEvents from the JTabbedPane.
1119
   *
1120
   * @specnote Apparently this class was intended to be protected,
1121
   *           but was made public by a compiler bug and is now
1122
   *           public for compatibility.
1123
   */
1124
  public class TabSelectionHandler implements ChangeListener
1125
  {
1126
    /**
1127
     * This method is called whenever a ChangeEvent is fired from the
1128
     * JTabbedPane.
1129
     *
1130
     * @param e The ChangeEvent fired.
1131
     */
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
  /**
1142
   * This helper class is a JPanel that fits inside the ScrollViewport. This
1143
   * panel's sole job is to paint the tab rectangles inside the  viewport so
1144
   * that it's clipped correctly.
1145
   */
1146
  private class ScrollingPanel extends JPanel
1147
  {
1148
    /**
1149
     * This is a private UI class for our panel.
1150
     */
1151
    private class ScrollingPanelUI extends BasicPanelUI
1152
    {
1153
      /**
1154
       * This method overrides the default paint method. It paints the tab
1155
       * rectangles for the JTabbedPane in the panel.
1156
       *
1157
       * @param g The Graphics object to paint with.
1158
       * @param c The JComponent to paint.
1159
       */
1160
      public void paint(Graphics g, JComponent c)
1161
      {
1162
        paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
1163
      }
1164
    }
1165
 
1166
    /**
1167
     * This method overrides the updateUI method. It makes the default UI for
1168
     * this ScrollingPanel to be  a ScrollingPanelUI.
1169
     */
1170
    public void updateUI()
1171
    {
1172
      setUI((PanelUI) new ScrollingPanelUI());
1173
    }
1174
  }
1175
 
1176
  /**
1177
   * This is a helper class that paints the panel that paints tabs. This
1178
   * custom JViewport is used so that the tabs painted in the panel will be
1179
   * clipped. This class implements UIResource so tabs are not added when
1180
   * this objects of this class are added to the  JTabbedPane.
1181
   */
1182
  private class ScrollingViewport extends JViewport implements UIResource
1183
  {
1184
    // TODO: Maybe remove this inner class.
1185
  }
1186
 
1187
  /**
1188
   * This is a helper class that implements UIResource so it is not added as a
1189
   * tab when an object of this class is added to the JTabbedPane.
1190
   */
1191
  private class ScrollingButton extends BasicArrowButton implements UIResource
1192
  {
1193
    /**
1194
     * Creates a ScrollingButton given the direction.
1195
     *
1196
     * @param dir The direction to point in.
1197
     */
1198
    public ScrollingButton(int dir)
1199
    {
1200
      super(dir);
1201
    }
1202
  }
1203
 
1204
  /** The button that increments the current scroll location.
1205
   * This is package-private to avoid an accessor method.  */
1206
  transient ScrollingButton incrButton;
1207
 
1208
  /** The button that decrements the current scroll location.
1209
   * This is package-private to avoid an accessor method.  */
1210
  transient ScrollingButton decrButton;
1211
 
1212
  /** The viewport used to display the tabs.
1213
   * This is package-private to avoid an accessor method.  */
1214
  transient ScrollingViewport viewport;
1215
 
1216
  /** The panel inside the viewport that paints the tabs.
1217
   * This is package-private to avoid an accessor method.  */
1218
  transient ScrollingPanel panel;
1219
 
1220
  /** The starting visible tab in the run in SCROLL_TAB_MODE.
1221
   * This is package-private to avoid an accessor method.  */
1222
  transient int currentScrollLocation;
1223
 
1224
  /** A reusable rectangle. */
1225
  protected Rectangle calcRect;
1226
 
1227
  /** An array of Rectangles keeping track of the tabs' area and position. */
1228
  protected Rectangle[] rects;
1229
 
1230
  /** The insets around the content area. */
1231
  protected Insets contentBorderInsets;
1232
 
1233
  /** The extra insets around the selected tab. */
1234
  protected Insets selectedTabPadInsets;
1235
 
1236
  /** The insets around the tab area. */
1237
  protected Insets tabAreaInsets;
1238
 
1239
  /** The insets around each and every tab. */
1240
  protected Insets tabInsets;
1241
 
1242
  /**
1243
   * The outer bottom and right edge color for both the tab and content
1244
   * border.
1245
   */
1246
  protected Color darkShadow;
1247
 
1248
  /** The color of the focus outline on the selected tab. */
1249
  protected Color focus;
1250
 
1251
  /** FIXME: find a use for this. */
1252
  protected Color highlight;
1253
 
1254
  /** The top and left edge color for both the tab and content border. */
1255
  protected Color lightHighlight;
1256
 
1257
  /** The inner bottom and right edge color for the tab and content border. */
1258
  protected Color shadow;
1259
 
1260
  /** The maximum tab height. */
1261
  protected int maxTabHeight;
1262
 
1263
  /** The maximum tab width. */
1264
  protected int maxTabWidth;
1265
 
1266
  /** The number of runs in the JTabbedPane. */
1267
  protected int runCount;
1268
 
1269
  /** The index of the run that the selected index is in. */
1270
  protected int selectedRun;
1271
 
1272
  /** The amount of space each run overlaps the previous by. */
1273
  protected int tabRunOverlay;
1274
 
1275
  /** The gap between text and label */
1276
  protected int textIconGap;
1277
 
1278
  // Keeps track of tab runs.
1279
  // The organization of this array is as follows (lots of experimentation to
1280
  // figure this out)
1281
  // index 0 = furthest away from the component area (aka outer run)
1282
  // index 1 = closest to component area (aka selected run)
1283
  // index > 1 = listed in order leading from selected run to outer run.
1284
  // each int in the array is the tab index + 1 (counting starts at 1)
1285
  // for the last tab in the run. (same as the rects array)
1286
 
1287
  /** This array keeps track of which tabs are in which run. See above. */
1288
  protected int[] tabRuns;
1289
 
1290
  /**
1291
   * This is the keystroke for moving down.
1292
   *
1293
   * @deprecated 1.3
1294
   */
1295
  protected KeyStroke downKey;
1296
 
1297
  /**
1298
   * This is the keystroke for moving left.
1299
   *
1300
   * @deprecated 1.3
1301
   */
1302
  protected KeyStroke leftKey;
1303
 
1304
  /**
1305
   * This is the keystroke for moving right.
1306
   *
1307
   * @deprecated 1.3
1308
   */
1309
  protected KeyStroke rightKey;
1310
 
1311
  /**
1312
   * This is the keystroke for moving up.
1313
   *
1314
   * @deprecated 1.3
1315
   */
1316
  protected KeyStroke upKey;
1317
 
1318
  /** The listener that listens for focus events. */
1319
  protected FocusListener focusListener;
1320
 
1321
  /** The listener that listens for mouse events. */
1322
  protected MouseListener mouseListener;
1323
 
1324
  /** The listener that listens for property change events. */
1325
  protected PropertyChangeListener propertyChangeListener;
1326
 
1327
  /** The listener that listens for change events. */
1328
  protected ChangeListener tabChangeListener;
1329
 
1330
  /** The tab pane that this UI paints. */
1331
  protected JTabbedPane tabPane;
1332
 
1333
  /** The current layout manager for the tabPane.
1334
   * This is package-private to avoid an accessor method.  */
1335
  transient LayoutManager layoutManager;
1336
 
1337
  /** The rectangle that describes the tab area's position and size.
1338
   * This is package-private to avoid an accessor method.  */
1339
  transient Rectangle tabAreaRect;
1340
 
1341
  /** The rectangle that describes the content area's position and
1342
   * size.  This is package-private to avoid an accessor method.  */
1343
  transient Rectangle contentRect;
1344
 
1345
  /**
1346
   * Creates a new BasicTabbedPaneUI object.
1347
   */
1348
  public BasicTabbedPaneUI()
1349
  {
1350
    super();
1351
  }
1352
 
1353
  /**
1354
   * This method creates a ScrollingButton that  points in the appropriate
1355
   * direction for an increasing button.
1356
   * This is package-private to avoid an accessor method.
1357
   *
1358
   * @return The increase ScrollingButton.
1359
   */
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
  /**
1373
   * This method creates a ScrollingButton that points in the appropriate
1374
   * direction for a decreasing button.
1375
   * This is package-private to avoid an accessor method.
1376
   *
1377
   * @return The decrease ScrollingButton.
1378
   */
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
  /**
1392
   * This method finds the point to set the view  position at given the index
1393
   * of a tab. The tab will be the first visible tab in the run.
1394
   * This is package-private to avoid an accessor method.
1395
   *
1396
   * @param index The index of the first visible tab.
1397
   *
1398
   * @return The position of the first visible tab.
1399
   */
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
  /**
1433
   * This method creates a new BasicTabbedPaneUI.
1434
   *
1435
   * @param c The JComponent to create a UI for.
1436
   *
1437
   * @return A new BasicTabbedPaneUI.
1438
   */
1439
  public static ComponentUI createUI(JComponent c)
1440
  {
1441
    return new BasicTabbedPaneUI();
1442
  }
1443
 
1444
  /**
1445
   * This method installs the UI for the given JComponent.
1446
   *
1447
   * @param c The JComponent to install the UI for.
1448
   */
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
  /**
1468
   * This method uninstalls the UI for the  given JComponent.
1469
   *
1470
   * @param c The JComponent to uninstall the UI for.
1471
   */
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
  /**
1485
   * This method creates the appropriate layout manager for the JTabbedPane's
1486
   * current tab layout policy. If the tab layout policy is
1487
   * SCROLL_TAB_LAYOUT, then all the associated components that need to be
1488
   * created will be done so now.
1489
   *
1490
   * @return A layout manager given the tab layout policy.
1491
   */
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
  /**
1519
   * This method installs components for this JTabbedPane.
1520
   */
1521
  protected void installComponents()
1522
  {
1523
    // Nothing to be done.
1524
  }
1525
 
1526
  /**
1527
   * This method uninstalls components for this JTabbedPane.
1528
   */
1529
  protected void uninstallComponents()
1530
  {
1531
    // Nothing to be done.
1532
  }
1533
 
1534
  /**
1535
   * This method installs defaults for the Look and Feel.
1536
   */
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
  /**
1567
   * This method uninstalls defaults for the Look and Feel.
1568
   */
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
  /**
1593
   * This method creates and installs the listeners for this UI.
1594
   */
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
  /**
1609
   * This method removes and nulls the listeners for this UI.
1610
   */
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
  /**
1625
   * This method creates a new MouseListener.
1626
   *
1627
   * @return A new MouseListener.
1628
   */
1629
  protected MouseListener createMouseListener()
1630
  {
1631
    return new MouseHandler();
1632
  }
1633
 
1634
  /**
1635
   * This method creates a new FocusListener.
1636
   *
1637
   * @return A new FocusListener.
1638
   */
1639
  protected FocusListener createFocusListener()
1640
  {
1641
    return new FocusHandler();
1642
  }
1643
 
1644
  /**
1645
   * This method creates a new ChangeListener.
1646
   *
1647
   * @return A new ChangeListener.
1648
   */
1649
  protected ChangeListener createChangeListener()
1650
  {
1651
    return new TabSelectionHandler();
1652
  }
1653
 
1654
  /**
1655
   * This method creates a new PropertyChangeListener.
1656
   *
1657
   * @return A new PropertyChangeListener.
1658
   */
1659
  protected PropertyChangeListener createPropertyChangeListener()
1660
  {
1661
    return new PropertyChangeHandler();
1662
  }
1663
 
1664
  /**
1665
   * This method installs keyboard actions for the JTabbedPane.
1666
   */
1667
  protected void installKeyboardActions()
1668
  {
1669
    // FIXME: Implement.
1670
  }
1671
 
1672
  /**
1673
   * This method uninstalls keyboard actions for the JTabbedPane.
1674
   */
1675
  protected void uninstallKeyboardActions()
1676
  {
1677
    // FIXME: Implement.
1678
  }
1679
 
1680
  /**
1681
   * This method returns the minimum size of the JTabbedPane.
1682
   *
1683
   * @param c The JComponent to find a size for.
1684
   *
1685
   * @return The minimum size.
1686
   */
1687
  public Dimension getMinimumSize(JComponent c)
1688
  {
1689
    return layoutManager.minimumLayoutSize(tabPane);
1690
  }
1691
 
1692
  /**
1693
   * This method returns the maximum size of the JTabbedPane.
1694
   *
1695
   * @param c The JComponent to find a size for.
1696
   *
1697
   * @return The maximum size.
1698
   */
1699
  public Dimension getMaximumSize(JComponent c)
1700
  {
1701
    return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
1702
  }
1703
 
1704
  /**
1705
   * This method paints the JTabbedPane.
1706
   *
1707
   * @param g The Graphics object to paint with.
1708
   * @param c The JComponent to paint.
1709
   */
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
  /**
1720
   * This method paints the tab area. This includes painting the rectangles
1721
   * that make up the tabs.
1722
   *
1723
   * @param g The Graphics object to paint with.
1724
   * @param tabPlacement The JTabbedPane's tab placement.
1725
   * @param selectedIndex The selected index.
1726
   */
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
    // Please note: the ordering of the painting is important. 
1735
    // we WANT to paint the outermost run first and then work our way in.
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
  /**
1780
   * This method paints an individual tab.
1781
   *
1782
   * @param g The Graphics object to paint with.
1783
   * @param tabPlacement The JTabbedPane's tab placement.
1784
   * @param rects The array of rectangles that keep the size and position of
1785
   *        the tabs.
1786
   * @param tabIndex The tab index to paint.
1787
   * @param iconRect The rectangle to use for the icon.
1788
   * @param textRect The rectangle to use for the text.
1789
   */
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
    // FIXME: Paint little folding corner and jagged edge clipped tab.
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
  /**
1839
   * This method lays out the tab and finds the location to paint the  icon
1840
   * and text.
1841
   *
1842
   * @param tabPlacement The JTabbedPane's tab placement.
1843
   * @param metrics The font metrics for the font to paint with.
1844
   * @param tabIndex The tab index to paint.
1845
   * @param title The string painted.
1846
   * @param icon The icon painted.
1847
   * @param tabRect The tab bounds.
1848
   * @param iconRect The calculated icon bounds.
1849
   * @param textRect The calculated text bounds.
1850
   * @param isSelected Whether this tab is selected.
1851
   */
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
  /**
1875
   * This method paints the icon.
1876
   *
1877
   * @param g The Graphics object to paint.
1878
   * @param tabPlacement The JTabbedPane's tab placement.
1879
   * @param tabIndex The tab index to paint.
1880
   * @param icon The icon to paint.
1881
   * @param iconRect The bounds of the icon.
1882
   * @param isSelected Whether this tab is selected.
1883
   */
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
  /**
1891
   * This method paints the text for the given tab.
1892
   *
1893
   * @param g The Graphics object to paint with.
1894
   * @param tabPlacement The JTabbedPane's tab placement.
1895
   * @param font The font to paint with.
1896
   * @param metrics The fontmetrics of the given font.
1897
   * @param tabIndex The tab index.
1898
   * @param title The string to paint.
1899
   * @param textRect The bounds of the string.
1900
   * @param isSelected Whether this tab is selected.
1901
   */
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
  /**
1964
   * This method returns how much the label for the tab should shift in the X
1965
   * direction.
1966
   *
1967
   * @param tabPlacement The JTabbedPane's tab placement.
1968
   * @param tabIndex The tab index being painted.
1969
   * @param isSelected Whether this tab is selected.
1970
   *
1971
   * @return The amount the label should shift by in the X direction.
1972
   */
1973
  protected int getTabLabelShiftX(int tabPlacement, int tabIndex,
1974
                                  boolean isSelected)
1975
  {
1976
    // No reason to shift.
1977
    return 0;
1978
  }
1979
 
1980
  /**
1981
   * This method returns how much the label for the tab should shift in the Y
1982
   * direction.
1983
   *
1984
   * @param tabPlacement The JTabbedPane's tab placement.
1985
   * @param tabIndex The tab index being painted.
1986
   * @param isSelected Whether this tab is selected.
1987
   *
1988
   * @return The amount the label should shift by in the Y direction.
1989
   */
1990
  protected int getTabLabelShiftY(int tabPlacement, int tabIndex,
1991
                                  boolean isSelected)
1992
  {
1993
    // No reason to shift.
1994
    return 0;
1995
  }
1996
 
1997
  /**
1998
   * This method paints the focus rectangle around the selected tab.
1999
   *
2000
   * @param g The Graphics object to paint with.
2001
   * @param tabPlacement The JTabbedPane's tab placement.
2002
   * @param rects The array of rectangles keeping track of size and position.
2003
   * @param tabIndex The tab index.
2004
   * @param iconRect The icon bounds.
2005
   * @param textRect The text bounds.
2006
   * @param isSelected Whether this tab is selected.
2007
   */
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
  /**
2024
   * This method paints the border for an individual tab.
2025
   *
2026
   * @param g The Graphics object to paint with.
2027
   * @param tabPlacement The JTabbedPane's tab placement.
2028
   * @param tabIndex The tab index.
2029
   * @param x The x position of the tab.
2030
   * @param y The y position of the tab.
2031
   * @param w The width of the tab.
2032
   * @param h The height of the tab.
2033
   * @param isSelected Whether the tab is selected.
2034
   */
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
  /**
2072
   * This method paints the background for an individual tab.
2073
   *
2074
   * @param g The Graphics object to paint with.
2075
   * @param tabPlacement The JTabbedPane's tab placement.
2076
   * @param tabIndex The tab index.
2077
   * @param x The x position of the tab.
2078
   * @param y The y position of the tab.
2079
   * @param w The width of the tab.
2080
   * @param h The height of the tab.
2081
   * @param isSelected Whether the tab is selected.
2082
   */
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
  /**
2104
   * This method paints the border around the content area.
2105
   *
2106
   * @param g The Graphics object to paint with.
2107
   * @param tabPlacement The JTabbedPane's tab placement.
2108
   * @param selectedIndex The index of the selected tab.
2109
   */
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
  /**
2125
   * This method paints the top edge of the content border.
2126
   *
2127
   * @param g The Graphics object to paint with.
2128
   * @param tabPlacement The JTabbedPane's tab placement.
2129
   * @param selectedIndex The selected tab index.
2130
   * @param x The x coordinate for the content area.
2131
   * @param y The y coordinate for the content area.
2132
   * @param w The width of the content area.
2133
   * @param h The height of the content area.
2134
   */
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
  /**
2165
   * This method paints the left edge of the content border.
2166
   *
2167
   * @param g The Graphics object to paint with.
2168
   * @param tabPlacement The JTabbedPane's tab placement.
2169
   * @param selectedIndex The selected tab index.
2170
   * @param x The x coordinate for the content area.
2171
   * @param y The y coordinate for the content area.
2172
   * @param w The width of the content area.
2173
   * @param h The height of the content area.
2174
   */
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
  /**
2205
   * This method paints the bottom edge of the content border.
2206
   *
2207
   * @param g The Graphics object to paint with.
2208
   * @param tabPlacement The JTabbedPane's tab placement.
2209
   * @param selectedIndex The selected tab index.
2210
   * @param x The x coordinate for the content area.
2211
   * @param y The y coordinate for the content area.
2212
   * @param w The width of the content area.
2213
   * @param h The height of the content area.
2214
   */
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
  /**
2254
   * This method paints the right edge of the content border.
2255
   *
2256
   * @param g The Graphics object to paint with.
2257
   * @param tabPlacement The JTabbedPane's tab placement.
2258
   * @param selectedIndex The selected tab index.
2259
   * @param x The x coordinate for the content area.
2260
   * @param y The y coordinate for the content area.
2261
   * @param w The width of the content area.
2262
   * @param h The height of the content area.
2263
   */
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
  /**
2302
   * This method returns the tab bounds for the given index.
2303
   *
2304
   * @param pane The JTabbedPane.
2305
   * @param i The index to look for.
2306
   *
2307
   * @return The bounds of the tab with the given index.
2308
   */
2309
  public Rectangle getTabBounds(JTabbedPane pane, int i)
2310
  {
2311
    return rects[i];
2312
  }
2313
 
2314
  /**
2315
   * This method returns the number of runs.
2316
   *
2317
   * @param pane The JTabbedPane.
2318
   *
2319
   * @return The number of runs.
2320
   */
2321
  public int getTabRunCount(JTabbedPane pane)
2322
  {
2323
    return runCount;
2324
  }
2325
 
2326
  /**
2327
   * This method returns the tab index given a coordinate.
2328
   *
2329
   * @param pane The JTabbedPane.
2330
   * @param x The x coordinate.
2331
   * @param y The y coordinate.
2332
   *
2333
   * @return The tab index that the coordinate lands in.
2334
   */
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
  /**
2357
   * This method returns the tab bounds in the given rectangle.
2358
   *
2359
   * @param tabIndex The index to get bounds for.
2360
   * @param dest The rectangle to store bounds in.
2361
   *
2362
   * @return The rectangle passed in.
2363
   */
2364
  protected Rectangle getTabBounds(int tabIndex, Rectangle dest)
2365
  {
2366
    dest.setBounds(getTabBounds(tabPane, tabIndex));
2367
    return dest;
2368
  }
2369
 
2370
  /**
2371
   * This method returns the component that is shown in  the content area.
2372
   *
2373
   * @return The component that is shown in the content area.
2374
   */
2375
  protected Component getVisibleComponent()
2376
  {
2377
    return tabPane.getComponentAt(tabPane.getSelectedIndex());
2378
  }
2379
 
2380
  /**
2381
   * This method sets the visible component.
2382
   *
2383
   * @param component The component to be set visible.
2384
   */
2385
  protected void setVisibleComponent(Component component)
2386
  {
2387
    component.setVisible(true);
2388
    tabPane.setSelectedComponent(component);
2389
  }
2390
 
2391
  /**
2392
   * This method assures that enough rectangles are created given the
2393
   * tabCount. The old array is copied to the  new one.
2394
   *
2395
   * @param tabCount The number of tabs.
2396
   */
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
  /**
2413
   * This method expands the tabRuns array to give it more room. The old array
2414
   * is copied to the new one.
2415
   */
2416
  protected void expandTabRunsArray()
2417
  {
2418
    // This method adds another 10 index positions to the tabRuns array.
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
  /**
2430
   * This method returns which run a particular tab belongs to.
2431
   *
2432
   * @param tabCount The number of tabs.
2433
   * @param tabIndex The tab to find.
2434
   *
2435
   * @return The tabRuns index that it belongs to.
2436
   */
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
  /**
2454
   * This method returns the index of the last tab in  a run.
2455
   *
2456
   * @param tabCount The number of tabs.
2457
   * @param run The run to check.
2458
   *
2459
   * @return The last tab in the given run.
2460
   */
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
  /**
2470
   * This method returns the tab run overlay.
2471
   *
2472
   * @param tabPlacement The JTabbedPane's tab placement.
2473
   *
2474
   * @return The tab run overlay.
2475
   */
2476
  protected int getTabRunOverlay(int tabPlacement)
2477
  {
2478
    return tabRunOverlay;
2479
  }
2480
 
2481
  /**
2482
   * This method returns the tab run indent. It is used in WRAP_TAB_LAYOUT and
2483
   * makes each tab run start indented by a certain amount.
2484
   *
2485
   * @param tabPlacement The JTabbedPane's tab placement.
2486
   * @param run The run to get indent for.
2487
   *
2488
   * @return The amount a run should be indented.
2489
   */
2490
  protected int getTabRunIndent(int tabPlacement, int run)
2491
  {
2492
    return 0;
2493
  }
2494
 
2495
  /**
2496
   * This method returns whether a tab run should be padded.
2497
   *
2498
   * @param tabPlacement The JTabbedPane's tab placement.
2499
   * @param run The run to check.
2500
   *
2501
   * @return Whether the given run should be padded.
2502
   */
2503
  protected boolean shouldPadTabRun(int tabPlacement, int run)
2504
  {
2505
    return true;
2506
  }
2507
 
2508
  /**
2509
   * This method returns whether the tab runs should be rotated.
2510
   *
2511
   * @param tabPlacement The JTabbedPane's tab placement.
2512
   *
2513
   * @return Whether runs should be rotated.
2514
   */
2515
  protected boolean shouldRotateTabRuns(int tabPlacement)
2516
  {
2517
    return true;
2518
  }
2519
 
2520
  /**
2521
   * This method returns an icon for the tab. If the tab is disabled, it
2522
   * should return the disabledIcon. If it is enabled, then it should return
2523
   * the default icon.
2524
   *
2525
   * @param tabIndex The tab index to get an icon for.
2526
   *
2527
   * @return The icon for the tab index.
2528
   */
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
  /**
2538
   * This method returns a view that can paint the text for the label.
2539
   *
2540
   * @param tabIndex The tab index to get a view for.
2541
   *
2542
   * @return The view for the tab index.
2543
   */
2544
  protected View getTextViewForTab(int tabIndex)
2545
  {
2546
    return null;
2547
  }
2548
 
2549
  /**
2550
   * This method returns the tab height, including insets, for the given index
2551
   * and fontheight.
2552
   *
2553
   * @param tabPlacement The JTabbedPane's tab placement.
2554
   * @param tabIndex The index of the tab to calculate.
2555
   * @param fontHeight The font height.
2556
   *
2557
   * @return This tab's height.
2558
   */
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
  /**
2584
   * This method returns the max tab height.
2585
   *
2586
   * @param tabPlacement The JTabbedPane's tab placement.
2587
   *
2588
   * @return The maximum tab height.
2589
   */
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
  /**
2605
   * This method calculates the tab width, including insets, for the given tab
2606
   * index and font metrics.
2607
   *
2608
   * @param tabPlacement The JTabbedPane's tab placement.
2609
   * @param tabIndex The tab index to calculate for.
2610
   * @param metrics The font's metrics.
2611
   *
2612
   * @return The tab width for the given index.
2613
   */
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
  /**
2639
   * This method calculates the max tab width.
2640
   *
2641
   * @param tabPlacement The JTabbedPane's tab placement.
2642
   *
2643
   * @return The maximum tab width.
2644
   */
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
  /**
2659
   * This method calculates the tab area height, including insets, for the
2660
   * given amount of runs and tab height.
2661
   *
2662
   * @param tabPlacement The JTabbedPane's tab placement.
2663
   * @param horizRunCount The number of runs.
2664
   * @param maxTabHeight The max tab height.
2665
   *
2666
   * @return The tab area height.
2667
   */
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
  /**
2681
   * This method calculates the tab area width, including insets, for the
2682
   * given amount of runs and tab width.
2683
   *
2684
   * @param tabPlacement The JTabbedPane's tab placement.
2685
   * @param vertRunCount The number of runs.
2686
   * @param maxTabWidth The max tab width.
2687
   *
2688
   * @return The tab area width.
2689
   */
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
  /**
2703
   * This method returns the tab insets appropriately rotated.
2704
   *
2705
   * @param tabPlacement The JTabbedPane's tab placement.
2706
   * @param tabIndex The tab index.
2707
   *
2708
   * @return The tab insets for the given index.
2709
   */
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
  /**
2718
   * This method returns the selected tab pad insets appropriately rotated.
2719
   *
2720
   * @param tabPlacement The JTabbedPane's tab placement.
2721
   *
2722
   * @return The selected tab pad insets.
2723
   */
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
  /**
2732
   * This method returns the tab area insets appropriately rotated.
2733
   *
2734
   * @param tabPlacement The JTabbedPane's tab placement.
2735
   *
2736
   * @return The tab area insets.
2737
   */
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
  /**
2746
   * This method returns the content border insets appropriately rotated.
2747
   *
2748
   * @param tabPlacement The JTabbedPane's tab placement.
2749
   *
2750
   * @return The content border insets.
2751
   */
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
  /**
2760
   * This method returns the fontmetrics for the font of the JTabbedPane.
2761
   *
2762
   * @return The font metrics for the JTabbedPane.
2763
   */
2764
  protected FontMetrics getFontMetrics()
2765
  {
2766
    FontMetrics fm = tabPane.getToolkit().getFontMetrics(tabPane.getFont());
2767
    return fm;
2768
  }
2769
 
2770
  /**
2771
   * This method navigates from the selected tab into the given direction. As
2772
   * a result, a new tab will be selected (if possible).
2773
   *
2774
   * @param direction The direction to navigate in.
2775
   */
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
  /**
2817
   * This method selects the next tab in the run.
2818
   *
2819
   * @param current The current selected index.
2820
   */
2821
  protected void selectNextTabInRun(int current)
2822
  {
2823
    tabPane.setSelectedIndex(getNextTabIndexInRun(tabPane.getTabCount(),
2824
                                                  current));
2825
  }
2826
 
2827
  /**
2828
   * This method selects the previous tab in the run.
2829
   *
2830
   * @param current The current selected index.
2831
   */
2832
  protected void selectPreviousTabInRun(int current)
2833
  {
2834
    tabPane.setSelectedIndex(getPreviousTabIndexInRun(tabPane.getTabCount(),
2835
                                                      current));
2836
  }
2837
 
2838
  /**
2839
   * This method selects the next tab (regardless of runs).
2840
   *
2841
   * @param current The current selected index.
2842
   */
2843
  protected void selectNextTab(int current)
2844
  {
2845
    tabPane.setSelectedIndex(getNextTabIndex(current));
2846
  }
2847
 
2848
  /**
2849
   * This method selects the previous tab (regardless of runs).
2850
   *
2851
   * @param current The current selected index.
2852
   */
2853
  protected void selectPreviousTab(int current)
2854
  {
2855
    tabPane.setSelectedIndex(getPreviousTabIndex(current));
2856
  }
2857
 
2858
  /**
2859
   * This method selects the correct tab given an offset from the current tab
2860
   * index. If the tab placement is TOP or BOTTOM, the offset will be in the
2861
   * y direction, otherwise, it will be in the x direction. A new coordinate
2862
   * will be found by adding the offset to the current location of the tab.
2863
   * The tab that the new location will be selected.
2864
   *
2865
   * @param tabPlacement The JTabbedPane's tab placement.
2866
   * @param tabIndex The tab to start from.
2867
   * @param offset The coordinate offset.
2868
   */
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
  // This method is called when you press up/down to cycle through tab runs.
2893
  // it returns the distance (between the two runs' x/y position.
2894
  // where one run is the current selected run and the other run is the run in the
2895
  // direction of the scroll (dictated by the forward flag)
2896
  // the offset is an absolute value of the difference
2897
 
2898
  /**
2899
   * This method calculates the offset distance for use in
2900
   * selectAdjacentRunTab. The offset returned will be a difference in the y
2901
   * coordinate between the run in  the desired direction and the current run
2902
   * (for tabPlacement in TOP or BOTTOM). Use x coordinate for LEFT and
2903
   * RIGHT.
2904
   *
2905
   * @param tabPlacement The JTabbedPane's tab placement.
2906
   * @param tabCount The number of tabs.
2907
   * @param tabIndex The starting index.
2908
   * @param forward If forward, the run in the desired direction will be the
2909
   *        next run.
2910
   *
2911
   * @return The offset between the two runs.
2912
   */
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
  /**
2930
   * This method returns the previous tab index.
2931
   *
2932
   * @param base The index to start from.
2933
   *
2934
   * @return The previous tab index.
2935
   */
2936
  protected int getPreviousTabIndex(int base)
2937
  {
2938
    base--;
2939
    if (base < 0)
2940
      return tabPane.getTabCount() - 1;
2941
    return base;
2942
  }
2943
 
2944
  /**
2945
   * This method returns the next tab index.
2946
   *
2947
   * @param base The index to start from.
2948
   *
2949
   * @return The next tab index.
2950
   */
2951
  protected int getNextTabIndex(int base)
2952
  {
2953
    base++;
2954
    if (base == tabPane.getTabCount())
2955
      return 0;
2956
    return base;
2957
  }
2958
 
2959
  /**
2960
   * This method returns the next tab index in the run. If the next index is
2961
   * out of this run, it will return the starting tab index for the run.
2962
   *
2963
   * @param tabCount The number of tabs.
2964
   * @param base The index to start from.
2965
   *
2966
   * @return The next tab index in the run.
2967
   */
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
  /**
2978
   * This method returns the previous tab index in the run. If the previous
2979
   * index is out of this run, it will return the last index for the run.
2980
   *
2981
   * @param tabCount The number of tabs.
2982
   * @param base The index to start from.
2983
   *
2984
   * @return The previous tab index in the run.
2985
   */
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
  /**
2996
   * This method returns the index of the previous run.
2997
   *
2998
   * @param baseRun The run to start from.
2999
   *
3000
   * @return The index of the previous run.
3001
   */
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
  /**
3014
   * This method returns the index of the next run.
3015
   *
3016
   * @param baseRun The run to start from.
3017
   *
3018
   * @return The index of the next run.
3019
   */
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
  /**
3032
   * This method rotates the insets given a direction to rotate them in.
3033
   * Target placement should be one of TOP, LEFT, BOTTOM, RIGHT. The  rotated
3034
   * insets will be stored in targetInsets. Passing in TOP as  the direction
3035
   * does nothing. Passing in LEFT switches top and left, right and bottom.
3036
   * Passing in BOTTOM switches top and bottom. Passing in RIGHT switches top
3037
   * for left, left for bottom, bottom for right, and right for top.
3038
   *
3039
   * @param topInsets The reference insets.
3040
   * @param targetInsets An Insets object to store the new insets.
3041
   * @param targetPlacement The rotation direction.
3042
   */
3043
  protected static void rotateInsets(Insets topInsets, Insets targetInsets,
3044
                                     int targetPlacement)
3045
  {
3046
    // Sun's version will happily throw an NPE if params are null,
3047
    // so I won't check it either.
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.