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.upload.basic;
35
36 import info.magnolia.i18nsystem.SimpleTranslator;
37 import info.magnolia.ui.api.context.UiContext;
38 import info.magnolia.ui.form.field.definition.BasicUploadFieldDefinition;
39 import info.magnolia.ui.form.field.upload.AbstractUploadField;
40 import info.magnolia.ui.form.field.upload.UploadProgressIndicator;
41 import info.magnolia.ui.form.field.upload.UploadReceiver;
42 import info.magnolia.ui.imageprovider.ImageProvider;
43 import info.magnolia.ui.vaadin.overlay.MessageStyleTypeEnum;
44
45 import org.apache.commons.io.FileUtils;
46 import org.apache.commons.lang3.StringUtils;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 import com.vaadin.ui.Alignment;
51 import com.vaadin.ui.Button;
52 import com.vaadin.ui.Button.ClickEvent;
53 import com.vaadin.ui.Component;
54 import com.vaadin.ui.CssLayout;
55 import com.vaadin.ui.FormLayout;
56 import com.vaadin.ui.Layout;
57 import com.vaadin.ui.NativeButton;
58 import com.vaadin.v7.data.Property;
59 import com.vaadin.v7.shared.ui.label.ContentMode;
60 import com.vaadin.v7.ui.HorizontalLayout;
61 import com.vaadin.v7.ui.Label;
62 import com.vaadin.v7.ui.TextField;
63
64
65
66
67
68
69
70
71
72
73
74
75 public class BasicUploadField<T extends UploadReceiver> extends AbstractUploadField<T> {
76 private static final long serialVersionUID = 1L;
77 private static final Logger log = LoggerFactory.getLogger(BasicUploadField.class);
78
79 private static final String PREFIX_MEDIA_KEY = "field.upload.media";
80 private static final String MEDIA = "media";
81
82
83 private final CssLayout layout;
84 private UploadProgressIndicator progress;
85 protected final ImageProvider imageProvider;
86 private boolean editFileName = false;
87 private boolean editFileFormat = false;
88 protected UiContext uiContext;
89 private final SimpleTranslator i18n;
90
91 public BasicUploadField(ImageProvider imageProvider, UiContext uiContext, BasicUploadFieldDefinition definition, SimpleTranslator i18n) {
92 super();
93
94 populateFromDefinition(definition);
95
96 this.imageProvider = imageProvider;
97 this.layout = new CssLayout();
98 this.layout.setSizeUndefined();
99 this.uiContext = uiContext;
100 this.i18n = i18n;
101
102 setRootLayout(createDropZone(layout));
103
104 addStyleName("upload-image-field");
105 addStyleName("no-horizontal-drag-hints");
106 addStyleName("no-vertical-drag-hints");
107 }
108
109
110
111
112
113
114
115 @Override
116 public void attach() {
117 super.attach();
118 updateDisplay();
119 log.debug("Component was attached ...");
120 }
121
122
123
124
125
126
127
128 @Override
129 protected void buildEmptyLayout() {
130 layout.removeAllComponents();
131 if (isReadOnly()) {
132 return;
133 }
134
135 getUpload().setButtonCaption(getCaption(selectNewCaption, null));
136 layout.addComponent(getUpload());
137
138 Label uploadText = new Label(getCaption(dropZoneCaption, null), ContentMode.HTML);
139 uploadText.addStyleName("upload-text");
140 layout.addComponent(uploadText);
141
142
143 getRootLayout().removeStyleName("start");
144 getRootLayout().removeStyleName("done");
145 getRootLayout().removeStyleName("in-progress");
146 getRootLayout().addStyleName("upload");
147 getRootLayout().addStyleName("initial");
148
149 log.debug("buildEmptyLayout() called ...");
150 }
151
152
153
154
155
156
157
158 @Override
159 protected void buildInProgressLayout(String uploadedFileMimeType) {
160 layout.removeAllComponents();
161
162 setCaptionExtension(uploadedFileMimeType);
163
164 progress = new BasicUploadProgressIndicator(inProgressCaption, inProgressRatioCaption, i18n);
165 progress.setVisible(true);
166 progress.setProgress(0);
167 layout.addComponent(progress.asVaadinComponent());
168
169
170 layout.addComponent(createCancelButton());
171
172
173 getRootLayout().removeStyleName("done");
174 getRootLayout().addStyleName("upload");
175 getRootLayout().addStyleName("initial");
176 getRootLayout().addStyleName("in-progress");
177
178 log.debug("buildInProgressLayout() called ...");
179 }
180
181 @Override
182 protected void refreshInProgressLayout(long readBytes, long contentLength, String fileName) {
183 if (progress != null) {
184 progress.refreshLayout(readBytes, contentLength, fileName);
185 }
186 }
187
188
189
190
191
192
193
194
195
196
197
198 @Override
199 protected void buildCompletedLayout() {
200 layout.removeAllComponents();
201
202 setCaptionExtension(null);
203
204 layout.addComponent(createFileInfoComponent());
205
206 layout.addComponent(createCompletedActionLayout());
207
208
209 layout.addComponent(createThumbnailComponent());
210
211
212 getRootLayout().addStyleName("upload");
213 getRootLayout().removeStyleName("in-progress");
214 getRootLayout().removeStyleName("initial");
215 getRootLayout().addStyleName("done");
216
217 log.debug("buildCompletedLayout() called ...");
218 }
219
220
221
222
223 protected Layout createCompletedActionLayout() {
224
225 HorizontalLayout actionLayout = new HorizontalLayout();
226 actionLayout.setSizeUndefined();
227 actionLayout.addStyleName("buttons");
228 actionLayout.setSpacing(true);
229
230 getUpload().setButtonCaption(getCaption(selectAnotherCaption, null));
231 actionLayout.addComponent(getUpload());
232
233 if (!getValue().isEmpty()) {
234 Button delete = createDeleteButton();
235 actionLayout.addComponent(delete);
236 actionLayout.setComponentAlignment(delete, Alignment.MIDDLE_RIGHT);
237 }
238 return actionLayout;
239 }
240
241
242
243
244
245 private Button createCancelButton() {
246 Button cancelButton = new NativeButton(null, new Button.ClickListener() {
247 private static final long serialVersionUID = 1L;
248
249 @Override
250 public void buttonClick(ClickEvent event) {
251 interruptUpload(InterruptionReason.USER);
252 }
253 });
254 cancelButton.addStyleName("cancel");
255 return cancelButton;
256 }
257
258
259
260
261 protected Button createDeleteButton() {
262 Button deleteButton = new Button();
263 deleteButton.setHtmlContentAllowed(true);
264 deleteButton.setCaption("<span class=\"" + "icon-trash" + "\"></span>");
265 deleteButton.addStyleName("inline");
266 deleteButton.setDescription(i18n.translate(deleteCaption));
267
268 deleteButton.addClickListener(new Button.ClickListener() {
269 private static final long serialVersionUID = 1L;
270
271 @Override
272 public void buttonClick(ClickEvent event) {
273 resetDataSource();
274 updateDisplay();
275 }
276 });
277 return deleteButton;
278 }
279
280
281
282
283
284
285
286 private Component createFileInfoComponent() {
287 FormLayout fileInfo = new FormLayout();
288 fileInfo.setSizeUndefined();
289 fileInfo.addStyleName("file-details");
290 fileInfo.addComponent(getFileDetailHeader());
291 fileInfo.addComponent(getFileDetailFileName());
292 fileInfo.addComponent(getFileDetailSize());
293 fileInfo.addComponent(getFileDetailFileFormat());
294 return fileInfo;
295 }
296
297
298
299
300 protected Component getFileDetailHeader() {
301 Label label = new Label();
302 label.setValue(getCaption(fileDetailHeaderCaption, null));
303 return label;
304 }
305
306
307
308
309
310
311 protected Component getFileDetailFileName() {
312
313 final boolean hasExtension = StringUtils.isNotBlank(getValue().getExtension());
314 final String extension = hasExtension ? "." + getValue().getExtension() : "";
315 String fileName = StringUtils.removeEnd(getValue().getFileName(), extension);
316
317 if (this.editFileName && !isReadOnly()) {
318 TextField textField = new TextField(i18n.translate(fileDetailNameCaption), fileName);
319 textField.setNullRepresentation("");
320 textField.setCaption(i18n.translate(fileDetailNameCaption));
321 textField.addValueChangeListener(new Property.ValueChangeListener() {
322 @Override
323 public void valueChange(Property.ValueChangeEvent event) {
324 Object newFileNameObject = event.getProperty().getValue();
325 String newFileName = (newFileNameObject != null && StringUtils.isNotBlank(newFileNameObject.toString())) ? newFileNameObject.toString() : UploadReceiver.INVALID_FILE_NAME;
326 getValue().setFileName(newFileName + extension);
327 getPropertyDataSource().setValue(getValue());
328 }
329 });
330 return textField;
331 } else {
332 Label label = new Label();
333 label.setCaption(i18n.translate(fileDetailNameCaption));
334 label.setValue(fileName);
335 return label;
336 }
337 }
338
339
340
341
342 protected Component getFileDetailSize() {
343 Label label = new Label();
344 label.setCaption(i18n.translate(fileDetailSizeCaption));
345 label.setValue(FileUtils.byteCountToDisplaySize(getValue().getFileSize()));
346 return label;
347 }
348
349
350
351
352
353
354 protected Component getFileDetailFileFormat() {
355 if (this.editFileFormat && !isReadOnly()) {
356 TextField textField = new TextField(i18n.translate(fileDetailFormatCaption), getValue().getExtension());
357 textField.setNullRepresentation("");
358 textField.setCaption(i18n.translate(fileDetailFormatCaption));
359 return textField;
360 } else {
361 Label label = new Label();
362 label.setValue(getValue().getExtension());
363 label.setCaption(i18n.translate(fileDetailFormatCaption));
364 return label;
365 }
366 }
367
368
369
370
371 protected Component createThumbnailComponent() {
372 Label thumbnail = new Label();
373 thumbnail.setSizeUndefined();
374 thumbnail.addStyleName("preview-image");
375 thumbnail.addStyleName("file-preview");
376 thumbnail.addStyleName(createIconStyleName());
377 return thumbnail;
378 }
379
380
381
382
383
384
385
386 protected String createIconStyleName() {
387 return "icon-" + imageProvider.resolveIconClassName(getValue().getMimeType());
388 }
389
390 @Override
391 protected Component initContent() {
392 return getRootLayout();
393 }
394
395
396
397
398 protected void populateFromDefinition(BasicUploadFieldDefinition definition) {
399 this.setMaxUploadSize(definition.getMaxUploadSize());
400 this.setAllowedMimeTypePattern(definition.getAllowedMimeTypePattern());
401
402 this.setSelectNewCaption(definition.getSelectNewCaption());
403 this.setSelectAnotherCaption(definition.getSelectAnotherCaption());
404 this.setDropZoneCaption(definition.getDropZoneCaption());
405 this.setInProgressCaption(definition.getInProgressCaption());
406 this.setInProgressRatioCaption(definition.getInProgressRatioCaption());
407 this.setFileDetailHeaderCaption(definition.getFileDetailHeaderCaption());
408 this.setFileDetailNameCaption(definition.getFileDetailNameCaption());
409 this.setFileDetailSizeCaption(definition.getFileDetailSizeCaption());
410 this.setFileDetailFormatCaption(definition.getFileDetailFormatCaption());
411 this.setFileDetailSourceCaption(definition.getFileDetailSourceCaption());
412 this.setSuccessNoteCaption(definition.getSuccessNoteCaption());
413 this.setWarningNoteCaption(definition.getWarningNoteCaption());
414 this.setErrorNoteCaption(definition.getErrorNoteCaption());
415 this.setDeteteCaption(definition.getDeleteCaption());
416 this.setEditFileFormat(definition.isEditFileFormat());
417 this.setEditFileName(definition.isEditFileName());
418 this.setUserInterruption(definition.getUserInterruption());
419 this.setTypeInterruption(definition.getTypeInterruption());
420 this.setSizeInterruption(definition.getSizeInterruption());
421 }
422
423
424
425
426 protected String captionExtension;
427
428 protected void setCaptionExtension(String mimeType) {
429 captionExtension = "";
430 }
431
432 protected String getCaption(String caption, String[] args) {
433 if (StringUtils.isEmpty(caption)) {
434 return "";
435 }
436 if (StringUtils.isNotBlank(captionExtension)) {
437 String mediaName = i18n.translate(PREFIX_MEDIA_KEY + '.' + captionExtension);
438 String[] paras;
439 if (args != null && args.length > 0) {
440 paras = new String[args.length + 1];
441 paras[0] = mediaName;
442 System.arraycopy(args, 0, paras, 1, args.length);
443 } else {
444 paras = new String[] { mediaName };
445 }
446 return i18n.translate(caption + '.' + MEDIA, paras);
447 }
448 if (args != null && args.length > 0) {
449 return i18n.translate(caption, args);
450 } else {
451 return i18n.translate(caption);
452 }
453 }
454
455 protected String selectNewCaption;
456 protected String selectAnotherCaption;
457 protected String deleteCaption;
458 protected String dropZoneCaption;
459 protected String inProgressCaption;
460 protected String inProgressRatioCaption;
461 protected String fileDetailHeaderCaption;
462 protected String fileDetailNameCaption;
463 protected String fileDetailSizeCaption;
464 protected String fileDetailFormatCaption;
465 protected String fileDetailSourceCaption;
466 protected String successNoteCaption;
467 protected String warningNoteCaption;
468 protected String errorNoteCaption;
469 private String sizeInterruption;
470 private String typeInterruption;
471 private String userInterruption;
472
473 public void setSelectNewCaption(String selectNewCaption) {
474 this.selectNewCaption = selectNewCaption;
475 }
476
477 public void setSelectAnotherCaption(String selectAnotherCaption) {
478 this.selectAnotherCaption = selectAnotherCaption;
479 }
480
481 public void setDropZoneCaption(String dropZoneCaption) {
482 this.dropZoneCaption = dropZoneCaption;
483 }
484
485 public void setInProgressCaption(String inProgressCaption) {
486 this.inProgressCaption = inProgressCaption;
487 }
488
489 public void setInProgressRatioCaption(String inProgressRatioCaption) {
490 this.inProgressRatioCaption = inProgressRatioCaption;
491 }
492
493 public void setFileDetailHeaderCaption(String fileDetailHeaderCaption) {
494 this.fileDetailHeaderCaption = fileDetailHeaderCaption;
495 }
496
497 public void setFileDetailNameCaption(String fileDetailNameCaption) {
498 this.fileDetailNameCaption = fileDetailNameCaption;
499 }
500
501 public void setFileDetailSizeCaption(String fileDetailSizeCaption) {
502 this.fileDetailSizeCaption = fileDetailSizeCaption;
503 }
504
505 public void setFileDetailFormatCaption(String fileDetailFormatCaption) {
506 this.fileDetailFormatCaption = fileDetailFormatCaption;
507 }
508
509 public void setFileDetailSourceCaption(String fileDetailSourceCaption) {
510 this.fileDetailSourceCaption = fileDetailSourceCaption;
511 }
512
513 public void setSuccessNoteCaption(String successNoteCaption) {
514 this.successNoteCaption = successNoteCaption;
515 }
516
517 public void setWarningNoteCaption(String warningNoteCaption) {
518 this.warningNoteCaption = warningNoteCaption;
519 }
520
521 public void setErrorNoteCaption(String errorNoteCaption) {
522 this.errorNoteCaption = errorNoteCaption;
523 }
524
525 public void setDeteteCaption(String deleteCaption) {
526 this.deleteCaption = deleteCaption;
527 }
528
529 public void setSizeInterruption(String sizeInterruption) {
530 this.sizeInterruption = sizeInterruption;
531 }
532
533 public void setTypeInterruption(String typeInterruption) {
534 this.typeInterruption = typeInterruption;
535 }
536
537 public void setUserInterruption(String userInterruption) {
538 this.userInterruption = userInterruption;
539 }
540
541 @Override
542 protected void displayUploadInterruptNote(InterruptionReason reason) {
543 String caption = "";
544 if (reason.equals(InterruptionReason.USER)) {
545 caption = userInterruption;
546 } else if (reason.equals(InterruptionReason.FILE_SIZE)) {
547 caption = sizeInterruption;
548 } else {
549 caption = typeInterruption;
550 }
551 uiContext.openNotification(MessageStyleTypeEnum.WARNING, true, getCaption(warningNoteCaption, new String[] { i18n.translate(caption) }));
552 }
553
554 @Override
555 protected void displayUploadFinishedNote(String fileName) {
556 uiContext.openNotification(MessageStyleTypeEnum.INFO, true, getCaption(successNoteCaption, new String[] { fileName }));
557 }
558
559 @Override
560 protected void displayUploadFailedNote(String fileName) {
561 uiContext.openAlert(MessageStyleTypeEnum.ERROR, "ERROR", getCaption(errorNoteCaption, new String[] { fileName }), i18n.translate("button.ok"), null);
562 }
563
564 public void setEditFileName(boolean editFileName) {
565 this.editFileName = editFileName;
566 }
567
568 public void setEditFileFormat(boolean editFileFormat) {
569 this.editFileFormat = editFileFormat;
570 }
571
572
573
574
575 public CssLayout getCssLayout() {
576 return this.layout;
577 }
578
579 @Override
580 public boolean isEmpty() {
581 return getValue().isEmpty();
582 }
583
584 @Override
585 public void setReadOnly(boolean readOnly) {
586 super.setReadOnly(readOnly);
587 if (readOnly) {
588
589 if (getDropZone() != null) {
590 getDropZone().setDropHandler(null);
591 }
592 if (getUpload() != null) {
593 getUpload().removeStartedListener(this);
594 getUpload().removeFinishedListener(this);
595 getUpload().removeProgressListener(this);
596 }
597 if (getValue().isEmpty()) {
598 buildEmptyLayout();
599 }
600 }
601
602 }
603 }