View Javadoc
1   /**
2    * This file Copyright (c) 2012-2018 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.pages.app.editor;
35  
36  import info.magnolia.event.EventBus;
37  import info.magnolia.i18nsystem.SimpleTranslator;
38  import info.magnolia.pages.app.editor.event.ComponentMoveEvent;
39  import info.magnolia.pages.app.editor.event.NodeSelectedEvent;
40  import info.magnolia.pages.app.editor.parameters.PageEditorStatus;
41  import info.magnolia.ui.api.action.ActionExecutionException;
42  import info.magnolia.ui.api.action.ActionExecutor;
43  import info.magnolia.ui.api.app.SubAppContext;
44  import info.magnolia.ui.api.app.SubAppEventBus;
45  import info.magnolia.ui.api.ioc.SubAppScoped;
46  import info.magnolia.ui.api.message.Message;
47  import info.magnolia.ui.api.message.MessageType;
48  import info.magnolia.ui.contentapp.detail.DetailLocation;
49  import info.magnolia.ui.vaadin.editor.PageEditorListener;
50  import info.magnolia.ui.vaadin.editor.PageEditorView;
51  import info.magnolia.ui.vaadin.editor.events.PageEditorNavigationEvent;
52  import info.magnolia.ui.vaadin.gwt.client.shared.AbstractElement;
53  import info.magnolia.ui.vaadin.gwt.client.shared.ErrorType;
54  import info.magnolia.ui.vaadin.gwt.client.shared.PageEditorParameters;
55  import info.magnolia.ui.vaadin.overlay.MessageStyleTypeEnum;
56  
57  import java.util.Arrays;
58  import java.util.function.Function;
59  import java.util.stream.Collectors;
60  
61  import javax.inject.Inject;
62  import javax.inject.Named;
63  
64  import org.slf4j.Logger;
65  import org.slf4j.LoggerFactory;
66  
67  import com.google.common.base.CaseFormat;
68  
69  /**
70   * Presenter for the server side {@link PageEditorView}.
71   * Serves multiple methods for actions triggered from the page editor.
72   */
73  @SubAppScoped
74  public class PageEditorPresenter implements PageEditorListener {
75  
76      private static final Logger log = LoggerFactory.getLogger(PageEditorPresenter.class);
77      private static final String EXTERNAL_PAGE_CAPTION = "pages.edit.external.page.caption";
78      private static final String[] AREAS_I18N_KEYS = {"pages.areas.maxComponentsReached", "pages.areas.newComponent", "pages.areas.newLabelComponent"};
79  
80      private final ActionExecutor actionExecutor;
81      private final PageEditorView view;
82      private final EventBus subAppEventBus;
83      private final SubAppContext subAppContext;
84      private final SimpleTranslator i18n;
85      private final PageEditorStatus pageEditorStatus;
86  
87      private boolean moving = false;
88      private Listener listener;
89  
90      @Inject
91      public PageEditorPresenter(final ActionExecutor actionExecutor, PageEditorView view, final @Named(SubAppEventBus.NAME) EventBus subAppEventBus,
92              SubAppContext subAppContext, SimpleTranslator i18n, PageEditorStatus pageEditorStatus) {
93          this.actionExecutor = actionExecutor;
94          this.view = view;
95          this.subAppEventBus = subAppEventBus;
96          this.subAppContext = subAppContext;
97          this.i18n = i18n;
98          this.pageEditorStatus = pageEditorStatus;
99          registerHandlers();
100     }
101 
102     public PageEditorView start(DetailLocation location) {
103         view.setListener(this);
104         pageEditorStatus.setI18nKeys(Arrays.stream(AREAS_I18N_KEYS).collect(Collectors.toMap(Function.identity(), i18n::translate)));
105         pageEditorStatus.updateStatusFromLocation(location);
106         loadPageEditor();
107         return view;
108     }
109 
110     public void reload(DetailLocation location) {
111         pageEditorStatus.updateStatusFromLocation(location);
112         loadPageEditor();
113     }
114 
115     private void registerHandlers() {
116         subAppEventBus.addHandler(ComponentMoveEvent.class, event -> {
117             moving = event.isStart();
118             if (moving) {
119                 view.startMoveComponent();
120             } else if (event.isServerSide()) {
121                 view.cancelMoveComponent();
122             }
123             listener.onMove();
124         });
125 
126     }
127 
128     @Override
129     public void onElementSelect(AbstractElement selectedElement) {
130         getStatus().setSelectedElement(selectedElement);
131         updateParameters();
132         subAppEventBus.fireEvent(new NodeSelectedEvent(selectedElement));
133     }
134 
135     @Override
136     public void onExternalPageSelect() {
137         listener.updateCaptionForExternalPage(i18n.translate(EXTERNAL_PAGE_CAPTION));
138         listener.deactivateComponents();
139     }
140 
141     /**
142      * Used for executing actions from 'client-side'. These might have a {@link AbstractElement} as part of the arguments, but don't have to.
143      * See {@link info.magnolia.ui.vaadin.gwt.client.rpc.PageEditorServerRpc} which receives the calls from 'client-side'.
144      *
145      * @see PagesEditorSubApp#prepareAndExecutePagesEditorAction(String) for 'server-side' action execution as comparison.
146      */
147     @Override
148     public void onError(ErrorType errorType, String... parameters) {
149         if (errorType == null) {
150             throw new IllegalArgumentException("ErrorType must be one of ErrorType.values().");
151         }
152 
153         String key = String.format("pages.templateErrorAlert.%s.message", CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, errorType.name()));
154         String message = i18n.translate(key, parameters);
155         subAppContext.openAlert(MessageStyleTypeEnum.WARNING, i18n.translate("pages.templateErrorAlert.title"), message, i18n.translate("button.ok"), () -> {
156             // Do nothing.
157         });
158     }
159 
160     @Override
161     public void onNavigation(String url) {
162         subAppEventBus.fireEvent(new PageEditorNavigationEvent(url));
163     }
164 
165     /**
166      * Used for executing actions from 'client-side'. These might have a {@link AbstractElement} as part of the arguments, but don't have to.
167      * See {@link info.magnolia.ui.vaadin.gwt.client.rpc.PageEditorServerRpc} which receives the calls from 'client-side'.
168      *
169      * @see PagesEditorSubApp#prepareAndExecutePagesEditorAction(String) for 'server-side' action execution as comparison.
170      */
171     @Override
172     public void onAction(String actionName, Object... args) {
173         try {
174             actionExecutor.execute(actionName, args);
175         } catch (ActionExecutionException e) {
176             Message error = new Message(MessageType.ERROR, i18n.translate("pages.pageEditorPresenter.actionExecutionError.message"), e.getMessage());
177             log.error("An error occurred while executing action [{}]", actionName, e);
178             subAppContext.getAppContext().sendLocalMessage(error);
179         }
180     }
181 
182     public AbstractElement getSelectedElement() {
183         return pageEditorStatus.getSelectedElement();
184     }
185 
186     public void loadPageEditor() {
187         PageEditorParameters pageEditorParameters = pageEditorStatus.getParameters();
188         view.load(pageEditorParameters);
189     }
190 
191     public void updateParameters() {
192         PageEditorParameters pageEditorParameters = pageEditorStatus.getParameters();
193         view.update(pageEditorParameters);
194     }
195 
196     public void refresh() {
197         view.refresh();
198     }
199 
200     public boolean isMoving() {
201         return moving;
202     }
203 
204     public void setListener(Listener listener) {
205         this.listener = listener;
206     }
207 
208     public PageEditorStatus getStatus() {
209         return pageEditorStatus;
210     }
211 
212     /**
213      * Listener interface to call {@link PageEditorPresenter}.
214      */
215     interface Listener {
216         void onMove();
217 
218         void updateCaptionForExternalPage(String title);
219 
220         void deactivateComponents();
221     }
222 }