/*
* 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.HashMap;
import java.util.Map;
import org.deidentifier.arx.AttributeType;
import org.deidentifier.arx.DataDefinition;
import org.deidentifier.arx.DataHandle;
import org.deidentifier.arx.gui.Controller;
import org.deidentifier.arx.gui.model.Model;
import org.deidentifier.arx.gui.model.ModelEvent;
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.def.IView;
import org.eclipse.nebula.widgets.nattable.layer.ILayerListener;
import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent;
import org.eclipse.nebula.widgets.nattable.selection.event.CellSelectionEvent;
import org.eclipse.nebula.widgets.nattable.selection.event.ColumnSelectionEvent;
import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ToolItem;
/**
* A view on a <code>Data</code> object.
*
* @author Fabian Prasser
*/
public abstract class ViewData implements IView {
/** Image */
private final Image IMAGE_ASCENDING;
/** Image */
private final Image IMAGE_DESCENDING;
/** Widget */
private final ToolItem groupsButton;
/** Widget */
private final ToolItem subsetButton;
/** Widget */
private final ToolItem ascendingButton;
/** Widget */
private final ToolItem descendingButton;
/** Widget */
private final ComponentTitledFolder folder;
/** Widget */
protected final ComponentDataTable table;
/** Controller */
protected final Controller controller;
/** Model */
protected Model model;
/** View */
private final Map<Composite, String> helpids = new HashMap<Composite, String>();
/**
*
* Creates a new data view.
*
* @param parent
* @param controller
* @param title
* @param helpid
*/
public ViewData(final Composite parent,
final Controller controller,
final String helpid,
final String title) {
// Register
controller.addListener(ModelPart.ATTRIBUTE_TYPE, this);
controller.addListener(ModelPart.SELECTED_ATTRIBUTE, this);
controller.addListener(ModelPart.MODEL, this);
controller.addListener(ModelPart.OUTPUT, this);
controller.addListener(ModelPart.SELECTED_VIEW_CONFIG, this);
controller.addListener(ModelPart.INPUT, this);
// Store
this.controller = controller;
// Load images
IMAGE_ASCENDING = controller.getResources().getManagedImage("sort_ascending.png"); //$NON-NLS-1$
IMAGE_DESCENDING = controller.getResources().getManagedImage("sort_descending.png");//$NON-NLS-1$
// Create title bar
ComponentTitledFolderButtonBar bar = new ComponentTitledFolderButtonBar(helpid, helpids); //$NON-NLS-1$
bar.add(Resources.getMessage("DataView.1"), //$NON-NLS-1$
IMAGE_ASCENDING,
new Runnable() {
@Override
public void run() {
model.getViewConfig().setSortOrder(true);
actionSort();
}
});
bar.add(Resources.getMessage("DataView.4"), //$NON-NLS-1$
IMAGE_DESCENDING,
new Runnable() {
@Override
public void run() {
model.getViewConfig().setSortOrder(false);
actionSort();
}
});
bar.add(Resources.getMessage("DataView.2"), //$NON-NLS-1$
controller.getResources().getManagedImage("sort_groups.png"), //$NON-NLS-1$
new Runnable() {
@Override
public void run() {
controller.actionDataShowGroups();
}
});
bar.add(Resources.getMessage("DataView.3"), //$NON-NLS-1$
controller.getResources().getManagedImage("sort_subset.png"), //$NON-NLS-1$
true,
new Runnable() {
@Override
public void run() {
controller.actionDataToggleSubset();
}
});
// Build border
folder = new ComponentTitledFolder(parent, controller, bar, null);
folder.setLayoutData(SWTUtil.createFillGridData());
Composite c = folder.createItem(title, null);
folder.setSelection(0);
GridLayout l = new GridLayout();
l.numColumns = 1;
c.setLayout(l);
// Build table
table = new ComponentDataTable(controller, c);
table.addSelectionLayerListener(new ILayerListener(){
@Override
public void handleLayerEvent(ILayerEvent arg0) {
if (arg0 instanceof CellSelectionEvent) {
actionCellSelected((CellSelectionEvent)arg0);
} else if (arg0 instanceof ColumnSelectionEvent) {
actionColumnSelected((ColumnSelectionEvent)arg0);
}
}
});
// Build buttons
this.groupsButton = folder.getButtonItem(Resources.getMessage("DataView.2")); //$NON-NLS-1$
this.groupsButton.setEnabled(false);
this.subsetButton = folder.getButtonItem(Resources.getMessage("DataView.3")); //$NON-NLS-1$
this.subsetButton.setEnabled(false);
this.ascendingButton = folder.getButtonItem(Resources.getMessage("DataView.1")); //$NON-NLS-1$
this.ascendingButton.setEnabled(false);
this.descendingButton = folder.getButtonItem(Resources.getMessage("DataView.4")); //$NON-NLS-1$
this.descendingButton.setEnabled(false);
}
/**
* Add a scrollbar listener to this view.
*
* @param listener
*/
public void addScrollBarListener(final Listener listener) {
table.addScrollBarListener(listener);
}
/**
* Adds a listener to the folder
* @param listener
*/
public void addSelectionListener(SelectionListener listener) {
this.folder.addSelectionListener(listener);
}
/**
* Adds an additional item to the folder
* @param title
* @param helpid
* @return
*/
public Composite createAdditionalItem(String title, String helpid) {
Composite result = folder.createItem(title, null);
helpids.put(result, helpid);
return result;
}
@Override
public void dispose() {
controller.removeListener(this);
table.dispose();
}
/**
* Returns the selection index of the folder
* @return
*/
public int getSelectionIndex() {
return folder.getSelectionIndex();
}
/**
* Returns the NatTable viewport layer.
*
* @return
*/
public ViewportLayer getViewportLayer() {
return table.getViewportLayer();
}
@Override
public void reset() {
table.reset();
groupsButton.setEnabled(false);
subsetButton.setEnabled(false);
ascendingButton.setEnabled(false);
descendingButton.setEnabled(false);
}
/**
* Sets the selection
* @param index
*/
public void setSelectedItem(int index) {
folder.setSelection(index);
}
/**
* Sets the selection index of the folder
* @param index
*/
public void setSelectionIndex(int index) {
folder.setSelection(index);
}
@Override
public void update(final ModelEvent event) {
// Enable/Disable sort button
if (event.part == ModelPart.OUTPUT ||
event.part == ModelPart.INPUT ||
event.part == ModelPart.SELECTED_VIEW_CONFIG) {
if (model != null && model.getOutput() != null){
groupsButton.setEnabled(true);
subsetButton.setEnabled(true);
} else {
groupsButton.setEnabled(false);
subsetButton.setEnabled(false);
}
}
// Update model
if (event.part == ModelPart.MODEL) {
model = (Model) event.data;
reset();
}
if (event.part == ModelPart.SELECTED_VIEW_CONFIG) {
subsetButton.setSelection(model.getViewConfig().isSubset());
}
if (event.part == ModelPart.SELECTED_ATTRIBUTE) {
table.setSelectedAttribute((String)event.data);
}
}
/**
* Selects the given column.
*
* @param index
*/
private void actionColumnSelected(int index){
DataHandle handle = getHandle();
if (handle != null && index < handle.getNumColumns()){
final String attr = handle.getAttributeName(index);
model.setSelectedAttribute(attr);
table.setSelectedAttribute(attr);
controller.update(new ModelEvent(this, ModelPart.SELECTED_ATTRIBUTE, attr));
}
}
/**
* Cell selection event.
*
* @param arg1
*/
protected void actionCellSelected(CellSelectionEvent arg1){
if (model != null) {
int column = arg1.getColumnPosition() - 1;
if (column>=0) actionColumnSelected(column);
}
}
/**
* Column selection event.
*
* @param arg1
*/
protected void actionColumnSelected(ColumnSelectionEvent arg1) {
if (model != null) {
int column = arg1.getColumnPositionRanges().iterator().next().start - 1;
if (column>=0) actionColumnSelected(column);
}
}
/**
* Called when the sort button is pressed.
*/
protected abstract void actionSort();
/**
* Enable sorting.
*/
protected void enableSorting(){
ascendingButton.setEnabled(true);
descendingButton.setEnabled(true);
}
/**
* Returns the data definition.
*
* @return
*/
protected abstract DataDefinition getDefinition();
/**
* Returns the data definition.
*
* @return
*/
protected abstract DataHandle getHandle();
/**
* Updates the header image in the table.
*
* @param index
* @param type
*/
protected void updateHeaderImage(final int index, final AttributeType type) {
while (table.getHeaderImages().size() <= index) {
table.getHeaderImages().add(null);
}
table.getHeaderImages().set(index, controller.getResources().getImage(type));
}
}