Package org.pushingpixels.substance.internal.ui

Source Code of org.pushingpixels.substance.internal.ui.SubstanceTableHeaderUI$ScrollPaneCornerFiller

/*
* Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  o Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
*  o Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
*  o Neither the name of Substance Kirill Grouchnikov nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.pushingpixels.substance.internal.ui;

import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.*;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.*;

import org.pushingpixels.lafwidget.LafWidgetUtilities;
import org.pushingpixels.lafwidget.animation.AnimationConfigurationManager;
import org.pushingpixels.lafwidget.animation.AnimationFacet;
import org.pushingpixels.substance.api.*;
import org.pushingpixels.substance.api.renderers.SubstanceDefaultTableHeaderCellRenderer;
import org.pushingpixels.substance.internal.animation.StateTransitionMultiTracker;
import org.pushingpixels.substance.internal.animation.StateTransitionTracker;
import org.pushingpixels.substance.internal.animation.StateTransitionTracker.RepaintCallback;
import org.pushingpixels.substance.internal.painter.HighlightPainterUtils;
import org.pushingpixels.substance.internal.utils.*;
import org.pushingpixels.trident.Timeline.TimelineState;
import org.pushingpixels.trident.callback.TimelineCallback;
import org.pushingpixels.trident.callback.UIThreadTimelineCallbackAdapter;

/**
* UI for table headers in <b>Substance</b> look and feel.
*
* @author Kirill Grouchnikov
*/
public class SubstanceTableHeaderUI extends BasicTableHeaderUI {
  /**
   * Repaints the header on column selection.
   */
  protected TableHeaderListener substanceHeaderListener;

  /**
   * The default renderer.
   */
  protected TableCellRenderer defaultHeaderRenderer;

  /**
   * Holds the list of currently selected indices.
   */
  protected Map<Integer, Object> selectedIndices;

  /**
   * Listener for transition animations on list selections.
   */
  protected ListSelectionListener substanceFadeSelectionListener;

  private StateTransitionMultiTracker<Integer> stateTransitionMultiTracker;

  /**
   * Property change listener.
   */
  protected PropertyChangeListener substancePropertyChangeListener;

  /**
   * Listener for table header.
   *
   * @author Kirill Grouchnikov
   */
  private static class TableHeaderListener implements ListSelectionListener {
    /**
     * The associated table header UI.
     */
    private SubstanceTableHeaderUI ui;

