ref #7481 inReference options filtered by applicable type
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / vaadin / view / reference / ReferencePopupEditor.java
1 /**
2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.vaadin.view.reference;
10
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.EnumSet;
14 import java.util.HashMap;
15 import java.util.LinkedHashMap;
16 import java.util.Map;
17 import java.util.Set;
18
19 import org.apache.log4j.Logger;
20 import org.springframework.context.annotation.Scope;
21 import org.springframework.security.core.GrantedAuthority;
22
23 import com.vaadin.spring.annotation.SpringComponent;
24 import com.vaadin.ui.AbstractField;
25 import com.vaadin.ui.Alignment;
26 import com.vaadin.ui.Component;
27 import com.vaadin.ui.Field;
28 import com.vaadin.ui.GridLayout;
29 import com.vaadin.ui.ListSelect;
30 import com.vaadin.ui.TextField;
31
32 import eu.etaxonomy.cdm.api.utility.RoleProber;
33 import eu.etaxonomy.cdm.model.agent.Institution;
34 import eu.etaxonomy.cdm.model.common.AnnotationType;
35 import eu.etaxonomy.cdm.model.reference.Reference;
36 import eu.etaxonomy.cdm.model.reference.ReferencePropertyDefinitions;
37 import eu.etaxonomy.cdm.model.reference.ReferencePropertyDefinitions.UnimplemetedCaseException;
38 import eu.etaxonomy.cdm.model.reference.ReferenceType;
39 import eu.etaxonomy.cdm.service.UserHelperAccess;
40 import eu.etaxonomy.cdm.vaadin.component.TextFieldNFix;
41 import eu.etaxonomy.cdm.vaadin.component.common.FilterableAnnotationsField;
42 import eu.etaxonomy.cdm.vaadin.component.common.TeamOrPersonField;
43 import eu.etaxonomy.cdm.vaadin.component.common.VerbatimTimePeriodField;
44 import eu.etaxonomy.cdm.vaadin.event.InstitutionEditorAction;
45 import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
46 import eu.etaxonomy.cdm.vaadin.permission.AccessRestrictedView;
47 import eu.etaxonomy.cdm.vaadin.permission.RolesAndPermissions;
48 import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
49 import eu.etaxonomy.cdm.vaadin.util.CdmTitleCacheCaptionGenerator;
50 import eu.etaxonomy.cdm.vaadin.util.TeamOrPersonBaseCaptionGenerator;
51 import eu.etaxonomy.cdm.vaadin.util.converter.DoiConverter;
52 import eu.etaxonomy.cdm.vaadin.util.converter.UriConverter;
53 import eu.etaxonomy.vaadin.component.SwitchableTextField;
54 import eu.etaxonomy.vaadin.component.ToOneRelatedEntityCombobox;
55 import eu.etaxonomy.vaadin.event.EditorActionType;
56 import eu.etaxonomy.vaadin.mvp.AbstractCdmPopupEditor;
57 import eu.etaxonomy.vaadin.util.PropertyIdPath;
58
59 /**
60 * @author a.kohlbecker
61 * @since Apr 4, 2017
62 *
63 */
64 @SpringComponent
65 @Scope("prototype")
66 public class ReferencePopupEditor extends AbstractCdmPopupEditor<Reference, ReferenceEditorPresenter> implements ReferencePopupEditorView, AccessRestrictedView {
67
68 private static final long serialVersionUID = -4347633563800758815L;
69
70 private static final Logger logger = Logger.getLogger(ReferencePopupEditor.class);
71
72 private TextField titleField;
73
74 private final static int GRID_COLS = 4; // 12 would fits for 2,3, and 4 Components per row
75
76 private final static int GRID_ROWS = 14;
77
78 private ListSelect typeSelect;
79
80 private ToOneRelatedEntityCombobox<Reference> inReferenceCombobox;
81
82 private TeamOrPersonField authorshipField;
83
84 private ToOneRelatedEntityCombobox<Institution> institutionCombobox;
85 private ToOneRelatedEntityCombobox<Institution> schoolCombobox;
86
87 private FilterableAnnotationsField annotationsListField;
88
89 private AnnotationType[] editableAnotationTypes = RegistrationUIDefaults.EDITABLE_ANOTATION_TYPES;
90
91 private EnumSet<ReferenceType> referenceTypes = EnumSet.allOf(ReferenceType.class);
92
93 private static Map<String,String> propertyNameLabelMap = new HashMap<>();
94
95 private int variableGridStartRow;
96
97 private int variableGridLastRow;
98
99 /**
100 * Used to record the fields from the variable grid part in their original order.
101 */
102 private LinkedHashMap<String, Field<?>> adaptiveFields = new LinkedHashMap<>();
103
104 private VerbatimTimePeriodField datePublishedField;
105
106 static {
107 propertyNameLabelMap.put("inReference", "In reference");
108 propertyNameLabelMap.put("inJournal", "In journal");
109 propertyNameLabelMap.put("inSeries", "In series");
110 propertyNameLabelMap.put("inBook", "In book");
111 }
112
113 /**
114 * @param layout
115 * @param dtoType
116 */
117 public ReferencePopupEditor() {
118 super(new GridLayout(GRID_COLS, GRID_ROWS), Reference.class);
119 }
120
121 @Override
122 protected void initContent() {
123 GridLayout grid = (GridLayout)getFieldLayout();
124 grid.setSpacing(true);
125 grid.setMargin(true);
126
127 /*
128 "type",
129 "uri",
130 "abbrevTitleCache",
131 "protectedAbbrevTitleCache",
132 "nomenclaturallyRelevant",
133 "authorship",
134 "referenceAbstract",
135 "title",
136 "abbrevTitle",
137 "editor",
138 "volume",
139 "pages",
140 "edition",
141 "isbn",
142 "issn",
143 "doi",
144 "seriesPart",
145 "datePublished",
146 "publisher",
147 "placePublished",
148 "institution",
149 "school",
150 "organization",
151 "inReference"
152 */
153 int row = 0;
154 datePublishedField = new VerbatimTimePeriodField("Date published");
155 addField(datePublishedField, "datePublished", 0, row, 1, row);
156 typeSelect = new ListSelect("Reference type");
157 typeSelect.addItems(referenceTypes);
158 typeSelect.setNullSelectionAllowed(false);
159 typeSelect.setRows(1);
160 typeSelect.addValueChangeListener(e -> updateFieldVisibility((ReferenceType)e.getProperty().getValue()));
161 addField(typeSelect, "type", GRID_COLS - 1, row);
162 grid.setComponentAlignment(typeSelect, Alignment.TOP_RIGHT);
163 row++;
164
165 SwitchableTextField titleCacheField = addSwitchableTextField("Reference cache", "titleCache", "protectedTitleCache", 0, row, GRID_COLS-1, row);
166 titleCacheField.setWidth(100, Unit.PERCENTAGE);
167 row++;
168
169 SwitchableTextField abbrevTitleCacheField = addSwitchableTextField("Abbrev. cache", "abbrevTitleCache", "protectedAbbrevTitleCache", 0, row, GRID_COLS-1, row);
170 abbrevTitleCacheField.setWidth(100, Unit.PERCENTAGE);
171 row++;
172
173 titleField = addTextField("Title", "title", 0, row, GRID_COLS-1, row);
174 titleField.setWidth(100, Unit.PERCENTAGE);
175 row++;
176 addTextField("Nomenclatural title", "abbrevTitle", 0, row, GRID_COLS-1, row).setWidth(100, Unit.PERCENTAGE);
177 row++;
178
179 authorshipField = new TeamOrPersonField("Author(s)", TeamOrPersonBaseCaptionGenerator.CacheType.BIBLIOGRAPHIC_TITLE);
180 authorshipField.setWidth(100, Unit.PERCENTAGE);
181 addField(authorshipField, "authorship", 0, row, GRID_COLS -1, row);
182 row++;
183
184 inReferenceCombobox = new ToOneRelatedEntityCombobox<Reference>("In-reference", Reference.class);
185 inReferenceCombobox.setWidth(100, Unit.PERCENTAGE);
186 inReferenceCombobox.addClickListenerAddEntity(e -> getViewEventBus().publish(this,
187 new ReferenceEditorAction(EditorActionType.ADD, e.getButton(), inReferenceCombobox, this)
188 ));
189 inReferenceCombobox.addClickListenerEditEntity(e -> {
190 if(inReferenceCombobox.getValue() != null){
191 getViewEventBus().publish(this,
192 new ReferenceEditorAction(
193 EditorActionType.EDIT,
194 inReferenceCombobox.getValue().getUuid(),
195 e.getButton(),
196 inReferenceCombobox,
197 this)
198 );
199 }
200 });
201 addField(inReferenceCombobox, "inReference", 0, row, GRID_COLS -1, row);
202
203 institutionCombobox = new ToOneRelatedEntityCombobox<Institution>("Institution", Institution.class);
204 institutionCombobox.getSelect().setCaptionGenerator(
205 new CdmTitleCacheCaptionGenerator<Institution>()
206 );
207 institutionCombobox.setWidth(100, Unit.PERCENTAGE);
208 institutionCombobox.addClickListenerAddEntity(e -> getViewEventBus().publish(this,
209 new InstitutionEditorAction(EditorActionType.ADD, e.getButton(), institutionCombobox, this)
210 ));
211 institutionCombobox.addClickListenerEditEntity(e -> {
212 if(institutionCombobox.getValue() != null){
213 getViewEventBus().publish(this,
214 new InstitutionEditorAction(
215 EditorActionType.EDIT,
216 institutionCombobox.getValue().getUuid(),
217 e.getButton(),
218 institutionCombobox,
219 this)
220 );
221 }
222 });
223
224 schoolCombobox = new ToOneRelatedEntityCombobox<Institution>("School", Institution.class);
225 schoolCombobox.getSelect().setCaptionGenerator(
226 new CdmTitleCacheCaptionGenerator<Institution>()
227 );
228 schoolCombobox.addClickListenerAddEntity(e -> getViewEventBus().publish(this,
229 new InstitutionEditorAction(EditorActionType.ADD, e.getButton(), schoolCombobox, this)
230 ));
231 schoolCombobox.addClickListenerEditEntity(e -> {
232 if(schoolCombobox.getValue() != null){
233 getViewEventBus().publish(this,
234 new InstitutionEditorAction(
235 EditorActionType.EDIT,
236 schoolCombobox.getValue().getUuid(),
237 e.getButton(),
238 schoolCombobox,
239 this)
240 );
241 }
242 });
243 row++;
244 addField(institutionCombobox, "institution", 0, row, GRID_COLS -1, row);
245 row++;
246 addField(schoolCombobox, "school", 0, row, GRID_COLS -1, row);
247 row++;
248
249 variableGridStartRow = row;
250
251 addTextField("Organization", "organization", 0, row).setWidth(100, Unit.PERCENTAGE);
252 row++;
253 addTextField("Series", "seriesPart", 0, row).setWidth(100, Unit.PERCENTAGE);
254 addTextField("Volume", "volume", 1, row).setWidth(100, Unit.PERCENTAGE);
255 addTextField("Pages", "pages", 2, row).setWidth(100, Unit.PERCENTAGE);
256 addTextField("Edition", "edition", 3, row).setWidth(100, Unit.PERCENTAGE);
257 row++;
258
259 addTextField("Place published", "placePublished", 0, row, 0, row).setWidth(100, Unit.PERCENTAGE);
260 TextField publisherField = addTextField("Publisher", "publisher", 1, row, 1, row);
261 publisherField.setWidth(100, Unit.PERCENTAGE);
262 addTextField("Editor", "editor", 2, row).setWidth(100, Unit.PERCENTAGE);
263 row++;
264
265 addTextField("ISSN", "issn", 0, row).setWidth(100, Unit.PERCENTAGE);
266 addTextField("ISBN", "isbn", 1, row).setWidth(100, Unit.PERCENTAGE);
267 TextFieldNFix doiField = new TextFieldNFix("DOI");
268 doiField.setConverter(new DoiConverter());
269 doiField.setWidth(100, Unit.PERCENTAGE);
270 addField(doiField, "doi", 2, row);
271 TextFieldNFix uriField = new TextFieldNFix("Uri");
272 uriField.setConverter(new UriConverter());
273 uriField.setWidth(100, Unit.PERCENTAGE);
274 addField(uriField, "uri", 3, row);
275
276
277 variableGridLastRow = row;
278
279 row++;
280 annotationsListField = new FilterableAnnotationsField("Editorial notes");
281 annotationsListField.setWidth(100, Unit.PERCENTAGE);
282 annotationsListField.setAnnotationTypesVisible(editableAnotationTypes);
283 addField(annotationsListField, "annotations", 0, row, GRID_COLS-1, row);
284
285
286 // titleField.setRequired(true);
287 // publisherField.setRequired(true);
288
289 setAdvancedModeEnabled(true);
290 registerAdvancedModeComponents(titleCacheField, abbrevTitleCacheField);
291 registerAdvancedModeComponents(authorshipField.getCachFields());
292 setAdvancedMode(false);
293
294 }
295
296 /**
297 * @param value
298 * @return
299 */
300 private Object updateFieldVisibility(ReferenceType referenceType) {
301
302 GridLayout grid = (GridLayout)getFieldLayout();
303
304 initAdaptiveFields();
305
306 // clear the variable grid part
307 for(int row = variableGridStartRow; row <= variableGridLastRow; row++){
308 for(int x=0; x < grid.getColumns(); x++){
309 grid.removeComponent(x, row);
310 }
311 }
312
313 // set cursor at the beginning of the variable grid part
314 grid.setCursorY(variableGridStartRow);
315 grid.setCursorX(0);
316
317 // place the fields which are required for the given referenceType in the variable grid part while
318 // and retain the original order which is recorded in the adaptiveFields
319 try {
320 Map<String, String> fieldPropertyDefinition = ReferencePropertyDefinitions.fieldPropertyDefinition(referenceType);
321
322 datePublishedField.setVisible(fieldPropertyDefinition.containsKey("datePublished"));
323 authorshipField.setVisible(fieldPropertyDefinition.containsKey("authorship"));
324 String inRefCaption = fieldPropertyDefinition.get("inReference");
325 inReferenceCombobox.setVisible(inRefCaption != null);
326 if(inRefCaption != null){
327 inReferenceCombobox.setCaption(propertyNameLabelMap.get(inRefCaption));
328 }
329 getField("title").setVisible(fieldPropertyDefinition.containsKey("title"));
330
331 EnumSet<ReferenceType> hideNomTitle = EnumSet.of(ReferenceType.Article, ReferenceType.Section, ReferenceType.BookSection, ReferenceType.InProceedings);
332 getField("abbrevTitle").setVisible(!hideNomTitle.contains(referenceType));
333 institutionCombobox.setVisible(fieldPropertyDefinition.containsKey("institution"));
334 schoolCombobox.setVisible(fieldPropertyDefinition.containsKey("school"));
335
336 for(String fieldName : adaptiveFields.keySet()){ // iterate over the LinkedHashMap to retain the original order of the fields
337 if(fieldPropertyDefinition.containsKey(fieldName)){
338 Field<?> field = adaptiveFields.get(fieldName);
339 grid.addComponent(field);
340 String propertyName = fieldPropertyDefinition.get(fieldName);
341 if(propertyName != fieldName){
342 field.setCaption(propertyNameLabelMap.get(propertyName));
343 }
344 }
345 }
346 } catch (UnimplemetedCaseException e) {
347 logger.error(e);
348 // enable all fields
349 setAllFieldsVisible(true);
350 // fix inReference label
351 getField("inReference").setCaption(propertyNameLabelMap.get("inReference"));
352 }
353
354
355
356 return null;
357 }
358
359 /**
360 * @param grid
361 */
362 protected void initAdaptiveFields() {
363 GridLayout grid = (GridLayout)getFieldLayout();
364 // initialize the map of adaptive fields
365 if(adaptiveFields.isEmpty()){
366 try{
367 Map<String, String> fieldPropertyDefinition = ReferencePropertyDefinitions.fieldPropertyDefinition(null);
368 Set<String> fieldNames = fieldPropertyDefinition.keySet();
369 for(int row = variableGridStartRow; row <= variableGridLastRow; row++){
370 for(int x=0; x < grid.getColumns(); x++){
371 Component c = grid.getComponent(x, row);
372 logger.trace("initAdaptiveFields() - y: " + row + " x: " + x + " component:" + (c != null ? c.getClass().getSimpleName(): "NULL"));
373 if(c != null && c instanceof Field){
374 Field<?> field = (Field<?>)c;
375 PropertyIdPath propertyIdPath = boundPropertyIdPath(field);
376 logger.trace("initAdaptiveFields() - " + field.getCaption() + " -> " + propertyIdPath);
377 if(propertyIdPath != null && fieldNames.contains(propertyIdPath.toString())){
378 adaptiveFields.put(propertyIdPath.toString(), field);
379 }
380 }
381 }
382 }
383 } catch (UnimplemetedCaseException e) {
384 throw new RuntimeException(e);
385 }
386 }
387 }
388
389 protected void setAllFieldsVisible(boolean visible){
390 GridLayout grid = (GridLayout)getFieldLayout();
391 for(Component c : grid){
392 if(AbstractField.class.isAssignableFrom(c.getClass())){
393 c.setVisible(visible);
394 }
395 }
396 }
397
398
399 @Override
400 public void setAdvancedMode(boolean isAdvancedMode) {
401 boolean isCurator = UserHelperAccess.userHelper().userIs(new RoleProber(RolesAndPermissions.ROLE_CURATION));
402 boolean isAdmin = UserHelperAccess.userHelper().userIsAdmin();
403
404 boolean canEditAllCaches = isAdmin || isCurator;
405 super.setAdvancedMode(isAdvancedMode);
406 if(!canEditAllCaches){
407 advancedModeComponents.forEach(c -> c.setReadOnly(true));
408 Arrays.asList(authorshipField.getCachFields()).forEach(c -> c.setReadOnly(false));
409 }
410 }
411
412
413 /**
414 * {@inheritDoc}
415 */
416 @Override
417 public String getWindowCaption() {
418 return "Reference editor";
419 }
420
421 /**
422 * {@inheritDoc}
423 */
424 @Override
425 protected String getDefaultComponentStyles() {
426 return "tiny";
427 }
428
429 /**
430 * {@inheritDoc} // TODO Auto-generated method stub
431 */
432 @Override
433 public void focusFirst() {
434 titleField.focus();
435 }
436
437 /**
438 * {@inheritDoc}
439 */
440 @Override
441 public boolean isResizable() {
442 return false;
443 }
444
445 /**
446 * {@inheritDoc}
447 */
448 @Override
449 public boolean allowAnonymousAccess() {
450 return false;
451 }
452
453 /**
454 * {@inheritDoc}
455 */
456 @Override
457 public Collection<Collection<GrantedAuthority>> allowedGrantedAuthorities() {
458 return null;
459 }
460
461 @Override
462 public ListSelect getTypeSelect() {
463 return typeSelect;
464 }
465
466 /**
467 * {@inheritDoc}
468 */
469 @Override
470 public ToOneRelatedEntityCombobox<Reference> getInReferenceCombobox() {
471 return inReferenceCombobox;
472 }
473
474 /**
475 * {@inheritDoc}
476 */
477 @Override
478 public TeamOrPersonField getAuthorshipField() {
479 return authorshipField;
480 }
481
482 @Override
483 public FilterableAnnotationsField getAnnotationsField() {
484 return annotationsListField;
485 }
486
487 public void withReferenceTypes(EnumSet<ReferenceType> types){
488 this.referenceTypes = types;
489 if(typeSelect != null){
490 typeSelect.removeAllItems();
491 typeSelect.addItems(referenceTypes);
492 }
493 }
494
495 @Override
496 public ToOneRelatedEntityCombobox<Institution> getInstitutionCombobox() {
497 return institutionCombobox;
498 }
499
500 @Override
501 public ToOneRelatedEntityCombobox<Institution> getSchoolCombobox() {
502 return schoolCombobox;
503 }
504
505
506 }