/*
* 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.utility;
import org.deidentifier.arx.ARXCostBenefitConfiguration;
import org.deidentifier.arx.DataDefinition;
import org.deidentifier.arx.DataHandle;
import org.deidentifier.arx.DataType;
import org.deidentifier.arx.DataType.DataTypeWithFormat;
import org.deidentifier.arx.gui.Controller;
import org.deidentifier.arx.gui.model.ModelConfiguration;
import org.deidentifier.arx.gui.model.ModelEvent.ModelPart;
import org.deidentifier.arx.gui.resources.Resources;
import org.deidentifier.arx.gui.view.SWTUtil;
import org.deidentifier.arx.gui.view.impl.common.ClipboardHandlerTree;
import org.deidentifier.arx.metric.Metric;
import org.deidentifier.arx.metric.v2.MetricSDNMPublisherPayout;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
/**
* This view displays basic properties about input data.
*
* @author Fabian Prasser
*/
public class ViewPropertiesInput extends ViewProperties {
/**
* A content provider.
*
* @author Fabian Prasser
*/
private class InputContentProvider implements ITreeContentProvider {
@Override
public void dispose() {
// Nothing to do
}
@Override
public Object[] getChildren(final Object arg0) {
return ((Property) arg0).children.toArray();
}
@Override
public Object[] getElements(final Object arg0) {
return roots.toArray();
}
@Override
public Object getParent(final Object arg0) {
return ((Property) arg0).parent;
}
@Override
public boolean hasChildren(final Object arg0) {
return !((Property) arg0).children.isEmpty();
}
@Override
public void inputChanged(final Viewer arg0,
final Object arg1,
final Object arg2) {
// Nothing to do
}
}
/**
* A label provider.
*
* @author Fabian Prasser
*/
private class InputLabelProvider implements ITableLabelProvider {
@Override
public void addListener(final ILabelProviderListener listener) {
// Nothing to do
}
@Override
public void dispose() {
// Nothing to do
}
@Override
public Image
getColumnImage(final Object element, final int columnIndex) {
return null;
}
@Override
public String
getColumnText(final Object element, final int columnIndex) {
switch (columnIndex) {
case 0:
return ((Property) element).property;
default:
if ((columnIndex - 1) >= ((Property) element).values.length) {
return null;
} else {
return ((Property) element).values[columnIndex - 1];
}
}
}
@Override
public boolean isLabelProperty(final Object element,
final String property) {
return false;
}
@Override
public void removeListener(final ILabelProviderListener listener) {
// Nothing to do
}
}
/**
* Constructor.
*
* @param parent
* @param controller
*/
public ViewPropertiesInput(final Composite parent,
final Controller controller) {
super(parent, controller, ModelPart.INPUT, null);
create(parent);
reset();
}
/**
* Returns the view type
* @return
*/
public LayoutUtility.ViewUtilityType getType() {
return LayoutUtility.ViewUtilityType.PROPERTIES;
}
/**
* Creates the view.
*
* @param root
*/
private void create(final Composite root) {
root.setLayout(new FillLayout());
Tree tree = new Tree(root, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
tree.setHeaderVisible(true);
treeViewer = new TreeViewer(tree);
tree.setMenu(new ClipboardHandlerTree(treeViewer).getMenu());
final TreeColumn column1 = new TreeColumn(tree, SWT.LEFT);
tree.setLinesVisible(true);
column1.setAlignment(SWT.LEFT);
column1.setText(Resources.getMessage("PropertiesView.3")); //$NON-NLS-1$
column1.setWidth(160);
final TreeColumn column2 = new TreeColumn(tree, SWT.RIGHT);
column2.setAlignment(SWT.LEFT);
column2.setText(Resources.getMessage("PropertiesView.4")); //$NON-NLS-1$
column2.setWidth(100);
final TreeColumn column6 = new TreeColumn(tree, SWT.RIGHT);
column6.setAlignment(SWT.LEFT);
column6.setText(Resources.getMessage("PropertiesView.5")); //$NON-NLS-1$
column6.setWidth(100);
final TreeColumn column7 = new TreeColumn(tree, SWT.RIGHT);
column7.setAlignment(SWT.LEFT);
column7.setText(Resources.getMessage("PropertiesView.101")); //$NON-NLS-1$
column7.setWidth(80);
final TreeColumn column3 = new TreeColumn(tree, SWT.RIGHT);
column3.setAlignment(SWT.LEFT);
column3.setText(Resources.getMessage("PropertiesView.6")); //$NON-NLS-1$
column3.setWidth(50);
final TreeColumn column4 = new TreeColumn(tree, SWT.RIGHT);
column4.setAlignment(SWT.LEFT);
column4.setText(Resources.getMessage("PropertiesView.7")); //$NON-NLS-1$
column4.setWidth(50);
final TreeColumn column5 = new TreeColumn(tree, SWT.RIGHT);
column5.setAlignment(SWT.LEFT);
column5.setText(Resources.getMessage("PropertiesView.8")); //$NON-NLS-1$
column5.setWidth(50);
final TreeColumn column8 = new TreeColumn(tree, SWT.RIGHT);
column8.setAlignment(SWT.LEFT);
column8.setText(Resources.getMessage("PropertiesView.113")); //$NON-NLS-1$
column8.setWidth(50);
final TreeColumn column9 = new TreeColumn(tree, SWT.RIGHT);
column9.setAlignment(SWT.LEFT);
column9.setText(Resources.getMessage("PropertiesView.126")); //$NON-NLS-1$
column9.setWidth(50);
treeViewer.setContentProvider(new InputContentProvider());
treeViewer.setLabelProvider(new InputLabelProvider());
treeViewer.setInput(roots);
treeViewer.expandAll();
}
/**
* Update the view.
* @param part
*/
protected void doUpdate(ModelPart part) {
// Check model
if (model == null) { return; }
// Obtain definition
DataDefinition definition = model.getOutputDefinition();
if (definition == null) definition = model.getInputDefinition();
// Obtain relevant configuration objects;
ModelConfiguration config = null;
Metric<?> metric = null;
if (model.getOutputConfig() != null){
config = model.getOutputConfig();
metric = config.getMetric();
// We don't need to update in many cases, if we are displaying an output configuration
if (part == ModelPart.ATTRIBUTE_TYPE || part == ModelPart.METRIC ||
part == ModelPart.ATTRIBUTE_WEIGHT || part == ModelPart.GS_FACTOR ||
part == ModelPart.MAX_OUTLIERS || part == ModelPart.DATA_TYPE ||
part == ModelPart.COST_BENEFIT_MODEL) {
return;
}
} else {
config = model.getInputConfig();
// TODO: This is such an ugly hack
metric = model.getMetricDescription().createInstance(model.getMetricConfiguration());
}
// Check
if (definition == null || config == null || model.getInputConfig().getInput()==null){
reset();
return;
}
// Obtain handle
DataHandle data = model.getInputConfig().getInput().getHandle();
// Disable redrawing
root.setRedraw(false);
// Clear
roots.clear();
// Print basic properties
new Property(Resources.getMessage("PropertiesView.9"), new String[] { String.valueOf(data.getNumRows()) }); //$NON-NLS-1$
new Property(Resources.getMessage("PropertiesView.10"), new String[] { SWTUtil.getPrettyString(config.getAllowedOutliers() * 100d) + Resources.getMessage("PropertiesView.11") }); //$NON-NLS-1$ //$NON-NLS-2$
// Utility measure
Property m = new Property(Resources.getMessage("PropertiesView.114"), new String[] { metric.getDescription().getName() }); //$NON-NLS-1$
// Properties of the utility measure
if (metric.getAggregateFunction() != null) {
new Property(m, Resources.getMessage("PropertiesView.149"), new String[] { metric.getAggregateFunction().toString() }); //$NON-NLS-1$
}
if (metric.isGSFactorSupported()) {
new Property(m, Resources.getMessage("PropertiesView.151"), new String[] { SWTUtil.getPrettyString(metric.getGeneralizationSuppressionFactor()) }); //$NON-NLS-1$
new Property(m, Resources.getMessage("PropertiesView.152"), new String[] { SWTUtil.getPrettyString(metric.getGeneralizationFactor()) }); //$NON-NLS-1$
new Property(m, Resources.getMessage("PropertiesView.153"), new String[] { SWTUtil.getPrettyString(metric.getSuppressionFactor()) }); //$NON-NLS-1$
}
new Property(m, Resources.getMessage("PropertiesView.155"), new String[] { SWTUtil.getPrettyString(metric.isMonotonic(config.getAllowedOutliers())) }); //$NON-NLS-1$
new Property(m, Resources.getMessage("PropertiesView.156"), new String[] { SWTUtil.getPrettyString(metric.isWeighted()) }); //$NON-NLS-1$
new Property(m, Resources.getMessage("PropertiesView.157"), new String[] { SWTUtil.getPrettyString(metric.isPrecomputed()) }); //$NON-NLS-1$
new Property(m, Resources.getMessage("PropertiesView.158"), new String[] { SWTUtil.getPrettyString(metric.isAbleToHandleMicroaggregation() && config.isUtilityBasedMicroaggregation())}); //$NON-NLS-1$
// Cost/benefit configuration
if (metric instanceof MetricSDNMPublisherPayout) {
// Obtain for output data
ARXCostBenefitConfiguration costBenefitConfig = ((MetricSDNMPublisherPayout)metric).getCostBenefitConfiguration();
// Obtain for input only. This is a bit ugly.
if (costBenefitConfig == null) {
costBenefitConfig = ARXCostBenefitConfiguration.create();
costBenefitConfig.setAdversaryCost(config.getAdversaryCost())
.setAdversaryGain(config.getAdversaryGain())
.setPublisherBenefit(config.getPublisherBenefit())
.setPublisherLoss(config.getPublisherLoss());
}
// Render
new Property(m, Resources.getMessage("PropertiesView.135"), new String[] { SWTUtil.getPrettyString(costBenefitConfig.getPublisherBenefit())}); //$NON-NLS-1$
new Property(m, Resources.getMessage("PropertiesView.136"), new String[] { SWTUtil.getPrettyString(costBenefitConfig.getPublisherLoss())}); //$NON-NLS-1$
new Property(m, Resources.getMessage("PropertiesView.137"), new String[] { SWTUtil.getPrettyString(costBenefitConfig.getAdversaryGain())}); //$NON-NLS-1$
new Property(m, Resources.getMessage("PropertiesView.138"), new String[] { SWTUtil.getPrettyString(costBenefitConfig.getAdversaryCost())}); //$NON-NLS-1$
if (((MetricSDNMPublisherPayout)metric).isProsecutorAttackerModel()) {
new Property(m, Resources.getMessage("PropertiesView.139"), new String[] { Resources.getMessage("PropertiesView.160") }); //$NON-NLS-1$ //$NON-NLS-2$
}
if (((MetricSDNMPublisherPayout)metric).isJournalistAttackerModel()) {
new Property(m, Resources.getMessage("PropertiesView.139"), new String[] { Resources.getMessage("PropertiesView.161") }); //$NON-NLS-1$ //$NON-NLS-2$
}
}
// Attributes
final Property attributes = new Property(Resources.getMessage("PropertiesView.12"), new String[] { String.valueOf(data.getNumColumns()) }); //$NON-NLS-1$
// Print identifying attributes
final Property identifying = new Property(attributes, Resources.getMessage("PropertiesView.13"), new String[] { String.valueOf(definition.getIdentifyingAttributes().size()) }); //$NON-NLS-1$
int index = 0;
for (int i = 0; i < data.getNumColumns(); i++) {
final String s = data.getAttributeName(i);
if (definition.getIdentifyingAttributes().contains(s)) {
final String[] values = new String[] { "", "", "", "", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
values[0] = s;
values[1] = definition.getDataType(s).toString();
new Property(identifying, Resources.getMessage("PropertiesView.19") + (index++), values); //$NON-NLS-1$
}
}
// Print quasi-identifying attributes
final Property quasiIdentifying = new Property(attributes, Resources.getMessage("PropertiesView.20"), new String[] { String.valueOf(definition.getQuasiIdentifyingAttributes().size()) }); //$NON-NLS-1$
index = 0;
for (int i = 0; i < data.getNumColumns(); i++) {
final String s = data.getAttributeName(i);
if (definition.getQuasiIdentifyingAttributes().contains(s)) {
final String[] values = new String[] { "", "", "", "", "" , "", "", ""}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
values[0] = s;
if (definition.getHierarchy(s) != null) {
DataType<?> type = definition.getDataType(s);
values[1] = type.getDescription().getLabel();
if (type.getDescription().hasFormat() &&
((DataTypeWithFormat)type).getFormat() != null){
values[2] = ((DataTypeWithFormat)type).getFormat();
}
// Determine height of hierarchy
int height = 0;
String[][] hierarchy = definition.getHierarchy(s);
if (hierarchy != null && hierarchy.length != 0 && hierarchy[0] != null) {
height = hierarchy[0].length;
}
values[3] = String.valueOf(height);
values[4] = String.valueOf(definition.getMinimumGeneralization(s));
values[5] = String.valueOf(definition.getMaximumGeneralization(s));
}
if (definition.getMicroAggregationFunction(s) != null){
values[7] = definition.getMicroAggregationFunction(s).getLabel();
}
values[6] = SWTUtil.getPrettyString(config.getAttributeWeight(s));
new Property(quasiIdentifying, Resources.getMessage("PropertiesView.26") + (index++), values); //$NON-NLS-1$
}
}
// Print sensitive attributes
final Property sensitive = new Property(attributes, Resources.getMessage("PropertiesView.27"), new String[] { String.valueOf(definition.getSensitiveAttributes().size()) }); //$NON-NLS-1$
index = 0;
for (int i = 0; i < data.getNumColumns(); i++) {
final String s = data.getAttributeName(i);
if (definition.getSensitiveAttributes().contains(s)) {
final String[] values = new String[] { "", "", "", "", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
values[0] = s;
if (config.getHierarchy(s) != null && config.getHierarchy(s).getHierarchy() != null) {
int height = 0;
if (config.getHierarchy(s).getHierarchy().length > 0) {
height = config.getHierarchy(s).getHierarchy()[0].length;
}
values[1] = definition.getDataType(s).toString();
values[2] = String.valueOf(height);
}
new Property(sensitive, Resources.getMessage("PropertiesView.33") + (index++), values); //$NON-NLS-1$
}
}
// Print insensitive attributes
final Property insensitive = new Property(attributes, Resources.getMessage("PropertiesView.34"), new String[] { String.valueOf(definition.getInsensitiveAttributes().size()) }); //$NON-NLS-1$
index = 0;
for (int i = 0; i < data.getNumColumns(); i++) {
final String s = data.getAttributeName(i);
if (definition.getInsensitiveAttributes().contains(s)) {
final String[] values = new String[] { "", "", "", "", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
values[0] = s;
values[1] = definition.getDataType(s).toString();
new Property(insensitive, Resources.getMessage("PropertiesView.40") + (index++), values); //$NON-NLS-1$
}
}
// Refresh and initialize
refresh();
// Redraw
root.setRedraw(true);
}
}