/*
* 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.gui.Controller;
import org.deidentifier.arx.gui.model.Model;
import org.deidentifier.arx.gui.model.Model.Perspective;
import org.deidentifier.arx.gui.model.ModelEvent;
import org.deidentifier.arx.gui.model.ModelEvent.ModelPart;
import org.deidentifier.arx.gui.view.def.IView;
import org.deidentifier.arx.gui.view.impl.common.ComponentStatus;
import org.deidentifier.arx.gui.view.impl.common.ComponentStatusLabelProgressProvider;
import org.deidentifier.arx.gui.view.impl.common.async.AnalysisContext;
import org.deidentifier.arx.gui.view.impl.common.async.AnalysisContextVisualization;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
/**
* This is a base class for displaying utility data.
*
* @author Fabian Prasser
* @param <T>
*/
public abstract class ViewStatistics<T extends AnalysisContextVisualization> implements IView {
/** Our users are patient. */
public static final int MINIMAL_WORKING_TIME = 500;
/** Internal stuff. */
private AnalysisContext context = new AnalysisContext();
/** Internal stuff. */
private final Controller controller;
/** Internal stuff. */
private Model model;
/** Internal stuff. */
private final ModelPart reset;
/** Internal stuff. */
private final ModelPart target;
/** Internal stuff. */
private final ComponentStatus status;
/** Internal stuff. */
private T viewContext;
/** Internal stuff. */
private final boolean dependsOnAttribute;
/** Is this view enabled */
private boolean enabled = false;
/** Parent */
private final Composite parent;
/**
* Creates a new instance.
*
* @param parent
* @param controller
* @param target
* @param reset
* @param dependsOnAttribute
*/
public ViewStatistics( final Composite parent,
final Controller controller,
final ModelPart target,
final ModelPart reset,
final boolean dependsOnAttribute) {
// Register
controller.addListener(ModelPart.SELECTED_ATTRIBUTE, this);
controller.addListener(ModelPart.MODEL, this);
controller.addListener(ModelPart.SELECTED_VIEW_CONFIG, this);
controller.addListener(ModelPart.ATTRIBUTE_TYPE, this);
controller.addListener(ModelPart.DATA_TYPE, this);
controller.addListener(ModelPart.SELECTED_UTILITY_VISUALIZATION, this);
controller.addListener(ModelPart.ATTRIBUTE_VALUE, this);
controller.addListener(target, this);
if (reset != null) {
controller.addListener(reset, this);
}
// Init
this.controller = controller;
this.reset = reset;
this.target = target;
this.dependsOnAttribute = dependsOnAttribute;
this.parent = parent;
// Create controls
parent.setLayout(new StackLayout());
Control control = this.createControl(parent);
// Obtain progress provider
ComponentStatusLabelProgressProvider provider = getProgressProvider();
// Update status
if (provider == null) {
this.status = new ComponentStatus(controller,
parent,
control);
} else {
this.status = new ComponentStatus(controller,
parent,
control,
getProgressProvider());
}
// Reset
this.reset();
}
@Override
public void dispose() {
controller.removeListener(this);
}
/**
* Returns the type
* @return
*/
public abstract LayoutUtility.ViewUtilityType getType();
@Override
public void reset() {
this.doReset();
status.setEmpty();
}
@Override
public void update(final ModelEvent event) {
// Store
if (event.part == ModelPart.MODEL) {
this.model = (Model)event.data;
this.model.resetAttributePair();
this.context.setModel(model);
this.context.setTarget(target);
this.viewContext = null;
this.reset();
}
// Reset on null-target
if (event.part == target && event.data==null) {
this.viewContext = null;
this.reset();
return;
}
// Invalidate
if (event.part == ModelPart.OUTPUT || event.part == target || event.part == ModelPart.SELECTED_VIEW_CONFIG) {
this.triggerUpdate();
return;
}
// Invalidate
if (event.part == ModelPart.SELECTED_ATTRIBUTE || event.part == ModelPart.ATTRIBUTE_VALUE) {
if (dependsOnAttribute) {
this.triggerUpdate();
return;
}
}
// Potentially invalidate
if (event.part == ModelPart.DATA_TYPE || event.part == ModelPart.ATTRIBUTE_TYPE) {
if (dependsOnAttribute) {
if (model == null || viewContext == null || viewContext.isAttributeSelected(model.getSelectedAttribute())) {
this.triggerUpdate();
return;
}
}
}
// Reset
if (event.part == reset) {
this.viewContext = null;
this.reset();
return;
}
// Update
if (event.part == target ||
event.part == ModelPart.SELECTED_ATTRIBUTE ||
event.part == ModelPart.ATTRIBUTE_TYPE ||
event.part == ModelPart.SELECTED_VIEW_CONFIG ||
event.part == ModelPart.SELECTED_UTILITY_VISUALIZATION ||
(event.part == ModelPart.SELECTED_PERSPECTIVE && model != null && model.getPerspective() == Perspective.ANALYSIS)) {
this.update();
}
}
/**
* Redraws the plot.
*/
private void update() {
// Disable the view
if (model != null && !model.isVisualizationEnabled()) {
this.doReset();
this.setStatusEmpty();
this.enabled = false;
return;
}
// Check visibility
if (!this.status.isVisible()){
return;
}
// Enable the view
if (model != null && model.isVisualizationEnabled() && !this.enabled) {
this.enabled = true;
this.viewContext = null;
}
// Check if already done
if (this.viewContext != null) {
if (!isRunning()) {
this.status.setDone();
}
return;
}
// Update
T context = createViewConfig(this.context);
if (context.isValid()) {
// Update context
this.viewContext = context;
// Update
this.doUpdate(context);
// Update status
status.setWorking();
}
}
/**
*
* Implement this to create the widget.
*
* @param parent
* @return
*/
protected abstract Control createControl(Composite parent);
/**
*
*
* @param context
* @return
*/
protected abstract T createViewConfig(AnalysisContext context);
/**
* Implement this to reset.
*/
protected abstract void doReset();
/**
* Implement this to update.
*
* @param context
*/
protected abstract void doUpdate(T context);
/**
* Returns the controller
* @return
*/
protected Controller getController() {
return this.controller;
}
/**
* Returns the model
* @return
*/
protected Model getModel() {
return this.model;
}
/**
* Returns the parent composite
*/
protected Composite getParent() {
return this.parent;
}
/**
* Overwrite this to return a progress provider
* @return
*/
protected ComponentStatusLabelProgressProvider getProgressProvider() {
return null;
}
/**
* Returns the target
* @return
*/
protected ModelPart getTarget() {
return target;
}
/**
* Is this view enabled
* @return
*/
protected boolean isEnabled() {
return enabled;
}
/**
* Is a job running
* @return
*/
protected abstract boolean isRunning();
/**
* Status update.
*/
protected void setStatusDone(){
this.status.setDone();
}
/**
* Status empty.
*/
protected void setStatusEmpty(){
this.status.setEmpty();
}
/**
* Status working.
*/
protected void setStatusWorking(){
this.status.setWorking();
}
/**
* Triggers an update
*/
protected void triggerUpdate() {
this.viewContext = null;
this.update();
}
}