rename TaggedCacheHelper to TaggedTextFormatter in vaadin
[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.RegistrationWrapperDTO;
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.TaggedTextFormatter;
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 private 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 private boolean userHasAddPermission;
84
85 public RegistrationItemNameAndTypeButtons(RegistrationWrapperDTO regDto, ICdmEntityUuidCacher entitiyCacher) {
86
87 isRegistrationLocked = EnumSet.of(
88 RegistrationStatus.PUBLISHED, RegistrationStatus.REJECTED)
89 .contains(regDto.getStatus());
90
91 setWidth(100, Unit.PERCENTAGE);
92
93 UserHelper userHelper;
94 if(entitiyCacher != null){
95 userHelper = UserHelperAccess.userHelper().withCache(entitiyCacher);
96 } else {
97 userHelper = UserHelperAccess.userHelper();
98 }
99
100 if(regDto.getNameRef() != null){
101 Button nameButton = new Button("Name:");
102 nameButton.setDescription("Edit the Name");
103 nameIdButton = new IdButton<TaxonName>(TaxonName.class, regDto.getNameRef().getUuid(), nameButton);
104 Label nameLabel = new Label(regDto.getNameRef().getLabel());
105 nameLabel.setWidthUndefined();
106 boolean userHasPermission = userHelper.userHasPermission(regDto.registration().getName(), CRUD.UPDATE);
107 editButtons.add(new ButtonWithUserEditPermission(nameButton, userHasPermission));
108
109 addComponent(nameIdButton.getButton());
110 PermissionDebugUtils.addGainPerEntityPermissionButton(this, TaxonName.class, regDto.getNameRef().getUuid(),
111 EnumSet.of(CRUD.UPDATE, CRUD.DELETE), null);
112 addComponent(nameLabel);
113 } else {
114 // no name in the registration! we only show the typified name as label
115 if(regDto.getTypifiedNameRef() != null){
116 nameLabel = new Label(regDto.getTypifiedNameRef().getLabel());
117 addComponent(nameLabel);
118 }
119 }
120
121 userHasAddPermission = !regDto.isPersisted() || userHelper.userHasPermission(regDto.registration(), CRUD.UPDATE);
122 Map<TypedEntityReference<? extends VersionableEntity>,TypeDesignationSet> typeDesignationSets = regDto.getOrderedTypeDesignationSets();
123
124 if(typeDesignationSets != null){
125 // order the typeDesignationSet keys so that holotypes come first, etc
126 List<TypedEntityRefWithStatus> baseRefsByHighestStatus = new ArrayList<>();
127 for(TypedEntityReference<? extends VersionableEntity> baseEntityRef : typeDesignationSets.keySet()) {
128 baseRefsByHighestStatus.add(new TypedEntityRefWithStatus(baseEntityRef, typeDesignationSets.get(baseEntityRef).highestTypeStatus(new RegistrationTypeDesignationStatusComparator())));
129 }
130
131 Collections.sort(baseRefsByHighestStatus);
132
133 for(TypedEntityRefWithStatus typedEntityRefWithStatus : baseRefsByHighestStatus) {
134 TypedEntityReference<? extends VersionableEntity> baseEntity = typedEntityRefWithStatus.typedEntity;
135 TypeDesignationSet typeDesignationSet = typeDesignationSets.get(baseEntity);
136 if (logger.isDebugEnabled()) {logger.debug("WorkingSet:" + typeDesignationSet.getWorkingsetType() + ">" + typeDesignationSet.getBaseEntity().toString());}
137 String buttonLabel = SpecimenOrObservationBase.class.isAssignableFrom(baseEntity.getType()) ? "Type": "NameType";
138 Button tdButton = new Button(buttonLabel + ":");
139 tdButton.setDescription("Edit the type designation working set");
140 boolean userHasUpdatePermission = userHelper.userHasPermission(baseEntity.getType(), baseEntity.getUuid(), CRUD.UPDATE, CRUD.DELETE);
141 editButtons.add(new ButtonWithUserEditPermission(tdButton, userHasUpdatePermission));
142 addComponent(tdButton);
143
144 PermissionDebugUtils.addGainPerEntityPermissionButton(this, SpecimenOrObservationBase.class,
145 baseEntity.getUuid(), EnumSet.of(CRUD.UPDATE, CRUD.DELETE), RegistrationStatus.PREPARATION.name());
146
147 typeDesignationButtons.add(new TypeDesignationSetButton(
148 typeDesignationSet.getWorkingsetType(),
149 typeDesignationSet.getBaseEntity(),
150 tdButton)
151 );
152
153 String labelText = "<span class=\"field-unit-label\">" + baseEntity.getLabel() + "</span>"; // renders the FieldUnit label
154 for(TypeDesignationStatusBase<?> typeStatus : typeDesignationSet.keySet()){
155 Collection<TypeDesignationDTO> tdPerStatus = typeDesignationSet.get(typeStatus);
156 labelText += " <strong>" + typeStatus.getLabel() + (tdPerStatus.size() > 1 ? "s":"" ) + "</strong>: ";
157 boolean isFirst = true;
158 for(TypeDesignationDTO<?> dtDTO : tdPerStatus) {
159 labelText += ( isFirst ? "" : ", ") + TaggedTextFormatter.createString(
160 TaggedTextFormatter.cropAt(dtDTO.getTaggedText(), TagEnum.separator, "designated\\s+[bB]y"));
161 isFirst = false;
162 }
163 }
164
165 Label label = new Label(labelText, ContentMode.HTML);
166 label.setWidthUndefined();
167 addComponent(label);
168 labels.add(label);
169 }
170 }
171 addTypeDesignationButton = ButtonFactory.ADD_ITEM.createButton();
172 addTypeDesignationButton.setDescription("Add a new type designation workingset.");
173 addComponent(addTypeDesignationButton);
174
175 //TODO make responsive and use specificIdentifier in case the space gets too narrow
176 if(regDto.isPersisted()){
177 identifierLink = new Link(regDto.getIdentifier(), new ExternalResource(regDto.getIdentifier()));
178 identifierLink.setEnabled(regDto.getStatus() == RegistrationStatus.PUBLISHED);
179 addComponents(identifierLink);
180 }
181
182 iterator().forEachRemaining(c -> addStyledComponent(c));
183 updateEditorButtonReadonlyStates();
184 addDefaultStyles();
185 }
186
187 private void updateEditorButtonReadonlyStates() {
188 for(ButtonWithUserEditPermission b : editButtons){
189 boolean impossibleToUnlock = !b.userCanEdit && isLockOverride && isRegistrationLocked;
190 b.button.setReadOnly((isRegistrationLocked && !isLockOverride) || !b.userCanEdit);
191 b.button.setEnabled(!impossibleToUnlock);
192 b.button.setDescription(impossibleToUnlock ? "Unlock failed due to missing permissions!" : "");
193 b.button.setIcon(isLockOverride ? FontAwesome.UNLOCK_ALT : null);
194 }
195
196 //by AM to fix #10435
197 boolean addTypeDesignationButtonVisible = (!isRegistrationLocked || isLockOverride)
198 && userHasAddPermission;
199 addTypeDesignationButton.setVisible(addTypeDesignationButtonVisible);
200 }
201
202 public IdButton<TaxonName> getNameButton() {
203 return nameIdButton;
204 }
205
206 public List<TypeDesignationSetButton> getTypeDesignationButtons() {
207 return typeDesignationButtons;
208 }
209
210 public Button getAddTypeDesignationButton() {
211 return addTypeDesignationButton;
212 }
213
214 @Override
215 protected void addDefaultStyles() {
216 addStyleName(STYLE_NAMES);
217 if(nameIdButton != null){
218 nameIdButton.getButton().addStyleName(DEFAULT_BUTTON_STYLES);
219 }
220 if(nameLabel != null){
221 nameLabel.addStyleName("v-disabled");
222 }
223 typeDesignationButtons.forEach(idb -> idb.getButton().addStyleName(DEFAULT_BUTTON_STYLES));
224 addTypeDesignationButton.addStyleName(DEFAULT_BUTTON_STYLES);
225 }
226
227 public class TypeDesignationSetButton {
228
229 private VersionableEntity baseEntity;
230 private TypeDesignationSetType type;
231 private Button button;
232
233 public TypeDesignationSetButton(TypeDesignationSetType type, VersionableEntity baseEntity, Button button){
234 this.type = type;
235 this.baseEntity = baseEntity;
236 this.button = button;
237 }
238
239 public VersionableEntity getBaseEntity() {
240 return baseEntity;
241 }
242
243 public Button getButton() {
244 return button;
245 }
246
247 public TypeDesignationSetType getType() {
248 return type;
249 }
250 }
251
252 public class IdButton<T> {
253 private UUID uuid;
254 private Class<T> entityType;
255 private Button button;
256
257 public IdButton(Class<T> type, UUID uuid, Button button){
258 this.entityType = type;
259 this.uuid = uuid;
260 this.button = button;
261 }
262
263 public UUID getUuid() {
264 return uuid;
265 }
266
267 public Button getButton() {
268 return button;
269 }
270
271 public Class<T> getType() {
272 return entityType;
273 }
274 }
275
276 public class ButtonWithUserEditPermission {
277
278 Button button;
279 boolean userCanEdit;
280 public ButtonWithUserEditPermission(Button button, boolean userCanEdit) {
281 super();
282 this.button = button;
283 this.userCanEdit = userCanEdit;
284 }
285 }
286
287 public boolean isRegistrationLocked() {
288 return isRegistrationLocked;
289 }
290
291 public boolean isLockOverride() {
292 return isLockOverride;
293 }
294
295 public void setLockOverride(boolean isLockOverride) {
296 if(this.isLockOverride != isLockOverride){
297 this.isLockOverride = isLockOverride;
298 updateEditorButtonReadonlyStates();
299 }
300 }
301
302 private class TypedEntityRefWithStatus implements Comparable<TypedEntityRefWithStatus> {
303
304 public TypedEntityReference<? extends VersionableEntity> typedEntity;
305 public TypeDesignationStatusBase<?> status;
306 private RegistrationTypeDesignationStatusComparator comparator = new RegistrationTypeDesignationStatusComparator();
307
308 public TypedEntityRefWithStatus(TypedEntityReference<? extends VersionableEntity> typedEntity,
309 TypeDesignationStatusBase<?> status) {
310 this.typedEntity = typedEntity;
311 this.status = status;
312 }
313
314 @Override
315 public int compareTo(TypedEntityRefWithStatus o) {
316 return comparator.compare(this.status, o.status);
317 }
318 }
319 }