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