cleanup
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / vaadin / component / registration / RegistrationItemNameAndTypeButtons.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.component.registration;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.EnumSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.UUID;
18
19 import org.apache.logging.log4j.LogManager;
20 import org.apache.logging.log4j.Logger;
21
22 import com.vaadin.server.ExternalResource;
23 import com.vaadin.server.FontAwesome;
24 import com.vaadin.shared.ui.label.ContentMode;
25 import com.vaadin.ui.Button;
26 import com.vaadin.ui.Label;
27 import com.vaadin.ui.Link;
28 import com.vaadin.ui.themes.ValoTheme;
29
30 import eu.etaxonomy.cdm.api.service.dto.RegistrationDTO;
31 import eu.etaxonomy.cdm.api.service.name.TypeDesignationDTO;
32 import eu.etaxonomy.cdm.api.service.name.TypeDesignationSet;
33 import eu.etaxonomy.cdm.api.service.name.TypeDesignationSet.TypeDesignationSetType;
34 import eu.etaxonomy.cdm.api.util.UserHelper;
35 import eu.etaxonomy.cdm.model.ICdmEntityUuidCacher;
36 import eu.etaxonomy.cdm.model.common.VersionableEntity;
37 import eu.etaxonomy.cdm.model.name.RegistrationStatus;
38 import eu.etaxonomy.cdm.model.name.TaxonName;
39 import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
40 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
41 import eu.etaxonomy.cdm.model.permission.CRUD;
42 import eu.etaxonomy.cdm.ref.TypedEntityReference;
43 import eu.etaxonomy.cdm.service.UserHelperAccess;
44 import eu.etaxonomy.cdm.strategy.cache.TagEnum;
45 import eu.etaxonomy.cdm.strategy.cache.TaggedCacheHelper;
46 import eu.etaxonomy.cdm.vaadin.component.ButtonFactory;
47 import eu.etaxonomy.cdm.vaadin.model.registration.RegistrationTermLists.RegistrationTypeDesignationStatusComparator;
48 import eu.etaxonomy.cdm.vaadin.permission.PermissionDebugUtils;
49 import eu.etaxonomy.vaadin.component.CompositeStyledComponent;
50
51 /**
52 * @author a.kohlbecker
53 * @since May 19, 2017
54 */
55 public class RegistrationItemNameAndTypeButtons extends CompositeStyledComponent {
56
57 private static final Logger logger = LogManager.getLogger();
58
59 private static final String DEFAULT_BUTTON_STYLES = "";
60
61 private static final long serialVersionUID = -5059163772392864050L;
62
63 public static final String STYLE_NAMES = "edit-button-group " + ValoTheme.LAYOUT_COMPONENT_GROUP;
64
65 private IdButton<TaxonName> nameIdButton = null;
66
67 private List<TypeDesignationSetButton> typeDesignationButtons = new ArrayList<>();
68
69 private List<Label> labels = new ArrayList<>();
70
71 private List<ButtonWithUserEditPermission> editButtons = new ArrayList<>();
72
73 private Button addTypeDesignationButton;
74
75 private Label nameLabel = null;
76
77 private Link identifierLink;
78
79 private boolean isRegistrationLocked;
80
81 private boolean isLockOverride;
82
83 public RegistrationItemNameAndTypeButtons(RegistrationDTO regDto, ICdmEntityUuidCacher entitiyCacher) {
84
85 isRegistrationLocked = EnumSet.of(
86 RegistrationStatus.PUBLISHED, RegistrationStatus.REJECTED)
87 .contains(regDto.getStatus());
88
89 setWidth(100, Unit.PERCENTAGE);
90
91 UserHelper userHelper;
92 if(entitiyCacher != null){
93 userHelper = UserHelperAccess.userHelper().withCache(entitiyCacher);
94 } else {
95 userHelper = UserHelperAccess.userHelper();
96 }
97
98 if(regDto.getNameRef() != null){
99 Button nameButton = new Button("Name:");
100 nameButton.setDescription("Edit the Name");
101 nameIdButton = new IdButton<TaxonName>(TaxonName.class, regDto.getNameRef().getUuid(), nameButton);
102 Label nameLabel = new Label(regDto.getNameRef().getLabel());
103 nameLabel.setWidthUndefined();
104 boolean userHasPermission = userHelper.userHasPermission(regDto.registration().getName(), CRUD.UPDATE);
105 editButtons.add(new ButtonWithUserEditPermission(nameButton, userHasPermission));
106
107 addComponent(nameIdButton.getButton());
108 PermissionDebugUtils.addGainPerEntityPermissionButton(this, TaxonName.class, regDto.getNameRef().getUuid(),
109 EnumSet.of(CRUD.UPDATE, CRUD.DELETE), null);
110 addComponent(nameLabel);
111 } else {
112 // no name in the registration! we only show the typified name as label
113 if(regDto.getTypifiedNameRef() != null){
114 nameLabel = new Label(regDto.getTypifiedNameRef().getLabel());
115 addComponent(nameLabel);
116 }
117 }
118 boolean userHasAddPermission = !regDto.isPersisted() || userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
119 Map<TypedEntityReference<? extends VersionableEntity>,TypeDesignationSet> typeDesignationSets = regDto.getOrderedTypeDesignationSets();
120
121 if(typeDesignationSets != null){
122 // order the typeDesignationSet keys so that holotypes come first, etc
123 List<TypedEntityRefWithStatus> baseRefsByHighestStatus = new ArrayList<>();
124 for(TypedEntityReference<? extends VersionableEntity> baseEntityRef : typeDesignationSets.keySet()) {
125 baseRefsByHighestStatus.add(new TypedEntityRefWithStatus(baseEntityRef, typeDesignationSets.get(baseEntityRef).highestTypeStatus(new RegistrationTypeDesignationStatusComparator())));
126 }
127
128 Collections.sort(baseRefsByHighestStatus);
129
130 for(TypedEntityRefWithStatus typedEntityRefWithStatus : baseRefsByHighestStatus) {
131 TypedEntityReference<? extends VersionableEntity> baseEntity = typedEntityRefWithStatus.typedEntity;
132 TypeDesignationSet typeDesignationSet = typeDesignationSets.get(baseEntity);
133 if (logger.isDebugEnabled()) {logger.debug("WorkingSet:" + typeDesignationSet.getWorkingsetType() + ">" + typeDesignationSet.getBaseEntity().toString());}
134 String buttonLabel = SpecimenOrObservationBase.class.isAssignableFrom(baseEntity.getType()) ? "Type": "NameType";
135 Button tdButton = new Button(buttonLabel + ":");
136 tdButton.setDescription("Edit the type designation working set");
137 boolean userHasUpdatePermission = userHelper.userHasPermission(baseEntity.getType(), baseEntity.getUuid(), CRUD.UPDATE, CRUD.DELETE);
138 editButtons.add(new ButtonWithUserEditPermission(tdButton, userHasUpdatePermission));
139 addComponent(tdButton);
140
141 PermissionDebugUtils.addGainPerEntityPermissionButton(this, SpecimenOrObservationBase.class,
142 baseEntity.getUuid(), EnumSet.of(CRUD.UPDATE, CRUD.DELETE), RegistrationStatus.PREPARATION.name());
143
144 typeDesignationButtons.add(new TypeDesignationSetButton(
145 typeDesignationSet.getWorkingsetType(),
146 typeDesignationSet.getBaseEntity(),
147 tdButton)
148 );
149
150 String labelText = "<span class=\"field-unit-label\">" + baseEntity.getLabel() + "</span>"; // renders the FieldUnit label
151 for(TypeDesignationStatusBase<?> typeStatus : typeDesignationSet.keySet()){
152 Collection<TypeDesignationDTO> tdPerStatus = typeDesignationSet.get(typeStatus);
153 labelText += " <strong>" + typeStatus.getLabel() + (tdPerStatus.size() > 1 ? "s":"" ) + "</strong>: ";
154 boolean isFirst = true;
155 for(TypeDesignationDTO<?> dtDTO : tdPerStatus) {
156 labelText += ( isFirst ? "" : ", ") + TaggedCacheHelper.createString(
157 TaggedCacheHelper.cropAt(dtDTO.getTaggedText(), TagEnum.separator, "designated\\s+[bB]y"));
158 isFirst = false;
159 }
160 }
161
162 Label label = new Label(labelText, ContentMode.HTML);
163 label.setWidthUndefined();
164 addComponent(label);
165 labels.add(label);
166 }
167 }
168 addTypeDesignationButton = ButtonFactory.ADD_ITEM.createButton();
169 addTypeDesignationButton.setDescription("Add a new type designation workingset.");
170 addTypeDesignationButton.setVisible(!isRegistrationLocked && userHasAddPermission);
171 addComponent(addTypeDesignationButton);
172
173 //TODO make responsive and use specificIdentifier in case the space gets too narrow
174 if(regDto.isPersisted()){
175 identifierLink = new Link(regDto.getIdentifier(), new ExternalResource(regDto.getIdentifier()));
176 identifierLink.setEnabled(regDto.getStatus() == RegistrationStatus.PUBLISHED);
177 addComponents(identifierLink);
178 }
179
180 iterator().forEachRemaining(c -> addStyledComponent(c));
181 updateEditorButtonReadonlyStates();
182 addDefaultStyles();
183 }
184
185 private void updateEditorButtonReadonlyStates() {
186 for(ButtonWithUserEditPermission b : editButtons){
187 boolean impossibleToUnlock = !b.userCanEdit && isLockOverride && isRegistrationLocked;
188 b.button.setReadOnly((isRegistrationLocked && !isLockOverride) || !b.userCanEdit);
189 b.button.setEnabled(!impossibleToUnlock);
190 b.button.setDescription(impossibleToUnlock ? "Unlock failed due to missing permissions!" : "");
191 b.button.setIcon(isLockOverride ? FontAwesome.UNLOCK_ALT : null);
192 }
193 }
194
195 public IdButton<TaxonName> getNameButton() {
196 return nameIdButton;
197 }
198
199 public List<TypeDesignationSetButton> getTypeDesignationButtons() {
200 return typeDesignationButtons;
201 }
202
203 public Button getAddTypeDesignationButton() {
204 return addTypeDesignationButton;
205 }
206
207 @Override
208 protected void addDefaultStyles() {
209 addStyleName(STYLE_NAMES);
210 if(nameIdButton != null){
211 nameIdButton.getButton().addStyleName(DEFAULT_BUTTON_STYLES);
212 }
213 if(nameLabel != null){
214 nameLabel.addStyleName("v-disabled");
215 }
216 typeDesignationButtons.forEach(idb -> idb.getButton().addStyleName(DEFAULT_BUTTON_STYLES));
217 addTypeDesignationButton.addStyleName(DEFAULT_BUTTON_STYLES);
218 }
219
220 public class TypeDesignationSetButton {
221
222 private VersionableEntity baseEntity;
223 private TypeDesignationSetType type;
224 private Button button;
225
226 public TypeDesignationSetButton(TypeDesignationSetType type, VersionableEntity baseEntity, Button button){
227 this.type = type;
228 this.baseEntity = baseEntity;
229 this.button = button;
230 }
231
232 public VersionableEntity getBaseEntity() {
233 return baseEntity;
234 }
235
236 public Button getButton() {
237 return button;
238 }
239
240 public TypeDesignationSetType getType() {
241 return type;
242 }
243 }
244
245 public class IdButton<T> {
246 private UUID uuid;
247 private Class<T> entityType;
248 private Button button;
249
250 public IdButton(Class<T> type, UUID uuid, Button button){
251 this.entityType = type;
252 this.uuid = uuid;
253 this.button = button;
254 }
255
256 public UUID getUuid() {
257 return uuid;
258 }
259
260 public Button getButton() {
261 return button;
262 }
263
264 public Class<T> getType() {
265 return entityType;
266 }
267 }
268
269 public class ButtonWithUserEditPermission {
270
271 Button button;
272 boolean userCanEdit;
273 public ButtonWithUserEditPermission(Button button, boolean userCanEdit) {
274 super();
275 this.button = button;
276 this.userCanEdit = userCanEdit;
277 }
278 }
279
280 public boolean isRegistrationLocked() {
281 return isRegistrationLocked;
282 }
283
284 public boolean isLockOverride() {
285 return isLockOverride;
286 }
287
288 public void setLockOverride(boolean isLockOverride) {
289 if(this.isLockOverride != isLockOverride){
290 this.isLockOverride = isLockOverride;
291 updateEditorButtonReadonlyStates();
292 }
293 }
294
295 private class TypedEntityRefWithStatus implements Comparable<TypedEntityRefWithStatus> {
296
297 public TypedEntityReference<? extends VersionableEntity> typedEntity;
298 public TypeDesignationStatusBase<?> status;
299 private RegistrationTypeDesignationStatusComparator comparator = new RegistrationTypeDesignationStatusComparator();
300
301 public TypedEntityRefWithStatus(TypedEntityReference<? extends VersionableEntity> typedEntity,
302 TypeDesignationStatusBase<?> status) {
303 this.typedEntity = typedEntity;
304 this.status = status;
305 }
306
307 @Override
308 public int compareTo(TypedEntityRefWithStatus o) {
309 return comparator.compare(this.status, o.status);
310 }
311 }
312 }