1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.ui.form.field;
35
36 import com.vaadin.data.Item;
37 import com.vaadin.data.Property;
38 import com.vaadin.data.util.converter.Converter.ConversionException;
39 import com.vaadin.server.ErrorMessage;
40 import com.vaadin.server.UserError;
41 import com.vaadin.ui.Alignment;
42 import com.vaadin.ui.Button;
43 import com.vaadin.ui.Button.ClickEvent;
44 import com.vaadin.ui.Component;
45 import com.vaadin.ui.CustomField;
46 import com.vaadin.ui.HorizontalLayout;
47 import com.vaadin.ui.NativeButton;
48 import com.vaadin.ui.TextField;
49 import com.vaadin.ui.VerticalLayout;
50 import info.magnolia.objectfactory.ComponentProvider;
51 import info.magnolia.objectfactory.Components;
52 import info.magnolia.ui.api.app.AppController;
53 import info.magnolia.ui.api.app.ChooseDialogCallback;
54 import info.magnolia.ui.api.context.UiContext;
55 import info.magnolia.ui.form.field.component.ContentPreviewComponent;
56 import info.magnolia.ui.form.field.converter.IdentifierToPathConverter;
57 import info.magnolia.ui.form.field.definition.LinkFieldDefinition;
58 import info.magnolia.ui.vaadin.integration.NullItem;
59 import info.magnolia.ui.vaadin.integration.jcr.JcrItemAdapter;
60 import org.apache.commons.lang.StringUtils;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 import javax.jcr.Node;
65 import javax.jcr.RepositoryException;
66
67
68
69
70
71
72 public class LinkField extends CustomField<String> {
73 private static final Logger log = LoggerFactory.getLogger(LinkField.class);
74
75
76
77
78 private final class LinkFieldTextBox extends TextField {
79 @Override
80 public void fireValueChange(boolean repaintIsNotNeeded) {
81 super.fireValueChange(repaintIsNotNeeded);
82 }
83 }
84
85
86 private final VerticalLayout rootLayout = new VerticalLayout();
87 private final HorizontalLayout linkLayout = new HorizontalLayout();
88 private final LinkFieldTextBox textField = new LinkFieldTextBox();
89 private final Button selectButton = new NativeButton();
90
91 private final IdentifierToPathConverter converter;
92 private final LinkFieldDefinition definition;
93 private String buttonCaptionNew;
94 private String buttonCaptionOther;
95
96 private final AppController appController;
97 private final UiContext uiContext;
98 private final ComponentProvider componentProvider;
99
100 public LinkField(LinkFieldDefinition linkFieldDefinition, AppController appController, UiContext uiContext, ComponentProvider componentProvider) {
101 this.definition = linkFieldDefinition;
102 this.converter = definition.getIdentifierToPathConverter();
103 if (this.converter != null) {
104 this.converter.setWorkspaceName(definition.getTargetWorkspace());
105 }
106 this.appController = appController;
107 this.uiContext = uiContext;
108 this.componentProvider = componentProvider;
109 setImmediate(true);
110 }
111
112 @Override
113 protected Component initContent() {
114 addStyleName("linkfield");
115
116 rootLayout.setSizeFull();
117 rootLayout.setSpacing(true);
118
119 textField.setImmediate(true);
120 textField.setWidth(100, Unit.PERCENTAGE);
121 textField.setNullRepresentation("");
122 textField.setNullSettingAllowed(true);
123
124 linkLayout.setSizeFull();
125 linkLayout.addComponent(textField);
126 linkLayout.setExpandRatio(textField, 1);
127 linkLayout.setComponentAlignment(textField, Alignment.MIDDLE_LEFT);
128
129 if (!textField.isReadOnly()) {
130 selectButton.addStyleName("magnoliabutton");
131 linkLayout.addComponent(selectButton);
132 linkLayout.setExpandRatio(selectButton, 0);
133 linkLayout.setComponentAlignment(selectButton, Alignment.MIDDLE_RIGHT);
134 }
135 selectButton.addClickListener(createButtonClickListener());
136 setButtonCaption(StringUtils.EMPTY);
137 rootLayout.addComponent(linkLayout);
138
139
140 if (definition.getContentPreviewDefinition() != null && definition.getContentPreviewDefinition().getContentPreviewClass() != null) {
141 registerContentPreview();
142 }
143 return rootLayout;
144 }
145
146 public TextField getTextField() {
147 return this.textField;
148 }
149
150 public Button getSelectButton() {
151 return this.selectButton;
152 }
153
154 @Override
155 public String getValue() {
156 return textField.getValue();
157 }
158
159 @Override
160 public void setValue(String newValue) throws ReadOnlyException, ConversionException {
161 textField.setValue(newValue);
162 }
163
164
165
166
167
168
169 private void updateComponents(String currentValue) {
170 if (!definition.isFieldEditable() && StringUtils.isNotBlank(currentValue)) {
171 textField.setReadOnly(true);
172 if (linkLayout.getComponentIndex(selectButton) != -1) {
173 linkLayout.removeComponent(selectButton);
174 }
175 } else {
176 setButtonCaption(currentValue);
177 }
178 }
179
180
181
182
183
184 @Override
185 @SuppressWarnings("rawtypes")
186 public void setPropertyDataSource(Property newDataSource) {
187 if (converter != null) {
188 textField.setConverter(converter);
189 }
190 textField.setPropertyDataSource(newDataSource);
191 textField.addValueChangeListener(new ValueChangeListener() {
192 @Override
193 public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) {
194 String value = event.getProperty().getValue() != null ? event.getProperty().getValue().toString() : StringUtils.EMPTY;
195 updateComponents(value);
196 }
197 });
198
199 super.setPropertyDataSource(newDataSource);
200 }
201
202 @Override
203 @SuppressWarnings("rawtypes")
204 public Property getPropertyDataSource() {
205 return textField.getPropertyDataSource();
206 }
207
208 @Override
209 public Class<String> getType() {
210 return String.class;
211 }
212
213 private void setButtonCaption(String value) {
214 if (StringUtils.isNotBlank(value)) {
215 selectButton.setCaption(buttonCaptionOther);
216 selectButton.setDescription(buttonCaptionOther);
217 } else {
218 selectButton.setCaption(buttonCaptionNew);
219 selectButton.setDescription(buttonCaptionNew);
220 }
221 }
222
223 private void registerContentPreview() {
224 final ContentPreviewComponent<?> contentPreviewComponent = Components.newInstance(definition.getContentPreviewDefinition().getContentPreviewClass(), definition.getTargetWorkspace(), componentProvider);
225 textField.addValueChangeListener(new ValueChangeListener() {
226 @Override
227 public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) {
228 String itemReference = event.getProperty().getValue().toString();
229 contentPreviewComponent.onValueChange(itemReference);
230 }
231 });
232 rootLayout.addComponentAsFirst(contentPreviewComponent);
233 if (StringUtils.isNotBlank(textField.getValue())) {
234 textField.fireValueChange(false);
235 }
236 }
237
238
239
240
241
242 private Button.ClickListener createButtonClickListener() {
243 return new Button.ClickListener() {
244 @Override
245 public void buttonClick(ClickEvent event) {
246
247 appController.openChooseDialog(definition.getAppName(), uiContext, textField.getValue(), new ChooseDialogCallback() {
248 @Override
249 public void onItemChosen(String actionName, final Item chosenValue) {
250 String propertyName = definition.getTargetPropertyToPopulate();
251 String newValue = null;
252 if (chosenValue != null && !(chosenValue instanceof NullItem)) {
253 javax.jcr.Item jcrItem = ((JcrItemAdapter) chosenValue).getJcrItem();
254 if (jcrItem.isNode()) {
255 final Node selected = (Node) jcrItem;
256 try {
257 boolean isPropertyExisting = StringUtils.isNotBlank(propertyName) && selected.hasProperty(propertyName);
258 newValue = isPropertyExisting ? selected.getProperty(propertyName).getString() : selected.getPath();
259 } catch (RepositoryException e) {
260 log.error("Not able to access the configured property. Value will not be set.", e);
261 }
262 }
263 }
264 setValue(newValue);
265 }
266
267 @Override
268 public void onCancel() {
269 }
270 });
271 }
272 };
273 }
274
275
276
277
278 public void setButtonCaptionNew(String buttonCaptionNew) {
279 this.buttonCaptionNew = buttonCaptionNew;
280 }
281
282 public void setButtonCaptionOther(String buttonCaptionOther) {
283 this.buttonCaptionOther = buttonCaptionOther;
284 }
285
286 @Override
287 public boolean isValid() {
288 if (this.isRequired() && StringUtils.isBlank(getValue())) {
289 return false;
290 } else {
291 return true;
292 }
293 }
294
295
296 @Override
297 public ErrorMessage getErrorMessage() {
298 if (this.isRequired() && StringUtils.isBlank(getValue())) {
299 return new UserError(getRequiredError());
300 } else {
301 return null;
302 }
303 }
304
305 }