/* * 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; import org.eclipse.jface.resource.JFaceColors; import org.eclipse.jface.viewers.AbstractTreeViewer; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.*; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.model.DBPNamedObject; import org.jkiss.dbeaver.model.DBPNamedValueObject; import org.jkiss.dbeaver.ui.ImageUtils; import org.jkiss.dbeaver.ui.UIUtils; import org.jkiss.dbeaver.utils.GeneralUtils; /** * ObjectListControl */ public abstract class ObjectViewerRenderer { //static final Log log = Log.getLog(ObjectViewerRenderer.class); private boolean isTree; // Current selection coordinates private transient Item selectedItem; private transient int selectedColumn = -1; private ColumnViewer itemsViewer; private final TextLayout linkLayout; //private final Color linkColor; private final Cursor linkCursor; private final Cursor arrowCursor; private final Color selectionBackgroundColor; public ObjectViewerRenderer( ColumnViewer viewer) { itemsViewer = viewer; this.isTree = (itemsViewer instanceof AbstractTreeViewer); Display display = itemsViewer.getControl().getDisplay(); this.linkLayout = new TextLayout(display); this.selectionBackgroundColor = display.getSystemColor(SWT.COLOR_LIST_SELECTION); //this.linkColor = display.getSystemColor(SWT.COLOR_BLUE); this.linkCursor = display.getSystemCursor(SWT.CURSOR_HAND); this.arrowCursor = display.getSystemCursor(SWT.CURSOR_ARROW); itemsViewer.getControl().setCursor(arrowCursor); final CellTrackListener actionsListener = new CellTrackListener(); itemsViewer.getControl().addMouseListener(new MouseListener()); itemsViewer.getControl().addMouseTrackListener(actionsListener); itemsViewer.getControl().addMouseMoveListener(actionsListener); itemsViewer.getControl().addKeyListener(actionsListener); } public boolean isTree() { return isTree; } private TableItem detectTableItem(int x, int y) { selectedItem = null; selectedColumn = -1; Point pt = new Point(x, y); selectedItem = getTable().getItem(pt); if (selectedItem == null) return null; selectedColumn = UIUtils.getColumnAtPos((TableItem) selectedItem, x, y); return (TableItem) selectedItem; } private TreeItem detectTreeItem(int x, int y) { selectedItem = null; selectedColumn = -1; Point pt = new Point(x, y); selectedItem = getTree().getItem(pt); if (selectedItem == null) { return null; } selectedColumn = UIUtils.getColumnAtPos((TreeItem) selectedItem, x, y); return (TreeItem) selectedItem; } public String getSelectedText() { if (selectedItem == null || selectedColumn == -1) { return null; } Object cellValue = getCellValue(selectedItem.getData(), selectedColumn); return getCellString(cellValue, false); } protected ColumnViewer getItemsViewer() { return itemsViewer; } public Composite getControl() { // Both table and tree are composites so its ok return (Composite) itemsViewer.getControl(); } public void dispose() { UIUtils.dispose(linkLayout); } private Tree getTree() { return ((TreeViewer)itemsViewer).getTree(); } private Table getTable() { return ((TableViewer)itemsViewer).getTable(); } private Rectangle getCellLinkBounds(Item item, int column, Object cellValue) { prepareLinkStyle(cellValue, null); Rectangle itemBounds; if (isTree) { itemBounds = ((TreeItem)item).getTextBounds(column); } else { itemBounds = ((TableItem)item).getTextBounds(column); } Rectangle linkBounds = linkLayout.getBounds(); linkBounds.x += itemBounds.x; linkBounds.y += itemBounds.y + 1; linkBounds.height -= 2; return linkBounds; } ////////////////////////////////////////////////////// // List sorter public void paintCell(Event event, Object element, Widget item, int columnIndex, boolean editable) { Object cellValue = getCellValue(element, columnIndex); if (cellValue != null ) { GC gc = event.gc; if (cellValue instanceof Boolean) { Image image = editable ? ((Boolean)cellValue ? ImageUtils.getImageCheckboxEnabledOn() : ImageUtils.getImageCheckboxEnabledOff()) : ((Boolean)cellValue ? ImageUtils.getImageCheckboxDisabledOn() : ImageUtils.getImageCheckboxDisabledOff()); final Rectangle imageBounds = image.getBounds(); int columnWidth = isTree ? ((TreeItem)item).getBounds(columnIndex).width : ((TableItem)item).getBounds(columnIndex).width; gc.drawImage(image, event.x + (columnWidth - imageBounds.width) / 2, event.y + 2); //gc.drawImage(image, event.x + 2, event.y + 2); event.doit = false; } else if (isHyperlink(cellValue)) { // Print link boolean isSelected = gc.getBackground().equals(selectionBackgroundColor); prepareLinkStyle(cellValue, isSelected ? gc.getForeground() : JFaceColors.getHyperlinkText(event.item.getDisplay())); Rectangle textBounds; if (event.item instanceof TreeItem) { textBounds = ((TreeItem) event.item).getTextBounds(event.index); } else { textBounds = ((TableItem) event.item).getTextBounds(event.index); } linkLayout.draw(gc, textBounds.x, textBounds.y + 1); } } } class CellTrackListener implements MouseTrackListener, MouseMoveListener, KeyListener { @Override public void mouseEnter(MouseEvent e) { } @Override public void mouseExit(MouseEvent e) { resetCursor(); } @Override public void mouseHover(MouseEvent e) { } private void resetCursor() { getItemsViewer().getControl().setCursor(arrowCursor); } @Override public void mouseMove(MouseEvent e) { updateCursor(e.x, e.y, e.stateMask); } private void updateCursor(int x, int y, int stateMask) { Item hoverItem; if (isTree) { hoverItem = detectTreeItem(x, y); } else { hoverItem = detectTableItem(x, y); } if (hoverItem == null || selectedColumn < 0) { resetCursor(); } else { Object element = hoverItem.getData(); int checkColumn = selectedColumn; Object cellValue = getCellValue(element, checkColumn); if (cellValue == null) { resetCursor(); } else { //tip = getCellString(cellValue); if ((stateMask & SWT.CTRL) != 0 && isHyperlink(cellValue) && getCellLinkBounds(hoverItem, checkColumn, cellValue).contains(x, y)) { getItemsViewer().getControl().setCursor(linkCursor); } else { resetCursor(); } } } } @Override public void keyPressed(KeyEvent e) { if (e.keyCode == SWT.CTRL) { Point mousePoint = itemsViewer.getControl().getDisplay().getCursorLocation(); mousePoint = itemsViewer.getControl().getDisplay().map(null, itemsViewer.getControl(), mousePoint); updateCursor(mousePoint.x, mousePoint.y, SWT.CTRL); } } @Override public void keyReleased(KeyEvent e) { if (e.keyCode == SWT.CTRL) { Point mousePoint = itemsViewer.getControl().getDisplay().getCursorLocation(); mousePoint = itemsViewer.getControl().getDisplay().map(null, itemsViewer.getControl(), mousePoint); updateCursor(mousePoint.x, mousePoint.y, SWT.NONE); } } } private void prepareLinkStyle(Object cellValue, Color foreground) { // Print link TextStyle linkStyle = new TextStyle( getControl().getFont(), foreground, null); linkStyle.underline = true; linkStyle.underlineStyle = SWT.UNDERLINE_LINK; String text = getCellString(cellValue, false); linkLayout.setText(text); linkLayout.setIndent(0); linkLayout.setStyle(linkStyle, 0, text.length()); } public static String getCellString(@Nullable Object value, boolean nameColumn) { if (value == null) { return ""; } else { if (!nameColumn && value instanceof DBPNamedValueObject) { value = ((DBPNamedValueObject) value).getObjectValue(); } else if (value instanceof DBPNamedObject) { value = ((DBPNamedObject) value).getName(); } } return GeneralUtils.makeDisplayString(value).toString(); } private class MouseListener extends MouseAdapter { @Override public void mouseDown(MouseEvent e) { Item hoverItem; if (isTree) { hoverItem = detectTreeItem(e.x, e.y); } else { hoverItem = detectTableItem(e.x, e.y); } if ((e.stateMask & SWT.CTRL) == 0) { // Navigate only if CTRL pressed return; } if (hoverItem != null && selectedColumn >= 0 && e.button == 1) { Object element = hoverItem.getData(); int checkColumn = selectedColumn; Object cellValue = getCellValue(element, checkColumn); if (isHyperlink(cellValue) && getCellLinkBounds(hoverItem, checkColumn, cellValue).contains(e.x, e.y)) { navigateHyperlink(cellValue); } } } } public boolean isHyperlink(@Nullable Object cellValue) { return false; } public void navigateHyperlink(Object cellValue) { // do nothing. by default all cells are not navigable } @Nullable protected abstract Object getCellValue(Object element, int columnIndex); }