View Javadoc
1   /**
2    * This file Copyright (c) 2020 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.ui.editor;
35  
36  import info.magnolia.objectfactory.ComponentProvider;
37  import info.magnolia.ui.datasource.PropertySetFactory;
38  import info.magnolia.ui.field.FieldBinder;
39  import info.magnolia.ui.field.UploadField;
40  import info.magnolia.ui.field.UploadFieldDefinition;
41  import info.magnolia.ui.field.factory.AbstractFieldFactory;
42  import info.magnolia.ui.field.factory.HiddenFieldFactory;
43  import info.magnolia.ui.vaadin.form.field.FieldLayout;
44  
45  import java.io.File;
46  import java.util.Collections;
47  import java.util.HashMap;
48  import java.util.List;
49  import java.util.Map;
50  import java.util.Optional;
51  
52  import javax.inject.Inject;
53  
54  import org.apache.jackrabbit.JcrConstants;
55  
56  import com.vaadin.data.Binder;
57  import com.vaadin.data.BinderValidationStatus;
58  import com.vaadin.data.HasValue;
59  import com.vaadin.data.PropertySet;
60  import com.vaadin.server.ClientConnector;
61  import com.vaadin.ui.Component;
62  import com.vaadin.ui.Composite;
63  
64  /**
65   * Adapts the {@link UploadField} to {@link info.magnolia.ui.editor.EditorView}. Allows to set additional properties besides the
66   * binary data to the JCR node.
67   *
68   * @param <T> The item type.
69   */
70  public class UploadView<T> extends Composite implements EditorView<T>, Component.Focusable {
71  
72      private static final String WIDTH = "width";
73      private static final String HEIGHT = "height";
74      private static final String FILE_NAME = "fileName";
75  
76      private final UploadField uploadField;
77      private final Binder<T> binder;
78  
79      @Inject
80      public UploadView(UploadViewDefinition<T> definition,
81                        PropertySetFactory<T> propertySetFactory,
82                        HiddenFieldFactory hiddenFieldFactory,
83                        ComponentProvider componentProvider) {
84  
85          UploadFieldDefinitioneldDefinition">UploadFieldDefinition uploadFieldDefinition = new UploadFieldDefinition();
86          uploadFieldDefinition.setRequiredErrorMessage(definition.getRequiredErrorMessage());
87          uploadFieldDefinition.setRequired(definition.isRequired());
88          uploadFieldDefinition.setValidators(definition.getValidators());
89          uploadFieldDefinition.setConverterClass(definition.getConverterClass());
90  
91          Class<? extends AbstractFieldFactory<File, ? extends UploadFieldDefinition>> factoryClass = definition.getFactoryClass();
92          uploadField = (UploadField) componentProvider.newInstance(factoryClass).createField();
93  
94          Map<String, Class> properties = new HashMap<>();
95          properties.put(WIDTH, Integer.class);
96          properties.put(HEIGHT, Integer.class);
97          properties.put(FILE_NAME, String.class);
98          properties.put(JcrConstants.JCR_DATA, File.class);
99  
100 
101         PropertySet<T> propertySet = propertySetFactory.withProperties(properties);
102         binder = Binder.withPropertySet(propertySet);
103         binder.forField(hiddenFieldFactory.createField()).bind(WIDTH);
104         binder.forField(hiddenFieldFactory.createField()).bind(HEIGHT);
105         binder.forField(hiddenFieldFactory.createField()).bind(FILE_NAME);
106 
107         Binder.BindingBuilder<T, File> uploadFieldBinder = binder.forField(uploadField);
108         if (definition.isRequired()) {
109             final String errorMessage = definition.getRequiredErrorMessage();
110             uploadFieldBinder.asRequired();
111             uploadFieldBinder
112                     .withValidationStatusHandler(statusChange -> findParent(uploadField, FieldLayout.class)
113                     .ifPresent(fieldLayout -> fieldLayout.getValidationStatusHandler().accept(statusChange.isError() ? errorMessage : "")));
114         }
115 
116         new FieldBinder.Default<File>(componentProvider).configureBinding(uploadFieldDefinition, uploadFieldBinder);
117         uploadFieldBinder.bind(JcrConstants.JCR_DATA);
118 
119         uploadField.addValueChangeListener(event -> uploadField.getFileInfo().ifPresent(this::updateProperties));
120 
121         setCompositionRoot(uploadField);
122     }
123 
124     private  <V extends Component> Optional<V> findParent(Component field, Class<V> parentClass) {
125         ClientConnector connector = field;
126         while (connector != null) {
127             if (parentClass.isInstance(connector)) {
128                 return Optional.of((V) connector);
129             }
130             connector = connector.getParent();
131         }
132         return Optional.empty();
133     }
134 
135     private void updateProperties(UploadField.FileInfo fileInfo) {
136         setPropertyValue(FILE_NAME, fileInfo.getName());
137         fileInfo.getImageInfo().ifPresent(imageInfo -> {
138             setPropertyValue(WIDTH, imageInfo.getWidth());
139             setPropertyValue(HEIGHT, imageInfo.getHeight());
140         });
141     }
142 
143     private void setPropertyValue(String propertyName, Object value) {
144         binder.getBinding(propertyName)
145                 .map(Binder.Binding::getField)
146                 .ifPresent(field -> ((HasValue) field).setValue(value));
147     }
148 
149     @Override
150     public List<BinderValidationStatus<?>> validate() {
151         return Collections.singletonList(binder.validate());
152     }
153 
154     @Override
155     public void populate(T item) {
156         binder.readBean(item);
157     }
158 
159     @Override
160     public void write(T item) {
161         binder.writeBeanIfValid(item);
162     }
163 
164     @Override
165     public void focus() {
166         uploadField.focus();
167     }
168 
169     @Override
170     public int getTabIndex() {
171         return 0;
172     }
173 
174     @Override
175     public void setTabIndex(int tabIndex) {
176 
177     }
178 }