<commit_before>/*
 * Copyright (C) 2010-2012 <NAME>
 * <EMAIL>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package  org.jkiss.dbeaver.ui.controls.lightgrid;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Listener;
import org.jkiss.dbeaver.ui.controls.lightgrid.renderers.*;

/**
 * Instances of this class represent a column in a grid widget.
 * For grid internal use.
 */
public class GridColumn extends Item {

	private GridHeaderEditor controlEditor;

	/**
	 * Default width of the column.
	 */
	private static final int DEFAULT_WIDTH = 10;

    private static final int topMargin = 3;
    private static final int bottomMargin = 3;
    private static final int leftMargin = 6;
    private static final int rightMargin = 6;
    private static final int imageSpacing = 3;
    private static final int insideMargin = 3;

	/**
	 * Parent table.
	 */
	private LightGrid parent;

	/**
	 * Header renderer.
	 */
	private GridColumnRenderer headerRenderer;

	private GridColumnRenderer footerRenderer;

    private AbstractRenderer sortRenderer;
	/**
	 * Cell renderer.
	 */
	private GridCellRenderer cellRenderer;

	/**
	 * Width of column.
	 */
	private int width = DEFAULT_WIDTH;

	/**
	 * Sort style of column. Only used to draw indicator, does not actually sort
	 * data.
	 */
	private int sortStyle = SWT.UP;

	/**
	 * Is this column resizable?
	 */
	private boolean resizeable = true;

	private boolean cellSelectionEnabled = true;

	private Image footerImage;

	private String footerText = "";

	private int minimumWidth = 0;

	private String headerTooltip = null;

	/**
	 * Constructs a new instance of this class given its parent (which must be a
	 * <code>Grid</code>) and a style value describing its behavior and
	 * appearance. The item is added to the end of the items maintained by its
	 * parent.
	 *
	 * @param parent
	 *            an Grid control which will be the parent of the new instance
	 *            (cannot be null)
	 * @param style
	 *            the style of control to construct
	 */
	public GridColumn(LightGrid parent, int style) {
		this(parent, style, -1);
	}

	/**
	 * Constructs a new instance of this class given its parent (which must be a
	 * <code>Grid</code>), a style value describing its behavior and appearance,
	 * and the index at which to place it in the items maintained by its parent.
	 *
	 * @param parent
	 *            an Grid control which will be the parent of the new instance
	 *            (cannot be null)
	 * @param style
	 *            the style of control to construct
	 * @param index
	 *            the index to store the receiver in its parent
	 */
	public GridColumn(LightGrid parent, int style, int index) {
		super(parent, style, index);

		init(parent, index);
	}

    public int getIndex()
    {
        return getParent().indexOf(this);
    }

	private void init(LightGrid grid, int index) {
		this.parent = grid;
        sortRenderer = new SortArrowRenderer(grid);
        headerRenderer = new DefaultColumnHeaderRenderer(grid);
        footerRenderer = new DefaultColumnFooterRenderer(grid);
        cellRenderer = new DefaultCellRenderer(grid);
		grid.newColumn(this, index);

		initCellRenderer();

/*
        Button btn = new Button(grid, SWT.PUSH | SWT.NO_FOCUS);
        btn.setText("xxx");

        setHeaderControl(btn);
*/
	}

    public AbstractRenderer getSortRenderer()
    {
        return sortRenderer;
    }

    public void setSortRenderer(AbstractRenderer sortRenderer)
    {
        this.sortRenderer = sortRenderer;
    }

    /**
	 * {@inheritDoc}
	 */
	@Override
    public void dispose() {
		if (!parent.isDisposing()) {
			parent.removeColumn(this);
		}
		super.dispose();
	}

	/**
	 * Initialize cell renderer.
	 */
	private void initCellRenderer() {
		cellRenderer.setColumn(getIndex());

		if ((getStyle() & SWT.RIGHT) == SWT.RIGHT) {
			cellRenderer.setAlignment(SWT.RIGHT);
		}

		if ((getStyle() & SWT.CENTER) == SWT.CENTER) {
			cellRenderer.setAlignment(SWT.CENTER);
		}

	}

	/**
	 * Returns the header renderer.
	 *
	 * @return header renderer
	 */
	public GridColumnRenderer getHeaderRenderer() {
		return headerRenderer;
	}

	GridColumnRenderer getFooterRenderer() {
		return footerRenderer;
	}

	/**
	 * Returns the cell renderer.
	 *
	 * @return cell renderer.
	 */
	public GridCellRenderer getCellRenderer() {
		return cellRenderer;
	}

	/**
	 * Returns the width of the column.
	 *
	 * @return width of column
	 */
	public int getWidth() {
		checkWidget();
		return width;
	}

