/**
   * Creates a close all tabs button that closes all tabs in the given Tabbed Panel when the button
   * is selected
   *
   * @param tabbedPanel the tabbed panel that the button will close all tabs in
   * @return the close button
   */
  private JButton createCloseAllTabsButton(final TabbedPanel tabbedPanel) {
    final JButton closeButton = createXButton();
    closeButton.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            // Iterate over all tabs and remove them.
            int tabCount = tabbedPanel.getTabCount();
            for (int i = 0; i < tabCount; i++) tabbedPanel.removeTab(tabbedPanel.getTabAt(0));
          }
        });

    // Add a tab listener to the tabbed panel so that we know when tabs are
    // added
    // and removed so that the close button can be hidden when the tabbed
    // panel
    // doesn't contain any tabs.
    tabbedPanel.addTabListener(
        new TabAdapter() {
          public void tabAdded(TabEvent event) {
            closeButton.setVisible(true);
          }

          public void tabRemoved(TabRemovedEvent event) {
            // Hide the close button when there are no tabs in the tabbed
            // panel
            closeButton.setVisible(event.getTabbedPanel().getTabCount() > 0);
          }
        });
    return closeButton;
  }
  private Point getLocationInTabbedPanel(Component c, TabbedPanel tp) {
    Point l = SwingUtilities.convertPoint(c.getParent(), c.getLocation(), tp);
    Insets tpInsets = tp.getInsets();
    l.x -= tpInsets.left;
    l.y -= tpInsets.top;

    return l;
  }
  /** Constructor */
  private SimpleTabbedPanelExample() {
    frame.setSize(600, 400);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setJMenuBar(createMenuBar());
    frame.getContentPane().add(tabbedPanel, BorderLayout.CENTER);

    // Set the "close all tabs" button as a tab area component
    tabbedPanel.setTabAreaComponents(new JComponent[] {createCloseAllTabsButton(tabbedPanel)});

    // Create 6 titled tabs and add them to the tabbed panel
    for (int i = 0; i < 6; i++) tabbedPanel.addTab(createTab());

    // Apply the default theme
    tabbedPanel.getProperties().addSuperObject(themes[0].getTabbedPanelProperties());
    titledTabProperties.addSuperObject(themes[0].getTitledTabProperties());
    activeTheme = themes[0];

    frame.setVisible(true);
  }
  /**
   * Applies properties from a theme to tabbed panel and all the titled tabs.
   *
   * @param theme theme to apply
   */
  private void applyTheme(TabbedPanelTitledTabTheme theme) {
    // Remove the previous theme. If we hadn't added the DefaultTheme the
    // first time we wouldn't have any theme to remove and thus we would
    // have had to implement a flag or theme reference to tell us if we
    // needed to remove a theme or not.
    tabbedPanel.getProperties().removeSuperObject(activeTheme.getTabbedPanelProperties());
    titledTabProperties.removeSuperObject(activeTheme.getTitledTabProperties());

    // Adding a super object means that any properties that are set in the
    // super
    // object will be used instead of the same properties in the default
    // properties. Note that if you have explicitly set a property, for
    // example setTabAreaOrientation in the properties for the tabbed
    // panel, then that property will not be affected by the super object
    // i.e. it will still return the same value after adding the super
    // object.
    tabbedPanel.getProperties().addSuperObject(theme.getTabbedPanelProperties());
    titledTabProperties.addSuperObject(theme.getTitledTabProperties());

    activeTheme = theme;
  }
  protected void paintPolygon(Component c, Graphics2D g, Polygon polygon, int width, int height) {
    TabbedPanel tp = TabbedUtils.getParentTabbedPanel(c);
    if (tp != null) {
      Direction d = tp.getProperties().getTabAreaOrientation();

      int i = 0;

      Color c1 = topLeftColor.getColor();
      Color c2 = bottomRightColor.getColor();

      if (d == Direction.UP) {
        g.setColor(c1);
        while (i < (roundCorners ? 3 : 1)) {
          GraphicsUtil.drawOptimizedLine(
              g,
              polygon.xpoints[i],
              polygon.ypoints[i],
              polygon.xpoints[i + 1],
              polygon.ypoints[i + 1]);
          i++;
        }

        g.setColor(c2);
        while (i < polygon.npoints - 1) {
          GraphicsUtil.drawOptimizedLine(
              g,
              polygon.xpoints[i],
              polygon.ypoints[i],
              polygon.xpoints[i + 1],
              polygon.ypoints[i + 1]);
          i++;
        }

        g.setColor(c1);
        GraphicsUtil.drawOptimizedLine(
            g, polygon.xpoints[i], polygon.ypoints[i], polygon.xpoints[0], polygon.ypoints[0]);

      } else if (d == Direction.RIGHT) {
        g.setColor(c2);
        while (i < polygon.npoints - (open ? 2 : roundCorners ? 3 : 2)) {
          GraphicsUtil.drawOptimizedLine(
              g,
              polygon.xpoints[i],
              polygon.ypoints[i],
              polygon.xpoints[i + 1],
              polygon.ypoints[i + 1]);
          i++;
        }

        g.setColor(c1);
        for (int k = i - 1; k < polygon.npoints - 2; k++) {
          GraphicsUtil.drawOptimizedLine(
              g,
              polygon.xpoints[i],
              polygon.ypoints[i],
              polygon.xpoints[i + 1],
              polygon.ypoints[i + 1]);
          i++;
        }
        GraphicsUtil.drawOptimizedLine(
            g, polygon.xpoints[i], polygon.ypoints[i], polygon.xpoints[0], polygon.ypoints[0]);

      } else if (d == Direction.DOWN) {
        g.setColor(c2);
        while (i < (roundCorners ? 5 : 2)) {
          GraphicsUtil.drawOptimizedLine(
              g,
              polygon.xpoints[i],
              polygon.ypoints[i],
              polygon.xpoints[i + 1],
              polygon.ypoints[i + 1]);
          i++;
        }

        g.setColor(c1);
        while (i < polygon.npoints - 1) {
          GraphicsUtil.drawOptimizedLine(
              g,
              polygon.xpoints[i],
              polygon.ypoints[i],
              polygon.xpoints[i + 1],
              polygon.ypoints[i + 1]);
          i++;
        }

        GraphicsUtil.drawOptimizedLine(
            g, polygon.xpoints[i], polygon.ypoints[i], polygon.xpoints[0], polygon.ypoints[0]);
      } else {
        g.setColor(c1);
        while (i < (roundCorners ? 3 : 1)) {
          GraphicsUtil.drawOptimizedLine(
              g,
              polygon.xpoints[i],
              polygon.ypoints[i],
              polygon.xpoints[i + 1],
              polygon.ypoints[i + 1]);
          i++;
        }

        g.setColor(c2);
        while (i < polygon.npoints - 1) {
          GraphicsUtil.drawOptimizedLine(
              g,
              polygon.xpoints[i],
              polygon.ypoints[i],
              polygon.xpoints[i + 1],
              polygon.ypoints[i + 1]);
          i++;
        }

        g.setColor(c1);

        GraphicsUtil.drawOptimizedLine(
            g, polygon.xpoints[i], polygon.ypoints[i], polygon.xpoints[0], polygon.ypoints[0]);
      }
    }
  }
  public void paintTabArea(TabbedPanel tp, Graphics g, int x, int y, int width, int height) {
    int heightTemp = height;
    int widthTemp = width;
    int xTemp = x;
    int yTemp = y;
    if (enabled && tp.isTabAreaVisible()) {

      tabData.initialize(tp);

      PanePainter pane = paneHandler.getPainter(tabData.getAreaOrientation());

      initTabLocations(pane);
      Insets aInsets = getTabAreaInsets(tabData.getAreaOrientation());

      if (tp.getTabCount() > 0) {
        // Adjust x, y
        if (tabData.getAreaOrientation() == Direction.DOWN) {
          yTemp += tabData.getTabbedPanelHeight() - heightTemp;
        } else if (tabData.getAreaOrientation() == Direction.RIGHT) {
          xTemp += tabData.getTabbedPanelWidth() - widthTemp;
        }

        widthTemp = xTemp < 0 ? widthTemp + xTemp : widthTemp;
        heightTemp = yTemp < 0 ? heightTemp + yTemp : heightTemp;

        xTemp = Math.max(0, xTemp);
        yTemp = Math.max(0, yTemp);

        if (tabData.isHorizontalLayout())
          pane.setSize(tabData.getTabbedPanelSize().width, getTabbedPanelExtraSize());
        else pane.setSize(getTabbedPanelExtraSize(), tabData.getTabbedPanelHeight());

        if (PAINT_TAB_AREA && !(pane.getTabCount() == 0 && tabData.getTabCount() > 0)) {
          Shape originalClip = g.getClip();

          int tx =
              -xTemp
                  - (tabData.getAreaOrientation() == Direction.RIGHT
                      ? -tabData.getTabbedPanelWidth() + getTabbedPanelExtraSize()
                      : 0);
          int ty =
              -yTemp
                  - (tabData.getAreaOrientation() == Direction.DOWN
                      ? -tabData.getTabbedPanelHeight() + getTabbedPanelExtraSize()
                      : 0);

          Rectangle firstVisibleRect = (Rectangle) tabData.getVisibleTabRects().get(0);
          Rectangle lastVisibleRect =
              (Rectangle) tabData.getVisibleTabRects().get(tabData.getTabCount() - 1);
          Tab lastTab = (Tab) tabData.getTabList().get(tabData.getTabCount() - 1);

          if (tabData.isHorizontalLayout()) {
            int extraWidth =
                lastTab.getWidth() == lastVisibleRect.width
                    ? 0
                    : 2 * tabData.getTabbedPanelSize().width - tabData.getTabAreaWidth();
            pane.setSize(pane.getWidth() + extraWidth, pane.getHeight());

            pane.doValidation();

            // Before tabs
            g.clipRect(
                0,
                0,
                aInsets.left + (firstVisibleRect.width > 0 && firstVisibleRect.x == 0 ? 1 : 0),
                heightTemp);
            pane.paint(g, tx, ty);
            g.setClip(originalClip);

            // After tabs
            tx -= extraWidth;

            int clipExtraWidth = extraWidth == 0 ? 1 : 0;
            g.clipRect(
                aInsets.left + tabData.getTabAreaWidth() - clipExtraWidth,
                0,
                widthTemp - aInsets.left - tabData.getTabAreaWidth() + clipExtraWidth,
                heightTemp);
            pane.paint(g, tx, ty);
            g.setClip(originalClip);
          } else {
            int extraHeight =
                lastTab.getHeight() == lastVisibleRect.height
                    ? 0
                    : 2 * tabData.getTabbedPanelSize().height - tabData.getTabAreaHeight();
            pane.setSize(pane.getWidth(), pane.getHeight() + extraHeight);

            pane.doValidation();

            // Before tabs
            g.clipRect(
                0,
                0,
                widthTemp,
                aInsets.top + (firstVisibleRect.height > 0 && firstVisibleRect.y == 0 ? 1 : 0));
            pane.paint(g, tx, ty);
            g.setClip(originalClip);

            // After tabs
            ty -= extraHeight;

            int clipExtraHeight = extraHeight == 0 ? 1 : 0;
            g.clipRect(
                0,
                aInsets.top + tabData.getTabAreaHeight() - clipExtraHeight,
                widthTemp,
                heightTemp - aInsets.top - tabData.getTabAreaHeight() + clipExtraHeight);
            pane.paint(g, tx, ty);
            g.setClip(originalClip);
          }
        }

        // First and last tab
        paintTabs(pane, tabData, g, xTemp, yTemp, widthTemp, heightTemp);

        tabData.reset();

        reset(pane);
      }
    }
  }
 private void removeTabbedPanel(TabbedPanel tabbedPanel) {
   if (applied) {
     tabbedPanel.getProperties().removeSuperObject(tabbedPanelProperties);
     applied = false;
   }
 }
 private void applyTabbedPanel(TabbedPanel tabbedPanel) {
   if (!applied) {
     tabbedPanel.getProperties().addSuperObject(tabbedPanelProperties);
     applied = true;
   }
 }