/* * 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.Arrays; import org.deidentifier.arx.AttributeType.Hierarchy; import org.deidentifier.arx.gui.resources.Resources; import org.deidentifier.arx.gui.view.SWTUtil; import org.deidentifier.arx.gui.view.impl.common.table.CTConfiguration; import org.eclipse.nebula.widgets.nattable.data.IDataProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; /** * This class implements an editor for generalization hierarchies. * * @author Fabian Prasser * @author Florian Kohlmayer * @author Ledian Xhani * @author Ljubomir Dshevlekov * */ public class ComponentHierarchy { /** * A data provider for hierarchies. * * @author Fabian Prasser */ private class HierarchyDataProvider implements IDataProvider { @Override public int getColumnCount() { if (hierarchy == null) return 0; else if (hierarchy.length == 0) return 0; else if (hierarchy[0] == null) return 0; else return hierarchy[0].length; } @Override public Object getDataValue(int columnIndex, int rowIndex) { return hierarchy[rowIndex][columnIndex]; } @Override public int getRowCount() { if (hierarchy == null) return 0; else return hierarchy.length; } @Override public void setDataValue(int columnIndex, int rowIndex, Object newValue) { // Ignore } } /** * A header data provider for hierarchies. * * @author Fabian Prasser */ private class HierarchyHeaderDataProvider extends HierarchyDataProvider { @Override public Object getDataValue(int columnIndex, int rowIndex) { return Resources.getMessage("ViewHierarchy.0") + columnIndex; //$NON-NLS-1$ } @Override public int getRowCount() { return 1; } } /** Widget. */ private Composite base; /** Widget. */ private ComponentTable table = null; /** Model. */ private String[][] hierarchy = new String[][] { new String[] {} }; /** Listener */ private final ModifyListener listener; /** * Constructor for non-editable views. * * @param parent */ public ComponentHierarchy(final Composite parent) { this.listener = null; this.createTable(parent); } /** * Constructor for editable views. * * @param parent * @param listener */ public ComponentHierarchy(final Composite parent, final ModifyListener listener) { this.listener = listener; this.createTable(parent); } /** * Clears the hierarchy. */ public void actionClear() { this.setHierarchy(null); this.triggerChangedEvent(); } /** * Deletes a column. */ public void actionDeleteColumn() { if (table.getSelectedColumn() == null) { return; } int selected = table.getSelectedColumn(); int columns = hierarchy[0].length - 1; int rows = hierarchy.length; String[][] temp = new String[rows][columns]; for (int i = 0; i < rows; i++) { String[] row = new String[columns]; System.arraycopy(hierarchy[i], 0, row, 0, selected); System.arraycopy(hierarchy[i], selected + 1, row, selected, columns - selected); temp[i] = row; } if (columns == 0) { actionClear(); } else { this.hierarchy = temp; this.table.refresh(); } this.triggerChangedEvent(); } /** * Deletes a row. */ public void actionDeleteRow() { if (table.getSelectedRow() == null) { return; } int selected = table.getSelectedRow(); int columns = hierarchy[0].length; int rows = hierarchy.length - 1; String[][] temp = new String[rows][columns]; System.arraycopy(hierarchy, 0, temp, 0, selected); System.arraycopy(hierarchy, selected + 1, temp, selected, rows - selected); if (rows == 0) { actionClear(); } else { this.hierarchy = temp; this.table.refresh(); } this.triggerChangedEvent(); } /** * Renames an item. */ public void actionEditItem(String newValue) { if (table.getSelectedRow() == null || table.getSelectedColumn() == null) { return; } int selectedRow = table.getSelectedRow(); int selectedColumn = table.getSelectedColumn(); if (newValue != null) { hierarchy[selectedRow][selectedColumn] = newValue; } this.table.refresh(); this.triggerChangedEvent(); } /** * Inserts a column. */ public void actionInsertColumn() { if (table.getSelectedColumn() == null) { return; } int selected = table.getSelectedColumn(); int columns = hierarchy[0].length + 1; int rows = hierarchy.length; String[][] temp = new String[rows][columns]; for (int i = 0; i < rows; i++) { String[] row = new String[columns]; System.arraycopy(hierarchy[i], 0, row, 0, selected + 1); System.arraycopy(hierarchy[i], selected + 1, row, selected + 2, columns - selected - 2); row[selected + 1] = ""; //$NON-NLS-1$ temp[i] = row; } this.hierarchy = temp; this.table.refresh(); this.triggerChangedEvent(); } /** * Inserts a row. */ public void actionInsertRow() { if (table.getSelectedRow() == null) { return; } int selected = table.getSelectedRow(); int columns = hierarchy[0].length; int rows = hierarchy.length + 1; String[][] temp = new String[rows][columns]; System.arraycopy(hierarchy, 0, temp, 0, selected + 1); System.arraycopy(hierarchy, selected + 1, temp, selected + 2, rows - selected - 2); temp[selected + 1] = new String[columns]; Arrays.fill(temp[selected + 1], ""); //$NON-NLS-1$ this.hierarchy = temp; this.table.refresh(); this.triggerChangedEvent(); } /** * Moves an element down. */ public void actionMoveRowDown() { if (table.getSelectedRow() == null) { return; } int selected = table.getSelectedRow(); if (selected == hierarchy.length - 1) { return; } String[] temp = hierarchy[selected + 1]; hierarchy[selected + 1] = hierarchy[selected]; hierarchy[selected] = temp; this.table.refresh(); this.triggerChangedEvent(); } /** * Moves an element up. */ public void actionMoveRowUp() { if (table.getSelectedRow() == null) { return; } int selected = table.getSelectedRow(); if (selected <= 0) { return; } String[] temp = hierarchy[selected - 1]; hierarchy[selected - 1] = hierarchy[selected]; hierarchy[selected] = temp; this.table.refresh(); this.triggerChangedEvent(); } /** * Renames an item. */ public void actionRenameItem(String newValue) { if (table.getSelectedRow() == null || table.getSelectedColumn() == null) { return; } int selectedRow = table.getSelectedRow(); int selectedColumn = table.getSelectedColumn(); final String oldValue = hierarchy[selectedRow][selectedColumn]; if (newValue != null) { for (int i = 0; i < hierarchy.length; i++) { if (hierarchy[i][selectedColumn].equals(oldValue)) { hierarchy[i][selectedColumn] = newValue; } } } this.table.refresh(); this.triggerChangedEvent(); } /** * Clears the hierarchy. */ public void actionReset() { this.setHierarchy(null); } /** * Adds a mouse listener * @param listener */ public void addMouseListener(MouseListener listener) { this.table.addMouseListener(listener); this.table.getControl().addMouseListener(listener); } /** * Returns the underlying control * @return */ public Control getControl() { return table.getControl(); } /** * Returns the selected value. Returns null if no value is selected. * @return */ public String getSelectedValue() { if (table.getSelectedRow() == null || table.getSelectedColumn() == null) { return null; } int selectedRow = table.getSelectedRow(); int selectedColumn = table.getSelectedColumn(); return hierarchy[selectedRow][selectedColumn]; } /** * Returns whether a cell is selected * @return */ public boolean isCellSelected() { return table.getSelectedColumn() != null && table.getSelectedRow() != null; } /** * Returns whether a column is selected * @return */ public boolean isColumnSelected() { return !isCellSelected() && table.getSelectedColumn() != null; } /** * Returns whether this component is empty * @return */ public boolean isEmpty() { return hierarchy == null || hierarchy.length == 0 || hierarchy[0] == null || hierarchy[0].length == 0; } /** * Returns whether a row is selected * @return */ public boolean isRowSelected() { return !isCellSelected() && table.getSelectedRow() != null; } /** * Sets the hierarchy displayed by this component. Call with null to reset. * * @param hierarchy */ public void setHierarchy(final Hierarchy hierarchy) { this.hierarchy = (hierarchy == null ? null : hierarchy.getHierarchy()); this.table.refresh(); } /** * Sets the layout data. * * @param d */ public void setLayoutData(final Object d) { base.setLayoutData(d); } /** * Creates the control. * * @param parent */ private void createTable(final Composite parent) { // Create base composite this.base = new Composite(parent, SWT.NONE); GridData bottomLayoutData = SWTUtil.createFillGridData(); bottomLayoutData.grabExcessVerticalSpace = true; GridLayout bottomLayout = new GridLayout(); bottomLayout.numColumns = 1; this.base.setLayout(bottomLayout); this.base.setLayoutData(bottomLayoutData); // Configure table CTConfiguration config = new CTConfiguration(parent, CTConfiguration.STYLE_TABLE); config.setHorizontalAlignment(SWT.LEFT); config.setCellSelectionEnabled(true); config.setColumnSelectionEnabled(true); config.setRowSelectionEnabled(false); config.setColumnHeaderLayout(CTConfiguration.COLUMN_HEADER_LAYOUT_FILL); config.setRowHeaderLayout(CTConfiguration.ROW_HEADER_LAYOUT_FILL); // Create table this.table = new ComponentTable(base, SWT.BORDER, config); this.table.getControl().setLayoutData(SWTUtil.createFillGridData()); this.table.setData(new HierarchyDataProvider(), new HierarchyHeaderDataProvider()); } /** * Triggers a change event. New hierarchy is passed as event.data */ private void triggerChangedEvent() { if (listener != null) { Event event = new Event(); event.data = Hierarchy.create(hierarchy); event.widget = table.getControl(); listener.modifyText(new ModifyEvent(event)); } } }