/* * 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.correction; import static de.tudarmstadt.ukp.clarin.webanno.api.annotation.util.WebAnnoCasUtil.selectByAddr; import static org.apache.uima.fit.util.JCasUtil.select; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.uima.UIMAException; import org.apache.uima.jcas.JCas; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.OnLoadHeaderItem; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.NumberTextField; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; import org.apache.wicket.spring.injection.annot.SpringBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.context.SecurityContextHolder; import org.wicketstuff.annotation.mount.MountPath; import de.tudarmstadt.ukp.clarin.webanno.api.AnnotationSchemaService; import de.tudarmstadt.ukp.clarin.webanno.api.CorrectionDocumentService; import de.tudarmstadt.ukp.clarin.webanno.api.DocumentService; import de.tudarmstadt.ukp.clarin.webanno.api.ProjectService; import de.tudarmstadt.ukp.clarin.webanno.api.ProjectType; import de.tudarmstadt.ukp.clarin.webanno.api.SecurityUtil; import de.tudarmstadt.ukp.clarin.webanno.api.SettingsService; import de.tudarmstadt.ukp.clarin.webanno.api.WebAnnoConst; import de.tudarmstadt.ukp.clarin.webanno.api.annotation.AnnotationEditorBase; import de.tudarmstadt.ukp.clarin.webanno.api.annotation.exception.AnnotationException; import de.tudarmstadt.ukp.clarin.webanno.api.annotation.model.AnnotatorState; import de.tudarmstadt.ukp.clarin.webanno.api.annotation.model.AnnotatorStateImpl; import de.tudarmstadt.ukp.clarin.webanno.api.annotation.util.WebAnnoCasUtil; import de.tudarmstadt.ukp.clarin.webanno.brat.annotation.BratAnnotationEditor; import de.tudarmstadt.ukp.clarin.webanno.brat.util.BratAnnotatorUtility; import de.tudarmstadt.ukp.clarin.webanno.constraints.ConstraintsService; import de.tudarmstadt.ukp.clarin.webanno.curation.storage.CurationDocumentService; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationDocument; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationDocumentStateTransition; 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.model.SourceDocumentStateTransition; import de.tudarmstadt.ukp.clarin.webanno.security.UserDao; import de.tudarmstadt.ukp.clarin.webanno.security.model.User; import de.tudarmstadt.ukp.clarin.webanno.support.dialog.ConfirmationDialog; import de.tudarmstadt.ukp.clarin.webanno.support.lambda.LambdaAjaxLink; import de.tudarmstadt.ukp.clarin.webanno.support.lambda.LambdaAjaxSubmitLink; import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.AnnotationPageBase; import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.PreferencesUtil; import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.component.AnnotationPreferencesModalPanel; import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.component.DocumentNamePanel; import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.component.ExportModalPanel; import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.component.FinishImage; import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.component.GuidelineModalPanel; import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.detail.AnnotationDetailEditorPanel; import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.dialog.OpenDocumentDialog; import de.tudarmstadt.ukp.clarin.webanno.ui.core.menu.MenuItem; import de.tudarmstadt.ukp.clarin.webanno.ui.core.menu.MenuItemCondition; import de.tudarmstadt.ukp.clarin.webanno.ui.curation.component.SuggestionViewPanel; import de.tudarmstadt.ukp.clarin.webanno.ui.curation.component.model.AnnotationSelection; import de.tudarmstadt.ukp.clarin.webanno.ui.curation.component.model.CurationContainer; import de.tudarmstadt.ukp.clarin.webanno.ui.curation.component.model.CurationUserSegmentForAnnotationDocument; import de.tudarmstadt.ukp.clarin.webanno.ui.curation.component.model.SourceListView; import de.tudarmstadt.ukp.clarin.webanno.ui.curation.component.model.SuggestionBuilder; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence; import wicket.contrib.input.events.EventType; import wicket.contrib.input.events.InputBehavior; import wicket.contrib.input.events.key.KeyType; /** * This is the main class for the correction page. Displays in the lower panel the Automatically * annotated document and in the upper panel the corrected annotation */ @MenuItem(icon = "images/check_box.png", label = "Correction", prio = 120) @MountPath("/correction.html") @ProjectType(id = WebAnnoConst.PROJECT_TYPE_CORRECTION, prio = 120) public class CorrectionPage extends AnnotationPageBase { private static final Logger LOG = LoggerFactory.getLogger(CorrectionPage.class); private static final long serialVersionUID = 1378872465851908515L; private @SpringBean DocumentService documentService; private @SpringBean CurationDocumentService curationDocumentService; private @SpringBean CorrectionDocumentService correctionDocumentService; private @SpringBean ProjectService projectService; private @SpringBean ConstraintsService constraintsService; private @SpringBean SettingsService settingsService; private @SpringBean AnnotationSchemaService annotationService; private @SpringBean UserDao userRepository; private NumberTextField<Integer> gotoPageTextField; private DocumentNamePanel documentNamePanel; private long currentprojectId; // Open the dialog window on first load private boolean firstLoad = true; private ModalWindow openDocumentsModal; private FinishImage finishDocumentIcon; private ConfirmationDialog finishDocumentDialog; private LambdaAjaxLink finishDocumentLink; private AnnotationEditorBase annotationEditor; private AnnotationDetailEditorPanel detailEditor; private SuggestionViewPanel suggestionView; private CurationContainer curationContainer; private Map<String, Map<Integer, AnnotationSelection>> annotationSelectionByUsernameAndAddress = new HashMap<String, Map<Integer, AnnotationSelection>>(); private SourceListView curationSegment = new SourceListView(); public CorrectionPage() { commonInit(); } private void commonInit() { setVersioned(false); setModel(Model.of(new AnnotatorStateImpl(Mode.CORRECTION))); WebMarkupContainer sidebarCell = new WebMarkupContainer("sidebarCell") { private static final long serialVersionUID = 1L; @Override protected void onComponentTag(ComponentTag aTag) { super.onComponentTag(aTag); AnnotatorState state = CorrectionPage.this.getModelObject(); aTag.put("width", state.getPreferences().getSidebarSize()+"%"); } }; add(sidebarCell); WebMarkupContainer annotationViewCell = new WebMarkupContainer("annotationViewCell") { private static final long serialVersionUID = 1L; @Override protected void onComponentTag(ComponentTag aTag) { super.onComponentTag(aTag); AnnotatorState state = CorrectionPage.this.getModelObject(); aTag.put("width", (100-state.getPreferences().getSidebarSize())+"%"); } }; add(annotationViewCell); LinkedList<CurationUserSegmentForAnnotationDocument> sentences = new LinkedList<CurationUserSegmentForAnnotationDocument>(); CurationUserSegmentForAnnotationDocument curationUserSegmentForAnnotationDocument = new CurationUserSegmentForAnnotationDocument(); if (getModelObject().getDocument() != null) { curationUserSegmentForAnnotationDocument .setAnnotationSelectionByUsernameAndAddress(annotationSelectionByUsernameAndAddress); curationUserSegmentForAnnotationDocument.setBratAnnotatorModel(getModelObject()); sentences.add(curationUserSegmentForAnnotationDocument); } suggestionView = new SuggestionViewPanel("correctionView", new Model<LinkedList<CurationUserSegmentForAnnotationDocument>>(sentences)) { private static final long serialVersionUID = 2583509126979792202L; @Override public void onChange(AjaxRequestTarget aTarget) { AnnotatorState state = CorrectionPage.this.getModelObject(); aTarget.addChildren(getPage(), FeedbackPanel.class); try { // update begin/end of the curation segment based on bratAnnotatorModel changes // (like sentence change in auto-scroll mode,.... curationContainer.setBratAnnotatorModel(state); JCas editorCas = getEditorCas(); setCurationSegmentBeginEnd(editorCas); suggestionView.updatePanel(aTarget, curationContainer, annotationEditor, annotationSelectionByUsernameAndAddress, curationSegment); annotationEditor.render(aTarget, editorCas); aTarget.add(getOrCreatePositionInfoLabel()); update(aTarget); } catch (UIMAException e) { LOG.error("Error: " + e.getMessage(), e); error(ExceptionUtils.getRootCause(e)); } catch (Exception e) { LOG.error("Error: " + e.getMessage(), e); error(e.getMessage()); } } }; suggestionView.setOutputMarkupId(true); annotationViewCell.add(suggestionView); sidebarCell.add(detailEditor = createDetailEditor()); annotationEditor = new BratAnnotationEditor("mergeView", getModel(), detailEditor, () -> { return getEditorCas(); }); annotationViewCell.add(annotationEditor); curationContainer = new CurationContainer(); curationContainer.setBratAnnotatorModel(getModelObject()); add(documentNamePanel = createDocumentInfoLabel()); add(getOrCreatePositionInfoLabel()); add(openDocumentsModal = new OpenDocumentDialog("openDocumentsModal", getModel(), getAllowedProjects()) { private static final long serialVersionUID = 5474030848589262638L; @Override public void onDocumentSelected(AjaxRequestTarget aTarget) { // Reload the page using AJAX. This does not add the project/document ID to the URL, // but being AJAX it flickers less. actionLoadDocument(aTarget); // aCallbackTarget.addChildren(getPage(), FeedbackPanel.class); // try { // actionLoadDocument(aCallbackTarget); // // String username = SecurityContextHolder.getContext().getAuthentication() // .getName(); // User user = userRepository.get(username); // detailEditor // .setEnabled(!FinishImage.isFinished(getModel(), user, documentService)); // detailEditor.loadFeatureEditorModels(aCallbackTarget); // } // catch (Exception e) { // LOG.error("Unable to load data", e); // error("Unable to load data: " + ExceptionUtils.getRootCauseMessage(e)); // } // aCallbackTarget.add(finishDocumentIcon); // aCallbackTarget.appendJavaScript( // "Wicket.Window.unloadConfirmation=false;window.location.reload()"); // aCallbackTarget.add(documentNamePanel); // aCallbackTarget.add(getOrCreatePositionInfoLabel()); } }); add(new AnnotationPreferencesModalPanel("annotationLayersModalPanel", getModel(), detailEditor) { private static final long serialVersionUID = -4657965743173979437L; @Override protected void onChange(AjaxRequestTarget aTarget) { actionCompletePreferencesChange(aTarget); } }); add(new ExportModalPanel("exportModalPanel", getModel()){ private static final long serialVersionUID = -468896211970839443L; { setOutputMarkupId(true); setOutputMarkupPlaceholderTag(true); } @Override protected void onConfigure() { super.onConfigure(); AnnotatorState state = CorrectionPage.this.getModelObject(); setVisible(state.getProject() != null && (SecurityUtil.isAdmin(state.getProject(), projectService, state.getUser()) || !state.getProject().isDisableExport())); } }); Form<Void> gotoPageTextFieldForm = new Form<Void>("gotoPageTextFieldForm"); gotoPageTextField = new NumberTextField<Integer>("gotoPageText", Model.of(1), Integer.class); // FIXME minimum and maximum should be obtained from the annotator state gotoPageTextField.setMinimum(1); gotoPageTextField.setOutputMarkupId(true); gotoPageTextFieldForm.add(gotoPageTextField); gotoPageTextFieldForm.add(new LambdaAjaxSubmitLink("gotoPageLink", gotoPageTextFieldForm, this::actionGotoPage)); add(gotoPageTextFieldForm); add(new LambdaAjaxLink("showOpenDocumentModal", this::actionShowOpenDocumentDialog)); add(new LambdaAjaxLink("showPreviousDocument", t -> actionShowPreviousDocument(t)) .add(new InputBehavior(new KeyType[] { KeyType.Shift, KeyType.Page_up }, EventType.click))); add(new LambdaAjaxLink("showNextDocument", t -> actionShowNextDocument(t)) .add(new InputBehavior(new KeyType[] { KeyType.Shift, KeyType.Page_down }, EventType.click))); add(new LambdaAjaxLink("showNext", t -> actionShowNextPage(t)) .add(new InputBehavior(new KeyType[] { KeyType.Page_down }, EventType.click))); add(new LambdaAjaxLink("showPrevious", t -> actionShowPreviousPage(t)) .add(new InputBehavior(new KeyType[] { KeyType.Page_up }, EventType.click))); add(new LambdaAjaxLink("showFirst", t -> actionShowFirstPage(t)) .add(new InputBehavior(new KeyType[] { KeyType.Home }, EventType.click))); add(new LambdaAjaxLink("showLast", t -> actionShowLastPage(t)) .add(new InputBehavior(new KeyType[] { KeyType.End }, EventType.click))); add(new LambdaAjaxLink("toggleScriptDirection", this::actionToggleScriptDirection)); add(new GuidelineModalPanel("guidelineModalPanel", getModel())); add(createOrGetResetDocumentDialog()); add(createOrGetResetDocumentLink()); add(finishDocumentDialog = new ConfirmationDialog("finishDocumentDialog", new StringResourceModel("FinishDocumentDialog.title", this, null), new StringResourceModel("FinishDocumentDialog.text", this, null))); add(finishDocumentLink = new LambdaAjaxLink("showFinishDocumentDialog", this::actionFinishDocument) { private static final long serialVersionUID = 874573384012299998L; @Override protected void onConfigure() { super.onConfigure(); AnnotatorState state = CorrectionPage.this.getModelObject(); setEnabled(state.getDocument() != null && !documentService .isAnnotationFinished(state.getDocument(), state.getUser())); } }); finishDocumentIcon = new FinishImage("finishImage", getModel()); finishDocumentIcon.setOutputMarkupId(true); finishDocumentLink.add(finishDocumentIcon); } private IModel<List<Pair<Project, String>>> getAllowedProjects() { return new LoadableDetachableModel<List<Pair<Project, String>>>() { private static final long serialVersionUID = -2518743298741342852L; @Override protected List<Pair<Project, String>> load() { User user = userRepository.get( SecurityContextHolder.getContext().getAuthentication().getName()); List<Pair<Project, String>> allowedProject = new ArrayList<>(); for (Project project : projectService.listProjects()) { if (SecurityUtil.isAnnotator(project, projectService, user) && WebAnnoConst.PROJECT_TYPE_CORRECTION.equals(project.getMode())) { allowedProject.add(Pair.of(project, null)); } } return allowedProject; } }; } private DocumentNamePanel createDocumentInfoLabel() { return new DocumentNamePanel("documentNamePanel", getModel()); } private AnnotationDetailEditorPanel createDetailEditor() { return new AnnotationDetailEditorPanel("annotationDetailEditorPanel", getModel()) { private static final long serialVersionUID = 2857345299480098279L; @Override protected void onChange(AjaxRequestTarget aTarget) { aTarget.addChildren(getPage(), FeedbackPanel.class); aTarget.add(getOrCreatePositionInfoLabel()); aTarget.add(suggestionView); try { AnnotatorState state = getModelObject(); JCas editorCas = getEditorCas(); //JCas correctionCas = repository.readCorrectionCas(state.getDocument()); annotationEditor.render(aTarget, editorCas); annotationEditor.setHighlight(aTarget, state.getSelection().getAnnotation()); // info(bratAnnotatorModel.getMessage()); SuggestionBuilder builder = new SuggestionBuilder(documentService, correctionDocumentService, curationDocumentService, annotationService, userRepository); curationContainer = builder.buildCurationContainer(state); setCurationSegmentBeginEnd(editorCas); curationContainer.setBratAnnotatorModel(state); suggestionView.updatePanel(aTarget, curationContainer, annotationEditor, annotationSelectionByUsernameAndAddress, curationSegment); update(aTarget); } catch (Exception e) { handleException(this, aTarget, e); } } @Override protected void onAutoForward(AjaxRequestTarget aTarget) { try { annotationEditor.render(aTarget, getEditorCas()); } catch (Exception e) { LOG.info("Error reading CAS: {} " + e.getMessage(), e); error("Error reading CAS " + e.getMessage()); return; } } }; } @Override protected List<SourceDocument> getListOfDocs() { AnnotatorState state = getModelObject(); return new ArrayList<>(documentService .listAnnotatableDocuments(state.getProject(), state.getUser()).keySet()); } /** * for the first time the page is accessed, open the <b>open document dialog</b> */ @Override public void renderHead(IHeaderResponse response) { super.renderHead(response); if (firstLoad) { response.render(OnLoadHeaderItem .forScript("jQuery('#showOpenDocumentModal').trigger('click');")); firstLoad = false; } } @Override protected JCas getEditorCas() throws IOException { AnnotatorState state = getModelObject(); if (state.getDocument() == null) { throw new IllegalStateException("Please open a document first!"); } SourceDocument aDocument = getModelObject().getDocument(); AnnotationDocument annotationDocument = documentService.getAnnotationDocument(aDocument, state.getUser()); // If there is no CAS yet for the annotation document, create one. return documentService.readAnnotationCas(annotationDocument); } private void setCurationSegmentBeginEnd(JCas aEditorCas) throws UIMAException, ClassNotFoundException, IOException { AnnotatorState state = getModelObject(); curationSegment.setBegin(state.getWindowBeginOffset()); curationSegment.setEnd(state.getWindowEndOffset()); } private void update(AjaxRequestTarget target) throws UIMAException, ClassNotFoundException, IOException, AnnotationException { suggestionView.updatePanel(target, curationContainer, annotationEditor, annotationSelectionByUsernameAndAddress, curationSegment); gotoPageTextField.setModelObject(getModelObject().getFirstVisibleSentenceNumber()); target.add(gotoPageTextField); target.add(suggestionView); target.add(getOrCreatePositionInfoLabel()); } private void actionShowOpenDocumentDialog(AjaxRequestTarget aTarget) { getModelObject().getSelection().clear(); openDocumentsModal.show(aTarget); } private void actionGotoPage(AjaxRequestTarget aTarget, Form<?> aForm) throws Exception { AnnotatorState state = getModelObject(); JCas editorCas = getEditorCas(); List<Sentence> sentences = new ArrayList<>(select(editorCas, Sentence.class)); int selectedSentence = gotoPageTextField.getModelObject(); selectedSentence = Math.min(selectedSentence, sentences.size()); gotoPageTextField.setModelObject(selectedSentence); state.setFirstVisibleSentence(sentences.get(selectedSentence - 1)); state.setFocusSentenceNumber(selectedSentence); SuggestionBuilder builder = new SuggestionBuilder(documentService, correctionDocumentService, curationDocumentService, annotationService, userRepository); curationContainer = builder.buildCurationContainer(state); setCurationSegmentBeginEnd(editorCas); curationContainer.setBratAnnotatorModel(state); update(aTarget); aTarget.add(gotoPageTextField); annotationEditor.render(aTarget, editorCas); } private void actionToggleScriptDirection(AjaxRequestTarget aTarget) throws Exception { getModelObject().toggleScriptDirection(); annotationEditor.renderLater(aTarget); curationContainer.setBratAnnotatorModel(getModelObject()); suggestionView.updatePanel(aTarget, curationContainer, annotationEditor, annotationSelectionByUsernameAndAddress, curationSegment); } private void actionCompletePreferencesChange(AjaxRequestTarget aTarget) { try { AnnotatorState state = getModelObject(); curationContainer.setBratAnnotatorModel(state); JCas editorCas = getEditorCas(); setCurationSegmentBeginEnd(editorCas); // The number of visible sentences may have changed - let the state recalculate // the visible sentences Sentence sentence = selectByAddr(editorCas, Sentence.class, state.getFirstVisibleSentenceAddress()); state.setFirstVisibleSentence(sentence); update(aTarget); aTarget.appendJavaScript( "Wicket.Window.unloadConfirmation = false;window.location.reload()"); // Re-render the whole page because the width of the sidebar may have changed aTarget.add(this); } catch (Exception e) { LOG.info("Error reading CAS " + e.getMessage()); error("Error reading CAS " + e.getMessage()); return; } } /** * Reset the document by removing all annotations form the initial CAS and using the result as * the editor CAS. */ @Override protected void actionResetDocument(AjaxRequestTarget aTarget) throws Exception { AnnotatorState state = getModelObject(); JCas editorCas = documentService.createOrReadInitialCas(state.getDocument()); editorCas = BratAnnotatorUtility.clearJcasAnnotations(editorCas, state.getDocument(), state.getUser(), documentService); documentService.writeAnnotationCas(editorCas, state.getDocument(), state.getUser(), false); actionLoadDocument(aTarget); } private void actionFinishDocument(AjaxRequestTarget aTarget) { finishDocumentDialog.setConfirmAction((aCallbackTarget) -> { ensureRequiredFeatureValuesSet(aCallbackTarget, getEditorCas()); AnnotatorState state = getModelObject(); AnnotationDocument annotationDocument = documentService.getAnnotationDocument( state.getDocument(), state.getUser()); annotationDocument.setState(AnnotationDocumentStateTransition.transition( AnnotationDocumentStateTransition.ANNOTATION_IN_PROGRESS_TO_ANNOTATION_FINISHED)); // manually update state change!! No idea why it is not updated in the DB // without calling createAnnotationDocument(...) documentService.createAnnotationDocument(annotationDocument); aCallbackTarget.add(finishDocumentIcon); aCallbackTarget.add(finishDocumentLink); aCallbackTarget.add(detailEditor); aCallbackTarget.add(createOrGetResetDocumentLink()); }); finishDocumentDialog.show(aTarget); } @Override protected void actionLoadDocument(AjaxRequestTarget aTarget) { LOG.info("BEGIN LOAD_DOCUMENT_ACTION"); AnnotatorState state = getModelObject(); String username = SecurityContextHolder.getContext().getAuthentication().getName(); User user = userRepository.get(username); state.setUser(user); state.setProject(state.getProject()); state.setDocument(state.getDocument(), getListOfDocs()); try { // Check if there is an annotation document entry in the database. If there is none, // create one. AnnotationDocument annotationDocument = documentService .createOrGetAnnotationDocument(state.getDocument(), user); // Read the correction CAS - if it does not exist yet, from the initial CAS JCas correctionCas; if (correctionDocumentService.existsCorrectionCas(state.getDocument())) { correctionCas = correctionDocumentService.readCorrectionCas(state.getDocument()); } else { correctionCas = documentService.createOrReadInitialCas(state.getDocument()); } // Read the annotation CAS or create an annotation CAS from the initial CAS by stripping // annotations JCas editorCas; if (documentService.existsCas(state.getDocument(), user.getUsername())) { editorCas = documentService.readAnnotationCas(annotationDocument); } else { editorCas = documentService.createOrReadInitialCas(state.getDocument()); editorCas = BratAnnotatorUtility.clearJcasAnnotations(editorCas, state.getDocument(), user, documentService); } // Update the CASes documentService.upgradeCas(editorCas.getCas(), annotationDocument); correctionDocumentService.upgradeCorrectionCas(correctionCas.getCas(), state.getDocument()); // After creating an new CAS or upgrading the CAS, we need to save it documentService.writeAnnotationCas(editorCas.getCas().getJCas(), annotationDocument.getDocument(), user, false); correctionDocumentService.writeCorrectionCas(correctionCas, state.getDocument(), user); // (Re)initialize brat model after potential creating / upgrading CAS state.clearAllSelections(); // Load constraints state.setConstraints(constraintsService.loadConstraints(state.getProject())); // Load user preferences PreferencesUtil.loadPreferences(username, settingsService, projectService, annotationService, state, state.getMode()); // Initialize the visible content state.setFirstVisibleSentence(WebAnnoCasUtil.getFirstSentence(editorCas)); // if project is changed, reset some project specific settings if (currentprojectId != state.getProject().getId()) { state.clearRememberedFeatures(); } currentprojectId = state.getProject().getId(); LOG.debug("Configured BratAnnotatorModel for user [" + state.getUser() + "] f:[" + state.getFirstVisibleSentenceNumber() + "] l:[" + state.getLastVisibleSentenceNumber() + "] s:[" + state.getFocusSentenceNumber() + "]"); gotoPageTextField.setModelObject(1); setCurationSegmentBeginEnd(editorCas); update(aTarget); // Re-render the whole page because the font size if (aTarget != null) { aTarget.add(this); } // Update document state if (state.getDocument().getState().equals(SourceDocumentState.NEW)) { state.getDocument().setState(SourceDocumentStateTransition .transition(SourceDocumentStateTransition.NEW_TO_ANNOTATION_IN_PROGRESS)); documentService.createSourceDocument(state.getDocument()); } // Reset the editor detailEditor.reset(aTarget); // Populate the layer dropdown box detailEditor.loadFeatureEditorModels(editorCas, aTarget); } catch (Exception e) { handleException(aTarget, e); } LOG.info("END LOAD_DOCUMENT_ACTION"); } @Override protected void actionRefreshDocument(AjaxRequestTarget aTarget, JCas aEditorCas) { try { AnnotatorState state = getModelObject(); SuggestionBuilder builder = new SuggestionBuilder(documentService, correctionDocumentService, curationDocumentService, annotationService, userRepository); curationContainer = builder.buildCurationContainer(state); setCurationSegmentBeginEnd(aEditorCas); curationContainer.setBratAnnotatorModel(state); update(aTarget); annotationEditor.render(aTarget, aEditorCas); } catch (Exception e) { handleException(aTarget, e); } } /** * Only project admins and annotators can see this page */ @MenuItemCondition public static boolean menuItemCondition(ProjectService aRepo, UserDao aUserRepo) { String username = SecurityContextHolder.getContext().getAuthentication().getName(); User user = aUserRepo.get(username); return SecurityUtil.annotationEnabeled(aRepo, user, WebAnnoConst.PROJECT_TYPE_CORRECTION); } }