/*
* Copyright 2012
* Ubiquitous Knowledge Processing (UKP) Lab and FG Language Technology
* 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.clarin.webanno.ui.annotation.dialog;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.extensions.markup.html.form.select.Select;
import org.apache.wicket.extensions.markup.html.form.select.SelectOption;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.form.Form;
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.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.springframework.security.core.context.SecurityContextHolder;
import de.tudarmstadt.ukp.clarin.webanno.api.DocumentService;
import de.tudarmstadt.ukp.clarin.webanno.api.ProjectService;
import de.tudarmstadt.ukp.clarin.webanno.api.annotation.model.AnnotatorState;
import de.tudarmstadt.ukp.clarin.webanno.curation.storage.CurationDocumentService;
import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationDocument;
import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationDocumentState;
import de.tudarmstadt.ukp.clarin.webanno.model.Mode;
import de.tudarmstadt.ukp.clarin.webanno.model.Project;
import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument;
import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocumentState;
import de.tudarmstadt.ukp.clarin.webanno.security.UserDao;
import de.tudarmstadt.ukp.clarin.webanno.security.model.User;
/**
* A panel used as Open dialog. It Lists all projects a user is member of for annotation/curation
* and associated documents
*/
public class OpenModalWindowPanel
extends Panel
{
private static final long serialVersionUID = 1299869948010875439L;
private @SpringBean ProjectService projectService;
private @SpringBean DocumentService documentService;
private @SpringBean CurationDocumentService curationDocumentService;
private @SpringBean UserDao userRepository;
// Project list, Document List and buttons List, contained in separet forms
private final ProjectSelectionForm projectSelectionForm;
private final DocumentSelectionForm documentSelectionForm;
private final ButtonsForm buttonsForm;
private Select<SourceDocument> documentSelection;
// The first project - selected by default
private Project selectedProject;
// The first document in the project // auto selected in the first time.
private SourceDocument selectedDocument;
private final String username;
private final User user;
private final Mode mode;
private final AnnotatorState bModel;
private IModel<List<Pair<Project, String>>> projects;
public OpenModalWindowPanel(String aId, AnnotatorState aBModel,
ModalWindow aModalWindow, Mode aSubject, IModel<List<Pair<Project, String>>> aProjects)
{
super(aId);
mode = aSubject;
bModel = aBModel;
username = SecurityContextHolder.getContext().getAuthentication().getName();
user = userRepository.get(username);
projects = aProjects;
List<Pair<Project, String>> allowedProjects = projects.getObject();
if (!allowedProjects.isEmpty()) {
selectedProject = allowedProjects.get(0).getKey();
}
projectSelectionForm = new ProjectSelectionForm("projectSelectionForm");
documentSelectionForm = new DocumentSelectionForm("documentSelectionForm", aModalWindow);
buttonsForm = new ButtonsForm("buttonsForm", aModalWindow);
add(buttonsForm);
add(projectSelectionForm);
add(documentSelectionForm);
}
private class ProjectSelectionForm
extends Form<SelectionModel>
{
private static final long serialVersionUID = -1L;
private Select<Project> projectSelection;
public ProjectSelectionForm(String id)
{
super(id, new CompoundPropertyModel<SelectionModel>(new SelectionModel()));
projectSelection = new Select<Project>("projectSelection");
ListView<Pair<Project, String>> lv = new ListView<Pair<Project, String>>("projects", projects)
{
private static final long serialVersionUID = 8901519963052692214L;
@Override
protected void populateItem(final ListItem<Pair<Project, String>> item)
{
String color = item.getModelObject().getValue();
if (color == null) {
color = "#008000";
}
item.add(new SelectOption<Project>("project", new Model<Project>(item
.getModelObject().getKey()))
{
private static final long serialVersionUID = 3095089418860168215L;
@Override
public void onComponentTagBody(MarkupStream markupStream,
ComponentTag openTag)
{
replaceComponentTagBody(markupStream, openTag,
item.getModelObject().getKey().getName());
}
}.add(new AttributeModifier("style", "color:" + color + ";")));
}
};
add(projectSelection.add(lv));
projectSelection.setOutputMarkupId(true);
projectSelection.add(new OnChangeAjaxBehavior()
{
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(AjaxRequestTarget aTarget)
{
selectedProject = getModelObject().projectSelection;
// Remove selected document from other project
selectedDocument = null;
documentSelection.setModelObject(selectedDocument);
aTarget.add(documentSelection);
}
}).add(new AjaxEventBehavior("dblclick")
{
private static final long serialVersionUID = 1L;
@Override
protected void onEvent(final AjaxRequestTarget aTarget)
{
selectedProject = getModelObject().projectSelection;
// Remove selected document from other project
selectedDocument = null;
aTarget.add(documentSelection.setOutputMarkupId(true));
}
});
}
}
private class SelectionModel
implements Serializable
{
private static final long serialVersionUID = -1L;
private Project projectSelection;
private SourceDocument documentSelection;
}
private class DocumentSelectionForm
extends Form<SelectionModel>
{
private static final long serialVersionUID = -1L;
ListView<SourceDocument> lv;
public DocumentSelectionForm(String id, final ModalWindow modalWindow)
{
super(id, new CompoundPropertyModel<SelectionModel>(new SelectionModel()));
final Map<SourceDocument, String> documentColors = new HashMap<SourceDocument, String>();
documentSelection = new Select<SourceDocument>("documentSelection");
lv = new ListView<SourceDocument>("documents",
new LoadableDetachableModel<List<SourceDocument>>()
{
private static final long serialVersionUID = 1L;
@Override
protected List<SourceDocument> load()
{
List<SourceDocument> allDocuments = listDocuments(documentColors);
return allDocuments;
}
})
{
private static final long serialVersionUID = 8901519963052692214L;
@Override
protected void populateItem(final ListItem<SourceDocument> item)
{
item.add(new SelectOption<SourceDocument>("document",
new Model<SourceDocument>(item.getModelObject()))
{
private static final long serialVersionUID = 3095089418860168215L;
@Override
public void onComponentTagBody(MarkupStream markupStream,
ComponentTag openTag)
{
replaceComponentTagBody(markupStream, openTag, item.getModelObject()
.getName());
}
}.add(new AttributeModifier("style", "color:"
+ documentColors.get(item.getModelObject()) + ";")));
}
};
add(documentSelection.add(lv));
documentSelection.setOutputMarkupId(true);
documentSelection.add(new OnChangeAjaxBehavior()
{
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(AjaxRequestTarget aTarget)
{
selectedDocument = getModelObject().documentSelection;
}
}).add(new AjaxEventBehavior("dblclick")
{
private static final long serialVersionUID = 1L;
@Override
protected void onEvent(final AjaxRequestTarget aTarget)
{
// do not use this default layer in that other project
if(bModel.getProject()!=null){
if(!bModel.getProject().equals(selectedProject)){
bModel.setDefaultAnnotationLayer(null);
}
}
if (selectedProject != null && selectedDocument != null) {
bModel.setProject(selectedProject);
bModel.setDocument(selectedDocument, lv.getModelObject());
modalWindow.close(aTarget);
}
}
});
}
}
private List<SourceDocument> listDocuments(final Map<SourceDocument, String> states)
{
if (selectedProject == null) {
return new ArrayList<SourceDocument>();
}
List<SourceDocument> allSourceDocuments = new ArrayList<>();
// Remove from the list source documents that are in IGNORE state OR
// that do not have at least one annotation document marked as
// finished for curation dialog
switch (mode) {
case ANNOTATION:
case AUTOMATION:
case CORRECTION: {
Map<SourceDocument, AnnotationDocument> docs = documentService
.listAnnotatableDocuments(selectedProject, user);
for (Entry<SourceDocument, AnnotationDocument> e : docs.entrySet()) {
if (e.getValue() != null) {
SourceDocument sourceDocument = e.getKey();
AnnotationDocument adoc = e.getValue();
if (AnnotationDocumentState.FINISHED.equals(adoc.getState())) {
states.put(sourceDocument, "red");
}
else if (AnnotationDocumentState.IN_PROGRESS.equals(adoc.getState())) {
states.put(sourceDocument, "blue");
}
}
}
allSourceDocuments = new ArrayList<>(docs.keySet());
break;
}
case CURATION: {
allSourceDocuments = curationDocumentService.listCuratableSourceDocuments(selectedProject);
for (SourceDocument sourceDocument : allSourceDocuments) {
if (SourceDocumentState.CURATION_FINISHED.equals(sourceDocument.getState())) {
states.put(sourceDocument, "red");
}
else if (SourceDocumentState.CURATION_IN_PROGRESS.equals(sourceDocument.getState())) {
states.put(sourceDocument, "blue");
}
}
break;
}
default:
break;
}
return allSourceDocuments;
}
private class ButtonsForm
extends Form<Void>
{
private static final long serialVersionUID = -1879323194964417564L;
public ButtonsForm(String id, final ModalWindow modalWindow)
{
super(id);
add(new AjaxSubmitLink("openButton")
{
private static final long serialVersionUID = -755759008587787147L;
@Override
protected void onSubmit(AjaxRequestTarget aTarget, Form<?> aForm)
{
if (selectedProject == null) {
aTarget.appendJavaScript("alert('No project is selected!')"); // If there is
// no project
// at all
}
else if (selectedDocument == null) {
if (documentService.existsFinishedAnnotation(selectedProject)) {
aTarget.appendJavaScript("alert('Please select a document for project: "
+ selectedProject.getName() + "')");
}
else {
aTarget.appendJavaScript("alert('There is no document that is ready for curation yet for project: "
+ selectedProject.getName() + "')");
}
}
else {
// do not use this default layer in that other project
if(bModel.getProject()!=null){
if(!bModel.getProject().equals(selectedProject)){
bModel.setDefaultAnnotationLayer(null);
}
}
bModel.setProject(selectedProject);
bModel.setDocument(selectedDocument,
documentSelectionForm.lv.getModelObject());
modalWindow.close(aTarget);
}
}
@Override
protected void onError(AjaxRequestTarget aTarget, Form<?> aForm)
{
}
});
add(new AjaxLink<Void>("cancelButton")
{
private static final long serialVersionUID = 7202600912406469768L;
@Override
public void onClick(AjaxRequestTarget aTarget)
{
projectSelectionForm.detach();
documentSelectionForm.detach();
if (mode.equals(Mode.CURATION)) {
bModel.setDocument(null, null); // on cancel, go welcomePage
}
onCancel(aTarget);
modalWindow.close(aTarget);
}
});
}
}
protected void onCancel(AjaxRequestTarget aTarget)
{
}
}