/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * * 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 org.jkiss.dbeaver.ui.controls.lightgrid; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.model.DBPImage; import org.jkiss.dbeaver.ui.DBeaverIcons; import org.jkiss.utils.CommonUtils; import java.util.ArrayList; import java.util.List; /** * Grid column info. * Holds information about column width and other UI properties * * @author serge@jkiss.org */ class GridColumn { /** * 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; private final LightGrid grid; private final Object element; private final GridColumn parent; private List<GridColumn> children; private int level; private int width = DEFAULT_WIDTH; private int height = -1; public GridColumn(LightGrid grid, Object element) { this.grid = grid; this.element = element; this.parent = null; this.level = 0; grid.newColumn(this, -1); } public GridColumn(GridColumn parent, Object element) { this.grid = parent.grid; this.element = element; this.parent = parent; this.level = parent.level + 1; parent.addChild(this); grid.newColumn(this, -1); } public Object getElement() { return element; } public int getIndex() { return grid.indexOf(this); } /** * Returns the width of the column. * * @return width of column */ public int getWidth() { return width; } /** * Sets the width of the column. * * @param width * new width */ public void setWidth(int width) { setWidth(width, true); } void setWidth(int width, boolean redraw) { int delta = width - this.width; this.width = width; if (parent != null) { parent.width += delta; } if (redraw) { grid.setScrollValuesObsolete(); grid.redraw(); } } public boolean isOverSortArrow(int x, int y) { if (!isSortable()) { return false; } Rectangle bounds = getBounds(); if (y < bounds.y || y > bounds.y + bounds.height) { return false; } int arrowEnd = bounds.width - rightMargin; Rectangle sortBounds = GridColumnRenderer.getSortControlBounds(); int arrowBegin = arrowEnd - sortBounds.width; return x >= arrowBegin && x <= arrowEnd && y < bounds.y + sortBounds.height; } int getHeaderHeight(boolean includeChildren) { if (height < 0) { height = topMargin + grid.fontMetrics.getHeight() + bottomMargin; Image image = grid.getLabelProvider().getImage(element); if (image != null) { height = Math.max(height, topMargin + image.getBounds().height + bottomMargin); } final String description = grid.getLabelProvider().getDescription(element); if (!CommonUtils.isEmpty(description)) { height += topMargin + grid.fontMetrics.getHeight(); } } int childHeight = 0; if (includeChildren && !CommonUtils.isEmpty(children)) { for (GridColumn child : children) { childHeight = Math.max(childHeight, child.getHeaderHeight(true)); } } return height + childHeight; } int computeHeaderWidth() { int x = leftMargin; final IGridLabelProvider labelProvider = grid.getLabelProvider(); Image image = labelProvider.getImage(element); String text = labelProvider.getText(element); String description = labelProvider.getDescription(element); if (image != null) { x += image.getBounds().width + imageSpacing; } int textWidth = grid.sizingGC.stringExtent(text).x; if (!CommonUtils.isEmpty(description)) { int descWidth = grid.sizingGC.stringExtent(description).x; if (descWidth > textWidth) { textWidth = descWidth; } } x += textWidth + rightMargin; if (isSortable()) { x += rightMargin + GridColumnRenderer.getSortControlBounds().width; } if (!CommonUtils.isEmpty(children)) { int childWidth = 0; for (GridColumn child : children) { childWidth += child.computeHeaderWidth(); } return Math.max(x, childWidth); } return x; } public boolean isSortable() { return grid.getContentProvider().getSortOrder(element) != SWT.NONE; } /** * Causes the receiver to be resized to its preferred size. * */ void pack(boolean reflect) { int newWidth = computeHeaderWidth(); if (CommonUtils.isEmpty(children)) { // Calculate width of visible cells int topIndex = grid.getTopIndex(); int bottomIndex = grid.getBottomIndex(); if (topIndex >= 0 && bottomIndex >= topIndex) { int itemCount = grid.getItemCount(); for (int i = topIndex; i <= bottomIndex && i < itemCount; i++) { newWidth = Math.max(newWidth, computeCellWidth(element, grid.getRowElement(i))); } } } else { int childrenWidth = 0; for (GridColumn child : children) { child.pack(reflect); childrenWidth += child.getWidth(); } if (newWidth > childrenWidth) { // Header width bigger than children width GridColumn lastChild = children.get(children.size() - 1); lastChild.setWidth(lastChild.getWidth() + newWidth - childrenWidth); } else { newWidth = childrenWidth; } } if (reflect) { setWidth(newWidth, false); } else { this.width = newWidth; } } private int computeCellWidth(Object col, Object row) { int x = 0; x += leftMargin; String cellText = grid.getCellText(col, row); int state = grid.getContentProvider().getCellState(col, row, cellText); Rectangle imageBounds; if (GridCellRenderer.isLinkState(state)) { imageBounds = GridCellRenderer.LINK_IMAGE_BOUNDS; } else { DBPImage image = grid.getContentProvider().getCellImage(col, row); imageBounds = image == null ? null : DBeaverIcons.getImage(image).getBounds(); } if (imageBounds != null) { x += imageBounds.width + insideMargin; } x += grid.sizingGC.textExtent(cellText).x + rightMargin; return x; } /** * Returns the bounds of this column's header. * * @return bounds of the column header */ Rectangle getBounds() { Rectangle bounds = new Rectangle(0, 0, 0, 0); Point loc = grid.getOrigin(this, -1); bounds.x = loc.x; bounds.y = loc.y; bounds.width = getWidth(); bounds.height = grid.getHeaderHeight(); return bounds; } /** * Returns the parent grid. * * @return the parent grid. */ public LightGrid getGrid() { return grid; } /** * Returns the tooltip of the column header. * * @return the tooltip text */ @Nullable public String getHeaderTooltip() { String tip = grid.getLabelProvider().getToolTipText(element); if (tip == null) { tip = grid.getLabelProvider().getText(element); } return tip; } public GridColumn getParent() { return parent; } public List<GridColumn> getChildren() { return children; } private void addChild(GridColumn gridColumn) { if (children == null) { children = new ArrayList<>(); } children.add(gridColumn); } private void removeChild(GridColumn column) { children.remove(column); } public int getLevel() { return level; } public boolean isParent(GridColumn col) { for (GridColumn p = parent; p != null; p = p.parent) { if (p == col) { return true; } } return false; } public GridColumn getFirstLeaf() { if (children == null) { return this; } else { return children.get(0).getFirstLeaf(); } } }