	/**
	 * Sets the width of the column.
	 *
	 * @param width
	 *            new width
	 */
	public void setWidth(int width) {
		checkWidget();
		setWidth(width, true);
	}

	void setWidth(int width, boolean redraw) {
		this.width = Math.max(minimumWidth, width);
		if (redraw) {
			parent.setScrollValuesObsolete();
			parent.redraw();
		}
	}

    public int computeHeaderHeight()
    {
        int y = topMargin + parent.sizingGC.getFontMetrics().getHeight() + bottomMargin;


        if (getImage() != null) {
            y = Math.max(y, topMargin + getImage().getBounds().height + bottomMargin);
        }

        if( getHeaderControl() != null ) {
            y += getHeaderControl().computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
        }

		return y;
    }

    public boolean isOverSortArrow(int x)
    {
        if (!isSortable()) {
            return false;
        }
        int arrowEnd = getBounds().width - rightMargin;
        int arrowBegin = arrowEnd - sortRenderer.getBounds().width;
        return x >= arrowBegin && x <= arrowEnd;
    }

    public int computeHeaderWidth()
    {
        int x = leftMargin;
        if (getImage() != null) {
            x += getImage().getBounds().width + imageSpacing;
        }
        x += parent.sizingGC.stringExtent(getText()).x + rightMargin;
        if (isSortable()) {
            x += rightMargin + sortRenderer.getBounds().width;
        }

        return x;
    }

    public int computeFooterHeight()
    {
        int y = topMargin;

        y += parent.sizingGC.getFontMetrics().getHeight();

        y += bottomMargin;

        if (getFooterImage() != null) {
            y = Math.max(y, topMargin + getFooterImage().getBounds().height + bottomMargin);
        }

        return y;
    }

	/**
	 * Sets the sort indicator style for the column. This method does not actual
	 * sort the data in the table. Valid values include: SWT.UP, SWT.DOWN,
	 * SWT.NONE.
	 *
	 * @param style
	 *            SWT.UP, SWT.DOWN, SWT.NONE
	 */
	public void setSort(int style) {
		checkWidget();
		sortStyle = style;
		parent.redraw();
	}

	/**
	 * Returns the sort indicator value.
	 *
	 * @return SWT.UP, SWT.DOWN, SWT.NONE
	 */
	public int getSort() {
		checkWidget();
		return sortStyle;
	}

    public boolean isSortable()
    {
        return sortStyle != SWT.NONE;
    }

