ref #9596 rename TypeDesignationSet -> TypeDesignationGroup in vaadin
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / vaadin / view / name / SpecimenTypeDesignationSetPopupEditor.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.name;
10
11 import java.util.Collection;
12 import java.util.EnumSet;
13
14 import org.springframework.context.annotation.Scope;
15 import org.springframework.security.core.GrantedAuthority;
16 import org.vaadin.viritin.fields.ElementCollectionField;
17
18 import com.vaadin.data.Validator.InvalidValueException;
19 import com.vaadin.data.validator.DoubleRangeValidator;
20 import com.vaadin.server.ErrorMessage;
21 import com.vaadin.shared.ui.MarginInfo;
22 import com.vaadin.spring.annotation.SpringComponent;
23 import com.vaadin.ui.AbstractSelect.ItemCaptionMode;
24 import com.vaadin.ui.Component;
25 import com.vaadin.ui.GridLayout;
26 import com.vaadin.ui.NativeSelect;
27 import com.vaadin.ui.Panel;
28 import com.vaadin.ui.TextArea;
29
30 import eu.etaxonomy.cdm.api.util.RoleProberImpl;
31 import eu.etaxonomy.cdm.model.common.AnnotationType;
32 import eu.etaxonomy.cdm.model.permission.CRUD;
33 import eu.etaxonomy.cdm.service.UserHelperAccess;
34 import eu.etaxonomy.cdm.vaadin.component.CollectionRowRepresentative;
35 import eu.etaxonomy.cdm.vaadin.component.common.FilterableAnnotationsField;
36 import eu.etaxonomy.cdm.vaadin.component.common.GeoLocationField;
37 import eu.etaxonomy.cdm.vaadin.component.common.MinMaxTextField;
38 import eu.etaxonomy.cdm.vaadin.component.common.TeamOrPersonField;
39 import eu.etaxonomy.cdm.vaadin.component.common.TimePeriodField;
40 import eu.etaxonomy.cdm.vaadin.model.registration.SpecimenTypeDesignationDTO;
41 import eu.etaxonomy.cdm.vaadin.model.registration.SpecimenTypeDesignationSetDTO;
42 import eu.etaxonomy.cdm.vaadin.permission.AccessRestrictedView;
43 import eu.etaxonomy.cdm.vaadin.permission.RolesAndPermissions;
44 import eu.etaxonomy.cdm.vaadin.ui.RegistrationUIDefaults;
45 import eu.etaxonomy.cdm.vaadin.util.TeamOrPersonBaseCaptionGenerator;
46 import eu.etaxonomy.cdm.vaadin.util.converter.DoubleConverter;
47 import eu.etaxonomy.cdm.vaadin.util.converter.IntegerConverter;
48 import eu.etaxonomy.cdm.vaadin.view.PerEntityAuthorityGrantingEditor;
49 import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
50
51 /**
52 * @author a.kohlbecker
53 * @since May 15, 2017
54 *
55 * TODO as subclass of AbstractCdmPopupEditor?
56 */
57 @SpringComponent
58 @Scope("prototype")
59 public class SpecimenTypeDesignationSetPopupEditor
60 extends AbstractPopupEditor<SpecimenTypeDesignationSetDTO, SpecimenTypeDesignationSetEditorPresenter, SpecimenTypeDesignationSetPopupEditorView>
61 implements SpecimenTypeDesignationSetPopupEditorView, AccessRestrictedView, PerEntityAuthorityGrantingEditor {
62
63 private static final String CAN_T_SAVE_AS_LONG_AS_TYPE_DESIGNATIONS_ARE_MISSING = "Can't save as long as type designations are missing.";
64
65 public SpecimenTypeDesignationSetPopupEditor() {
66 super(new GridLayout(), SpecimenTypeDesignationSetDTO.class);
67 GridLayout grid = (GridLayout) getFieldLayout();
68 grid.setMargin(true);
69 grid.setSpacing(true);
70 }
71
72 private static final long serialVersionUID = 5418275817834009509L;
73
74 private NativeSelect countrySelectField;
75
76 private ElementCollectionField<SpecimenTypeDesignationDTO> typeDesignationsCollectionField;
77
78 private TeamOrPersonField collectorField;
79
80 private FilterableAnnotationsField annotationsListField;
81
82 private AnnotationType[] editableAnotationTypes = RegistrationUIDefaults.EDITABLE_ANOTATION_TYPES;
83
84 private GeoLocationField exactLocationField;
85
86 private Panel typeDesignationsScrollPanel;
87
88 private String accessDeniedMessage;
89
90
91 @Override
92 public NativeSelect getCountrySelectField() {
93 return countrySelectField;
94 }
95
96 @Override
97 protected void initContent() {
98
99 GridLayout grid = (GridLayout)getFieldLayout();
100 grid.setSpacing(true);
101 grid.setMargin(true);
102 grid.setColumns(3);
103 grid.setRows(10);
104 int endColumnIndex = 2;
105
106 //TODO typifyingAuthors
107
108 // FieldUnit + GatheringEvent
109
110 int row = 0;
111 countrySelectField = new NativeSelect("Country");
112 addField(countrySelectField, "country", 1, row , endColumnIndex, row);
113 countrySelectField.setWidth("100%");
114 countrySelectField.setItemCaptionMode(ItemCaptionMode.PROPERTY);
115 countrySelectField.setItemCaptionPropertyId("label");
116
117 row++;
118 TextArea localityField = new TextArea("Locality");
119 localityField.setNullRepresentation("");
120 addField(localityField, "locality", 0, row , endColumnIndex, row);
121 localityField.setWidth("100%");
122 // NOTE: setRows and SetCold breaks he width setting,
123 // see https://github.com/vaadin/framework/issues/3617
124
125 row++;
126 exactLocationField = new GeoLocationField("Geo location");
127 addField(exactLocationField, "exactLocation", 0, row, endColumnIndex, row);
128 exactLocationField.setWidth("100%");
129
130 row++;
131 MinMaxTextField absElevationMinMax = new MinMaxTextField("Altitude", "m");
132 absElevationMinMax.setWidth("100%");
133 absElevationMinMax.addSubComponentsStyleName(getDefaultComponentStyles());
134 grid.addComponent(absElevationMinMax, 0, row, endColumnIndex, row);
135
136 bindField(absElevationMinMax.getMinField(), "absoluteElevation");
137 bindField(absElevationMinMax.getMaxField(), "absoluteElevationMax");
138 bindField(absElevationMinMax.getTextField(), "absoluteElevationText");
139
140 absElevationMinMax.getMaxField().setConverter(new IntegerConverter());
141 absElevationMinMax.getMinField().setConverter(new IntegerConverter());
142
143 row++;
144 MinMaxTextField distanceToWaterSurfaceMinMax = new MinMaxTextField("Distance to water surface", "m");
145 distanceToWaterSurfaceMinMax.setWidth("100%");
146 distanceToWaterSurfaceMinMax.addSubComponentsStyleName(getDefaultComponentStyles());
147 grid.addComponent(distanceToWaterSurfaceMinMax, 0, row, endColumnIndex, row);
148
149 bindField(distanceToWaterSurfaceMinMax.getMinField(), "distanceToWaterSurface");
150 bindField(distanceToWaterSurfaceMinMax.getMaxField(), "distanceToWaterSurfaceMax");
151 bindField(distanceToWaterSurfaceMinMax.getTextField(), "distanceToWaterSurfaceText");
152 distanceToWaterSurfaceMinMax.getMaxField().setConverter(new DoubleConverter());
153 distanceToWaterSurfaceMinMax.getMinField().setConverter(new DoubleConverter());
154 distanceToWaterSurfaceMinMax.getMaxField().addValidator(new DoubleRangeValidator("Negative values are not allowed here.", 0.0, Double.MAX_VALUE));
155 distanceToWaterSurfaceMinMax.getMinField().addValidator(new DoubleRangeValidator("Negative values are not allowed here.", 0.0, Double.MAX_VALUE));
156
157 row++;
158 MinMaxTextField distanceToGroundMinMax = new MinMaxTextField("Distance to substrate", "m");
159 distanceToGroundMinMax.setWidth("100%");
160 distanceToGroundMinMax.addSubComponentsStyleName(getDefaultComponentStyles());
161 grid.addComponent(distanceToGroundMinMax, 0, row, endColumnIndex, row);
162
163 bindField(distanceToGroundMinMax.getMinField(), "distanceToGround");
164 bindField(distanceToGroundMinMax.getMaxField(), "distanceToGroundMax");
165 bindField(distanceToGroundMinMax.getTextField(), "distanceToGroundText");
166 distanceToGroundMinMax.getMaxField().setConverter(new DoubleConverter());
167 distanceToGroundMinMax.getMinField().setConverter(new DoubleConverter());
168
169 row++;
170 collectorField = new TeamOrPersonField("Collector", TeamOrPersonBaseCaptionGenerator.CacheType.COLLECTOR_TITLE);
171 addField(collectorField, "collector", 0, row, endColumnIndex, row);
172
173 row++;
174
175 TimePeriodField collectionDateField = new TimePeriodField("Collection date");
176 // collectionDateField.setInputPrompt("dd.mm.yyyy");
177 addField(collectionDateField, "gatheringDate", 0, row, 1, row);
178 addTextField("Field number", "fieldNumber", endColumnIndex, row);
179
180
181 row++;
182
183 // FIXME: can we use the Grid instead?
184 typeDesignationsCollectionField = new ElementCollectionField<SpecimenTypeDesignationDTO>(
185 SpecimenTypeDesignationDTO.class,
186 SpecimenTypeDesignationDTORow.class
187 ){
188
189 @Override
190 public void commit() throws SourceException, InvalidValueException {
191 validate(); // validate always so that empty rows are recognized
192 super.commit();
193 }
194
195 @Override
196 public boolean isEmpty() {
197 Collection value = getValue();
198 return value == null || value.isEmpty() ;
199 }
200
201 @Override
202 public void setComponentError(ErrorMessage componentError) {
203 typeDesignationsScrollPanel.setComponentError(componentError);
204 }
205
206 };
207 typeDesignationsCollectionField.withCaption("Types");
208 typeDesignationsCollectionField.getLayout().setSpacing(false);
209 typeDesignationsCollectionField.getLayout().setColumns(3);
210 typeDesignationsCollectionField.setRequired(true); // only works with the above overwritten commit()
211 typeDesignationsCollectionField.setRequiredError(CAN_T_SAVE_AS_LONG_AS_TYPE_DESIGNATIONS_ARE_MISSING);
212 typeDesignationsCollectionField.setVisibleProperties(SpecimenTypeDesignationDTORow.visibleFields());
213
214 typeDesignationsCollectionField.setPropertyHeader("accessionNumber", "Access. num.");
215 typeDesignationsCollectionField.setPropertyHeader("preferredStableUri", "Stable URI");
216 typeDesignationsCollectionField.setPropertyHeader("mediaSpecimenReference", "Image reference");
217 typeDesignationsCollectionField.setPropertyHeader("mediaSpecimenReferenceDetail", "Reference detail");
218 typeDesignationsCollectionField.addElementAddedListener( e -> typeDesignationsCollectionField.setComponentError(null));
219 typeDesignationsCollectionField.getLayout().setMargin(new MarginInfo(false, true));
220
221 // typeDesignationsCollectionField.getLayout().setMargin(false);
222 // typeDesignationsCollectionField.addStyleName("composite-field-wrapper");
223 // addField(typeDesignationsCollectionField, "specimenTypeDesignationDTOs", 0, row, 2, row);
224
225 typeDesignationsScrollPanel = new Panel(typeDesignationsCollectionField.getLayout());
226 typeDesignationsScrollPanel.setCaption("Types");
227 typeDesignationsScrollPanel.setWidth(800, Unit.PIXELS);
228
229 bindField(typeDesignationsCollectionField, "specimenTypeDesignationDTOs");
230 addComponent(typeDesignationsScrollPanel, 0, row, endColumnIndex, row);
231
232 row++;
233 annotationsListField = new FilterableAnnotationsField("Editorial notes");
234 annotationsListField.setWidth(100, Unit.PERCENTAGE);
235 boolean isCurator = UserHelperAccess.userHelper().userIs(new RoleProberImpl(RolesAndPermissions.ROLE_CURATION));
236 boolean isAdmin = UserHelperAccess.userHelper().userIsAdmin();
237 if(isCurator || isAdmin){
238 annotationsListField.withNewButton(true);
239 } else {
240 annotationsListField.setAnnotationTypesVisible(editableAnotationTypes);
241 }
242 addField(annotationsListField, "annotations", 0, row, endColumnIndex, row);
243
244 }
245
246 @Override
247 public String getWindowCaption() {
248 return "Specimen typedesignations editor";
249 }
250
251 @Override
252 public void focusFirst() {
253 // none
254 }
255
256 @Override
257 protected String getDefaultComponentStyles() {
258 return "tiny";
259 }
260
261 @Override
262 public boolean allowAnonymousAccess() {
263 return false;
264 }
265
266 @Override
267 public Collection<Collection<GrantedAuthority>> allowedGrantedAuthorities() {
268 return null;
269 }
270
271 @Override
272 public String getAccessDeniedMessage() {
273 return accessDeniedMessage;
274 }
275
276 @Override
277 public void setAccessDeniedMessage(String accessDeniedMessage) {
278 this.accessDeniedMessage = accessDeniedMessage;
279 }
280
281 @Override
282 public boolean isResizable() {
283 return true;
284 }
285
286
287 // ------- SpecimenTypeDesignationSetPopupEditorView methods ---- //
288 @Override
289 public ElementCollectionField<SpecimenTypeDesignationDTO> getTypeDesignationsCollectionField() {
290 return typeDesignationsCollectionField;
291 }
292
293 @Override
294 public void applyDefaultComponentStyle(Component ... components){
295 for(int i = 0; i <components.length; i++){
296 components[i].setStyleName(getDefaultComponentStyles());
297 }
298 }
299
300 @Override
301 public void grantToCurrentUser(EnumSet<CRUD> crud) {
302 getPresenter().setGrantsForCurrentUser(crud);
303
304 }
305
306 @Override
307 protected void afterItemDataSourceSet() {
308 super.afterItemDataSourceSet();
309 GridLayout gridLayout = this.typeDesignationsCollectionField.getLayout();
310 for(int rowIndex = 1; rowIndex < gridLayout.getRows(); rowIndex++){ // first row is header
311 Component item = gridLayout.getComponent(SpecimenTypeDesignationDTORow.rowListSelectColumn(), rowIndex);
312 ((CollectionRowRepresentative)item).updateRowItemsEnabledStates();
313 }
314 updateAllowDeleteTypeDesignation();
315 }
316
317 @Override
318 public void updateAllowDeleteTypeDesignation(){
319 // disable the delete button if there is only one typeDesignation
320 // if this typeDesignation is deleted the fieldUnit would become orphan in the
321 // TypeDesignationGroup
322 GridLayout gridLayout = this.typeDesignationsCollectionField.getLayout();
323 if(gridLayout.getRows() == 3){ // first row is header, last row is next new item
324 gridLayout.getComponent(gridLayout.getColumns() - 1, 1).setEnabled(false);
325 }
326 }
327
328 @Override
329 public void setReadOnly(boolean readOnly) {
330 super.setReadOnly(readOnly);
331 getFieldLayout().iterator().forEachRemaining(c -> c.setReadOnly(readOnly));
332 collectorField.setEditorReadOnly(readOnly);
333 typeDesignationsCollectionField.getLayout().iterator().forEachRemaining(c -> c.setReadOnly(readOnly));
334 }
335
336 @Override
337 public TeamOrPersonField getCollectorField() {
338 return collectorField;
339 }
340
341 /**
342 * By default AnnotationType.EDITORIAL() is enabled.
343 */
344 @Override
345 public AnnotationType[] getEditableAnotationTypes() {
346 return editableAnotationTypes;
347 }
348
349 /**
350 * By default AnnotationType.EDITORIAL() is enabled.
351 *
352 * @param editableAnotationTypes the editableAnotationTypes to set
353 */
354 @Override
355 public void setEditableAnotationTypes(AnnotationType ... editableAnotationTypes) {
356 this.editableAnotationTypes = editableAnotationTypes;
357 }
358
359
360 @Override
361 public FilterableAnnotationsField getAnnotationsField() {
362 return annotationsListField;
363 }
364
365 @Override
366 public GeoLocationField getExactLocationField() {
367 return exactLocationField;
368 }
369 }