View Javadoc
1   /**
2    * This file Copyright (c) 2013-2018 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.form.field;
35  
36  import info.magnolia.cms.i18n.I18nContentSupport;
37  import info.magnolia.objectfactory.ComponentProvider;
38  import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
39  import info.magnolia.ui.form.field.definition.ConfiguredFieldDefinition;
40  import info.magnolia.ui.form.field.definition.SwitchableFieldDefinition;
41  import info.magnolia.ui.form.field.factory.FieldFactoryFactory;
42  
43  import java.util.HashMap;
44  import java.util.Map;
45  
46  import org.apache.commons.lang3.StringUtils;
47  import org.slf4j.Logger;
48  import org.slf4j.LoggerFactory;
49  
50  import com.vaadin.ui.Component;
51  import com.vaadin.v7.data.Item;
52  import com.vaadin.v7.data.util.PropertysetItem;
53  import com.vaadin.v7.ui.Field;
54  import com.vaadin.v7.ui.Label;
55  import com.vaadin.v7.ui.VerticalLayout;
56  
57  /**
58   * Switchable field.<br>
59   * Display a field composed of two main sections <br>
60   * - a Select Section (list or checkBox) <br>
61   * - a Field Section displaying the field currently selected. <br>
62   *
63   * @deprecated since 6.2 - use {@link info.magnolia.ui.editor.SwitchableFormView} instead.
64   *
65   * @see <a href="https://documentation.magnolia-cms.com/display/DOCS62/Upgrading+to+Magnolia+6.2.x">Upgrading to Magnolia 6.2.x</a>
66   */
67  @Deprecated
68  public class SwitchableField extends AbstractCustomMultiField<SwitchableFieldDefinition, PropertysetItem> {
69  
70      private static final Logger log = LoggerFactory.getLogger(SwitchableField.class);
71  
72      // - key : Field name. Should be the same as the related select value.<br>
73      // - value : Related Field. Created based on the definition coming from the Fields Definition list.
74      private final Map<String, Field<?>> fieldMap = new HashMap<>();
75  
76      private Field<?> selectField;
77  
78      public SwitchableField(SwitchableFieldDefinition definition, FieldFactoryFactory fieldFactoryFactory, ComponentProvider componentProvider, Item relatedFieldItem, I18NAuthoringSupport i18nAuthoringSupport) {
79          super(definition, fieldFactoryFactory, componentProvider, relatedFieldItem, i18nAuthoringSupport);
80      }
81  
82      /**
83       * @deprecated since 5.3.5 removing i18nContentSupport dependency (actually unused way before that). Besides, fields should use i18nAuthoringSupport for internationalization.
84       */
85      @Deprecated
86      public SwitchableField(SwitchableFieldDefinition definition, FieldFactoryFactory fieldFactoryFactory, I18nContentSupport i18nContentSupport, ComponentProvider componentProvider, Item relatedFieldItem) {
87          this(definition, fieldFactoryFactory, componentProvider, relatedFieldItem, componentProvider.getComponent(I18NAuthoringSupport.class));
88      }
89  
90      @Override
91      protected Component initContent() {
92          // Initialize root
93          root = new VerticalLayout();
94          setWidth(100, Unit.PERCENTAGE);
95          setHeight(-1, Unit.PIXELS);
96          addStyleName("switchablefield");
97          root.setWidth(100, Unit.PERCENTAGE);
98          root.setHeight(-1, Unit.PIXELS);
99          root.setSpacing(true);
100 
101         // Initialize Existing field
102         initFields();
103         return root;
104     }
105 
106     @Override
107     protected void initFields(PropertysetItem fieldValues) {
108         root.removeAllComponents();
109         fieldMap.clear();
110         // Create all Fields including the select Field.
111         for (ConfiguredFieldDefinition fieldDefinition : definition.getFields()) {
112             String name = fieldDefinition.getName();
113             // Only propagate read only if the parent definition is read only
114             if (definition.isReadOnly()) {
115                 fieldDefinition.setReadOnly(true);
116             }
117             Field<?> field = createLocalField(fieldDefinition, fieldValues.getItemProperty(fieldDefinition.getName()), false);
118             // Do not add hidden field.
119             if (!field.isVisible()) {
120                 continue;
121             }
122             if (fieldValues.getItemProperty(fieldDefinition.getName()) == null) {
123                 fieldValues.addItemProperty(fieldDefinition.getName(), field.getPropertyDataSource());
124             }
125             field.setWidth(100, Unit.PERCENTAGE);
126             fieldMap.put(name, field);
127             // set select field at the first position
128             if (StringUtils.equals(fieldDefinition.getName(), definition.getName())) {
129                 root.addComponentAsFirst(field);
130             } else {
131                 root.addComponent(field);
132             }
133         }
134 
135         // add listener to the select field
136         selectField = fieldMap.get(definition.getName());
137         selectField.setCaption(null);
138         selectField.addValueChangeListener(createSelectValueChangeListener());
139         selectField.addValueChangeListener(selectionListener);
140         switchField((String) selectField.getValue());
141     }
142 
143     /**
144      * Returns a {@link Field} if it's existing. Otherwise returns a null.
145      */
146     protected Field<?> getFieldByName(String fieldName) {
147         return fieldMap.get(fieldName);
148     }
149 
150     /**
151      * Change Listener bound to the select field. Once a selection is done, <br>
152      * the value change listener will switch to the field linked to the current select value.
153      */
154     private ValueChangeListener createSelectValueChangeListener() {
155         return (ValueChangeListener) event -> switchField(String.valueOf(event.getProperty().getValue()));
156     }
157 
158     /**
159      * Switch to the desired field. It the field is not part of the List, display a warn label.
160      */
161     private void switchField(String fieldName) {
162         // Check
163         if (root.getComponentCount() < 2 && StringUtils.equals(root.getComponent(0).getId(), definition.getName())) {
164             log.warn("{} is not associated to a field. Nothing will be displayed.", fieldName);
165             root.addComponent(new Label("No field configured for this switchable field "), 1);
166             return;
167         }
168 
169         for (String innerFieldName : fieldMap.keySet()) {
170             Field<?> field = fieldMap.get(innerFieldName);
171             // Set the select component visible and the selected field
172             if (StringUtils.equals(innerFieldName, fieldName) || StringUtils.equals(innerFieldName, definition.getName())) {
173                 field.setVisible(true);
174             } else {
175                 field.setVisible(false);
176             }
177         }
178     }
179 
180     @Override
181     public Class<? extends PropertysetItem> getType() {
182         return PropertysetItem.class;
183     }
184 
185     /**
186      * A switchable field is empty when no choice has been made yet. This method is called by Vaadin framework to perform a basic isRequired check.
187      */
188     @Override
189     public boolean isEmpty() {
190         return selectField.isEmpty();
191     }
192 }