	/**
	 * Adds the listener to the collection of listeners who will be notified
	 * when the receiver's is pushed, by sending it one of the messages defined
	 * in the <code>SelectionListener</code> interface.
	 *
	 * @param listener
	 *            the listener which should be notified
	 */
	public void addSelectionListener(final SelectionListener listener) {
		checkWidget();
		this.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event)
            {
                listener.widgetSelected(new SelectionEvent(event));
            }
        });
	}

	/**
	 * Removes the listener from the collection of listeners who will be
	 * notified when the receiver's selection changes.
	 *
	 * @param listener
	 *            the listener which should no longer be notified
	 * @see SelectionListener
	 * @see #addSelectionListener(SelectionListener)
	 */
	public void removeSelectionListener(SelectionListener listener) {
		checkWidget();
		this.removeListener(SWT.Selection, listener);
	}

	/**
	 * Fires selection listeners.
	 */
	void fireListeners() {
		Event e = new Event();
		e.display = this.getDisplay();
		e.item = this;
		e.widget = parent;

		this.notifyListeners(SWT.Selection, e);
	}

	/**
	 * Causes the receiver to be resized to its preferred size.
	 *
	 */
	public void pack() {
		checkWidget();

		int newWidth = computeHeaderWidth();
        if (parent.getContentLabelProvider() != null) {
            int columnIndex = getIndex();
            int topIndex = parent.getTopIndex();
            int bottomIndex = parent.getBottomIndex();
            if (topIndex >= 0 && bottomIndex > topIndex) {
                for (int i = topIndex; i <= bottomIndex; i++) {
                    newWidth = Math.max(newWidth, computeCellWidth(columnIndex, i));
                }
            }
        }
		setWidth(newWidth);
		parent.redraw();
	}

    private int computeCellWidth(int column, int row) {
        int x = 0;

        x += leftMargin;

        Image image = parent.getCellImage(column, row);
        if (image != null) {
            x += image.getBounds().width + insideMargin;
        }

        x += parent.sizingGC.textExtent(parent.getCellText(column, row)).x + rightMargin;<commit_msg>Grid width compute fix (for single row)<commit_after>/*
 * Copyright (C) 2010-2012 <NAME>
 * <EMAIL>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package  org.jkiss.dbeaver.ui.controls.lightgrid;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Listener;
import org.jkiss.dbeaver.ui.controls.lightgrid.renderers.*;

/**
 * Instances of this class represent a column in a grid widget.
 * For grid internal use.
 */
public class GridColumn extends Item {

	private GridHeaderEditor controlEditor;

	/**
	 * Default width of the column.
	 */
	private static final int DEFAULT_WIDTH = 10;

    private static final int topMargin = 3;
    private static final int bottomMargin = 3;
    private static final int leftMargin = 6;
    private static final int rightMargin = 6;
    private static final int imageSpacing = 3;
    private static final int insideMargin = 3;

	/**
	 * Parent table.
	 */
	private LightGrid parent;

	/**
	 * Header renderer.
	 */
	private GridColumnRenderer headerRenderer;

	private GridColumnRenderer footerRenderer;

    private AbstractRenderer sortRenderer;
	/**
	 * Cell renderer.
	 */
	private GridCellRenderer cellRenderer;

	/**
	 * Width of column.
	 */
	private int width = DEFAULT_WIDTH;

	/**
	 * Sort style of column. Only used to draw indicator, does not actually sort
	 * data.
	 */
	private int sortStyle = SWT.UP;

	/**
	 * Is this column resizable?
	 */
	private boolean resizeable = true;

	private boolean cellSelectionEnabled = true;

	private Image footerImage;

	private String footerText = "";

	private int minimumWidth = 0;

	private String headerTooltip = null;

	/**
	 * Constructs a new instance of this class given its parent (which must be a
	 * <code>Grid</code>) and a style value describing its behavior and
	 * appearance. The item is added to the end of the items maintained by its
	 * parent.
	 *
	 * @param parent
	 *            an Grid control which will be the parent of the new instance
	 *            (cannot be null)
	 * @param style
	 *            the style of control to construct
	 */
	public GridColumn(LightGrid parent, int style) {
		this(parent, style, -1);
	}

	/**
	 * Constructs a new instance of this class given its parent (which must be a
	 * <code>Grid</code>), a style value describing its behavior and appearance,
	 * and the index at which to place it in the items maintained by its parent.
	 *
	 * @param parent
	 *            an Grid control which will be the parent of the new instance
	 *            (cannot be null)
	 * @param style
	 *            the style of control to construct
	 * @param index
	 *            the index to store the receiver in its parent
	 */
	public GridColumn(LightGrid parent, int style, int index) {
		super(parent, style, index);

		init(parent, index);
	}

    public int getIndex()
    {
        return getParent().indexOf(this);
    }

	private void init(LightGrid grid, int index) {
		this.parent = grid;
        sortRenderer = new SortArrowRenderer(grid);
        headerRenderer = new DefaultColumnHeaderRenderer(grid);
        footerRenderer = new DefaultColumnFooterRenderer(grid);
        cellRenderer = new DefaultCellRenderer(grid);
		grid.newColumn(this, index);

		initCellRenderer();

/*
        Button btn = new Button(grid, SWT.PUSH | SWT.NO_FOCUS);
        btn.setText("xxx");

        setHeaderControl(btn);
*/
	}

    public AbstractRenderer getSortRenderer()
    {
        return sortRenderer;
    }

    public void setSortRenderer(AbstractRenderer sortRenderer)
    {
        this.sortRenderer = sortRenderer;
    }

    /**
	 * {@inheritDoc}
	 */
	@Override
    public void dispose() {
		if (!parent.isDisposing()) {
			parent.removeColumn(this);
		}
		super.dispose();
	}

	/**
	 * Initialize cell renderer.
	 */
	private void initCellRenderer() {
		cellRenderer.setColumn(getIndex());

		if ((getStyle() & SWT.RIGHT) == SWT.RIGHT) {
			cellRenderer.setAlignment(SWT.RIGHT);
		}

		if ((getStyle() & SWT.CENTER) == SWT.CENTER) {
			cellRenderer.setAlignment(SWT.CENTER);
		}

	}

	/**
	 * Returns the header renderer.
	 *
	 * @return header renderer
	 */
	public GridColumnRenderer getHeaderRenderer() {
		return headerRenderer;
	}

	GridColumnRenderer getFooterRenderer() {
		return footerRenderer;
	}

	/**
	 * Returns the cell renderer.
	 *
	 * @return cell renderer.
	 */
	public GridCellRenderer getCellRenderer() {
		return cellRenderer;
	}

	/**
	 * Returns the width of the column.
	 *
	 * @return width of column
	 */
	public int getWidth() {
		checkWidget();
		return width;
	}

	/**
	 * Sets the width of the column.
	 *
	 * @param width
	 *            new width
	 */
	public void setWidth(int width) {
		checkWidget();
		setWidth(width, true);
	}

	void setWidth(int width, boolean redraw) {
		this.width = Math.max(minimumWidth, width);
		if (redraw) {
			parent.setScrollValuesObsolete();
			parent.redraw();
		}
	}

    public int computeHeaderHeight()
    {
        int y = topMargin + parent.sizingGC.getFontMetrics().getHeight() + bottomMargin;


        if (getImage() != null) {
            y = Math.max(y, topMargin + getImage().getBounds().height + bottomMargin);
        }

        if( getHeaderControl() != null ) {
            y += getHeaderControl().computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
        }

		return y;
    }

    public boolean isOverSortArrow(int x)
    {
        if (!isSortable()) {
            return false;
        }
        int arrowEnd = getBounds().width - rightMargin;
        int arrowBegin = arrowEnd - sortRenderer.getBounds().width;
        return x >= arrowBegin && x <= arrowEnd;
    }

    public int computeHeaderWidth()
    {
        int x = leftMargin;
        if (getImage() != null) {
            x += getImage().getBounds().width + imageSpacing;
        }
        x += parent.sizingGC.stringExtent(getText()).x + rightMargin;
        if (isSortable()) {
            x += rightMargin + sortRenderer.getBounds().width;
        }

        return x;
    }

    public int computeFooterHeight()
    {
        int y = topMargin;

        y += parent.sizingGC.getFontMetrics().getHeight();

        y += bottomMargin;

        if (getFooterImage() != null) {
            y = Math.max(y, topMargin + getFooterImage().getBounds().height + bottomMargin);
        }

        return y;
    }

	/**
	 * Sets the sort indicator style for the column. This method does not actual
	 * sort the data in the table. Valid values include: SWT.UP, SWT.DOWN,
	 * SWT.NONE.
	 *
	 * @param style
	 *            SWT.UP, SWT.DOWN, SWT.NONE
	 */
	public void setSort(int style) {
		checkWidget();
		sortStyle = style;
		parent.redraw();
	}

	/**
	 * Returns the sort indicator value.
	 *
	 * @return SWT.UP, SWT.DOWN, SWT.NONE
	 */
	public int getSort() {
		checkWidget();
		return sortStyle;
	}

    public boolean isSortable()
    {
        return sortStyle != SWT.NONE;
    }

	/**
	 * Adds the listener to the collection of listeners who will be notified
	 * when the receiver's is pushed, by sending it one of the messages defined
	 * in the <code>SelectionListener</code> interface.
	 *
	 * @param listener
	 *            the listener which should be notified
	 */
	public void addSelectionListener(final SelectionListener listener) {
		checkWidget();
		this.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event)
            {
                listener.widgetSelected(new SelectionEvent(event));
            }
        });
	}

	/**
	 * Removes the listener from the collection of listeners who will be
	 * notified when the receiver's selection changes.
	 *
	 * @param listener
	 *            the listener which should no longer be notified
	 * @see SelectionListener
	 * @see #addSelectionListener(SelectionListener)
	 */
	public void removeSelectionListener(SelectionListener listener) {
		checkWidget();
		this.removeListener(SWT.Selection, listener);
	}

	/**
	 * Fires selection listeners.
	 */
	void fireListeners() {
		Event e = new Event();
		e.display = this.getDisplay();
		e.item = this;
		e.widget = parent;

		this.notifyListeners(SWT.Selection, e);
	}

	/**
	 * Causes the receiver to be resized to its preferred size.
	 *
	 */
	public void pack() {
		checkWidget();

		int newWidth = computeHeaderWidth();
        if (parent.getContentLabelProvider() != null) {
            int columnIndex = getIndex();
            int topIndex = parent.getTopIndex();
            int bottomIndex = parent.getBottomIndex();
            if (topIndex >= 0 && bottomIndex >= topIndex) {
                for (int i = topIndex; i <= bottomIndex; i++) {
                    newWidth = Math.max(newWidth, computeCellWidth(columnIndex, i));
                }
            }
        }
		setWidth(newWidth);
		parent.redraw();
	}

    private int computeCellWidth(int column, int row) {
        int x = 0;

        x += leftMargin;

        Image image = parent.getCellImage(column, row);
        if (image != null) {
            x += image.getBounds().width + insideMargin;
        }

        x += parent.sizingGC.textExtent(parent.getCellText(column, row)).x + rightMargin;
{'fraction_non_alphanumeric': 0.1033436138444216, 'fraction_numerical': 0.0035247466588338963, 'mean_word_length': 2.706768281618581, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7492219', 'n_tokens_mistral': 6205, 'n_tokens_neox': 5736, 'n_words': 1851}