/*
 * Licensed Materials - Property of Perforce Software, Inc. 
 * © Copyright Perforce Software, Inc. 2014, 2021 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */
package dualTable;

import java.awt.BorderLayout;
import java.awt.Container;
import java.text.DateFormat;

import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;

import ilog.views.gantt.IlvGanttChart;
import ilog.views.gantt.IlvGanttComponentManager;
import ilog.views.gantt.IlvHierarchyChart;
import ilog.views.gantt.IlvJScrollPane;
import ilog.views.gantt.event.HeaderHeightChangedEvent;
import ilog.views.gantt.event.HeaderListener;
import ilog.views.gantt.swing.IlvJTable;
import ilog.views.gantt.swing.IlvJTableColumn;
import ilog.views.gantt.swing.IlvJTableHeader;
import shared.swing.ExampleFrame;
import xml.XMLGanttExample;

/**
 * An example of adding a secondary table to the right side of a Gantt chart.
 */
public class DualTableExample extends XMLGanttExample {

  /**
   * The new table on the right side.
   */
  protected IlvJTable rightTable;

  /**
   * The scroll pane containing the new table.
   */
  protected IlvJScrollPane rightScrollPane;

  /**
   * The new splitter that separates the table on the right from the Gantt
   * chart.
   */
  protected JSplitPane rightSplitter;

  /**
   * Initializes the user interface of the example in the specified container.
   * 
   * @param container
   *          The container that the example is running in. This will be the
   *          <code>contentPane</code> of the <code>JApplet</code> or the
   *          <code>JFrame</code>, depending on whether the example is run as an
   *          applet or as an application.
   */
  Override
  public void init(Container container) {
    super.init(container);

    // Create a new table and move the "Start" and "End" columns into it.
    rightTable = new IlvJTable();
    IlvJTable leftTable = chart.getTable();
    IlvJTableColumn startColumn = leftTable.getTableColumn("Start");
    leftTable.removeColumn(startColumn);
    rightTable.addColumn(startColumn);
    IlvJTableColumn endColumn = leftTable.getTableColumn("End");
    leftTable.removeColumn(endColumn);
    rightTable.addColumn(endColumn);

    // Place the new table into an IlvJScrollPane.
    rightScrollPane = new IlvJScrollPane(rightTable);
    rightScrollPane.setPreferredSize(rightTable.getPreferredSize());

    // Create opaque labels to fill the corners when the vertical scroll bar
    // becomes visible.
    JLabel urLabel = new JLabel();
    urLabel.setOpaque(true);
    rightScrollPane.setCorner(JScrollPane.UPPER_RIGHT_CORNER, urLabel);
    JLabel lrLabel = new JLabel();
    lrLabel.setOpaque(true);
    rightScrollPane.setCorner(JScrollPane.LOWER_RIGHT_CORNER, lrLabel);

    // Create a new split pane. Place the Gantt chart on the left side and the
    // new table on the right side.
    rightSplitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
    container.remove(chart);
    rightSplitter.add(chart, JSplitPane.LEFT);
    rightSplitter.add(rightScrollPane, JSplitPane.RIGHT);
    rightSplitter.setResizeWeight(1);
    container.add(rightSplitter, BorderLayout.CENTER);

    // If the example is running as an applet, the container will have a defined
    // fixed width already. In this case, we set the divider location to respect
    // the preferred size of the new table. If the example is running as an
    // application, the container will not have a defined size yet. In this
    // case, the preferred sizes of the components will be respected when the
    // frame is packed.
    int containerWidth = container.getWidth();
    if (containerWidth > 0)
      rightSplitter.setDividerLocation(containerWidth - rightTable.getPreferredSize().width);

    // Synchronize the vertical scrolling, the horizontal scrolling, and
    // selection behavior of the new table with the Gantt chart.
    IlvGanttComponentManager componentManager = chart.getComponentManager();
    componentManager.addVerticalScrollable(rightScrollPane);
    componentManager.addVerticalExpandable(rightTable);
    componentManager.addSelectable(rightTable);

    // Synchronize the visibility of the new table's horizontal scroll bar to
    // that of the Gantt chart.
    rightScrollPane.setHorizontalScrollBarPolicy(chart.isHorizontalScrollBarVisible()
        ? JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS : JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

    // Disable the vertical scroll bar from the Gantt chart and enable it for
    // the new table.
    rightScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
    chart.setVerticalScrollBarPolicy(IlvHierarchyChart.VERTICAL_SCROLLBAR_NEVER);

    // Synchronize the borders, insets, and preferred size of the new table to
    // the Gantt chart. This ensures that the new table aligns properly with
    // the chart.
    chart.addHeaderListener(new HeaderHeightListener());
  }

  /**
   * Creates the Gantt chart.
   */
  Override
  protected IlvHierarchyChart createChart() {
    return new IlvGanttChart() {
      /**
       * This method is a notification that the look and feel of the chart has
       * been initialized or changed. This method is overridden to resynchronize
       * the size and layout of the new table with the Gantt chart.
       */
      Override
      public void updateUI() {
        // Update the Gantt's UI before we synchronize the new table.
        super.updateUI();

        // Update the new table on the Swing event queue so that all other
        // components update first.
        SwingUtilities.invokeLater(new Runnable() {
          Override
          public void run() {
            // The first invocation of this method occurs while the chart is
            // still being constructed. Until the constructor has completed, the
            // reference from the chart to the outer example class is not
            // initialized yet.
            if (DualTableExample.this != null && chart != null)
              syncRightTableUI();
          }
        });
      }
    };

  }

  /**
   * Synchronizes the borders, insets, and preferred size of the new table to
   * the Gantt chart. This synchronization makes sure that the new table aligns
   * properly with the chart.
   */
  private void syncRightTableUI() {
    // Set the chart to have no border. This will ensure that the chart's table
    // and Gantt sheet will be aligned vertically with the new table.
    chart.setBorder(null);
    chart.setInsideBorder(null);

    // If the table is smaller than the view port, make the exposed area of the
    // view port the same background color.
    rightScrollPane.setViewportBackground(rightTable.getBackground());

    // Synchronize the size of the splitters.
    rightSplitter.setDividerSize(chart.getDividerSize());
    rightSplitter.setOneTouchExpandable(chart.isDividerOneTouchExpandable());
  }

  /**
   * Sets the current date format. This method is overridden to update the
   * columns of the secondary table.
   */
  Override
  public void setDateFormat(DateFormat format) {
    if (format.equals(getDateFormat()))
      return;
    setDateFormat(rightTable, format);
    super.setDateFormat(format);
  }

  /**
   * This class listens for header height changes of the chart time scale and
   * makes the necessary UI rearrangements. It synchronizes the height of the
   * table header with the height of the time scale.
   */
  class HeaderHeightListener implements HeaderListener {
    /**
     * This method is called when the height value of the Gantt header changes.
     * 
     * @param event
     *          <code>HeaderHeightChangedEvent</code> The event.
     */
    Override
    public void headerHeightChanged(HeaderHeightChangedEvent event) {
      IlvJTableHeader tableHeader = rightTable.getHeader();
      int preferredHeight = tableHeader.computePreferredHeight(chart);
      tableHeader.setPreferredHeight(preferredHeight);
      tableHeader.revalidate();
    }
  }

  // =========================================
  // Example Application
  // =========================================

  /**
   * Returns the title of the example.
   */
  Override
  public String getTitle() {
    return "Secondary Data Table Example";
  }

  /**
   * Application mainline.
   *
   * @param args
   *          The command line arguments.
   */
  public static void main(String[] args) {
    ExampleFrame.createAndShowGUI(DualTableExample.class);
  }

}