    /**
     * Simple constructor.
     *
     * @param ui
     *            The associated table header UI
     */
    public TableHeaderListener(SubstanceTableHeaderUI ui) {
      this.ui = ui;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * javax.swing.event.ListSelectionListener#valueChanged(javax.swing.
     * event.ListSelectionEvent)
     */
    public void valueChanged(ListSelectionEvent e) {
      if (ui.header == null)
        return;
      if (ui.header.isValid())
        ui.header.repaint();
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
   */
  public static ComponentUI createUI(JComponent comp) {
    SubstanceCoreUtilities.testComponentCreationThreadingViolation(comp);
    return new SubstanceTableHeaderUI();
  }

  /**
   * Creates a new UI delegate.
   */
  public SubstanceTableHeaderUI() {
    this.stateTransitionMultiTracker = new StateTransitionMultiTracker<Integer>();
    selectedIndices = new HashMap<Integer, Object>();
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.plaf.basic.BasicTableHeaderUI#installListeners()
   */
  @Override
  protected void installListeners() {
    super.installListeners();
    TableColumnModel columnModel = header.getColumnModel();
    if (columnModel != null) {
      ListSelectionModel lsm = columnModel.getSelectionModel();
      if (lsm != null) {
        // fix for defect 109 - memory leak on skin switch
        substanceHeaderListener = new TableHeaderListener(this);
        lsm.addListSelectionListener(substanceHeaderListener);
      }
    }

    // Add listener for the selection animation
    this.substanceFadeSelectionListener = new ListSelectionListener() {
      public void valueChanged(ListSelectionEvent e) {
        if (header == null)
          return;

        if (!header.getColumnModel().getColumnSelectionAllowed())
          return;

        // fix for issue 367 - check that there is an associated
        // table and that it has a substance UI delegate
        JTable table = header.getTable();
        if (table == null)
          return;

        TableUI ui = table.getUI();
        if (!(ui instanceof SubstanceTableUI)) {
          stateTransitionMultiTracker.clear();
          return;
        }

        // optimization on large tables and large selections
        // and syncing the fade presence with the table
        // (issue 309)
        SubstanceTableUI tableUI = (SubstanceTableUI) ui;
        // System.out.println("Sel anim: "
        // + tableUI.hasSelectionAnimations());
        if (!tableUI._hasSelectionAnimations()) {
          stateTransitionMultiTracker.clear();
          return;
        }

        // Set<Long> initiatedFadeSequences = new HashSet<Long>();
        Set<StateTransitionTracker> initiatedTrackers = new HashSet<StateTransitionTracker>();
        boolean fadeCanceled = false;

        // if (SubstanceCoreUtilities.toBleedWatermark(list))
        // return;

        // FadeTracker fadeTrackerInstance = FadeTracker.getInstance();
        TableColumnModel columnModel = header.getColumnModel();
        int size = columnModel.getColumnCount();
        ListSelectionModel lsm = columnModel.getSelectionModel();
        for (int i = e.getFirstIndex(); i <= e.getLastIndex(); i++) {
          if (i >= size)
            continue;
          if (lsm.isSelectedIndex(i)) {
            // check if was selected before
            if (!selectedIndices.containsKey(i)) {
              // start fading in
              // System.out.println("Fade in on index " + i);

              if (!fadeCanceled) {
                StateTransitionTracker tracker = getTracker(i,
                    getColumnState(i).isFacetActive(
                        ComponentStateFacet.ROLLOVER),
                    false);
                tracker.getModel().setSelected(true);
                initiatedTrackers.add(tracker);
                if (initiatedTrackers.size() > 15) {
                  stateTransitionMultiTracker.clear();
                  initiatedTrackers.clear();
                  fadeCanceled = true;
                }
              }

              selectedIndices.put(i, columnModel.getColumn(i));
            }
          } else {
            // check if was selected before and still points to the
            // same element
            if (selectedIndices.containsKey(i)) {
              if (selectedIndices.get(i) == columnModel
                  .getColumn(i)) {
                // start fading out
                // System.out.println("Fade out on index " + i);

                if (!fadeCanceled) {
                  StateTransitionTracker tracker = getTracker(
                      i,
                      getColumnState(i)
                          .isFacetActive(
                              ComponentStateFacet.ROLLOVER),
                      true);
                  tracker.getModel().setSelected(false);
                  initiatedTrackers.add(tracker);
                  if (initiatedTrackers.size() > 15) {
                    stateTransitionMultiTracker.clear();
                    initiatedTrackers.clear();
                    fadeCanceled = true;
                  }
                }
              }
              selectedIndices.remove(i);
            }
          }
        }
      }
    };

    if (columnModel != null) {
      ListSelectionModel lsm = columnModel.getSelectionModel();
      if (lsm != null) {
        lsm.addListSelectionListener(substanceFadeSelectionListener);
      }
    }

    this.substancePropertyChangeListener = new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
        if ("table".equals(evt.getPropertyName())) {
          // track changes to the table and re-register the
          // column model listener to the new table.
          TableColumnModel oldModel = (evt.getOldValue() instanceof JTable) ? ((JTable) evt
              .getOldValue()).getColumnModel()
              : null;
          TableColumnModel newModel = (evt.getNewValue() instanceof JTable) ? ((JTable) evt
              .getNewValue()).getColumnModel()
              : null;
          processColumnModelChangeEvent(oldModel, newModel);
        }
      }
    };
    this.header
        .addPropertyChangeListener(this.substancePropertyChangeListener);
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.plaf.basic.BasicTableHeaderUI#installDefaults()
   */
  @Override
  protected void installDefaults() {
    super.installDefaults();

    defaultHeaderRenderer = header.getDefaultRenderer();
    if (defaultHeaderRenderer instanceof UIResource) {
      header
          .setDefaultRenderer(new SubstanceDefaultTableHeaderCellRenderer());
    }

    for (int i = 0; i < header.getColumnModel().getColumnCount(); i++) {
      if (header.getColumnModel().getSelectionModel().isSelectedIndex(i)) {
        selectedIndices.put(i, header.getColumnModel().getColumn(i));
      }
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.plaf.basic.BasicTableHeaderUI#uninstallListeners()
   */
  @Override
  protected void uninstallListeners() {
    // fix for defect 109 - memory leak on skin switch
    TableColumnModel columnModel = header.getColumnModel();
    if (columnModel != null) {
      ListSelectionModel lsm = columnModel.getSelectionModel();
      if (lsm != null) {
        lsm.removeListSelectionListener(substanceHeaderListener);
        substanceHeaderListener = null;
      }
    }

    this.header
        .removePropertyChangeListener(this.substancePropertyChangeListener);
    this.substancePropertyChangeListener = null;

    super.uninstallListeners();
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.plaf.basic.BasicTableHeaderUI#uninstallDefaults()
   */
  @Override
  protected void uninstallDefaults() {
    super.uninstallDefaults();

    selectedIndices.clear();

    if (header.getDefaultRenderer() instanceof SubstanceDefaultTableHeaderCellRenderer) {
      header.setDefaultRenderer(defaultHeaderRenderer);
      if (defaultHeaderRenderer instanceof Component)
        SwingUtilities
            .updateComponentTreeUI((Component) defaultHeaderRenderer);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.plaf.ComponentUI#paint(java.awt.Graphics,
   * javax.swing.JComponent)
   */
  @Override
  public void paint(Graphics g, JComponent c) {
    if (header.getColumnModel().getColumnCount() <= 0) {
      return;
    }
    boolean ltr = header.getComponentOrientation().isLeftToRight();

    Rectangle clip = g.getClipBounds();
    Point left = clip.getLocation();
    Point right = new Point(clip.x + clip.width - 1, clip.y);

    TableColumnModel cm = header.getColumnModel();
    int[] selectedColumns = cm.getSelectedColumns();
    Set<Integer> selected = new HashSet<Integer>();
    for (int sel : selectedColumns)
      selected.add(sel);

    int cMin = header.columnAtPoint(ltr ? left : right);
    int cMax = header.columnAtPoint(ltr ? right : left);
    // This should never happen.
    if (cMin == -1) {
      cMin = 0;
    }
    // If the table does not have enough columns to fill the view we'll get
    // -1.
    // Replace this with the index of the last column.
    if (cMax == -1) {
      cMax = cm.getColumnCount() - 1;
    }

    TableColumn draggedColumn = header.getDraggedColumn();
    int columnWidth;
    Rectangle cellRect = header.getHeaderRect(ltr ? cMin : cMax);
    TableColumn aColumn;
    if (ltr) {
      for (int column = cMin; column <= cMax; column++) {
        aColumn = cm.getColumn(column);
        columnWidth = aColumn.getWidth();
        cellRect.width = columnWidth;
        if (aColumn != draggedColumn) {
          this.paintCell(g, cellRect, column, selected
              .contains(column));
        }
        cellRect.x += columnWidth;
      }
    } else {
      for (int column = cMax; column >= cMin; column--) {
        aColumn = cm.getColumn(column);
        columnWidth = aColumn.getWidth();
        cellRect.width = columnWidth;
        if (aColumn != draggedColumn) {
          this.paintCell(g, cellRect, column, selected
              .contains(column));
        }
        cellRect.x += columnWidth;
      }
    }

    this.paintGrid(g, c);

    // Paint the dragged column if we are dragging.
    if (draggedColumn != null) {
      int draggedColumnIndex = viewIndexForColumn(draggedColumn);
      Rectangle draggedCellRect = header
          .getHeaderRect(draggedColumnIndex);

      // Draw a gray well in place of the moving column.
      g.setColor(header.getParent().getBackground());
      g.fillRect(draggedCellRect.x, draggedCellRect.y,
          draggedCellRect.width, draggedCellRect.height);

      draggedCellRect.x += header.getDraggedDistance();

      // Fill the background.
      g.setColor(header.getBackground());
      g.fillRect(draggedCellRect.x, draggedCellRect.y,
          draggedCellRect.width, draggedCellRect.height);

      this.paintCell(g, draggedCellRect, draggedColumnIndex, selected
          .contains(draggedColumnIndex));
    }

    // Remove all components in the rendererPane.
    rendererPane.removeAll();
  }

  /**
   * Retrieves renderer for the specified column header.
   *
   * @param columnIndex
   *            Column index.
   * @return Renderer for the specified column header.
   */
  private Component getHeaderRenderer(int columnIndex) {
    TableColumn aColumn = header.getColumnModel().getColumn(columnIndex);
    TableCellRenderer renderer = aColumn.getHeaderRenderer();
    if (renderer == null) {
      renderer = header.getDefaultRenderer();
    }
    return renderer.getTableCellRendererComponent(header.getTable(),
        aColumn.getHeaderValue(), false, false, -1, columnIndex);
  }

  /**
   *
   *
   * @param g
   * @param c
   */
  protected void paintGrid(Graphics g, JComponent c) {
    boolean ltr = header.getComponentOrientation().isLeftToRight();

    Graphics2D g2d = (Graphics2D) g.create();

    Rectangle clip = g.getClipBounds();
    Point left = clip.getLocation();
    // tweak the points for issue 378 - making sure that the
    // grid lines are repainted correctly on scroll.
    int lineWeight = (int) Math.ceil(SubstanceSizeUtils
        .getBorderStrokeWidth(SubstanceSizeUtils
            .getComponentFontSize(c)));
    left = new Point(left.x - 2 * lineWeight, left.y);
    Point right = new Point(clip.x + clip.width + 2 * lineWeight, clip.y);

    TableColumnModel cm = header.getColumnModel();

    int cMin = header.columnAtPoint(ltr ? left : right);
    int cMax = header.columnAtPoint(ltr ? right : left);
    // This should never happen.
    if (cMin == -1) {
      cMin = 0;
    }

    Rectangle cellRect0 = header.getHeaderRect(cMin);
    // int top = cellRect0.y;
    int bottom = cellRect0.y + cellRect0.height;

    Color gridColor = getGridColor(this.header);

    float strokeWidth = SubstanceSizeUtils
        .getBorderStrokeWidth(SubstanceSizeUtils
            .getComponentFontSize(this.header));
    g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND,
        BasicStroke.JOIN_BEVEL));
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setColor(gridColor);
    g2d.setComposite(LafWidgetUtilities.getAlphaComposite(this.header,
        0.7f, g));

    g2d.drawLine((int) left.getX(), (int) (bottom - strokeWidth / 2),
        (int) right.getX(), (int) (bottom - strokeWidth / 2));
    // If the table does not have enough columns to fill the view we'll
    // get -1. Replace this with the index of the last column.
    if (cMax == -1) {
      cMax = cm.getColumnCount() - 1;
    }

    TableColumn draggedColumn = this.header.getDraggedColumn();
    int columnWidth;
    Rectangle cellRect = this.header.getHeaderRect(ltr ? cMin : cMax);
    TableColumn aColumn;
    if (ltr) {
      for (int column = cMin; column <= cMax; column++) {
        aColumn = cm.getColumn(column);
        columnWidth = aColumn.getWidth();
        cellRect.width = columnWidth;

        if (aColumn != draggedColumn) {
          if (hasLeadingVerticalGridLine(header, cellRect, column)) {
            g2d
                .drawLine(cellRect.x, cellRect.y, cellRect.x,
                    bottom);
          }
          if (hasTrailingVerticalGridLine(header, cellRect, column)) {
            g2d.drawLine(cellRect.x + cellRect.width - 1,
                cellRect.y, cellRect.x + cellRect.width - 1,
                bottom);
          }
        }

        cellRect.x += columnWidth;
      }
    } else {
      for (int column = cMax; column >= cMin; column--) {
        aColumn = cm.getColumn(column);
        columnWidth = aColumn.getWidth();
        cellRect.width = columnWidth;

        if (aColumn != draggedColumn) {
          if (hasLeadingVerticalGridLine(header, cellRect, column)) {
            g2d.drawLine(cellRect.x + cellRect.width - 1,
                cellRect.y, cellRect.x + cellRect.width - 1,
                bottom);
          }
          if (hasTrailingVerticalGridLine(header, cellRect, column)) {
            g2d
                .drawLine(cellRect.x, cellRect.y, cellRect.x,
                    bottom);
          }
        }
        cellRect.x += columnWidth;
      }
    }

    g2d.dispose();
  }

  private boolean hasTrailingVerticalGridLine(JTableHeader tableHeader,
      Rectangle cellRect, int column) {
    boolean toDrawLine = (column != (tableHeader.getColumnModel()
        .getColumnCount() - 1));
    if (!toDrawLine) {
      Container parent = this.header.getParent();
      if (tableHeader.getComponentOrientation().isLeftToRight()) {
        toDrawLine = (parent != null)
            && (parent.getWidth() > (cellRect.x + cellRect.width));
      } else {
        toDrawLine = (parent != null) && (cellRect.x > 0);
      }
    }
    return toDrawLine;
  }

  private boolean hasLeadingVerticalGridLine(JTableHeader tableHeader,
      Rectangle cellRect, int column) {
    if (column != 0) {
      return false;
    }
    Container parent = tableHeader.getParent();
    if (parent instanceof JViewport) {
      Container grand = parent.getParent();
      if (grand instanceof JScrollPane) {
        return (((JScrollPane) grand).getRowHeader() != null);
      }
    }
    return false;
  }

  /**
   * Returns the grid color for the table header.
   *
   * @param header
   *            Table header.
   * @return Grid color.
   */
  protected static Color getGridColor(JTableHeader header) {
    boolean isEnabled = header.isEnabled();
    if (header.getTable() != null) {
      // fix for issue 472 - handle standalone table headers
      isEnabled = isEnabled && header.getTable().isEnabled();
    }
    ComponentState currState = isEnabled ? ComponentState.ENABLED
        : ComponentState.DISABLED_UNSELECTED;
    Color gridColor = SubstanceColorSchemeUtilities.getColorScheme(header,
        ColorSchemeAssociationKind.BORDER, currState).getLineColor();
    return gridColor;
  }

  /**
   * Paints cell.
   *
   * @param g
   *            Graphic context.
   * @param cellRect
   *            Cell rectangle.
   * @param columnIndex
   *            Column index.
   * @param isSelected
   *            Selection indication.
   */
  private void paintCell(Graphics g, Rectangle cellRect, int columnIndex,
      boolean isSelected) {
    Graphics2D g2d = (Graphics2D) g.create();
    g2d.setComposite(LafWidgetUtilities.getAlphaComposite(header, g));

    // paint default background
    Component component = getHeaderRenderer(columnIndex);

    StateTransitionTracker.ModelStateInfo modelStateInfo = getModelStateInfo(columnIndex);
    Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = ((modelStateInfo == null) ? null
        : modelStateInfo.getStateContributionMap());
    ComponentState currState = ((modelStateInfo == null) ? getColumnState(columnIndex)
        : modelStateInfo.getCurrModelState());

    boolean hasHighlights = false;
    if (activeStates != null) {
      for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> stateEntry : activeStates
          .entrySet()) {
        hasHighlights = (SubstanceColorSchemeUtilities
            .getHighlightAlpha(this.header, stateEntry.getKey())
            * stateEntry.getValue().getContribution() > 0.0f);
        if (hasHighlights)
          break;
      }
    } else {
      hasHighlights = (SubstanceColorSchemeUtilities.getHighlightAlpha(
          this.header, currState) > 0.0f);
    }

    // System.out.println(row + ":" + prevTheme.getDisplayName() + "["
    // + alphaForPrevBackground + "]:" + currTheme.getDisplayName()
    // + "[" + alphaForCurrBackground + "]");

    if (hasHighlights) {
      if (activeStates == null) {
        float alpha = SubstanceColorSchemeUtilities.getHighlightAlpha(
            this.header, currState);
        if (alpha > 0.0f) {
          SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities
              .getColorScheme(this.header,
                  ColorSchemeAssociationKind.HIGHLIGHT,
                  currState);
          SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
              .getColorScheme(this.header,
                  ColorSchemeAssociationKind.HIGHLIGHT,
                  currState);
          g2d.setComposite(LafWidgetUtilities.getAlphaComposite(
              this.header, alpha, g));
          HighlightPainterUtils.paintHighlight(g2d,
              this.rendererPane, rendererPane, cellRect, 0.8f,
              null, fillScheme, borderScheme);
          g2d.setComposite(LafWidgetUtilities.getAlphaComposite(
              this.header, g));
        }
      } else {
        for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> stateEntry : activeStates
            .entrySet()) {
          ComponentState activeState = stateEntry.getKey();
          float alpha = SubstanceColorSchemeUtilities
              .getHighlightAlpha(this.header, activeState)
              * stateEntry.getValue().getContribution();
          if (alpha == 0.0f)
            continue;
          SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities
              .getColorScheme(this.header,
                  ColorSchemeAssociationKind.HIGHLIGHT,
                  activeState);
          SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
              .getColorScheme(this.header,
                  ColorSchemeAssociationKind.HIGHLIGHT,
                  activeState);
          g2d.setComposite(LafWidgetUtilities.getAlphaComposite(
              this.header, alpha, g));
          HighlightPainterUtils.paintHighlight(g2d,
              this.rendererPane, rendererPane, cellRect, 0.8f,
              null, fillScheme, borderScheme);
          g2d.setComposite(LafWidgetUtilities.getAlphaComposite(
              this.header, g));
        }
      }
    }

    rendererPane.paintComponent(g2d, component, header, cellRect.x,
        cellRect.y, cellRect.width, cellRect.height, true);

    g2d.dispose();
  }

  /**
   * Retrieves view index for the specified column.
   *
   * @param aColumn
   *            Table column.
   * @return View index for the specified column.
   */
  private int viewIndexForColumn(TableColumn aColumn) {
    TableColumnModel cm = header.getColumnModel();
    for (int column = 0; column < cm.getColumnCount(); column++) {
      if (cm.getColumn(column) == aColumn) {
        return column;
      }
    }
    return -1;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.plaf.ComponentUI#update(java.awt.Graphics,
   * javax.swing.JComponent)
   */
  @Override
  public void update(Graphics g, JComponent c) {
    // fix for issue 175 - table header under resize mode off
    // was painted in color scheme-agnostic (gray) color.
    boolean isEnabled = this.header.isEnabled();
    if (this.header.getTable() != null) {
      // fix for issue 472 - handle standalone table headers
      isEnabled = isEnabled && this.header.getTable().isEnabled();
    }
    ComponentState backgroundState = isEnabled ? ComponentState.ENABLED
        : ComponentState.DISABLED_UNSELECTED;

    // fix for issue 360 - respect the clip bounds of the
    // table header
    Rectangle clip = g.getClipBounds();
    if (clip == null)
      clip = c.getBounds();

    // do not use the highlight scheme for painting the
    // table header background
    SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities
        .getColorScheme(c, backgroundState);
    SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
        .getColorScheme(c, ColorSchemeAssociationKind.BORDER,
            backgroundState);

    HighlightPainterUtils.paintHighlight(g, null, c, clip, 0.0f, null,
        fillScheme, borderScheme);
    paint(g, c);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * javax.swing.plaf.basic.BasicTableHeaderUI#uninstallUI(javax.swing.JComponent
   * )
   */
  @Override
  public void uninstallUI(JComponent c) {
    for (int i = 0; i < header.getColumnModel().getColumnCount(); i++) {
      TableColumn aColumn = header.getColumnModel().getColumn(i);
      TableCellRenderer renderer = aColumn.getHeaderRenderer();
      if (renderer == null) {
        renderer = header.getDefaultRenderer();
      }
      Component rendComp = renderer.getTableCellRendererComponent(header
          .getTable(), aColumn.getHeaderValue(), false, false, -1, i);
      SwingUtilities.updateComponentTreeUI(rendComp);
    }
    super.uninstallUI(c);
  }

  /**
   * Returns the current state for the specified cell.
   *
   * @param columnIndex
   *            Column index.
   * @return The current state for the specified column.
   */
  public ComponentState getColumnState(int columnIndex) {
    // ButtonModel synthModel = new DefaultButtonModel();
    boolean toEnable = header.isEnabled();

    // get the rollover column index from the table UI delegate
    JTable table = this.header.getTable();
    if (table != null) {
      toEnable = toEnable && table.isEnabled();
    }

    StateTransitionTracker tracker = this.stateTransitionMultiTracker
        .getTracker(columnIndex);
    if (tracker == null) {
      boolean isRollover = false;
      TableColumnModel columnModel = header.getColumnModel();
      boolean isSelected = false;
      if (columnModel.getColumnSelectionAllowed()) {
        isSelected = columnModel.getSelectionModel().isSelectedIndex(
            columnIndex);
        if ((table != null)
            && (table.getUI() instanceof SubstanceTableUI)) {
          SubstanceTableUI tableUI = (SubstanceTableUI) table.getUI();
          int rolledOverIndex = tableUI.getRolloverColumnIndex();
          isRollover = (rolledOverIndex >= 0)
              && (rolledOverIndex == columnIndex);
          boolean hasSelectionAnimations = tableUI
              .hasSelectionAnimations();
          if (hasSelectionAnimations
              && AnimationConfigurationManager.getInstance()
                  .isAnimationAllowed(
                      AnimationFacet.SELECTION, table))
            isSelected = this.selectedIndices
                .containsKey(columnIndex);
        }
      }
      return ComponentState.getState(toEnable, isRollover, isSelected);
    } else {
      ComponentState fromTracker = tracker.getModelStateInfo()
          .getCurrModelState();
      return ComponentState.getState(toEnable, fromTracker
          .isFacetActive(ComponentStateFacet.ROLLOVER), fromTracker
          .isFacetActive(ComponentStateFacet.SELECTION));
    }
  }

  public StateTransitionTracker.ModelStateInfo getModelStateInfo(
      int columnIndex) {
    if (this.stateTransitionMultiTracker.size() == 0)
      return null;
    StateTransitionTracker tracker = this.stateTransitionMultiTracker
        .getTracker(columnIndex);
    if (tracker == null) {
      return null;
    } else {
      return tracker.getModelStateInfo();
    }
  }

  public StateTransitionTracker getStateTransitionTracker(int columnIndex) {
    return this.stateTransitionMultiTracker.getTracker(columnIndex);
  }

  /**
   * Returns the scroll pane corner filler component. This method is used in
   * {@link SubstanceScrollPaneUI} to put a consistent filler for tables.
   *
   * @return Scroll pane corner filler.
   */
  public JComponent getScrollPaneCornerFiller() {
    return new ScrollPaneCornerFiller(this.header);
  }

  /**
   * Corner filler for tables wrapped in scroll panes.
   *
   * @author Kirill Grouchnikov
   */
  protected static class ScrollPaneCornerFiller extends JComponent implements
      UIResource {
    /**
     * Associated table header.
     */
    protected JTableHeader header;

    /**
     * Creates a new corner filler.
     *
     * @param header
     *            Table header.
     */
    public ScrollPaneCornerFiller(JTableHeader header) {
      this.header = header;
    }

    @Override
    protected void paintComponent(Graphics g) {
      Graphics2D g2d = (Graphics2D) g.create();
      // System.err.println("Painting " + this.hashCode() + " from "
      // + ((header == null) ? "null" : header.hashCode()));

      boolean ltr = header.getComponentOrientation().isLeftToRight();
      final ComponentState backgroundState = (header.isEnabled() && header
          .getTable().isEnabled()) ? ComponentState.ENABLED
          : ComponentState.DISABLED_UNSELECTED;

      SubstanceColorScheme fillScheme = SubstanceColorSchemeUtilities
          .getColorScheme(this.header,
              ColorSchemeAssociationKind.HIGHLIGHT,
              backgroundState);
      SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
          .getColorScheme(this.header,
              ColorSchemeAssociationKind.HIGHLIGHT_BORDER,
              backgroundState);

      HighlightPainterUtils.paintHighlight(g2d, null, this.header,
          new Rectangle(0, 0, this.getWidth(), this.getHeight()),
          0.0f, null, fillScheme, borderScheme);

      g2d.setColor(getGridColor(this.header));
      float strokeWidth = SubstanceSizeUtils
          .getBorderStrokeWidth(SubstanceSizeUtils
              .getComponentFontSize(header));
      g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND,
          BasicStroke.JOIN_BEVEL));
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
          RenderingHints.VALUE_ANTIALIAS_ON);
      g2d.setComposite(LafWidgetUtilities.getAlphaComposite(this.header,
          0.7f, g));

