jenkins merging release branch into master (strategy: theirs)
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / vaadin / component / common / FilterableAnnotationsField.java
1 /**
2 * Copyright (C) 2018 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.common;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.List;
15 import java.util.Optional;
16
17 import org.apache.logging.log4j.LogManager;
18 import org.apache.logging.log4j.Logger;
19 import org.vaadin.viritin.FilterableListContainer;
20
21 import com.vaadin.data.Container;
22 import com.vaadin.data.Container.Filter;
23 import com.vaadin.data.Item;
24 import com.vaadin.data.Validator.InvalidValueException;
25 import com.vaadin.data.fieldgroup.FieldGroup;
26 import com.vaadin.data.util.BeanItemContainer;
27 import com.vaadin.ui.Button;
28 import com.vaadin.ui.Component;
29 import com.vaadin.ui.CssLayout;
30 import com.vaadin.ui.DefaultFieldFactory;
31 import com.vaadin.ui.Field;
32 import com.vaadin.ui.NativeSelect;
33 import com.vaadin.ui.Table;
34 import com.vaadin.ui.Table.ColumnHeaderMode;
35 import com.vaadin.ui.TextArea;
36
37 import eu.etaxonomy.cdm.model.common.Annotation;
38 import eu.etaxonomy.cdm.model.common.AnnotationType;
39 import eu.etaxonomy.cdm.model.common.Language;
40 import eu.etaxonomy.cdm.model.term.DefinedTermBase;
41 import eu.etaxonomy.cdm.vaadin.component.ButtonFactory;
42 import eu.etaxonomy.cdm.vaadin.util.converter.SetToListConverter;
43 import eu.etaxonomy.cdm.vaadin.util.filter.CdmTermFilter;
44 import eu.etaxonomy.vaadin.component.CompositeCustomField;
45
46 /**
47 * @author a.kohlbecker
48 * @since Jun 20, 2018
49 */
50 public class FilterableAnnotationsField extends CompositeCustomField<List<Annotation>> {
51
52 private static final long serialVersionUID = -8258550787601028813L;
53 protected static final Logger logger = LogManager.getLogger();
54
55 private CssLayout root = new CssLayout();
56
57 private Table table = new Table();
58
59 private Button newButton = ButtonFactory.CREATE_NEW.createButton();
60
61 private List<AnnotationType> typesFilter = null;
62
63 private BeanItemContainer<DefinedTermBase> typeSelectItemContainer;
64
65 private FilterableListContainer<Annotation> container;
66
67 private boolean withNewButton;
68
69 public FilterableAnnotationsField() {
70 this(null);
71 }
72
73 public FilterableAnnotationsField(String caption) {
74
75 setCaption(caption);
76 // annotations are always sets
77 setConverter(new SetToListConverter<>());
78
79 root.setWidth(100, Unit.PERCENTAGE);
80
81 // setup table
82 table.setPageLength(1);
83 table.setColumnHeaderMode(ColumnHeaderMode.HIDDEN);
84 table.setWidth(100, Unit.PERCENTAGE);
85 table.setTableFieldFactory(new DefaultFieldFactory() {
86
87 private static final long serialVersionUID = 5437750882205859178L;
88
89 @Override
90 public Field<?> createField(Item item, Object propertyId, Component uiContext) {
91
92 Field<?> field = createField(propertyId);
93 if(field == null) {
94 field = super.createField(item, propertyId, uiContext);
95 }
96 return field;
97
98 }
99
100 @Override
101 public Field<?> createField(Container container, Object itemId, Object propertyId, Component uiContext) {
102
103 Field<?> field = createField(propertyId);
104
105 if(field == null) {
106 field = super.createField(container, itemId, propertyId, uiContext);
107 }
108 return field;
109 }
110
111 protected Field<?> createField(Object propertyId) {
112 Field<?> field = null;
113 if(propertyId.equals("text")){
114 TextArea ta = new TextArea();
115 ta.setNullRepresentation("");
116 ta.setWidth(100, Unit.PERCENTAGE);
117 field = ta;
118 } else if(propertyId.equals("annotationType")) {
119 NativeSelect select = new NativeSelect();
120 select.setNullSelectionAllowed(false); //#10538
121 select.setContainerDataSource(typeSelectItemContainer);
122 select.setWidth(100, Unit.PIXELS);
123 //#10552
124 //the value is overriden by the row record new value setting of the surrounding table, so no need to set the value here
125 // select.select(AnnotationType.INTERNAL()); //AnnotationType.TECHNICAL()
126 select.focus();
127 field = select;
128 }
129 if(field != null) {
130 field.setStyleName(table.getStyleName());
131 }
132 return field;
133 }
134 });
135
136 addStyledComponent(table);
137
138 }
139
140 public void setAnnotationTypesVisible(AnnotationType ... types){
141 typesFilter = Arrays.asList(types);
142 }
143
144 @Override
145 protected void addDefaultStyles() {
146 // no default styles here
147 }
148
149 @Override
150 public Optional<FieldGroup> getFieldGroup() {
151 // holds a Container instead
152 return Optional.empty();
153 }
154
155 @Override
156 public void commit() throws SourceException, InvalidValueException {
157 table.commit();
158 Collection<Filter> filters = container.getContainerFilters();
159 super.commit();
160 for(Filter filter : filters){
161 container.addContainerFilter(filter);
162 }
163 logger.debug("container.size: " + container.size());
164 }
165
166 @Override
167 protected List<Annotation> getInternalValue() {
168 if(container == null || container.getItemIds() == null){
169 return null;
170 }
171 return new ArrayList<>(container.getItemIds());
172 }
173
174
175 @Override
176 protected void setInternalValue(List<Annotation> newValue) {
177
178 boolean hasIncludeFilter = typesFilter != null && !typesFilter.isEmpty();
179 boolean onlyOneType = hasIncludeFilter && typesFilter.size() == 1;
180
181 if(newValue.isEmpty()){
182 Annotation emptyDefaultAnnotation = newInstance();
183 newValue.add(emptyDefaultAnnotation );
184 if(onlyOneType){
185 emptyDefaultAnnotation.setAnnotationType(typesFilter.get(0));
186 }
187 }
188 container = new FilterableListContainer<>(newValue);
189 if(hasIncludeFilter){
190 container.addContainerFilter(new CdmTermFilter<>("annotationType", typesFilter));
191 }
192 table.setContainerDataSource(container);
193 if(onlyOneType){
194 table.setVisibleColumns("text");
195 } else {
196 table.setVisibleColumns("text", "annotationType");
197 }
198 table.setEditable(true);
199 if(newValue.size() > 1){
200 table.setPageLength(2);
201 }
202 }
203
204 @Override
205 protected Component initContent() {
206 root.addComponentAsFirst(table);
207
208 newButton.addClickListener(e -> addAnnotation());
209 withNewButton(true);
210 return root;
211 }
212
213 private void addAnnotation() {
214 container.addItem(newInstance());
215 if(container.size() > 1){
216 table.setPageLength(2);
217 }
218 }
219
220 private Annotation newInstance() {
221 //internal according to #10522
222 return Annotation.NewInstance(null, AnnotationType.INTERNAL(), Language.DEFAULT());
223 }
224
225 @Override
226 public Class<? extends List<Annotation>> getType() {
227 return (Class<? extends List<Annotation>>) new ArrayList<>().getClass();
228 }
229
230 public void setAnnotationTypeItemContainer(BeanItemContainer<DefinedTermBase> typeSelectItemContainer) {
231 this.typeSelectItemContainer = typeSelectItemContainer;
232 }
233
234 @Override
235 public void setReadOnly(boolean readOnly) {
236 super.setReadOnly(readOnly);
237 setDeepReadOnly(readOnly, table, null);
238 }
239
240 public void withNewButton(boolean withNewButton) {
241 if(this.withNewButton != withNewButton){
242 if(!this.withNewButton){
243 root.addComponent(newButton);
244 } else {
245 root.removeComponent(newButton);
246 }
247 this.withNewButton = withNewButton;
248 }
249 }
250 }