/* * Copyright 2015 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.eclipse.jface.viewers; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MenuDetectEvent; import org.eclipse.swt.events.MenuDetectListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Tree; /** * Helper methods for common configuration operations on * {@link org.eclipse.jface.viewers.TableViewer} and * {@link org.eclipse.jface.viewers.TreeViewer} * * @{author Michal Anglart */ public class ViewersConfigurator { /** * Disables context menu if the header of Table is clicked. Under Windows * normally context menu is also shown when clicking on table header * * @param viewer * Table viewer for which header context menu should be disabled */ public static void disableContextMenuOnHeader(final ColumnViewer viewer) { // no need to dispose viewer.getControl().addMenuDetectListener(new MenuDetectListener() { @Override public void menuDetected(final MenuDetectEvent e) { e.doit = !isClickedOnHeader(e); } private boolean isClickedOnHeader(final MenuDetectEvent e) { final Rectangle clientArea = getClientArea(viewer); final Point point = viewer.getControl().toControl(e.x, e.y); return clientArea.y <= point.y && point.y <= clientArea.y + getHeaderHeight(viewer); } private int getHeaderHeight(final ColumnViewer viewer) { if (viewer instanceof TableViewer) { return ((TableViewer) viewer).getTable().getHeaderHeight(); } else if (viewer instanceof TreeViewer) { return ((TreeViewer) viewer).getTree().getHeaderHeight(); } throw new IllegalStateException("Unknown viewer type: " + (viewer == null ? "null" : viewer.getClass().getSimpleName())); } private Rectangle getClientArea(final ColumnViewer viewer) { if (viewer instanceof TableViewer) { return ((TableViewer) viewer).getTable().getClientArea(); } else if (viewer instanceof TreeViewer) { return ((TreeViewer) viewer).getTree().getClientArea(); } throw new IllegalStateException("Unknown viewer type: " + (viewer == null ? "null" : viewer.getClass().getSimpleName())); } }); } /** * Enables deselection possibility in Table. When user clicks inside table * but after the last table item the selection is set to empty. * * @param viewer * Table viewer which should have deselection enabled */ public static void enableDeselectionPossibility(final ColumnViewer viewer) { // sets empty selection when user clicked outside the table items // section viewer.getControl().addMouseListener(new MouseAdapter() { @Override public void mouseUp(final MouseEvent e) { if (leftClickOutsideTable(e)) { viewer.setSelection(new StructuredSelection()); } } private boolean leftClickOutsideTable(final MouseEvent e) { if (viewer instanceof TableViewer) { return e.button == 1 && ((TableViewer) viewer).getTable().getItem(new Point(e.x, e.y)) == null; } else if (viewer instanceof TreeViewer) { return e.button == 1 && ((TreeViewer) viewer).getTree().getItem(new Point(e.x, e.y)) == null; } throw new IllegalStateException("Unknown viewer type: " + (viewer == null ? "null" : viewer.getClass().getSimpleName())); } }); } public static void enableContextMenuOnHeader(final RowExposingTreeViewer viewer, final MenuProvider viewerMenuProvider, final MenuProvider headerMenuProvider) { final Control control = viewer.getControl(); control.addMenuDetectListener(new MenuDetectListener() { @Override public void menuDetected(final MenuDetectEvent e) { final Point pointRelativeToControl = Display.getCurrent().map(null, control, new Point(e.x, e.y)); if (headerWasClicked(control, pointRelativeToControl)) { control.setMenu(headerMenuProvider.provide()); } else { control.setMenu(viewerMenuProvider.provide()); } } private boolean headerWasClicked(final Control control, final Point pt) { final Rectangle clientArea = getClientArea(control); return clientArea.y <= pt.y && pt.y <= clientArea.y + getHeaderHeight(control); } }); } public static void configureRowsHeight(final ColumnViewer viewer, final double fontMetricsMultiplier) { viewer.getControl().addListener(SWT.MeasureItem, new Listener() { @Override public void handleEvent(final Event event) { event.height = Double.valueOf(event.gc.getFontMetrics().getHeight() * fontMetricsMultiplier).intValue(); } }); } private static int getHeaderHeight(final Control control) { if (control instanceof Tree) { return ((Tree) control).getHeaderHeight(); } else if (control instanceof Table) { return ((Table) control).getHeaderHeight(); } throw new IllegalStateException("Given control has to be Tree or Table"); } private static Rectangle getClientArea(final Control control) { if (control instanceof Tree) { return ((Tree) control).getClientArea(); } else if (control instanceof Table) { return ((Table) control).getClientArea(); } throw new IllegalStateException("Given control has to be Tree or Table"); } public interface MenuProvider { Menu provide(); } }