View Javadoc

1   /**
2    * This file Copyright (c) 2012-2014 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.ui.contentapp.detail;
35  
36  import info.magnolia.event.EventBus;
37  import info.magnolia.i18nsystem.SimpleTranslator;
38  import info.magnolia.ui.api.app.SubAppContext;
39  import info.magnolia.ui.api.event.AdmincentralEventBus;
40  import info.magnolia.ui.api.event.ContentChangedEvent;
41  import info.magnolia.ui.api.location.Location;
42  import info.magnolia.ui.api.view.View;
43  import info.magnolia.ui.contentapp.ContentSubAppView;
44  import info.magnolia.ui.framework.app.BaseSubApp;
45  import info.magnolia.ui.vaadin.integration.contentconnector.ContentConnector;
46  
47  import javax.inject.Inject;
48  import javax.inject.Named;
49  
50  import org.apache.commons.lang3.StringUtils;
51  import org.slf4j.Logger;
52  import org.slf4j.LoggerFactory;
53  
54  /**
55   * Base implementation of an item subApp. Provides sensible implementation for
56   * services shared by all item subApps. Implementers of this class represent a
57   * tab for viewing and editing items typically opened from an {@link info.magnolia.ui.contentapp.browser.BrowserSubApp}. Subclasses can
58   * augment the default behavior and perform additional tasks by overriding the
59   * following methods:
60   * <ul>
61   * <li>{@link #onSubAppStart()}
62   * <li>{@link #locationChanged(Location)}
63   * </ul>
64   * Currently lacking listeners for {@link info.magnolia.ui.api.event.ContentChangedEvent}. Currently
65   * lacking handling of locationChanged. Related to MGNLUI-154
66   *
67   * @see DetailEditorPresenter
68   * @see info.magnolia.ui.contentapp.ContentSubAppView
69   * @see DetailLocation
70   */
71  public class DetailSubApp extends BaseSubApp<ContentSubAppView> {
72  
73      private static final Logger log = LoggerFactory.getLogger(DetailSubApp.class);
74  
75      private final DetailEditorPresenter presenter;
76      private final EventBus adminCentralEventBus;
77      private final SimpleTranslator i18n;
78  
79      private Object itemId;
80  
81      private String caption;
82  
83      private ContentConnector contentConnector;
84  
85      @Inject
86      protected DetailSubApp(final SubAppContext subAppContext, final ContentSubAppView view, @Named(AdmincentralEventBus.NAME) EventBus adminCentralEventBus,
87              DetailEditorPresenter presenter, SimpleTranslator i18n, ContentConnector contentConnector) {
88          super(subAppContext, view);
89  
90          this.adminCentralEventBus = adminCentralEventBus;
91          this.presenter = presenter;
92          this.i18n = i18n;
93          this.contentConnector = contentConnector;
94          bindHandlers();
95      }
96  
97      /**
98       * Performs some routine tasks needed by all item subApps before the view is displayed.
99       * The tasks are:
100      * <ul>
101      * <li>setting the current location
102      * <li>setting the presenter's view
103      * <li>calling {@link #onSubAppStart()} a hook-up method subclasses can override to perform additional work.
104      * </ul>
105      */
106     @Override
107     public ContentSubAppView start(final Location location) {
108         DetailLocation detailLocation = DetailLocation.wrap(location);
109         super.start(detailLocation);
110         // set caption
111         setCaption(detailLocation);
112         this.itemId = contentConnector.getItemIdByUrlFragment(detailLocation.getNodePath());
113 
114         View view;
115         if (detailLocation.hasVersion()) {
116             view = presenter.start(detailLocation.getNodePath(), detailLocation.getViewType(), contentConnector, detailLocation.getVersion());
117         } else {
118             view = presenter.start(detailLocation.getNodePath(), detailLocation.getViewType(), contentConnector);
119         }
120         getView().setContentView(view);
121         return getView();
122     }
123 
124     /**
125      * Wraps the current DefaultLocation in a ItemLocation. Providing getter and setters for used parameters.
126      */
127     @Override
128     public DetailLocation getCurrentLocation() {
129         return DetailLocation.wrap(super.getCurrentLocation());
130     }
131 
132     @Override
133     public boolean supportsLocation(Location location) {
134         DetailLocation itemLocation = DetailLocation.wrap(location);
135         String currentPath = getCurrentLocation().getNodePath();
136         return currentPath.equals(itemLocation.getNodePath());
137     }
138 
139     /**
140      * On location change, reload the view and tab caption.
141      */
142     @Override
143     public void locationChanged(Location location) {
144         DetailLocation detailLocation = DetailLocation.wrap(location);
145         if (!detailLocation.equals(getCurrentLocation())) {
146             setCaption(detailLocation);
147             View view = presenter.update(detailLocation);
148             getView().setContentView(view);
149         }
150     }
151 
152     @Override
153     public String getCaption() {
154         return caption;
155     }
156 
157     private void bindHandlers() {
158         adminCentralEventBus.addHandler(ContentChangedEvent.class, new ContentChangedEvent.Handler() {
159 
160             @Override
161             public void onContentChanged(ContentChangedEvent event) {
162                 // See if workspaces match
163                 if (contentConnector.canHandleItem(event.getItemId())) {
164                     // New item
165                     if (itemId == null) {
166                         // Check if parent is still existing, close supApp if it doesn't
167                         String currentNodePath = getCurrentLocation().getNodePath();
168 
169                         // resolve parent, removing trailing slash except for root
170                         int splitIndex = currentNodePath.lastIndexOf("/");
171                         if (splitIndex == 0) {
172                             splitIndex = 1;
173                         }
174                         String parentNodePath = currentNodePath.substring(0, splitIndex);
175                         Object parentItemId = contentConnector.getItemIdByUrlFragment(parentNodePath);
176                         if (!contentConnector.canHandleItem(parentItemId)) {
177                             getSubAppContext().close();
178                         }
179                         // Editing existing item
180                     } else {
181                         // Item (or parent) was deleted: close subApp
182                         if (!contentConnector.canHandleItem(itemId)) {
183                             getSubAppContext().close();
184                         }
185                         // Item still exists: update location if necessary
186                         else {
187                             String currentNodePath = getCurrentLocation().getNodePath();
188                             String itemPath = contentConnector.getItemUrlFragment(itemId);
189                             if (!currentNodePath.equals(itemPath)) {
190                                 DetailLocation location = DetailLocation.wrap(getSubAppContext().getLocation());
191                                 location.updateNodePath(itemPath);
192                                 // Update location
193                                 getSubAppContext().setLocation(location);
194                                 // Update Caption
195                                 setCaption(location);
196                             }
197                         }
198                     }
199                 }
200             }
201         });
202     }
203 
204     /**
205      * Set the Tab caption.
206      * If a version is part of the {@link DetailLocation}, add this version information to the Tab caption.
207      */
208     protected void setCaption(DetailLocation location) {
209         String caption = getBaseCaption(location);
210         // Set version information
211         if (StringUtils.isNotBlank(location.getVersion())) {
212             caption = i18n.translate("subapp.versioned_page", caption, location.getVersion() );
213         }
214         this.caption = caption;
215     }
216 
217     /**
218      * Create the base caption string.
219      * Default is the item path.
220      */
221     protected String getBaseCaption(DetailLocation location) {
222         return location.getNodePath();
223     }
224 
225 }