/*******************************************************************************
* Copyright 2013
* Ubiquitous Knowledge Processing (UKP) Lab
* Technische Universität Darmstadt
*
* 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 de.tudarmstadt.ukp.csniper.webapp.statistics.page;
import static java.util.Arrays.asList;
import static org.apache.commons.lang.WordUtils.capitalizeFully;
import java.awt.Color;
import java.awt.GradientPaint;
import java.io.IOException;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.mutable.MutableInt;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow.CloseButtonCallback;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.feedback.FeedbackMessage;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.CheckBoxMultipleChoice;
import org.apache.wicket.markup.html.form.ChoiceRenderer;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.ListMultipleChoice;
import org.apache.wicket.markup.html.form.NumberTextField;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.image.NonCachingImage;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.resource.ContextRelativeResource;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot3D;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.ui.GradientPaintTransformType;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.StandardGradientPaintTransformer;
import org.jfree.util.Rotation;
import org.jfree.util.UnitType;
import org.wicketstuff.progressbar.ProgressBar;
import de.tudarmstadt.ukp.csniper.webapp.DefaultValues;
import de.tudarmstadt.ukp.csniper.webapp.evaluation.EvaluationRepository;
import de.tudarmstadt.ukp.csniper.webapp.evaluation.model.AdditionalColumn;
import de.tudarmstadt.ukp.csniper.webapp.evaluation.page.ContextView;
import de.tudarmstadt.ukp.csniper.webapp.project.ProjectRepository;
import de.tudarmstadt.ukp.csniper.webapp.project.model.AnnotationType;
import de.tudarmstadt.ukp.csniper.webapp.search.ContextProvider;
import de.tudarmstadt.ukp.csniper.webapp.search.CorpusService;
import de.tudarmstadt.ukp.csniper.webapp.statistics.SortableAggregatedEvaluationResultDataProvider;
import de.tudarmstadt.ukp.csniper.webapp.statistics.SortableAggregatedEvaluationResultDataProvider.ResultFilter;
import de.tudarmstadt.ukp.csniper.webapp.statistics.model.AggregatedEvaluationResult;
import de.tudarmstadt.ukp.csniper.webapp.statistics.page.export.ExportCsvTask;
import de.tudarmstadt.ukp.csniper.webapp.statistics.page.export.ExportExcelTask;
import de.tudarmstadt.ukp.csniper.webapp.statistics.page.export.ExportHtmlTask;
import de.tudarmstadt.ukp.csniper.webapp.statistics.page.export.ExportTask;
import de.tudarmstadt.ukp.csniper.webapp.statistics.page.export.ExportTkSvmTask;
import de.tudarmstadt.ukp.csniper.webapp.support.task.ITaskService;
import de.tudarmstadt.ukp.csniper.webapp.support.task.TaskProgressionModel;
import de.tudarmstadt.ukp.csniper.webapp.support.task.Task.Message;
import de.tudarmstadt.ukp.csniper.webapp.support.wicket.AjaxFileDownload;
import de.tudarmstadt.ukp.csniper.webapp.support.wicket.ChartImageResource;
import de.tudarmstadt.ukp.csniper.webapp.support.wicket.CustomDataTable;
import de.tudarmstadt.ukp.csniper.webapp.support.wicket.EmbeddableImage;
import de.tudarmstadt.ukp.csniper.webapp.support.wicket.ExtendedIndicatingAjaxButton;
import de.tudarmstadt.ukp.csniper.webapp.support.wicket.ThresholdLink;
/**
* Statistics Page
*/
public class StatisticsPage
extends StatisticsPageBase
{
private static final long serialVersionUID = 1L;
private ModalWindow exportModal;
private AjaxFileDownload exportDownload;
private StatisticsForm statisticsForm;
private WebMarkupContainer displayOptions;
private WebMarkupContainer contextViewsContainer;
private ListView<ContextView> contextViews;
private List<IColumn<AggregatedEvaluationResult, String>> columns = new ArrayList<IColumn<AggregatedEvaluationResult, String>>();
private Component resultTable;
private SortableAggregatedEvaluationResultDataProvider dataProvider;
@SpringBean(name = "evaluationRepository")
private EvaluationRepository repository;
@SpringBean(name = "projectRepository")
private ProjectRepository projectRepository;
@SpringBean(name = "corpusService")
private CorpusService corpusService;
@SpringBean(name = "contextProvider")
private ContextProvider contextProvider;
private static final int ROWS_PER_PAGE = 10;
private static final int CHART_WIDTH = 300;
public static class StatisticsFormModel
implements Serializable
{
private static final long serialVersionUID = 1L;
// Settings
protected Set<String> collections = new HashSet<String>();
protected Set<AnnotationType> types = new HashSet<AnnotationType>();
protected Set<String> users = new HashSet<String>();
protected double userThreshold = DefaultValues.DEFAULT_CONFIDENCE_THRESHOLD;
protected double confidenceThreshold = DefaultValues.DEFAULT_USER_THRESHOLD;
protected List<ResultFilter> filters = new ArrayList<ResultFilter>();
// Statistics
private double fleissKappa = 0;
private TypeStatistics allTypes = new TypeStatistics();
private Map<String, TypeStatistics> perTypeStats = new HashMap<String, TypeStatistics>();
private Map<String, MutableInt> perUserStats = new HashMap<String, MutableInt>();
public int getComplete()
{
int value = 0;
for (TypeStatistics stats : perTypeStats.values()) {
value += Math.min(stats.goalCorrect, stats.correct);
value += Math.min(stats.goalWrong, stats.wrong);
}
return value;
}
public int getTotal()
{
int value = 0;
for (TypeStatistics stats : perTypeStats.values()) {
value += stats.correct;
value += stats.wrong;
value += stats.disputed;
value += stats.incomplete;
}
return value;
}
public int getGoal()
{
return allTypes.goalCorrect + allTypes.goalWrong;
}
public double getCompleteness()
{
return (double) getComplete() / getGoal();
}
private TypeStatistics getStatistics(String aType)
{
TypeStatistics s = perTypeStats.get(aType);
if (s == null) {
s = new TypeStatistics();
perTypeStats.put(aType, s);
}
return s;
}
public void reset()
{
allTypes = new TypeStatistics();
perTypeStats = new HashMap<String, TypeStatistics>();
perUserStats = new HashMap<String, MutableInt>();
}
public Set<String> getCollections()
{
return collections;
}
public Set<AnnotationType> getTypes()
{
return types;
}
public Set<String> getUsers()
{
return users;
}
public double getUserThreshold()
{
return userThreshold;
}
public double getConfidenceThreshold()
{
return confidenceThreshold;
}
public List<ResultFilter> getFilters()
{
return filters;
}
}
public static class TypeStatistics
implements Serializable
{
private static final long serialVersionUID = 1L;
public int goalCorrect;
public int goalWrong;
public int correct;
public int wrong;
public int disputed;
public int incomplete;
public double getCompleteness()
{
return (((double) Math.min(correct, goalCorrect) / goalCorrect) + ((double) Math.min(
wrong, goalWrong) / goalWrong)) / 2.0;
}
@Override
public String toString()
{
return "TypeStatistics [goalCorrect=" + goalCorrect + ", goalWrong=" + goalWrong
+ ", correct=" + correct + ", wrong=" + wrong + ", disputed=" + disputed
+ ", incomplete=" + incomplete + "]";
}
}
private class StatisticsForm
extends Form<StatisticsFormModel>
{
private static final long serialVersionUID = 1L;
private Image pieChart;
private Image progressChart;
private Image usersChart;
private Label fleissKappaLabel;
public StatisticsForm(String id)
{
super(id, new CompoundPropertyModel<StatisticsFormModel>(new StatisticsFormModel()));
StatisticsFormModel model = getModelObject();
// CSNIPER-120 - Misleading information about "unknown" instances on evaluation page
List<ResultFilter> availableFilters = new ArrayList<ResultFilter>(
asList(ResultFilter.values()));
availableFilters.remove(ResultFilter.UNKNOWN);
model.filters = new ArrayList<ResultFilter>(availableFilters);
add(new Label("goal"));
add(new Label("complete"));
// collection select
add(new ListMultipleChoice<String>("collections", corpusService.listCorpora()));
// type select
add(new ListMultipleChoice<AnnotationType>("types",
projectRepository.listAnnotationTypes(), new ChoiceRenderer<AnnotationType>(
"name")));
// user select
add(new ListMultipleChoice<String>("users", sort(repository.listUsers())));
// threshold link
add(new ThresholdLink("thresholdHelp"));
// vote field
add(new NumberTextField<Double>("userThreshold").setMinimum(0.0).setMaximum(1.0));
// confidence field
add(new NumberTextField<Double>("confidenceThreshold").setMinimum(0.0).setMaximum(1.0));
// filter
add(new CheckBoxMultipleChoice<ResultFilter>("filters", availableFilters,
new ChoiceRenderer<ResultFilter>("label")).setPrefix("<li>").setSuffix(
"</li>\n"));
// submit button
add(new ExtendedIndicatingAjaxButton("statisticsButton", new Model<String>(
"Show statistics"), new Model<String>("Calculating..."))
{
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(AjaxRequestTarget aTarget, Form<?> aForm)
{
StatisticsFormModel model = StatisticsForm.this.getModelObject();
// update resultTable
dataProvider = new SortableAggregatedEvaluationResultDataProvider(
repository.listAggregatedResults(model.collections, model.types,
model.users, model.userThreshold, model.confidenceThreshold),
model.users);
dataProvider.setSort("item.documentId", SortOrder.ASCENDING);
dataProvider.setFilters(model.filters);
resultTable = resultTable
.replaceWith(new CustomDataTable<AggregatedEvaluationResult>(
"resultTable", columns, dataProvider, ROWS_PER_PAGE));
calculateStatistics();
// update progress chart
progressChart.setImageResource(createProgressChart());
progressChart.setVisible(true);
// update users chart
usersChart.setImageResource(createUsersChart());
usersChart.setVisible(true);
// update pie chart
pieChart.setImageResource(new ChartImageResource(createPieChart(), CHART_WIDTH,
140));
pieChart.setVisible(true);
// show displayOptions
displayOptions.setVisible(true);
// aTarget.add(pieChart, progressChart, resultTable, displayOptions,
// fleissKappaLabel);
aTarget.add(StatisticsForm.this, resultTable, displayOptions);
}
@Override
public void onError(AjaxRequestTarget aTarget, Form<?> aForm)
{
super.onError(aTarget, aForm);
aTarget.add(getFeedbackPanel());
}
});
add(new AjaxSubmitLink("exportButton")
{
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget aTarget, Form<?> aForm)
{
aTarget.appendJavaScript("Wicket.Window.unloadConfirmation = false;");
// exportModal.get("content/settingsForm/progress").setVisible(false);
exportModal.show(aTarget);
}
@Override
protected void onError(AjaxRequestTarget aTarget, Form<?> aForm)
{
aTarget.add(getFeedbackPanel());
}
});
pieChart = new NonCachingImage("pieChart");
pieChart.setOutputMarkupPlaceholderTag(true).setVisible(false);
add(pieChart);
progressChart = new NonCachingImage("progressChart");
progressChart.setOutputMarkupPlaceholderTag(true).setVisible(false);
add(progressChart);
usersChart = new NonCachingImage("usersChart");
usersChart.setOutputMarkupPlaceholderTag(true).setVisible(false);
add(usersChart);
fleissKappaLabel = new Label("fleissKappa")
{
private static final long serialVersionUID = 1L;
@Override
public void onComponentTagBody(final MarkupStream markupStream,
final ComponentTag openTag)
{
double kappa = (Double) getDefaultModelObject();
String label;
if (Double.isNaN(kappa)) {
label = "not computable";
}
else {
label = new DecimalFormat("#.##").format(kappa);
}
replaceComponentTagBody(markupStream, openTag, label);
}
};
fleissKappaLabel.setOutputMarkupId(true);
add(fleissKappaLabel);
setOutputMarkupId(true);
}
/**
* Creates a pie chart from the classifications obtained from the dataProvider.
*
* @return a PieChart to use as a parameter for ChartImageResource
*/
private JFreeChart createPieChart()
{
StatisticsFormModel model = getModelObject();
// fill dataset
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setValue("Correct", model.allTypes.correct);
dataset.setValue("Wrong", model.allTypes.wrong);
// dataset.setValue("Incomplete", model.allTypes.incomplete);
dataset.setValue("Disputed", model.allTypes.disputed);
// create chart
JFreeChart chart = ChartFactory.createPieChart3D(null, dataset, false, true, false);
PiePlot3D plot = (PiePlot3D) chart.getPlot();
plot.setInsets(RectangleInsets.ZERO_INSETS);
plot.setStartAngle(290);
plot.setDirection(Rotation.CLOCKWISE);
plot.setIgnoreZeroValues(true);
plot.setOutlineVisible(false);
plot.setBackgroundPaint(null);
// plot.setInteriorGap(0.05);
plot.setInteriorGap(0.0);
plot.setMaximumLabelWidth(0.22);
plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} {1} ({2})"));
plot.setDepthFactor(0.25);
plot.setCircular(true);
plot.setDarkerSides(true);
for (ResultFilter filter : ResultFilter.values()) {
plot.setSectionPaint(capitalizeFully(filter.toString()), filter.getColor());
}
return chart;
}
private void calculateStatistics()
{
StatisticsFormModel model = getModelObject();
model.reset();
for (AnnotationType t : model.types) {
model.allTypes.goalCorrect += t.getGoal();
model.allTypes.goalWrong += t.getGoalWrong();
model.getStatistics(t.getName()).goalCorrect += t.getGoal();
model.getStatistics(t.getName()).goalWrong += t.getGoalWrong();
}
// get statistics for each type
dataProvider.getTypeStatistics(model.perTypeStats, model.perUserStats);
for (TypeStatistics tstats : model.perTypeStats.values()) {
model.allTypes.correct += tstats.correct;
model.allTypes.wrong += tstats.wrong;
model.allTypes.disputed += tstats.disputed;
model.allTypes.incomplete += tstats.incomplete;
}
// compute Fleiss' Kappa
model.fleissKappa = dataProvider.computeInterAnnotatorAgreement();
}
private ChartImageResource createProgressChart()
{
StatisticsFormModel model = getModelObject();
// fill dataset
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.setValue(model.getCompleteness(), "Completeness", "Overall");
List<String> types = new ArrayList<String>(model.perTypeStats.keySet());
Collections.sort(types);
for (String type : types) {
TypeStatistics stats = model.getStatistics(type);
dataset.setValue(stats.getCompleteness(), "Completeness", type);
}
// create chart
JFreeChart chart = ChartFactory.createBarChart(null, null, null, dataset,
PlotOrientation.HORIZONTAL, false, false, false);
CategoryPlot plot = chart.getCategoryPlot();
plot.setInsets(new RectangleInsets(UnitType.ABSOLUTE, 0, 20, 0, 20));
plot.getRangeAxis().setRange(0.0, 1.0);
((NumberAxis) plot.getRangeAxis()).setNumberFormatOverride(new DecimalFormat("0%"));
plot.setOutlineVisible(false);
plot.setBackgroundPaint(null);
BarRenderer renderer = new BarRenderer();
renderer.setBarPainter(new StandardBarPainter());
renderer.setShadowVisible(false);
renderer.setGradientPaintTransformer(new StandardGradientPaintTransformer(
GradientPaintTransformType.HORIZONTAL));
renderer.setSeriesPaint(0, new GradientPaint(0f, 0f, Color.RED, 0f, 0f, Color.GREEN));
chart.getCategoryPlot().setRenderer(renderer);
return new ChartImageResource(chart, CHART_WIDTH, 30 + (types.size() * 18));
}
private ChartImageResource createUsersChart()
{
StatisticsFormModel model = getModelObject();
// fill dataset
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
List<String> users = new ArrayList<String>(model.perUserStats.keySet());
Collections.sort(users);
for (String user : users) {
dataset.setValue(model.perUserStats.get(user).intValue(), "Votes", user);
}
// create chart
JFreeChart chart = ChartFactory.createBarChart(null, null, null, dataset,
PlotOrientation.HORIZONTAL, false, false, false);
CategoryPlot plot = chart.getCategoryPlot();
plot.setInsets(new RectangleInsets(UnitType.ABSOLUTE, 0, 20, 0, 20));
plot.getRangeAxis().setRange(0.0, model.getTotal());
((NumberAxis) plot.getRangeAxis()).setNumberFormatOverride(new DecimalFormat("0"));
plot.setOutlineVisible(false);
plot.setBackgroundPaint(null);
BarRenderer renderer = new BarRenderer();
renderer.setBarPainter(new StandardBarPainter());
renderer.setShadowVisible(false);
// renderer.setGradientPaintTransformer(new StandardGradientPaintTransformer(
// GradientPaintTransformType.HORIZONTAL));
renderer.setSeriesPaint(0, Color.BLUE);
chart.getCategoryPlot().setRenderer(renderer);
return new ChartImageResource(chart, CHART_WIDTH, 30 + (users.size() * 18));
}
private List<String> sort(List<String> aList)
{
Collections.sort(aList);
return aList;
}
}
/**
* Constructor that is invoked when page is invoked without a session.
*/
public StatisticsPage()
{
super();
contextViewsContainer = new WebMarkupContainer("contextViewsContainer")
{
{
contextViews = new ListView<ContextView>("contextViews")
{
@Override
protected void populateItem(ListItem aItem)
{
aItem.add((Component) aItem.getModelObject());
}
};
add(contextViews);
}
};
contextViewsContainer.setOutputMarkupId(true);
add(contextViewsContainer);
columns.add(new AbstractColumn<AggregatedEvaluationResult, String>(new Model<String>(""))
{
@Override
public void populateItem(
final Item<ICellPopulator<AggregatedEvaluationResult>> aCellItem,
String aComponentId, final IModel<AggregatedEvaluationResult> model)
{
EmbeddableImage iconContext = new EmbeddableImage(aComponentId,
new ContextRelativeResource("images/context.png"));
iconContext.add(new AjaxEventBehavior("onclick")
{
@Override
protected void onEvent(AjaxRequestTarget aTarget)
{
try {
contextViews.setList(asList(new ContextView(contextProvider, model
.getObject().getItem())));
aTarget.add(contextViewsContainer);
}
catch (IOException e) {
error("Unable to load context: " + e.getMessage());
}
}
});
iconContext.add(new AttributeModifier("class",
new Model<String>("clickableElement")));
aCellItem.add(iconContext);
}
});
columns.add(new PropertyColumn<AggregatedEvaluationResult, String>(new Model<String>("Type"),
"item.type", "item.type")
{
private static final long serialVersionUID = 1L;
@Override
public String getCssClass()
{
return super.getCssClass() + " nowrap";
}
});
columns.add(new PropertyColumn<AggregatedEvaluationResult, String>(new Model<String>("Collection"),
"item.collectionId", "item.collectionId")
{
private static final long serialVersionUID = 1L;
@Override
public String getCssClass()
{
return super.getCssClass() + " nowrap";
}
});
columns.add(new PropertyColumn<AggregatedEvaluationResult, String>(new Model<String>("Document"),
"item.documentId", "item.documentId")
{
private static final long serialVersionUID = 1L;
@Override
public String getCssClass()
{
return super.getCssClass() + " nowrap";
}
});
columns.add(new PropertyColumn<AggregatedEvaluationResult, String>(new Model<String>("Item"),
"item.coveredText", "item.coveredText"));
columns.add(new PropertyColumn<AggregatedEvaluationResult, String>(new Model<String>("#Correct"),
"correct", "correct"));
columns.add(new PropertyColumn<AggregatedEvaluationResult, String>(new Model<String>("#Wrong"),
"wrong", "wrong"));
columns.add(new PropertyColumn<AggregatedEvaluationResult, String>(
new Model<String>("#Incomplete"), "incomplete", "incomplete"));
columns.add(new PropertyColumn<AggregatedEvaluationResult, String>(new Model<String>("Aggregated"),
"classification", "classification"));
// {
// private static final long serialVersionUID = 1L;
//
// @Override
// public void populateItem(Item<ICellPopulator<AggregatedEvaluationResult>> aCellItem,
// String aComponentId, IModel<AggregatedEvaluationResult> aRowModel)
// {
// StatisticsFormModel sModel = statisticsForm.getModelObject();
// ResultFilter aggregated = aRowModel.getObject().getClassification(sModel.users,
// sModel.userThreshold, sModel.confidenceThreshold);
// aCellItem.add(new Label(aComponentId, aggregated.getLabel()));
// }
// });
columns.add(new PropertyColumn<AggregatedEvaluationResult, String>(new Model<String>("Confidence"),
"confidence", "confidence"));
// {
// private static final long serialVersionUID = 1L;
//
// @Override
// public void populateItem(Item<ICellPopulator<AggregatedEvaluationResult>> aCellItem,
// String aComponentId, IModel<AggregatedEvaluationResult> aRowModel)
// {
// StatisticsFormModel sModel = statisticsForm.getModelObject();
// double confidence = aRowModel.getObject().getConfidence(sModel.users,
// sModel.userThreshold);
// aCellItem.add(new Label(aComponentId, Double.toString(confidence)));
// }
// });
add(exportModal = new ModalWindow("exportModal"));
final ExportPanel exportPanel = new ExportPanel(exportModal.getContentId());
exportModal.setContent(exportPanel);
exportModal.setTitle("Export");
exportModal.setInitialWidth(550);
exportModal.setInitialHeight(350);
exportModal.setCloseButtonCallback(new CloseButtonCallback()
{
@Override
public boolean onCloseButtonClicked(AjaxRequestTarget aTarget)
{
exportPanel.cancel(aTarget);
return true;
}
});
add(exportDownload = new AjaxFileDownload());
add(statisticsForm = new StatisticsForm("statisticsForm"));
add(displayOptions = (WebMarkupContainer) new WebMarkupContainer("displayOptions")
{
private static final long serialVersionUID = 1L;
{
add(new Label("filterLabel", new PropertyModel<List<ResultFilter>>(statisticsForm,
"modelObject.filters")));
add(new Label("collectionIdLabel", new PropertyModel<Set<String>>(statisticsForm,
"modelObject.collections")));
add(new Label("typeLabel", new PropertyModel<Set<AnnotationType>>(statisticsForm,
"modelObject.types"))
{
private static final long serialVersionUID = 1L;
@Override
public void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag)
{
Set<AnnotationType> types = (Set<AnnotationType>) getDefaultModelObject();
List<String> typeNames = new ArrayList<String>();
for (AnnotationType t : types) {
typeNames.add(t.getName());
}
Collections.sort(typeNames);
replaceComponentTagBody(markupStream, openTag, typeNames.toString());
};
});
}
}.setOutputMarkupPlaceholderTag(true).setVisible(false));
add(resultTable = new Label("resultTable").setOutputMarkupId(true));
}
public class ExportPanel
extends Panel
{
private static final long serialVersionUID = 1L;
private Form<ExportModel> form;
private ProgressBar progressBar;
private TaskProgressionModel progressionModel;
private AjaxButton exportHtmlButton;
private AjaxButton exportCsvButton;
private AjaxButton exportXlsButton;
private AjaxButton exportTkSvmButton;
public ExportPanel(String aId)
{
super(aId);
progressionModel = new TaskProgressionModel()
{
private static final long serialVersionUID = 1L;
@Override
protected ITaskService getTaskService()
{
return StatisticsPage.this.getTaskService();
}
};
add(form = new Form<ExportModel>("settingsForm",
new CompoundPropertyModel<ExportModel>(new ExportModel())));
form.add(new CheckBox("includePos").setOutputMarkupId(true));
form.add(new NumberTextField<Integer>("contextSize").setMinimum(0).setMaximum(10000)
.setOutputMarkupId(true));
form.add(new ListMultipleChoice<AdditionalColumn>("additionalColumns",
new LoadableDetachableModel<List<AdditionalColumn>>()
{
private static final long serialVersionUID = 1L;
@Override
protected List<AdditionalColumn> load()
{
List<AdditionalColumn> acs = new ArrayList<AdditionalColumn>();
for (AnnotationType at : statisticsForm.getModelObject().types) {
acs.addAll(at.getAdditionalColumns());
}
return acs;
}
}, new ChoiceRenderer<AdditionalColumn>("name")));
form.add(exportHtmlButton = new AjaxButton("exportHtmlButton")
{
@Override
protected void onSubmit(AjaxRequestTarget aTarget, Form<?> aForm)
{
final ExportHtmlTask task = new ExportHtmlTask(statisticsForm.getModelObject(),
form.getModelObject(), repository, contextProvider);
// Schedule and start a new task
Long taskId = StatisticsPage.this.getTaskService().scheduleAndStart(task);
// Set taskId for model
progressionModel.setTaskId(taskId);
// disable buttons
exportHtmlButton.setVisible(false);
exportCsvButton.setVisible(false);
exportXlsButton.setVisible(false);
exportTkSvmButton.setVisible(false);
aTarget.add(form);
// Start the progress bar, will set visibility to true
progressBar.start(aTarget);
}
@Override
protected void onError(AjaxRequestTarget aTarget, Form<?> aForm)
{
// Make sure the feedback messages are rendered since we have a modal window,
// we don't want to show the messages on the regular feedback panel
for (FeedbackMessage fm : getFeedbackPanel().getFeedbackMessagesModel()
.getObject()) {
aTarget.appendJavaScript("alert('"
+ fm.getMessage().toString().replace("'", "\\'") + "');");
}
}
});
form.add(exportCsvButton = new AjaxButton("exportCsvButton")
{
@Override
protected void onSubmit(AjaxRequestTarget aTarget, Form<?> aForm)
{
final ExportCsvTask task = new ExportCsvTask(statisticsForm.getModelObject(),
form.getModelObject(), repository, contextProvider);
// Schedule and start a new task
Long taskId = StatisticsPage.this.getTaskService().scheduleAndStart(task);
// Set taskId for model
progressionModel.setTaskId(taskId);
// disable buttons
exportHtmlButton.setVisible(false);
exportCsvButton.setVisible(false);
exportXlsButton.setVisible(false);
exportTkSvmButton.setVisible(false);
aTarget.add(form);
// Start the progress bar, will set visibility to true
progressBar.start(aTarget);
}
@Override
protected void onError(AjaxRequestTarget aTarget, Form<?> aForm)
{
// Make sure the feedback messages are rendered since we have a modal window,
// we don't want to show the messages on the regular feedback panel
for (FeedbackMessage fm : getFeedbackPanel().getFeedbackMessagesModel()
.getObject()) {
aTarget.appendJavaScript("alert('"
+ fm.getMessage().toString().replace("'", "\\'") + "');");
}
}
});
form.add(exportXlsButton = new AjaxButton("exportXlsButton")
{
@Override
protected void onSubmit(AjaxRequestTarget aTarget, Form<?> aForm)
{
final ExportExcelTask task = new ExportExcelTask(statisticsForm
.getModelObject(), form.getModelObject(), repository, contextProvider);
// Schedule and start a new task
Long taskId = StatisticsPage.this.getTaskService().scheduleAndStart(task);
// Set taskId for model
progressionModel.setTaskId(taskId);
// disable buttons
exportHtmlButton.setVisible(false);
exportCsvButton.setVisible(false);
exportXlsButton.setVisible(false);
exportTkSvmButton.setVisible(false);
aTarget.add(form);
// Start the progress bar, will set visibility to true
progressBar.start(aTarget);
}
@Override
protected void onError(AjaxRequestTarget aTarget, Form<?> aForm)
{
// Make sure the feedback messages are rendered since we have a modal window,
// we don't want to show the messages on the regular feedback panel
for (FeedbackMessage fm : getFeedbackPanel().getFeedbackMessagesModel()
.getObject()) {
aTarget.appendJavaScript("alert('"
+ fm.getMessage().toString().replace("'", "\\'") + "');");
}
}
});
form.add(exportTkSvmButton = new AjaxButton("exportTkSvmButton")
{
@Override
protected void onSubmit(AjaxRequestTarget aTarget, Form<?> aForm)
{
if (statisticsForm.getModelObject().collections.size() == 0) {
error("Cannot export empty collection");
aTarget.add(getFeedbackPanel());
cancel(aTarget);
return;
}
String language = corpusService.getCorpus(
statisticsForm.getModelObject().collections.iterator().next())
.getLanguage();
for (String cId : statisticsForm.getModelObject().collections) {
if (!language.equals(corpusService.getCorpus(cId))) {
error("Can not export collections with different languages");
aTarget.add(getFeedbackPanel());
cancel(aTarget);
return;
}
}
final ExportTkSvmTask task = new ExportTkSvmTask(statisticsForm
.getModelObject(), form.getModelObject(), repository, language);
// Schedule and start a new task
Long taskId = StatisticsPage.this.getTaskService().scheduleAndStart(task);
// Set taskId for model
progressionModel.setTaskId(taskId);
// disable buttons
exportHtmlButton.setVisible(false);
exportCsvButton.setVisible(false);
exportXlsButton.setVisible(false);
exportTkSvmButton.setVisible(false);
aTarget.add(form);
// Start the progress bar, will set visibility to true
progressBar.start(aTarget);
}
@Override
protected void onError(AjaxRequestTarget aTarget, Form<?> aForm)
{
// Make sure the feedback messages are rendered since we have a modal window,
// we don't want to show the messages on the regular feedback panel
for (FeedbackMessage fm : getFeedbackPanel().getFeedbackMessagesModel()
.getObject()) {
aTarget.appendJavaScript("alert('"
+ fm.getMessage().toString().replace("'", "\\'") + "');");
}
}
});
form.add(progressBar = new ProgressBar("progress", progressionModel)
{
private static final long serialVersionUID = 1L;
@Override
protected void onFinished(AjaxRequestTarget aTarget)
{
finishTask(aTarget);
}
});
progressBar.setVisible(false);
form.add(new AjaxLink("cancelButton")
{
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget aTarget)
{
cancel(aTarget);
}
});
}
protected void cancel(AjaxRequestTarget aTarget)
{
getTaskService().cancel(progressionModel.getTaskId());
form.detach();
finishTask(aTarget);
}
protected void finishTask(AjaxRequestTarget aTarget)
{
ExportTask task = (ExportTask) getTaskService().getTask(progressionModel.getTaskId());
// show errors which might have occurred
for (Message m : getTaskService().getMessages(progressionModel.getTaskId())) {
error(m.messageKey);
}
// finish the task!
getTaskService().finish(progressionModel.getTaskId());
progressBar.setVisible(false);
// re-enable button
form.get("exportHtmlButton").setVisible(true);
form.get("exportCsvButton").setVisible(true);
form.get("exportXlsButton").setVisible(true);
form.get("exportTkSvmButton").setVisible(true);
aTarget.add(form, getFeedbackPanel());
exportModal.close(aTarget);
if (task != null && !task.isCancelled()) {
exportDownload.initiate(aTarget, task.getOutputFile(), task.getFilename(),
"binary/octet-stream");
}
}
}
public static class ExportModel
implements Serializable
{
private static final long serialVersionUID = 1L;
public boolean includePos = false;
public int contextSize = 130;
public List<AdditionalColumn> additionalColumns = new ArrayList<AdditionalColumn>();
}
}