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