View Javadoc
1   /**
2    * This file Copyright (c) 2019 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.dam.app.field;
35  
36  import info.magnolia.i18nsystem.SimpleTranslator;
37  import info.magnolia.icons.MagnoliaIcons;
38  import info.magnolia.ui.CloseHandler;
39  import info.magnolia.ui.UIComponent;
40  import info.magnolia.ui.api.message.Message;
41  import info.magnolia.ui.api.message.MessageType;
42  import info.magnolia.ui.field.UploadField;
43  import info.magnolia.ui.framework.message.MessagesManager;
44  import info.magnolia.ui.framework.util.TempFilesManager;
45  import info.magnolia.ui.mediaeditor.MediaEditorPresenter;
46  import info.magnolia.ui.mediaeditor.MediaEditorPresenterFactory;
47  import info.magnolia.ui.mediaeditor.event.MediaEditorCompletedEvent;
48  
49  import java.io.ByteArrayInputStream;
50  import java.io.File;
51  import java.io.FileInputStream;
52  import java.io.IOException;
53  import java.io.InputStream;
54  
55  import org.apache.commons.io.FileUtils;
56  import org.slf4j.Logger;
57  import org.slf4j.LoggerFactory;
58  
59  import com.machinezoo.noexception.Exceptions;
60  import com.vaadin.event.MouseEvents;
61  import com.vaadin.server.StreamResource;
62  import com.vaadin.ui.Button;
63  import com.vaadin.ui.Component;
64  import com.vaadin.ui.CssLayout;
65  import com.vaadin.ui.Image;
66  import com.vaadin.ui.UI;
67  import com.vaadin.ui.Window;
68  
69  /**
70   * Upload field for media editing features for an uploaded asset.
71   */
72  public class DamUploadField extends UploadField {
73      private static final Logger log = LoggerFactory.getLogger(DamUploadField.class);
74      private final DamUploadFieldDefinition definition;
75      private final MessagesManager messagesManager;
76      private final SimpleTranslator translator;
77      private final MediaEditorPresenterFactory mediaEditorFactory;
78  
79      private Button editUploadBtn;
80      private Button openLightboxViewBtn;
81  
82      public DamUploadField(TempFilesManager tempFilesManager,
83                            DamUploadFieldDefinition definition,
84                            MessagesManager messagesManager,
85                            SimpleTranslator translator,
86                            MediaEditorPresenterFactory mediaEditorFactory) {
87          super(tempFilesManager, definition, translator);
88          this.definition = definition;
89          this.messagesManager = messagesManager;
90          this.translator = translator;
91          this.mediaEditorFactory = mediaEditorFactory;
92      }
93  
94      @Override
95      protected Component initContent() {
96          return super.initContent();
97      }
98  
99      @Override
100     protected void additionalUploadButtons(CssLayout controlButtonPanel) {
101         editUploadBtn = createControlPanelButton(MagnoliaIcons.EDIT);
102         editUploadBtn.addClickListener(event -> openMediaEditor());
103         editUploadBtn.setDescription(translator.translate("dam.damUploadField.edit"));
104 
105         openLightboxViewBtn = createControlPanelButton(MagnoliaIcons.SEARCH);
106         openLightboxViewBtn.addClickListener(event -> openLightboxView());
107         openLightboxViewBtn.setDescription(translator.translate("dam.damUploadField.lightbox"));
108 
109         controlButtonPanel.addComponents(editUploadBtn, openLightboxViewBtn);
110     }
111 
112     void openMediaEditor() {
113         String mediaEditorId = definition.getMediaEditorId();
114         MediaEditorPresenter mediaEditorPresenter = mediaEditorFactory.getPresenterById(mediaEditorId);
115 
116         if (mediaEditorPresenter == null) {
117             Message message = new Message(MessageType.ERROR,
118                     translator.translate("dam.damUploadField.mediaeditor.edit.error.subject"),
119                     translator.translate("dam.damUploadField.mediaeditor.notfound.error.message", mediaEditorId));
120             messagesManager.sendLocalMessage(message);
121             log.warn("No Media Editor with id {} found", mediaEditorId);
122             return;
123         }
124 
125         try (FileInputStream inputStream = new FileInputStream(getValue())) {
126             UIComponent view = mediaEditorPresenter.start(inputStream);
127             Component component = view.asVaadinComponent();
128 
129             Window window = new Window();
130             window.setContent(component);
131             window.setCaption(component.getCaption());
132             window.center();
133             window.addStyleNames(component.getStyleName(), "dialog", "strong");
134             window.setDraggable(false);
135             window.setResizable(false);
136 
137             mediaEditorPresenter.addCompletionHandler(new DamMediaEditorHandler(this, window::close, inputStream));
138 
139             UI.getCurrent().addWindow(window);
140 
141         } catch (IOException e) {
142             Message message = new Message(MessageType.ERROR,
143                     translator.translate("dam.damUploadField.mediaeditor.edit.error.subject"),
144                     translator.translate("dam.damUploadField.mediaeditor.edit.error.message"));
145 
146             messagesManager.sendLocalMessage(message);
147             log.warn(e.getMessage());
148         }
149     }
150 
151     void openLightboxView() {
152         try (ByteArrayInputStream inputStream = new ByteArrayInputStream(FileUtils.readFileToByteArray(getValue()))) {
153             StreamResource.StreamSource streamSource = () -> inputStream;
154             StreamResource streamResource = new StreamResource(streamSource, "");
155             getFileInfo().map(FileInfo::getMimeType).ifPresent(streamResource::setMIMEType);
156 
157             CssLayout imageComponent = new CssLayout(new Image("", streamResource));
158             imageComponent.setSizeFull();
159             imageComponent.setStyleName("light-box-content");
160 
161             Window window = new Window();
162             window.addStyleName("light-box");
163             window.setDraggable(false);
164             window.setResizable(false);
165             window.setModal(true);
166             window.setContent(imageComponent);
167             window.center();
168 
169             UI.getCurrent().addWindow(window);
170 
171             window.addClickListener((MouseEvents.ClickListener) event -> window.close());
172         } catch (IOException e) {
173             Message message = new Message(MessageType.ERROR,
174                     translator.translate("dam.damUploadField.lightbox.error.subject"),
175                     translator.translate("dam.damUploadField.lightbox.error.message"));
176 
177             messagesManager.sendLocalMessage(message);
178             log.warn(e.getMessage());
179         }
180     }
181 
182     @Override
183     public void updateControlVisibilities() {
184         super.updateControlVisibilities();
185 
186         boolean isEditUploadBtnVisible = getFileInfo()
187                 .map(fileInfo -> fileInfo.getMimeType().matches(definition.getMediaEditorSupportedMimeTypes()))
188                 .orElse(false);
189 
190         editUploadBtn.setVisible(isEditUploadBtnVisible);
191         openLightboxViewBtn.setVisible(isEditUploadBtnVisible);
192     }
193 
194     Button getEditUploadBtn() {
195         return editUploadBtn;
196     }
197 
198     Button getOpenLightboxViewBtn() {
199         return openLightboxViewBtn;
200     }
201 
202     /**
203      * Handles events related to media editor configured for the assets app.
204      */
205     static class DamMediaEditorHandler implements MediaEditorCompletedEvent.Handler {
206         private final DamUploadField damUploadField;
207         private final CloseHandler closeHandler;
208         private final InputStream inputStream;
209 
210         DamMediaEditorHandler(DamUploadField damUploadField,
211                               CloseHandler closeHandler,
212                               InputStream inputStream) {
213             this.damUploadField = damUploadField;
214             this.closeHandler = closeHandler;
215             this.inputStream = inputStream;
216         }
217 
218         @Override
219         public void onSubmit(MediaEditorCompletedEvent event) {
220             Exceptions.wrap().run(() -> {
221                 String fileName = damUploadField.getValue().getCanonicalFile().getName();
222                 File file = damUploadField.getTempFilesManager().createTempFile(fileName);
223                 FileUtils.copyInputStreamToFile(event.getStream(), file);
224                 damUploadField.doSetValue(file);
225                 damUploadField.updateControlVisibilities();
226                 damUploadField.fireEvent(damUploadField.createValueChange(null, false));
227                 closeHandler.close();
228                 inputStream.close();
229             });
230         }
231 
232         @Override
233         public void onCancel(MediaEditorCompletedEvent event) {
234             closeHandler.close();
235             Exceptions.wrap().run(inputStream::close);
236         }
237     }
238 }