/* * ARX: Powerful Data Anonymization * Copyright 2012 - 2017 Fabian Prasser, Florian Kohlmayer and contributors * * 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.deidentifier.arx.gui.view.impl.common; import java.util.List; import org.deidentifier.arx.DataHandle; import org.deidentifier.arx.RowSet; import org.deidentifier.arx.gui.Controller; import org.deidentifier.arx.gui.view.def.IComponent; import org.deidentifier.arx.gui.view.impl.common.datatable.DataTableBodyLayerStack; import org.deidentifier.arx.gui.view.impl.common.datatable.DataTableColumnHeaderConfiguration; import org.deidentifier.arx.gui.view.impl.common.datatable.DataTableContext; import org.deidentifier.arx.gui.view.impl.common.datatable.DataTableDecorator; import org.deidentifier.arx.gui.view.impl.common.datatable.DataTableGridLayer; import org.deidentifier.arx.gui.view.impl.common.datatable.DataTableGridLayerStack; import org.deidentifier.arx.gui.view.impl.common.datatable.DataTableHandleDataProvider; import org.deidentifier.arx.gui.view.impl.common.datatable.DataTableRowHeaderConfiguration; import org.eclipse.nebula.widgets.nattable.NatTable; import org.eclipse.nebula.widgets.nattable.config.AbstractUiBindingConfiguration; import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes; import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration; import org.eclipse.nebula.widgets.nattable.data.IDataProvider; import org.eclipse.nebula.widgets.nattable.grid.GridRegion; import org.eclipse.nebula.widgets.nattable.grid.layer.config.DefaultRowStyleConfiguration; import org.eclipse.nebula.widgets.nattable.layer.DataLayer; import org.eclipse.nebula.widgets.nattable.layer.ILayerListener; import org.eclipse.nebula.widgets.nattable.layer.cell.AggregrateConfigLabelAccumulator; import org.eclipse.nebula.widgets.nattable.layer.cell.ColumnOverrideLabelAccumulator; import org.eclipse.nebula.widgets.nattable.painter.cell.CheckBoxPainter; import org.eclipse.nebula.widgets.nattable.painter.cell.TextPainter; import org.eclipse.nebula.widgets.nattable.painter.cell.decorator.PaddingDecorator; import org.eclipse.nebula.widgets.nattable.resize.action.AutoResizeColumnAction; import org.eclipse.nebula.widgets.nattable.resize.action.ColumnResizeCursorAction; import org.eclipse.nebula.widgets.nattable.resize.event.ColumnResizeEventMatcher; import org.eclipse.nebula.widgets.nattable.resize.mode.ColumnResizeDragMode; import org.eclipse.nebula.widgets.nattable.selection.config.DefaultSelectionStyleConfiguration; import org.eclipse.nebula.widgets.nattable.style.BorderStyle; import org.eclipse.nebula.widgets.nattable.style.BorderStyle.LineStyleEnum; import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes; import org.eclipse.nebula.widgets.nattable.style.DisplayMode; import org.eclipse.nebula.widgets.nattable.style.HorizontalAlignmentEnum; import org.eclipse.nebula.widgets.nattable.style.Style; import org.eclipse.nebula.widgets.nattable.style.VerticalAlignmentEnum; import org.eclipse.nebula.widgets.nattable.style.editor.command.DisplayColumnStyleEditorCommandHandler; import org.eclipse.nebula.widgets.nattable.ui.action.ClearCursorAction; import org.eclipse.nebula.widgets.nattable.ui.action.NoOpMouseAction; import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry; import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher; import org.eclipse.nebula.widgets.nattable.util.GUIHelper; import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Listener; /** * This component displays a data table. It provides ARX-specific methods for displaying * equivalence classes, research subsets and attribute types. * @author Fabian Prasser */ public class ComponentDataTable implements IComponent { /** TODO */ private NatTable table; /** TODO */ private DataTableContext context; /** TODO */ private DataTableBodyLayerStack bodyLayer; /** TODO */ private DataTableGridLayer gridLayer; /** TODO */ private Font font; /** TODO */ private Control parent; /** * Creates a new instance. * * @param controller * @param parent */ public ComponentDataTable(final Controller controller, final Composite parent) { this.context = new DataTableContext(controller); this.context.setFont(parent.getFont()); this.table = createControl(parent); this.table.setVisible(false); this.context.setTable(this.table); this.font = parent.getFont(); this.parent = parent; } /** * Adds a mouse listener * @param listener */ public void addMouseListener(MouseListener listener) { this.table.addMouseListener(listener); } /** * Adds a scroll bar listener. * * @param listener */ public void addScrollBarListener(final Listener listener) { this.table.getVerticalBar().addListener(SWT.Selection, listener); this.table.getHorizontalBar().addListener(SWT.Selection, listener); } /** * Adds a select layer listener. * * @param listener */ public void addSelectionLayerListener(ILayerListener listener){ this.context.getListeners().add(listener); } /** * Disposes the control. */ public void dispose() { if (!table.isDisposed()) table.dispose(); } /** * Returns the displayed data. * * @return */ public DataHandle getData() { return this.context.getHandle(); } /** * Returns the list of header images. * * @return */ public List<Image> getHeaderImages() { return this.context.getImages(); } /** * Returns the viewport layer. * * @return */ public ViewportLayer getViewportLayer() { return this.gridLayer.getBodyLayer().getViewportLayer(); } /** * Redraws the component. */ public void redraw() { this.table.redraw(); } /** * Resets the component. */ public void reset() { this.table.setRedraw(false); this.context.getImages().clear(); this.context.reset(); this.gridLayer = new DataTableGridLayerStack(new DataTableHandleDataProvider(context), table, context, parent); this.table.setLayer(gridLayer); this.table.refresh(); this.gridLayer.getBodyLayer().getViewportLayer().recalculateScrollBars(); this.table.getVerticalBar().setVisible(false); this.table.getHorizontalBar().setVisible(false); this.table.setRedraw(true); this.table.redraw(); this.table.setVisible(false); this.table.getVerticalBar().setVisible(true); this.table.getHorizontalBar().setVisible(true); this.table.setVisible(false); } /** * Sets the displayed data. * * @param handle */ public void setData(final DataHandle handle) { this.table.setRedraw(false); this.context.setHandle(handle); this.gridLayer = new DataTableGridLayerStack(new DataTableHandleDataProvider(context), table, context, parent); this.table.setLayer(gridLayer); this.table.refresh(); this.gridLayer.getBodyLayer().getViewportLayer().recalculateScrollBars(); ((DataLayer)this.gridLayer.getBodyDataLayer()).setColumnWidthByPosition(0, 18); ((DataLayer)this.gridLayer.getBodyDataLayer()).setColumnPositionResizable(0, false); this.table.getVerticalBar().setVisible(false); this.table.getHorizontalBar().setVisible(false); this.table.setRedraw(true); this.table.redraw(); this.table.setVisible(true); this.table.getVerticalBar().setVisible(true); this.table.getHorizontalBar().setVisible(true); this.table.setVisible(true); } /** * Enables/disables the component. * * @param val */ public void setEnabled(final boolean val) { if (table != null) { table.setEnabled(val); } } /** * Sets information about equivalence classes. * * @param groups */ public void setGroups(int[] groups) { this.context.setGroups(groups); } /** * Sets layout data. * * @param data */ public void setLayoutData(final Object data) { table.setLayoutData(data); } /** * Sets information about the research subset. * * @param researchSubset */ public void setResearchSubset(RowSet researchSubset) { this.context.setRows(researchSubset); } /** * Sets the selected attribute. * * @param attribute */ public void setSelectedAttribute(String attribute) { int index = -1; if (context.getHandle()!=null) { index = context.getHandle().getColumnIndexOf(attribute); } this.context.setSelectedIndex(index); this.redraw(); } /** * Translates coordinates * @param x * @param y * @return */ public Point toDisplay(int x, int y) { return table.toDisplay(x, y); } /** * Creates the control contents. * * @param parent * @return */ private NatTable createControl(final Composite parent) { final NatTable natTable = createTable(parent); createTableStyling(natTable); natTable.configure(); final GridData tableLayoutData = new GridData(); tableLayoutData.horizontalAlignment = SWT.FILL; tableLayoutData.verticalAlignment = SWT.FILL; tableLayoutData.grabExcessHorizontalSpace = true; tableLayoutData.grabExcessVerticalSpace = true; natTable.setLayoutData(tableLayoutData); return natTable; } /** * Creates the nattable. * * @param parent * @return */ private NatTable createTable(final Composite parent) { final IDataProvider provider = new DataTableHandleDataProvider(context); gridLayer = new DataTableGridLayerStack(provider, table, context, parent); final NatTable natTable = new NatTable(parent, gridLayer, false); final DataLayer bodyDataLayer = (DataLayer) gridLayer.getBodyDataLayer(); // Add an AggregrateConfigLabelAccumulator final AggregrateConfigLabelAccumulator aggregrateConfigLabelAccumulator = new AggregrateConfigLabelAccumulator(); bodyDataLayer.setConfigLabelAccumulator(aggregrateConfigLabelAccumulator); final ColumnOverrideLabelAccumulator columnLabelAccumulator = new ColumnOverrideLabelAccumulator(bodyDataLayer); final ColumnOverrideLabelAccumulator bodyLabelAccumulator = new ColumnOverrideLabelAccumulator(bodyDataLayer); aggregrateConfigLabelAccumulator.add(bodyLabelAccumulator); aggregrateConfigLabelAccumulator.add(columnLabelAccumulator); // Register a command handler for the StyleEditorDialog final DisplayColumnStyleEditorCommandHandler styleChooserCommandHandler = new DisplayColumnStyleEditorCommandHandler(gridLayer.getBodyLayer() .getSelectionLayer(), columnLabelAccumulator, natTable.getConfigRegistry()); bodyLayer = gridLayer.getBodyLayer(); bodyLayer.registerCommandHandler(styleChooserCommandHandler); // Register the style editor as persistable bodyLayer.registerPersistable(styleChooserCommandHandler); bodyLayer.registerPersistable(columnLabelAccumulator); // Register default cell painter natTable.getConfigRegistry().registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new DataTableDecorator( new TextPainter(false, true, 0, true), new BorderStyle(2, GUIHelper.COLOR_BLACK, LineStyleEnum.SOLID)), DisplayMode.NORMAL, GridRegion.BODY); // Register gradient painters for groups Color light = GUIHelper.getColor(240, 240, 240); Color dark = GUIHelper.getColor(180, 180, 180); Style style = new Style(); style.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, light); natTable.getConfigRegistry().registerConfigAttribute(CellConfigAttributes.CELL_STYLE, style, DisplayMode.NORMAL, "background0"); //$NON-NLS-1$ style = new Style(); style.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, dark); natTable.getConfigRegistry().registerConfigAttribute(CellConfigAttributes.CELL_STYLE, style, DisplayMode.NORMAL, "background1"); //$NON-NLS-1$ // Register checkbox painter for subset natTable.getConfigRegistry().registerConfigAttribute( CellConfigAttributes.CELL_PAINTER, new CheckBoxPainter(), DisplayMode.NORMAL, "checkbox"); //$NON-NLS-1$ return natTable; } /** * Creates the table styling. * * @param natTable */ private void createTableStyling(final NatTable natTable) { final DefaultNatTableStyleConfiguration natTableConfiguration = new DefaultNatTableStyleConfiguration(); natTableConfiguration.bgColor = GUIHelper.getColor(249, 172, 7); natTableConfiguration.fgColor = GUIHelper.getColor(0, 0, 0); natTableConfiguration.hAlign = HorizontalAlignmentEnum.LEFT; natTableConfiguration.vAlign = VerticalAlignmentEnum.TOP; natTableConfiguration.font = this.font; // A custom painter can be plugged in to paint the cells differently natTableConfiguration.cellPainter = new PaddingDecorator(new TextPainter(), 1); // Setup even odd row colors - row colors override the NatTable default colors final DefaultRowStyleConfiguration rowStyleConfiguration = new DefaultRowStyleConfiguration(); rowStyleConfiguration.oddRowBgColor = GUIHelper.getColor(254, 251, 243); rowStyleConfiguration.evenRowBgColor = GUIHelper.COLOR_WHITE; // Setup selection styling final DefaultSelectionStyleConfiguration selectionStyle = new DefaultSelectionStyleConfiguration(); selectionStyle.selectionFont = this.font; selectionStyle.selectionBgColor = GUIHelper.getColor(220, 220, 220); selectionStyle.selectionFgColor = GUIHelper.COLOR_BLACK; selectionStyle.anchorBorderStyle = new BorderStyle(1, GUIHelper.COLOR_DARK_GRAY, LineStyleEnum.SOLID); selectionStyle.anchorBgColor = GUIHelper.getColor(220, 220, 220); selectionStyle.anchorFgColor = GUIHelper.getColor(0, 0, 0); selectionStyle.selectedHeaderBgColor = GUIHelper.getColor(156, 209, 103); selectionStyle.selectedHeaderFont = this.font; // Add all style configurations to NatTable natTable.addConfiguration(natTableConfiguration); natTable.addConfiguration(rowStyleConfiguration); natTable.addConfiguration(selectionStyle); // Column/Row header style and custom painters natTable.addConfiguration(new DataTableRowHeaderConfiguration(context)); natTable.addConfiguration(new DataTableColumnHeaderConfiguration(context)); // Make corner resizable natTable.addConfiguration(new AbstractUiBindingConfiguration() { @Override public void configureUiBindings(UiBindingRegistry uiBindingRegistry) { // Mouse move - Show resize cursor uiBindingRegistry.registerFirstMouseMoveBinding(new ColumnResizeEventMatcher(SWT.NONE, GridRegion.CORNER, 0), new ColumnResizeCursorAction()); uiBindingRegistry.registerMouseMoveBinding(new MouseEventMatcher(), new ClearCursorAction()); // Column resize uiBindingRegistry.registerFirstMouseDragMode(new ColumnResizeEventMatcher(SWT.NONE, GridRegion.CORNER, 1), new ColumnResizeDragMode()); uiBindingRegistry.registerDoubleClickBinding(new ColumnResizeEventMatcher(SWT.NONE, GridRegion.CORNER, 1), new AutoResizeColumnAction()); uiBindingRegistry.registerSingleClickBinding(new ColumnResizeEventMatcher(SWT.NONE, GridRegion.CORNER, 1), new NoOpMouseAction()); } }); } }