      int x = ltr ? (int) strokeWidth / 2 : getWidth() - 1
          - (int) strokeWidth / 2;
      g2d.drawLine(x, 0, x, getHeight());

      g2d.dispose();
    }
  }

  /**
   * Processes the events on model changes on the table column model.
   *
   * @param oldModel
   *            Old column model.
   * @param newModel
   *            New column model.
   */
  public void processColumnModelChangeEvent(TableColumnModel oldModel,
      TableColumnModel newModel) {
    if (oldModel != null) {
      oldModel.getSelectionModel().removeListSelectionListener(
          substanceFadeSelectionListener);
    }
    if (newModel != null) {
      newModel.getSelectionModel().addListSelectionListener(
          substanceFadeSelectionListener);
    }
    selectedIndices.clear();
    stateTransitionMultiTracker.clear();
  }

  /**
   * Repaints a single column header during the fade animation cycle.
   *
   * @author Kirill Grouchnikov
   */
  protected class ColumnHeaderRepaintCallback extends
      UIThreadTimelineCallbackAdapter {
    /**
     * Associated table header.
     */
    protected JTableHeader header;

    /**
     * Associated (animated) column index.
     */
    protected int columnIndex;

    /**
     * Creates a new animation repaint callback.
     *
     * @param header
     *            Associated table header.
     * @param columnIndex
     *            Associated (animated) column index.
     */
    public ColumnHeaderRepaintCallback(JTableHeader header, int columnIndex) {
      this.header = header;
      this.columnIndex = columnIndex;
    }

    @Override
    public void onTimelinePulse(float durationFraction,
        float timelinePosition) {
      repaintColumnHeader();
    }

    @Override
    public void onTimelineStateChanged(TimelineState oldState,
        TimelineState newState, float durationFraction,
        float timelinePosition) {
      repaintColumnHeader();
    }

    /**
     * Repaints the associated cell.
     */
    private void repaintColumnHeader() {
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          if (header == null) {
            // may happen if the LAF was switched in the meantime
            return;
          }
          try {
            // maybeUpdateLayoutState();
            int cellCount = header.getColumnModel()
                .getColumnCount();
            if ((cellCount > 0) && (columnIndex < cellCount)) {
              // need to retrieve the cell rectangle since the
              // cells can be moved while animating
              Rectangle rect = header.getHeaderRect(columnIndex);
              Rectangle damaged = new Rectangle(rect.x - 5,
                  rect.y, rect.width + 10, rect.height);
              header.repaint(damaged);
            }
          } catch (RuntimeException re) {
            return;
          }
        }
      });
    }
  }

  public StateTransitionTracker getTracker(final int columnIndex,
      boolean initialRollover, boolean initialSelected) {
    StateTransitionTracker tracker = stateTransitionMultiTracker
        .getTracker(columnIndex);
    if (tracker == null) {
      ButtonModel model = new DefaultButtonModel();
      model.setSelected(initialSelected);
      model.setRollover(initialRollover);
      tracker = new StateTransitionTracker(header, model);
      tracker.registerModelListeners();
      tracker.setRepaintCallback(new RepaintCallback() {
        @Override
        public TimelineCallback getRepaintCallback() {
          return new ColumnHeaderRepaintCallback(header, columnIndex);
        }
      });
      stateTransitionMultiTracker.addTracker(columnIndex, tracker);
    }
    return tracker;
  }

}
TOP

Related Classes of org.pushingpixels.substance.internal.ui.SubstanceTableHeaderUI$ScrollPaneCornerFiller

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
d', 'pageview');