ghidra-master/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerHeader.java
/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ghidra.app.plugin.core.byteviewer;

import java.awt.*;
import java.util.HashMap;
import java.util.Iterator;

import javax.swing.*;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.*;

import generic.theme.Gui;
import ghidra.util.table.GhidraTable;

/**
 * JTableHeader that uses the default table column model to manage 
 * TableColumns. Sizes the column according to its corresponding viewer
 * component. Allows columns to be moved.
 */
class ByteViewerHeader extends JTableHeader implements Scrollable {

	private static final String FONT_ID = "font.byteviewer.header";
	private TableColumnModel columnModel;
	private Component container;

	private int separatorWidth;
	private HashMap<Component, TableColumn> components; // table of components that map to columns

	/**
	 * Constructor 
	 * @param container Container that will be used to calculate the 
	 * preferred size
	 */
	ByteViewerHeader(Component container) {

		super();

		this.container = container;
		components = new HashMap<Component, TableColumn>();
		Gui.registerFont(this, FONT_ID);
		setResizingAllowed(false);
		table = new GhidraTable();
		setTable(table);
		table.setTableHeader(this);
		columnModel = getColumnModel();
		columnModel.setColumnMargin(0);
		JSeparator s = new JSeparator(SwingConstants.VERTICAL);
		separatorWidth = s.getPreferredSize().width;
	}

	/**
	 * Add a new column.
	 * @param name name that will be displayed in the column
	 * @param c corresponding viewer component 
	 */
	public void addColumn(String name, Component c) {

		TableColumn col = new TableColumn(components.size());

		col.setHeaderValue(name);
//        col.setMinWidth((2*margin) + name.length() * unitWidth);
		col.setIdentifier(c);
		columnModel.addColumn(col);
		components.put(c, col);
		resizeAndRepaint();

	}

	/**
	 * Remove a column.
	 * @param c component that corresponds to a column to be removed.
	 */
	public void removeColumn(Component c) {
		TableColumn col = components.get(c);

		if (col != null) {
			columnModel.removeColumn(col);
			components.remove(c);
			setSize(getPreferredSize());
			resizeAndRepaint();
		}
	}

	/**
	 * Get the preferred size of the table header.
	 */
	@Override
	public Dimension getPreferredSize() {
		Dimension d = super.getPreferredSize();
		d.height += 4;
		return d;
	}

	/**
	 * Set the name on the column.
	 * @param c component that maps to the column
	 * @param name name to set on the column header
	 */
	public void setColumnName(Component c, String name) {
		TableColumn col = components.get(c);

		if (col != null) {
			col.setHeaderValue(name);
			recomputeColumnHeaders();
			resizeAndRepaint();
		}
	}

	/**
	 * Add a column model listener.
	 */
	public void addColumnModelListener(TableColumnModelListener l) {
		columnModel.addColumnModelListener(l);
	}

	/**
	 * Remove a column model listener.
	 */
	public void removeColumnModelListener(TableColumnModelListener l) {
		columnModel.removeColumnModelListener(l);
	}

	@Override
	public void paint(Graphics g) {
		recomputeColumnHeaders();
		super.paint(g);
	}

	// Scrollable interface methods

	@Override
	public Dimension getPreferredScrollableViewportSize() {
		return getPreferredSize();
	}

	@Override
	public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
		return 1;
	}

	@Override
	public boolean getScrollableTracksViewportHeight() {
		return false;
	}

	@Override
	public boolean getScrollableTracksViewportWidth() {
		return false;
	}

	@Override
	public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
		return 1;
	}

	/////////////////////////////////////////////////////////////////
	// *** private methods ***
	/////////////////////////////////////////////////////////////////
	/**
	 * Recompute the width of the column headers based on the width
	 * of the corresponding component.
	 */
	private void recomputeColumnHeaders() {

		Iterator<Component> iter = components.keySet().iterator();

		while (iter.hasNext()) {

			Component c = iter.next();
			TableColumn col = components.get(c);
			int width = c.getPreferredSize().width;
			int index = columnModel.getColumnIndex(col.getIdentifier());

			if (index == 0) {
				width += separatorWidth / 2;
			}
			else if (index == components.size() - 1) {
				width += separatorWidth / 2;
			}
			else {
				width += separatorWidth;
			}
			col.setMinWidth(width);
			col.setMaxWidth(width);
			col.setPreferredWidth(width);
		}

	}

}
